code-context-control 2.92.1__py3-none-any.whl → 2.92.3__py3-none-any.whl

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.
cli/c3.py CHANGED
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
92
92
  # Config
93
93
  CONFIG_DIR = ".c3"
94
94
  CONFIG_FILE = ".c3/config.json"
95
- __version__ = "2.92.1"
95
+ __version__ = "2.92.3"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.92.1
3
+ Version: 2.92.3
4
4
  Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -1,7 +1,7 @@
1
1
  cli/__init__.py,sha256=ec66drCZGNMRU4V6ov0zVhYZph1us12Vn8OvG_LJyRY,22
2
2
  cli/_hook_utils.py,sha256=lxYVHSqK4FTiFU2avXW2hbOheMbaaZhnAZqqwqtrZHI,20862
3
3
  cli/_shell_writes.py,sha256=XzUNlUDljmg-wZxK03xHnRe36WeQxe4tpO9HKVFwP5o,5090
4
- cli/c3.py,sha256=Hd_GSd1I139RbHO0raXWZajR4zuH1o79xtKzPkuRMn8,390431
4
+ cli/c3.py,sha256=_DNAo4tAgIsq8d-XPXELnqBk9bL03qQaXa-_u8A8gnU,390431
5
5
  cli/docs.html,sha256=X9M7qC7LWi8pPJNF-4yEM57jhuZ3WeTESECbdDOeNaA,143172
6
6
  cli/edits.html,sha256=UjAhoCmBmQ89cklGvJqzC6eyNP2tc8H6T-e01DVkLvE,43418
7
7
  cli/hook_access_guard.py,sha256=4SIX-A4-tlXcOpzV4k5PZvyXibRvw9buqAV1-_doJpg,17200
@@ -115,7 +115,7 @@ cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE
115
115
  cli/ui/components/settings.js,sha256=ATbAjBlVIwCNpxq7s191b49a_INQV38iwmySqtJLYwY,79066
116
116
  cli/ui/components/sidebar.js,sha256=K2ym2kUgpbyG-EBA_wBIIiqQY8qTatsiBZwzseMWuIQ,9939
117
117
  cli/ui/components/tasks.js,sha256=vyKQ3uwoppMwvdEaHlhWXW4oWcAisx4NveqzMhsYqHo,38438
118
- code_context_control-2.92.1.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
118
+ code_context_control-2.92.3.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
119
119
  core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
120
120
  core/config.py,sha256=YmkcZwedz_lfDM0ZuI_f4xpe98ixPLcSQFcTCHgRiRg,19206
121
121
  core/ide.py,sha256=V6VVMVsFdmmcsMyxikjQp7z9xa42CWiHKS-ya-MAcG4,6172
@@ -195,7 +195,7 @@ services/context_snapshot.py,sha256=2f_bxY3xX4ZC653ncYno8YSeSTFSavwBjrorytHA0Ns,
195
195
  services/conversation_store.py,sha256=-E2H6f9pMSOHiBjsq7tFUjrFAwWYExf7LJkibi5MRMA,35650
196
196
  services/cred_telemetry.py,sha256=LwDd4x0Mu6YXeDUrgICHnX9o1Ym_4hoouRp98qx0zlI,10926
197
197
  services/credential_store.py,sha256=3FURPyUCH1VK0yrst0RTuY72iRCdsWr9bJUdhSDqpA0,47118
198
- services/doc_index.py,sha256=ZEQD1kyGCAMm9AY4Kpi1zDWJTul-cAcAdi_4Md43Hpw,19205
198
+ services/doc_index.py,sha256=cIb1jk4GrKK7cLwD6phoc04TvKA7Ee94kKHXxB7tT_k,19223
199
199
  services/e2e_benchmark.py,sha256=5Z3rE42o08MKVbIX_769V0RX2yAzSVcApCvdAQ9YLAU,134988
200
200
  services/e2e_evaluator.py,sha256=FsB4vMzcFUcmicfIwRtA8JZ_XeMpuk2_-86F2iVNEDc,17783
201
201
  services/e2e_tasks.py,sha256=Ln5VbGDIcS3NY3aml5ERbgjfjLxEslmRZ8AyaYxpWEo,34524
