code-context-control 2.28.0__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/__init__.py +1 -0
- cli/_hook_utils.py +99 -0
- cli/c3.py +6152 -0
- cli/commands/__init__.py +1 -0
- cli/commands/common.py +312 -0
- cli/commands/parser.py +286 -0
- cli/docs.html +3178 -0
- cli/edits.html +878 -0
- cli/hook_auto_snapshot.py +142 -0
- cli/hook_c3_signal.py +61 -0
- cli/hook_c3read.py +116 -0
- cli/hook_edit_ledger.py +213 -0
- cli/hook_edit_unlock.py +170 -0
- cli/hook_filter.py +130 -0
- cli/hook_ghost_files.py +238 -0
- cli/hook_pretool_enforce.py +334 -0
- cli/hook_read.py +200 -0
- cli/hook_session_stats.py +62 -0
- cli/hook_terse_advisor.py +190 -0
- cli/hub.html +3764 -0
- cli/hub_server.py +1619 -0
- cli/mcp_proxy.py +428 -0
- cli/mcp_server.py +660 -0
- cli/server.py +2985 -0
- cli/tools/__init__.py +4 -0
- cli/tools/_helpers.py +65 -0
- cli/tools/agent.py +1165 -0
- cli/tools/compress.py +215 -0
- cli/tools/delegate.py +1184 -0
- cli/tools/edit.py +313 -0
- cli/tools/edits.py +118 -0
- cli/tools/filter.py +285 -0
- cli/tools/impact.py +163 -0
- cli/tools/memory.py +469 -0
- cli/tools/read.py +224 -0
- cli/tools/search.py +337 -0
- cli/tools/session.py +95 -0
- cli/tools/shell.py +193 -0
- cli/tools/status.py +306 -0
- cli/tools/validate.py +310 -0
- cli/ui/api.js +36 -0
- cli/ui/app.js +207 -0
- cli/ui/components/chat.js +758 -0
- cli/ui/components/dashboard.js +689 -0
- cli/ui/components/edits.js +220 -0
- cli/ui/components/instructions.js +481 -0
- cli/ui/components/memory.js +626 -0
- cli/ui/components/sessions.js +606 -0
- cli/ui/components/settings.js +1404 -0
- cli/ui/components/sidebar.js +156 -0
- cli/ui/icons.js +51 -0
- cli/ui/shared.js +119 -0
- cli/ui/theme.js +22 -0
- cli/ui.html +168 -0
- cli/ui_legacy.html +6797 -0
- cli/ui_nano.html +503 -0
- code_context_control-2.28.0.dist-info/METADATA +248 -0
- code_context_control-2.28.0.dist-info/RECORD +150 -0
- code_context_control-2.28.0.dist-info/WHEEL +5 -0
- code_context_control-2.28.0.dist-info/entry_points.txt +4 -0
- code_context_control-2.28.0.dist-info/licenses/LICENSE +201 -0
- code_context_control-2.28.0.dist-info/top_level.txt +5 -0
- core/__init__.py +75 -0
- core/config.py +269 -0
- core/ide.py +188 -0
- oracle/__init__.py +1 -0
- oracle/config.py +75 -0
- oracle/oracle.html +3900 -0
- oracle/oracle_server.py +663 -0
- oracle/services/__init__.py +1 -0
- oracle/services/c3_bridge.py +210 -0
- oracle/services/chat_engine.py +1103 -0
- oracle/services/chat_store.py +155 -0
- oracle/services/cross_memory.py +154 -0
- oracle/services/federated_graph.py +463 -0
- oracle/services/health_checker.py +117 -0
- oracle/services/insight_engine.py +307 -0
- oracle/services/memory_reader.py +106 -0
- oracle/services/memory_writer.py +182 -0
- oracle/services/ollama_bridge.py +332 -0
- oracle/services/project_scanner.py +87 -0
- oracle/services/review_agent.py +206 -0
- services/__init__.py +1 -0
- services/activity_log.py +93 -0
- services/agent_base.py +124 -0
- services/agents.py +1529 -0
- services/auto_memory.py +407 -0
- services/bench/__init__.py +6 -0
- services/bench/external/__init__.py +29 -0
- services/bench/external/aider_polyglot.py +405 -0
- services/bench/external/swe_bench.py +485 -0
- services/benchmark_dashboard.py +596 -0
- services/claude_md.py +785 -0
- services/compressor.py +592 -0
- services/context_snapshot.py +356 -0
- services/conversation_store.py +870 -0
- services/doc_index.py +537 -0
- services/e2e_benchmark.py +2884 -0
- services/e2e_evaluator.py +396 -0
- services/e2e_tasks.py +743 -0
- services/edit_ledger.py +459 -0
- services/embedding_index.py +341 -0
- services/error_reporting.py +123 -0
- services/file_memory.py +734 -0
- services/hub_service.py +585 -0
- services/indexer.py +712 -0
- services/memory.py +318 -0
- services/memory_consolidator.py +538 -0
- services/memory_graph.py +382 -0
- services/memory_grounder.py +304 -0
- services/memory_scorer.py +246 -0
- services/metrics.py +86 -0
- services/notifications.py +209 -0
- services/ollama_client.py +201 -0
- services/output_filter.py +488 -0
- services/parser.py +1238 -0
- services/project_manager.py +579 -0
- services/protocol.py +306 -0
- services/proxy_state.py +152 -0
- services/retrieval_broker.py +129 -0
- services/router.py +414 -0
- services/runtime.py +326 -0
- services/session_benchmark.py +1945 -0
- services/session_manager.py +1026 -0
- services/session_preloader.py +251 -0
- services/text_index.py +90 -0
- services/tool_classifier.py +176 -0
- services/transcript_index.py +340 -0
- services/validation_cache.py +155 -0
- services/vector_store.py +299 -0
- services/version_tracker.py +271 -0
- services/watcher.py +192 -0
- tui/__init__.py +0 -0
- tui/backend.py +59 -0
- tui/main.py +145 -0
- tui/screens/__init__.py +1 -0
- tui/screens/benchmark_view.py +109 -0
- tui/screens/claudemd_view.py +46 -0
- tui/screens/compress_view.py +52 -0
- tui/screens/index_view.py +74 -0
- tui/screens/init_view.py +82 -0
- tui/screens/mcp_view.py +73 -0
- tui/screens/optimize_view.py +41 -0
- tui/screens/pipe_view.py +46 -0
- tui/screens/projects_view.py +355 -0
- tui/screens/search_view.py +55 -0
- tui/screens/session_view.py +143 -0
- tui/screens/stats.py +158 -0
- tui/screens/ui_view.py +54 -0
- tui/theme.tcss +335 -0
cli/tools/compress.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""c3_compress — Token-efficient file summaries (6 modes: map, dense_map, smart, diff, bug_scan, ast).
|
|
2
|
+
Supports comma-separated paths for batch compression with parallel execution."""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from core import count_tokens
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _run_memory_mcp_cli(args: list, cwd: str, timeout: int = 30) -> tuple:
|
|
15
|
+
"""Run codebase-memory-mcp CLI and return (success, output_or_error)."""
|
|
16
|
+
binary = shutil.which("codebase-memory-mcp")
|
|
17
|
+
if not binary:
|
|
18
|
+
return False, "not_installed"
|
|
19
|
+
kwargs: dict = {}
|
|
20
|
+
if sys.platform == "win32":
|
|
21
|
+
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
|
|
22
|
+
try:
|
|
23
|
+
result = subprocess.run(
|
|
24
|
+
[binary] + args,
|
|
25
|
+
capture_output=True, text=True, timeout=timeout,
|
|
26
|
+
stdin=subprocess.DEVNULL, cwd=cwd, **kwargs,
|
|
27
|
+
)
|
|
28
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
29
|
+
return True, result.stdout.strip()
|
|
30
|
+
return False, result.stderr.strip() or f"exit {result.returncode}"
|
|
31
|
+
except subprocess.TimeoutExpired:
|
|
32
|
+
return False, "timeout"
|
|
33
|
+
except Exception as e:
|
|
34
|
+
return False, str(e)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _compress_ast(file_path: str, svc, finalize, maybe_facts) -> str:
|
|
38
|
+
"""Use codebase-memory-mcp binary for AST knowledge-graph structural analysis."""
|
|
39
|
+
cwd = str(svc.project_path)
|
|
40
|
+
ok, out = _run_memory_mcp_cli(["cli", "get_architecture"], cwd)
|
|
41
|
+
|
|
42
|
+
if not ok and out == "not_installed":
|
|
43
|
+
return finalize(
|
|
44
|
+
"c3_compress", {"file_path": file_path, "mode": "ast"},
|
|
45
|
+
"[compress:ast] codebase-memory-mcp not installed.\n"
|
|
46
|
+
"Install (macOS/Linux): curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash\n"
|
|
47
|
+
"Install (Windows): see https://github.com/DeusData/codebase-memory-mcp\n"
|
|
48
|
+
"Tip: use c3_compress(mode='map') for C3's built-in structural analysis.",
|
|
49
|
+
"not_installed",
|
|
50
|
+
)
|
|
51
|
+
if not ok:
|
|
52
|
+
hint = "Run: codebase-memory-mcp index" if not out or "not indexed" in out.lower() else out
|
|
53
|
+
return finalize(
|
|
54
|
+
"c3_compress", {"file_path": file_path, "mode": "ast"},
|
|
55
|
+
f"[compress:ast] {hint}\nTip: say 'Index this project' with codebase-memory-mcp active.",
|
|
56
|
+
"not_indexed",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
data = json.loads(out)
|
|
61
|
+
except json.JSONDecodeError:
|
|
62
|
+
return finalize("c3_compress", {"file_path": file_path, "mode": "ast"},
|
|
63
|
+
f"[compress:ast] Unexpected output — try: codebase-memory-mcp index\n{out[:200]}",
|
|
64
|
+
"error")
|
|
65
|
+
|
|
66
|
+
lines = ["[compress:ast] codebase-memory-mcp knowledge graph"]
|
|
67
|
+
if data.get("languages"):
|
|
68
|
+
lines.append(f"Languages: {', '.join(str(l) for l in data['languages'])}")
|
|
69
|
+
if data.get("entry_points"):
|
|
70
|
+
eps = [str(e) for e in data["entry_points"][:6]]
|
|
71
|
+
lines.append(f"Entry points: {', '.join(eps)}")
|
|
72
|
+
if data.get("packages"):
|
|
73
|
+
pkgs = [str(p) for p in data["packages"][:12]]
|
|
74
|
+
lines.append(f"Packages: {', '.join(pkgs)}")
|
|
75
|
+
if data.get("layers"):
|
|
76
|
+
layers = [str(l) for l in data["layers"][:8]]
|
|
77
|
+
lines.append(f"Layers: {', '.join(layers)}")
|
|
78
|
+
if data.get("hotspots"):
|
|
79
|
+
lines.append("Hotspots (high-churn):")
|
|
80
|
+
for h in data["hotspots"][:6]:
|
|
81
|
+
lines.append(f" {h}")
|
|
82
|
+
if data.get("clusters"):
|
|
83
|
+
lines.append(f"Clusters: {len(data['clusters'])} functional modules detected")
|
|
84
|
+
if data.get("routes"):
|
|
85
|
+
lines.append(f"Routes: {len(data['routes'])} HTTP endpoints")
|
|
86
|
+
|
|
87
|
+
return finalize("c3_compress", {"file_path": file_path, "mode": "ast"},
|
|
88
|
+
"\n".join(lines), "ast")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def handle_compress(file_path: str, mode: str, svc,
|
|
92
|
+
finalize, maybe_facts) -> str:
|
|
93
|
+
# Validate mode
|
|
94
|
+
valid_modes = ("map", "dense_map", "smart", "diff", "bug_scan", "ast")
|
|
95
|
+
if mode == "ast":
|
|
96
|
+
return _compress_ast(file_path, svc, finalize, maybe_facts)
|
|
97
|
+
if mode not in valid_modes:
|
|
98
|
+
# Graceful migration for removed modes
|
|
99
|
+
if mode in ("structure", "outline"):
|
|
100
|
+
mode = "map"
|
|
101
|
+
else:
|
|
102
|
+
return finalize("c3_compress", {"file_path": file_path, "mode": mode},
|
|
103
|
+
f"[compress:error] Unknown mode '{mode}'. Use: {', '.join(valid_modes)}",
|
|
104
|
+
"error")
|
|
105
|
+
|
|
106
|
+
# Batch dispatch: comma-separated paths
|
|
107
|
+
if "," in file_path:
|
|
108
|
+
paths = [p.strip() for p in file_path.split(",") if p.strip()]
|
|
109
|
+
return _compress_batch(paths, mode, svc, finalize, maybe_facts)
|
|
110
|
+
|
|
111
|
+
return _compress_single(file_path, mode, svc, finalize, maybe_facts)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> str:
|
|
115
|
+
"""Compress a single file."""
|
|
116
|
+
full = Path(svc.project_path) / file_path
|
|
117
|
+
if not full.exists():
|
|
118
|
+
full = Path(file_path)
|
|
119
|
+
|
|
120
|
+
if mode in ("map", "dense_map"):
|
|
121
|
+
if not full.exists():
|
|
122
|
+
return "[file_map:error] not found"
|
|
123
|
+
rel = str(full.resolve().relative_to(Path(svc.project_path).resolve())).replace("\\", "/")
|
|
124
|
+
queued = svc.file_memory.drain_queue()
|
|
125
|
+
completed = []
|
|
126
|
+
failed = []
|
|
127
|
+
for qp in queued[:10]:
|
|
128
|
+
try:
|
|
129
|
+
if svc.file_memory.update(qp):
|
|
130
|
+
completed.append(qp)
|
|
131
|
+
else:
|
|
132
|
+
failed.append(qp)
|
|
133
|
+
except Exception:
|
|
134
|
+
failed.append(qp)
|
|
135
|
+
if completed:
|
|
136
|
+
svc.file_memory.complete_updates(completed)
|
|
137
|
+
if failed:
|
|
138
|
+
svc.file_memory.complete_updates(failed, failed=True)
|
|
139
|
+
res = (svc.file_memory.get_or_build_dense_map(rel)
|
|
140
|
+
if mode == "dense_map"
|
|
141
|
+
else svc.file_memory.get_or_build_map(rel))
|
|
142
|
+
map_tokens = 0
|
|
143
|
+
try:
|
|
144
|
+
raw_tokens = count_tokens(full.read_text(encoding="utf-8", errors="replace"))
|
|
145
|
+
map_tokens = count_tokens(res)
|
|
146
|
+
summary = f"{raw_tokens}->{map_tokens}tok"
|
|
147
|
+
except Exception:
|
|
148
|
+
summary = "mapped"
|
|
149
|
+
return finalize("c3_compress", {"file_path": file_path, "mode": mode}, res, summary,
|
|
150
|
+
response_tokens=map_tokens)
|
|
151
|
+
|
|
152
|
+
res = svc.compressor.compress_file(str(full), mode)
|
|
153
|
+
if "error" in res:
|
|
154
|
+
return f"Error: {res['error']}"
|
|
155
|
+
resp = res['compressed']
|
|
156
|
+
summary = f"{res['original_tokens']}->{res['compressed_tokens']}tok"
|
|
157
|
+
return finalize("c3_compress", {"file_path": file_path},
|
|
158
|
+
resp + maybe_facts(svc, Path(file_path).name), summary)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _compress_batch(paths: list, mode: str, svc, finalize, maybe_facts) -> str:
|
|
162
|
+
"""Compress multiple files in parallel, return combined report."""
|
|
163
|
+
max_files = 10
|
|
164
|
+
paths = paths[:max_files]
|
|
165
|
+
|
|
166
|
+
results = {}
|
|
167
|
+
|
|
168
|
+
def _do_one(fp):
|
|
169
|
+
try:
|
|
170
|
+
full = Path(svc.project_path) / fp
|
|
171
|
+
if not full.exists():
|
|
172
|
+
full = Path(fp)
|
|
173
|
+
if not full.exists():
|
|
174
|
+
return fp, None, "not found"
|
|
175
|
+
|
|
176
|
+
if mode in ("map", "dense_map"):
|
|
177
|
+
rel = str(full.resolve().relative_to(
|
|
178
|
+
Path(svc.project_path).resolve())).replace("\\", "/")
|
|
179
|
+
res = (svc.file_memory.get_or_build_dense_map(rel)
|
|
180
|
+
if mode == "dense_map"
|
|
181
|
+
else svc.file_memory.get_or_build_map(rel))
|
|
182
|
+
try:
|
|
183
|
+
raw_tok = count_tokens(full.read_text(encoding="utf-8", errors="replace"))
|
|
184
|
+
map_tok = count_tokens(res)
|
|
185
|
+
return fp, res, f"{raw_tok}->{map_tok}tok"
|
|
186
|
+
except Exception:
|
|
187
|
+
return fp, res, "mapped"
|
|
188
|
+
else:
|
|
189
|
+
res = svc.compressor.compress_file(str(full), mode)
|
|
190
|
+
if "error" in res:
|
|
191
|
+
return fp, None, res["error"]
|
|
192
|
+
return fp, res["compressed"], f"{res['original_tokens']}->{res['compressed_tokens']}tok"
|
|
193
|
+
except Exception as e:
|
|
194
|
+
return fp, None, str(e)
|
|
195
|
+
|
|
196
|
+
with ThreadPoolExecutor(max_workers=min(len(paths), 8)) as pool:
|
|
197
|
+
futures = {pool.submit(_do_one, fp): fp for fp in paths}
|
|
198
|
+
for fut in as_completed(futures):
|
|
199
|
+
fp, compressed, summary = fut.result()
|
|
200
|
+
results[fp] = (compressed, summary)
|
|
201
|
+
|
|
202
|
+
parts = []
|
|
203
|
+
total_ok = 0
|
|
204
|
+
for fp in paths:
|
|
205
|
+
compressed, summary = results.get(fp, (None, "unknown"))
|
|
206
|
+
if compressed:
|
|
207
|
+
parts.append(f"## {fp} ({summary})\n{compressed}")
|
|
208
|
+
total_ok += 1
|
|
209
|
+
else:
|
|
210
|
+
parts.append(f"## {fp} — ERROR: {summary}")
|
|
211
|
+
|
|
212
|
+
header = f"[compress:batch] {total_ok}/{len(paths)} files ({mode})"
|
|
213
|
+
body = header + "\n\n" + "\n\n".join(parts)
|
|
214
|
+
return finalize("c3_compress", {"file_path": ",".join(paths), "mode": mode, "batch": True},
|
|
215
|
+
body, f"batch {total_ok}/{len(paths)}")
|