code-context-control 2.129.0__py3-none-any.whl → 2.129.1__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 +1 -1
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/METADATA +1 -1
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/RECORD +8 -8
- services/watcher.py +75 -11
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/WHEEL +0 -0
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/entry_points.txt +0 -0
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/licenses/LICENSE +0 -0
- {code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/top_level.txt +0 -0
cli/c3.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.129.
|
|
3
|
+
Version: 2.129.1
|
|
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=gAcd2dS9nVmnUocSv3YvLnaPJnhOJiuYdwSHp-1mXxg,22598
|
|
3
3
|
cli/_shell_writes.py,sha256=XzUNlUDljmg-wZxK03xHnRe36WeQxe4tpO9HKVFwP5o,5090
|
|
4
|
-
cli/c3.py,sha256=
|
|
4
|
+
cli/c3.py,sha256=lUfUuoifk0fH9_mmbK1GnQ4z9Inv4QywMC2Waocxsk8,419777
|
|
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=ba8-un6G9Ap8HCzx7nyhVq3c_G4sOtiVXRy0BzzX8-Y,23349
|
|
@@ -125,7 +125,7 @@ cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE
|
|
|
125
125
|
cli/ui/components/settings.js,sha256=ATbAjBlVIwCNpxq7s191b49a_INQV38iwmySqtJLYwY,79066
|
|
126
126
|
cli/ui/components/sidebar.js,sha256=K2ym2kUgpbyG-EBA_wBIIiqQY8qTatsiBZwzseMWuIQ,9939
|
|
127
127
|
cli/ui/components/tasks.js,sha256=vyKQ3uwoppMwvdEaHlhWXW4oWcAisx4NveqzMhsYqHo,38438
|
|
128
|
-
code_context_control-2.129.
|
|
128
|
+
code_context_control-2.129.1.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
|
|
129
129
|
core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
|
|
130
130
|
core/codex_patch.py,sha256=CxvT_rQIwPNTRJZj9EHJmx0ZdOeSLxjiixuLI3Z7lPc,2107
|
|
131
131
|
core/config.py,sha256=YmkcZwedz_lfDM0ZuI_f4xpe98ixPLcSQFcTCHgRiRg,19206
|
|
@@ -286,7 +286,7 @@ services/tool_classifier.py,sha256=Fgvq0ZcpnCskwtO8a3YI1MiecPNnw6UbPyJQIUwgfiQ,6
|
|
|
286
286
|
services/transcript_index.py,sha256=VQhvgkSyLVEYamXi_YIbiIhBnd0mqFHZlWG2HQu_1EA,12144
|
|
287
287
|
services/validation_cache.py,sha256=skFYR7CkSGvFb2gq6dfxOnvjQzz5Boa3jJWT7UfaIhY,5587
|
|
288
288
|
services/vector_store.py,sha256=satc4MJanC1Wsu_iveMCUXG6K2fd0Ke87JSyy2BMikw,13041
|
|
289
|
-
services/watcher.py,sha256=
|
|
289
|
+
services/watcher.py,sha256=WF6aTIUFzg5B5KepuLyUwmx8WvbmhT9IeenzdK0df3U,10779
|
|
290
290
|
services/win_subprocess.py,sha256=nt8Uwc2PrqsRW3-jcViEsoKj56GudW8TV3CQwryx8y4,4271
|
|
291
291
|
services/bench/__init__.py,sha256=WLEJIWJeaUj6FnH2nDO1qWugJDKfOKeM6WvKLSreYjI,231
|
|
292
292
|
services/bench/map_eval.py,sha256=i0M3hBJQM9wXX4dMB_2LjVKoFtXzFUKapoqjGB_8tcE,43456
|
|
@@ -313,8 +313,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
|
|
|
313
313
|
tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
|
|
314
314
|
tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
|
|
315
315
|
tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
|
|
316
|
-
code_context_control-2.129.
|
|
317
|
-
code_context_control-2.129.
|
|
318
|
-
code_context_control-2.129.
|
|
319
|
-
code_context_control-2.129.
|
|
320
|
-
code_context_control-2.129.
|
|
316
|
+
code_context_control-2.129.1.dist-info/METADATA,sha256=U-XNbatMHRQ60Wd54ZPtUY-Qt_WrwnxXJ9ldnr6GalA,28116
|
|
317
|
+
code_context_control-2.129.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
318
|
+
code_context_control-2.129.1.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
|
|
319
|
+
code_context_control-2.129.1.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
|
|
320
|
+
code_context_control-2.129.1.dist-info/RECORD,,
|
services/watcher.py
CHANGED
|
@@ -7,6 +7,7 @@ Watches project files for changes and tracks modifications:
|
|
|
7
7
|
- Accumulates changes for session logging
|
|
8
8
|
- Triggers index rebuild when enough changes accumulate
|
|
9
9
|
"""
|
|
10
|
+
import os
|
|
10
11
|
import threading
|
|
11
12
|
from datetime import datetime, timezone
|
|
12
13
|
from pathlib import Path
|
|
@@ -14,6 +15,8 @@ from pathlib import Path
|
|
|
14
15
|
from watchdog.events import FileSystemEventHandler
|
|
15
16
|
from watchdog.observers import Observer
|
|
16
17
|
|
|
18
|
+
from services.scanner import SKIP_DIRS, is_nested_checkout, make_dir_pruner
|
|
19
|
+
|
|
17
20
|
# Extensions to watch
|
|
18
21
|
CODE_EXTENSIONS = {
|
|
19
22
|
'.py', '.js', '.ts', '.tsx', '.jsx', '.r', '.R',
|
|
@@ -21,32 +24,93 @@ CODE_EXTENSIONS = {
|
|
|
21
24
|
'.sh', '.sql', '.go', '.rs', '.java', '.cpp', '.c', '.h',
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'env', '.venv', 'dist', 'build', '.next', '.cache',
|
|
28
|
-
'coverage', '.pytest_cache',
|
|
29
|
-
}
|
|
27
|
+
# SKIP_DIRS is re-exported from services.scanner: the watcher and the index
|
|
28
|
+
# walker must agree on what is not part of the project (see _ChangeHandler).
|
|
29
|
+
__all__ = ['CODE_EXTENSIONS', 'SKIP_DIRS', 'CodeWatcher']
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class _ChangeHandler(FileSystemEventHandler):
|
|
33
|
-
"""Collects file change events.
|
|
33
|
+
"""Collects file change events.
|
|
34
|
+
|
|
35
|
+
The filter is the index scanner's, not a private one. A change only
|
|
36
|
+
counts when the file could be IN the index: the same directory pruning
|
|
37
|
+
as ``scanner.iter_files`` (SKIP_DIRS, the root .gitignore's directory
|
|
38
|
+
entries, nested checkouts such as linked worktrees), then the
|
|
39
|
+
sub-project excluder, then the extension allowlist.
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
Before 2.129.1 the watcher kept its own shorter skip list and ignored
|
|
42
|
+
.gitignore and worktrees, so state files a daemon rewrites every few
|
|
43
|
+
seconds under a gitignored ``logs/`` counted as source changes. On one
|
|
44
|
+
project that tripped IndexStalenessAgent's rebuild threshold (15) every
|
|
45
|
+
single minute — the "Index auto-rebuilt" notification reached a count of
|
|
46
|
+
75,968 — and each refresh burst left the MCP server's process heap with
|
|
47
|
+
more pinned 16 MB segments it never gave back: 28 GB of commit charge
|
|
48
|
+
per server with under 1 GB touched, three servers on the project, and
|
|
49
|
+
the C3 Hub dying of MemoryError when the box ran out of commit.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, excluder=None, root=None):
|
|
36
53
|
super().__init__()
|
|
37
54
|
self._lock = threading.Lock()
|
|
38
55
|
self._changes = []
|
|
39
56
|
self._excluder = excluder # sub-project folders tracked by their own .c3
|
|
57
|
+
self._root = Path(root) if root else None
|
|
58
|
+
self._pruned = make_dir_pruner(root) if root else (lambda d: d in SKIP_DIRS)
|
|
59
|
+
# dir path -> is another checkout; one stat per directory, not per event
|
|
60
|
+
self._checkout_cache: dict = {}
|
|
61
|
+
|
|
62
|
+
def _reload_pruner(self):
|
|
63
|
+
"""Re-read the root .gitignore (called when it changes)."""
|
|
64
|
+
if self._root is not None:
|
|
65
|
+
self._pruned = make_dir_pruner(self._root)
|
|
66
|
+
|
|
67
|
+
def _rel_parts(self, p: Path) -> tuple:
|
|
68
|
+
if self._root is None:
|
|
69
|
+
return p.parts
|
|
70
|
+
try:
|
|
71
|
+
return p.relative_to(self._root).parts
|
|
72
|
+
except ValueError:
|
|
73
|
+
try:
|
|
74
|
+
return p.resolve().relative_to(self._root).parts
|
|
75
|
+
except (ValueError, OSError):
|
|
76
|
+
return p.parts
|
|
77
|
+
|
|
78
|
+
def _under_nested_checkout(self, rel_dirs: tuple) -> bool:
|
|
79
|
+
if self._root is None:
|
|
80
|
+
return False
|
|
81
|
+
cur = str(self._root)
|
|
82
|
+
for d in rel_dirs:
|
|
83
|
+
cur = os.path.join(cur, d)
|
|
84
|
+
hit = self._checkout_cache.get(cur)
|
|
85
|
+
if hit is None:
|
|
86
|
+
if len(self._checkout_cache) > 4096:
|
|
87
|
+
self._checkout_cache.clear()
|
|
88
|
+
hit = self._checkout_cache[cur] = is_nested_checkout(cur)
|
|
89
|
+
if hit:
|
|
90
|
+
return True
|
|
91
|
+
return False
|
|
40
92
|
|
|
41
93
|
def _should_track(self, path: str) -> bool:
|
|
42
94
|
p = Path(path)
|
|
43
|
-
if
|
|
95
|
+
if p.suffix.lower() not in CODE_EXTENSIONS:
|
|
96
|
+
return False
|
|
97
|
+
parts = self._rel_parts(p)
|
|
98
|
+
rel_dirs = parts[:-1]
|
|
99
|
+
if any(self._pruned(d) for d in rel_dirs):
|
|
100
|
+
return False
|
|
101
|
+
if self._under_nested_checkout(rel_dirs):
|
|
44
102
|
return False
|
|
45
103
|
if self._excluder is not None and self._excluder(path):
|
|
46
104
|
return False
|
|
47
|
-
return
|
|
105
|
+
return True
|
|
48
106
|
|
|
49
107
|
def _record(self, event_type: str, path: str):
|
|
108
|
+
if self._root is not None and Path(path).name == '.gitignore':
|
|
109
|
+
try:
|
|
110
|
+
if Path(path).parent.samefile(self._root):
|
|
111
|
+
self._reload_pruner()
|
|
112
|
+
except OSError:
|
|
113
|
+
pass
|
|
50
114
|
if not self._should_track(path):
|
|
51
115
|
return
|
|
52
116
|
with self._lock:
|
|
@@ -94,7 +158,7 @@ class CodeWatcher:
|
|
|
94
158
|
excluder = make_excluder(self.project_path)
|
|
95
159
|
except Exception:
|
|
96
160
|
excluder = None
|
|
97
|
-
self._handler = _ChangeHandler(excluder)
|
|
161
|
+
self._handler = _ChangeHandler(excluder, root=self.project_path)
|
|
98
162
|
self._observer = Observer()
|
|
99
163
|
self._observer.daemon = True
|
|
100
164
|
self._file_memory = None
|
|
File without changes
|
{code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{code_context_control-2.129.0.dist-info → code_context_control-2.129.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|