@@ -206,7 +206,7 @@ services/error_reporting.py,sha256=HZ3ru8i5RLf8nq2R4iRnTs5sm1blUxknSbv5hdxuxs0,4
206
206
  services/file_memory.py,sha256=vUvgBBdFC_rvCp9GXfvfojQIr6iSHWTRFrzWG5e0kHs,35048
207
207
  services/git_context.py,sha256=FFdA8Y46op4DYsUnZsXLTqxIjgxb0q_d-hkFTbosC8Q,9518
208
208
  services/hub_service.py,sha256=z2MZ2Rg9NLNXxQ17e05XGF_f6qSTDWLYtoC3WpuQfGU,2634
209
- services/indexer.py,sha256=FDzj7RA-szly8fDDgGQ2t1-tk_CuUy4lOHOAfEjCQMY,31134
209
+ services/indexer.py,sha256=sODQ7kV1dmLAuMVJTnd9JpSaPJsq2eNPIqGziM9sr3g,32963
210
210
  services/jira_client.py,sha256=blh2LhjHrWL3OUHMS_ab7JguQqtBbx66m5UYZz7sbXQ,18935
211
211
  services/jira_cloud.py,sha256=vOMQxwEuPa-FcLgmch-to7feiPkGrXXjUf9mNgpV4VE,12656
212
212
  services/jira_credentials.py,sha256=QmODZa2ivZ1DwsxSpnmM1XhPxNBiTJCR1LrdCPh7Nuk,9124
@@ -236,7 +236,7 @@ services/override_wake.py,sha256=HjSOXQTDi0irgeMyrTqngL7xLcSOOIgYsVW9yxod4ps,103
236
236
  services/parser.py,sha256=txDjhUiz-qnFfXO3rn4IopnXZ_0iJtCNcDu32ywu9dA,57035
237
237
  services/project_manager.py,sha256=ext0eXRkAoUuGvhE7if9Vimue5q9Ihp82xMNzf-sh98,36657
238
238
  services/project_runtime.py,sha256=yyftX48BFjq4B2KcR4KGszDAAa4xR6gn6j0SgTyro1s,11603
239
- services/protocol.py,sha256=XyUGjTHD9Zouw94IEqwH667pQ1TlroleLzlM3GRlEGk,12843
239
+ services/protocol.py,sha256=CWZ0BWWd-jPui-11hZlvGgkNk18gMFhhLWbp-BP35Kk,12861
240
240
  services/proxy_state.py,sha256=u5rd0k6CrOsywZA8FpRu_hMLwhR0TAJhZjy5MdWbCGc,6107
241
241
  services/repo_map.py,sha256=QNNXObo9_9GmGCLz1qF5b246kv42VE19WviH7WlG1Ys,22921
242
242
  services/repo_shape.py,sha256=QF0mXkY-bnBU8Q8mc5iimw2YBhMgZ4IYhoPc09Z8OBQ,4978
@@ -244,7 +244,7 @@ services/retention.py,sha256=I2_RV233kWBBXox5rc_w-1h1aPua93o9huuPf-pJVuE,18629
244
244
  services/retrieval_broker.py,sha256=9X67VZ_6AkbAzopHuuMFKmP4CGZLnW576kjSKMenBnw,5261
245
245
  services/router.py,sha256=Cz10nx2fKTbaGn14mSBePWIDrw5rdcs_1JFYXeik084,15626
246
246
  services/runtime.py,sha256=b79gN0dFlzBO4rPaUMWier8FZFamMZlwIM3aywLmbB4,12840
247
- services/scanner.py,sha256=-DL8BQ4ncivJec7E7k8Hz_s6H3CfRSRs1GTls66kQ-M,9542
247
+ services/scanner.py,sha256=lH0aiDCdCRruKS-VTAD_LsF4zrhMLpMRhFlOZZlw4VM,9613
248
248
  services/session_benchmark.py,sha256=GX3H8OwKC0X9Kk5U-vfY6Y7qq9Qaz2HwadNA7mjO8RY,105047
249
249
  services/session_manager.py,sha256=nSZcemk34U4yxn3AvKnOuYrNfiIDRgE3s7FXTNYKG0A,52617
250
250
  services/session_preloader.py,sha256=DsTAXMKVtrX9yu1sEFojYDi9-jkSAj1Ylt9JTy57Dow,9883
@@ -262,7 +262,7 @@ services/win_subprocess.py,sha256=nt8Uwc2PrqsRW3-jcViEsoKj56GudW8TV3CQwryx8y4,42
262
262
  services/bench/__init__.py,sha256=WLEJIWJeaUj6FnH2nDO1qWugJDKfOKeM6WvKLSreYjI,231
263
263
  services/bench/external/__init__.py,sha256=XgPS99ztx9igMd6x-1bLykcaePGXctkb6ujQ1MLgKAs,608
264
264
  services/bench/external/aider_polyglot.py,sha256=VkkPaDW5TOd_-J7ApVAtik76p0uY2Cfm_2hcRRY1cWc,14502
265
- services/bench/external/swe_bench.py,sha256=wZs_9Gr0oT-AdcsOFyh7q3yVye1aj6nL7-l8vsiwRgk,18151
265
+ services/bench/external/swe_bench.py,sha256=AtyBERtHe0-WtFtnXZYAZtcoukBRDKObZFVTWeqYXl8,18212
266
266
  tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
267
267
  tui/backend.py,sha256=AzuE6DXVi2e_8TZ-Qpdc0CVv-pJL-2FcfLGHh8iUs-g,1473
268
268
  tui/main.py,sha256=qsIqY_Oxo1djRH4w-qvTpYSwvbqDJ-UyFyYrMwP9F7w,5770
@@ -281,8 +281,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
281
281
  tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
282
282
  tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
283
283
  tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
284
- code_context_control-2.92.1.dist-info/METADATA,sha256=V_un_RtzHoDGuOh8e7GfY-Ihc-wGrt9zoSOHyyU1mAg,26368
285
- code_context_control-2.92.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
286
- code_context_control-2.92.1.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
287
- code_context_control-2.92.1.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
288
- code_context_control-2.92.1.dist-info/RECORD,,
284
+ code_context_control-2.92.3.dist-info/METADATA,sha256=69oubv8g3Xd1SiRr5Dcqn5RFP_ot3WvUF1FucgTOwp4,26368
285
+ code_context_control-2.92.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
286
+ code_context_control-2.92.3.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
287
+ code_context_control-2.92.3.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
288
+ code_context_control-2.92.3.dist-info/RECORD,,
@@ -446,7 +446,9 @@ def evaluate_with_docker(
446
446
  "--timeout", str(timeout),
447
447
  ]
448
448
  try:
449
- subprocess.run(cmd, check=True, timeout=timeout * len(list(predictions_path.read_text().splitlines())))
449
+ n_predictions = len(
450
+ predictions_path.read_text(encoding="utf-8").splitlines())
451
+ subprocess.run(cmd, check=True, timeout=timeout * n_predictions)
450
452
  except Exception as e:
451
453
  return {"error": str(e)}
452
454
 
services/doc_index.py CHANGED
@@ -113,7 +113,7 @@ class DocIndex:
113
113
  except Exception:
114
114
  pass
115
115
  try:
116
- content = fpath.read_text(errors="replace")
116
+ content = fpath.read_text(encoding="utf-8", errors="replace")
117
117
  except Exception:
118
118
  continue
119
119
 
services/indexer.py CHANGED
@@ -30,13 +30,27 @@ def _masked_content(fpath, project_path):
30
30
  if v.denial:
31
31
  return None
32
32
  if not v.masked:
33
- return fpath.read_text(errors="replace")
33
+ return fpath.read_text(encoding="utf-8", errors="replace")
34
34
  try:
35
35
  return mask_mirror.render_for_path(fpath, project_path).text
36
36
  except Exception:
37
37
  return None
38
38
 
39
39
 
40
+ # Co-occurrence is O(unique_tokens^2) per chunk, so one minified vendor
41
+ # bundle can dominate a whole index build. Both bounds below are deliberate
42
+ # and their effect is REPORTED in build_index()'s stats rather than applied
43
+ # silently — a capped build must never look like a complete one.
44
+ #
45
+ # 200: chunks above this are minified/bundled/data blobs, not code. The
46
+ # pruning step keeps only the top-5 co-occurring terms per token with at
47
+ # least 3 hits, so such a chunk contributes noise that is discarded anyway.
48
+ _COOC_MAX_CHUNK_TOKENS = 200
49
+ # 20M: whole-pass ceiling on pair updates, so no repository shape can make
50
+ # this step unbounded. ~10s of CPU on the boxes this runs on.
51
+ _COOC_MAX_PAIR_UPDATES = 20_000_000
52
+
53
+
40
54
  class CodeIndex:
41
55
  """TF-IDF based code search index with structural awareness."""
42
56
 
@@ -187,7 +201,8 @@ class CodeIndex:
187
201
  # (docs/mask-guard.md §6, row 2). Skip it instead.
188
202
  continue
189
203
  else:
190
- content = fpath.read_text(errors='replace')
204
+ content = fpath.read_text(encoding='utf-8',
205
+ errors='replace')
191
206
  except Exception:
192
207
  continue
193
208
 
@@ -239,6 +254,7 @@ class CodeIndex:
239
254
  "entries_scanned": scan_stats["entries"],
240
255
  "files_capped": files_capped,
241
256
  "max_files": max_files,
257
+ "cooccurrence": getattr(self, "_cooccurrence_stats", {}),
242
258
  }
243
259
 
244
260
  def _chunk_file(self, content: str, ext: str, doc_id: str) -> list:
@@ -624,16 +640,39 @@ class CodeIndex:
624
640
  self.chunk_tfidf[chunk_id][term] = normalized_tf * self.idf.get(term, 0)
625
641
 
626
642
  def _build_cooccurrence(self):
627
- """Build lightweight co-occurrence map from indexed chunks for auto-synonyms."""
643
+ """Build lightweight co-occurrence map from indexed chunks for auto-synonyms.
644
+
645
+ Bounded on purpose: the pair loop is quadratic in a chunk's unique
646
+ token count, so a single minified bundle (798 unique tokens x 4091
647
+ chunks = 1.9e9 pair updates, measured on a real project) can hang a
648
+ build that has nothing else wrong with it. Skipped chunks and an
649
+ exhausted budget are recorded in ``self._cooccurrence_stats`` and
650
+ returned by :meth:`build_index`.
651
+ """
628
652
  self._cooccurrence = {}
653
+ skipped = 0
654
+ updates = 0
655
+ budget_hit = False
629
656
  for chunk in self.chunks.values():
630
657
  tokens = set(self._tokenize(chunk["content"]))
658
+ if len(tokens) > _COOC_MAX_CHUNK_TOKENS:
659
+ skipped += 1
660
+ continue
661
+ if updates + len(tokens) * (len(tokens) - 1) > _COOC_MAX_PAIR_UPDATES:
662
+ budget_hit = True
663
+ break
631
664
  for t in tokens:
632
665
  if t not in self._cooccurrence:
633
666
  self._cooccurrence[t] = Counter()
634
667
  for t2 in tokens:
635
668
  if t != t2:
636
669
  self._cooccurrence[t][t2] += 1
670
+ updates += len(tokens) * (len(tokens) - 1)
671
+ self._cooccurrence_stats = {
672
+ "chunks_skipped": skipped,
673
+ "pair_updates": updates,
674
+ "budget_exhausted": budget_hit,
675
+ }
637
676
  # Prune: keep only top-5 co-occurring terms per token (minimum 3 co-occurrences)
638
677
  pruned = {}
639
678
  for term, counts in self._cooccurrence.items():
services/protocol.py CHANGED
@@ -261,7 +261,7 @@ class CompressionProtocol:
261
261
  if _sub_excluded(fpath):
262
262
  continue
263
263
  try:
264
- content = fpath.read_text(errors='replace')
264
+ content = fpath.read_text(encoding='utf-8', errors='replace')
265
265
  except Exception:
266
266
  continue
267
267
  _accumulate(content)
services/scanner.py CHANGED
@@ -43,7 +43,8 @@ def gitignore_dir_patterns(root) -> tuple:
43
43
  names: set = set()
44
44
  patterns: list = []
45
45
  try:
46
- text = (Path(root) / '.gitignore').read_text(errors='replace')
46
+ text = (Path(root) / '.gitignore').read_text(encoding='utf-8',
47
+ errors='replace')
47
48
  except OSError:
48
49
  return names, patterns
49
50
  for line in text.splitlines():