code-context-control 2.33.0__py3-none-any.whl → 2.35.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/c3.py CHANGED
@@ -85,7 +85,7 @@ console = Console() if HAS_RICH else None
85
85
  # Config
86
86
  CONFIG_DIR = ".c3"
87
87
  CONFIG_FILE = ".c3/config.json"
88
- __version__ = "2.33.0"
88
+ __version__ = "2.35.0"
89
89
 
90
90
 
91
91
  def _command_deps() -> CommandDeps:
cli/hub_server.py CHANGED
@@ -180,46 +180,12 @@ def _project_mcp_config_path(project_root: Path, profile) -> Path:
180
180
  return (Path.home() / profile.config_path) if profile.config_path_global else (project_root / profile.config_path)
181
181
 
182
182
 
183
- def _parse_toml_mcp_servers(content: str) -> dict:
184
- servers = {}
185
- current_server = None
186
-
187
- for raw in content.splitlines():
188
- line = raw.split("#", 1)[0].strip()
189
- if not line:
190
- continue
191
-
192
- if line.startswith("[") and line.endswith("]"):
193
- section = line[1:-1].strip()
194
- if section.startswith("mcp_servers."):
195
- current_server = section.split(".", 1)[1]
196
- servers.setdefault(current_server, {})
197
- else:
198
- current_server = None
199
- continue
200
-
201
- if not current_server or "=" not in line:
202
- continue
203
-
204
- key, value = line.split("=", 1)
205
- key = key.strip().strip('"')
206
- value = value.strip()
207
-
208
- if key == "args":
209
- servers[current_server]["args"] = re.findall(r"[\"']([^\"']*)[\"']", value)
210
- elif key in ("command", "type"):
211
- match = re.match(r"^[\"'](.*)[\"']$", value)
212
- servers[current_server][key] = match.group(1) if match else value
213
- elif key == "enabled":
214
- low = value.lower()
215
- if low.startswith("true"):
216
- servers[current_server]["enabled"] = True
217
- elif low.startswith("false"):
218
- servers[current_server]["enabled"] = False
219
- else:
220
- servers[current_server][key] = value
221
-
222
- return servers
183
+ from core.mcp_toml import (
184
+ parse_toml_mcp_servers as _parse_toml_mcp_servers,
185
+ )
186
+ from core.mcp_toml import (
187
+ upsert_toml_section as _upsert_toml_section,
188
+ )
223
189
 
224
190
 
225
191
  def _read_project_mcp_servers_for_profile(profile, mcp_file: Path) -> tuple[dict, dict]:
@@ -238,73 +204,6 @@ def _read_project_mcp_servers_for_profile(profile, mcp_file: Path) -> tuple[dict
238
204
  return servers, raw_config
239
205
 
240
206
 
241
- def _toml_escape_str(value: str) -> str:
242
- return value.replace("\\", "/")
243
-
244
-
245
- def _upsert_toml_section(toml_path: Path, section: str, entries: dict) -> None:
246
- content = toml_path.read_text(encoding="utf-8") if toml_path.exists() else ""
247
- header = f"[{section}]"
248
-
249
- lines = content.splitlines()
250
- new_lines = []
251
- skip = False
252
- for line in lines:
253
- stripped = line.strip()
254
- if stripped == header:
255
- skip = True
256
- continue
257
- if skip and stripped.startswith("["):
258
- skip = False
259
- if not skip:
260
- new_lines.append(line)
261
-
262
- content = "\n".join(new_lines).rstrip()
263
- section_lines = [f"\n\n{header}"]
264
- for key, value in entries.items():
265
- if isinstance(value, list):
266
- items = ", ".join(f'"{_toml_escape_str(str(item))}"' for item in value)
267
- section_lines.append(f'{key} = [{items}]')
268
- elif isinstance(value, bool):
269
- section_lines.append(f'{key} = {"true" if value else "false"}')
270
- else:
271
- section_lines.append(f'{key} = "{_toml_escape_str(str(value))}"')
272
- section_lines.append("")
273
-
274
- toml_path.parent.mkdir(parents=True, exist_ok=True)
275
- toml_path.write_text(content + "\n".join(section_lines), encoding="utf-8")
276
-
277
-
278
- def _remove_toml_section(toml_path: Path, section: str) -> bool:
279
- if not toml_path.exists():
280
- return False
281
- content = toml_path.read_text(encoding="utf-8")
282
- header = f"[{section}]"
283
-
284
- lines = content.splitlines()
285
- new_lines = []
286
- skip = False
287
- removed = False
288
- for line in lines:
289
- stripped = line.strip()
290
- if stripped == header:
291
- skip = True
292
- removed = True
293
- continue
294
- if skip and stripped.startswith("["):
295
- skip = False
296
- if not skip:
297
- new_lines.append(line)
298
-
299
- if removed:
300
- remaining = "\n".join(new_lines).rstrip()
301
- if remaining:
302
- toml_path.write_text(remaining + "\n", encoding="utf-8")
303
- else:
304
- toml_path.unlink()
305
- return removed
306
-
307
-
308
207
  def _build_mcp_cli_capabilities() -> dict:
309
208
  return {
310
209
  "commands": [
cli/mcp_server.py CHANGED
@@ -604,9 +604,10 @@ async def c3_edit(file_path: str, old_string: str = "", new_string: str = "",
604
604
  async def c3_edits(action: str, file: str = "", change_type: str = "modified",
605
605
  summary: str = "", lines_changed: str = "", tags: str = "",
606
606
  limit: int = 50, since: str = "", edit_id: str = "",
607
- tag: str = "", ctx: Context = None) -> str:
607
+ tag: str = "", branch: str = "", ctx: Context = None) -> str:
608
608
  """EDIT HISTORY — inspect the ledger. Different from c3_edit (which writes); this one reads.
609
- actions: log (append entry), history (recent edits), versions (per-file), stats, tag (mark edit_id)."""
609
+ actions: log (append entry), history (recent edits), versions (per-file), stats, tag (mark edit_id).
610
+ branch: filter history to edits stamped with a given git branch."""
610
611
  svc = _svc(ctx)
611
612
 
612
613
  def finalize(name, args, resp, summ, **kw):
@@ -615,7 +616,7 @@ async def c3_edits(action: str, file: str = "", change_type: str = "modified",
615
616
  from cli.tools.edits import handle_edits
616
617
  return await asyncio.to_thread(handle_edits, action, file, change_type, summary,
617
618
  lines_changed, tags, limit, since, edit_id, tag,
618
- svc, finalize)
619
+ svc, finalize, branch)
619
620
 
620
621
 
621
622
  @mcp.tool()
cli/server.py CHANGED
@@ -10,7 +10,6 @@ import csv
10
10
  import json
11
11
  import logging
12
12
  import os
13
- import re
14
13
  import signal
15
14
  import subprocess
16
15
  import sys
@@ -174,6 +173,9 @@ atexit.register(_cleanup_runtime)
174
173
  from core.web_security import (
175
174
  allowed_hostnames as _allowed_hostnames,
176
175
  )
176
+ from core.web_security import (
177
+ guard_summary as _guard_summary,
178
+ )
177
179
  from core.web_security import (
178
180
  install_guard as _install_web_guard,
179
181
  )
@@ -376,7 +378,8 @@ def api_health():
376
378
  except Exception:
377
379
  pass
378
380
 
379
- return jsonify({"service": "c3-ui", "sources": sources, "session": session_info})
381
+ return jsonify({"service": "c3-ui", "sources": sources, "session": session_info,
382
+ "web_guard": _guard_summary()})
380
383
 
381
384
 
382
385
  # ─── API: Session Registry ───────────────────────────────
@@ -2421,47 +2424,15 @@ def api_proxy_tools():
2421
2424
 
2422
2425
 
2423
2426
  # ─── API: MCP Status ─────────────────────────────────────
2424
- def _parse_toml_mcp_servers(content: str) -> dict:
2425
- """Parse [mcp_servers.<name>] sections from TOML content."""
2426
- servers = {}
2427
- current_server = None
2428
-
2429
- for raw in content.splitlines():
2430
- line = raw.split("#", 1)[0].strip()
2431
- if not line:
2432
- continue
2433
-
2434
- if line.startswith("[") and line.endswith("]"):
2435
- section = line[1:-1].strip()
2436
- if section.startswith("mcp_servers."):
2437
- current_server = section.split(".", 1)[1]
2438
- servers.setdefault(current_server, {})
2439
- else:
2440
- current_server = None
2441
- continue
2442
-
2443
- if not current_server or "=" not in line:
2444
- continue
2445
-
2446
- key, value = line.split("=", 1)
2447
- key = key.strip()
2448
- value = value.strip()
2449
-
2450
- if key == "args":
2451
- servers[current_server]["args"] = re.findall(r"[\"']([^\"']*)[\"']", value)
2452
- elif key in ("command", "type"):
2453
- match = re.match(r"^[\"'](.*)[\"']$", value)
2454
- servers[current_server][key] = match.group(1) if match else value
2455
- elif key == "enabled":
2456
- low = value.lower()
2457
- if low.startswith("true"):
2458
- servers[current_server]["enabled"] = True
2459
- elif low.startswith("false"):
2460
- servers[current_server]["enabled"] = False
2461
- else:
2462
- servers[current_server][key] = value
2463
-
2464
- return servers
2427
+ from core.mcp_toml import (
2428
+ parse_toml_mcp_servers as _parse_toml_mcp_servers,
2429
+ )
2430
+ from core.mcp_toml import (
2431
+ remove_toml_section as _remove_toml_section,
2432
+ )
2433
+ from core.mcp_toml import (
2434
+ upsert_toml_section as _upsert_toml_section,
2435
+ )
2465
2436
 
2466
2437
 
2467
2438
  def _find_server_script(servers: dict) -> bool:
@@ -2474,71 +2445,6 @@ def _find_server_script(servers: dict) -> bool:
2474
2445
  return False
2475
2446
 
2476
2447
 
2477
- def _toml_escape_str(value: str) -> str:
2478
- return value.replace("\\", "/")
2479
-
2480
-
2481
- def _upsert_toml_section(toml_path: Path, section: str, entries: dict) -> None:
2482
- """Add or replace a dotted TOML section in-place."""
2483
- content = toml_path.read_text(encoding="utf-8") if toml_path.exists() else ""
2484
- header = f"[{section}]"
2485
-
2486
- lines = content.splitlines()
2487
- new_lines = []
2488
- skip = False
2489
- for line in lines:
2490
- stripped = line.strip()
2491
- if stripped == header:
2492
- skip = True
2493
- continue
2494
- if skip and stripped.startswith("["):
2495
- skip = False
2496
- if not skip:
2497
- new_lines.append(line)
2498
-
2499
- content = "\n".join(new_lines).rstrip()
2500
- section_lines = [f"\n\n{header}"]
2501
- for k, v in entries.items():
2502
- if isinstance(v, list):
2503
- items = ", ".join(f'"{_toml_escape_str(str(x))}"' for x in v)
2504
- section_lines.append(f'{k} = [{items}]')
2505
- elif isinstance(v, bool):
2506
- section_lines.append(f'{k} = {"true" if v else "false"}')
2507
- else:
2508
- section_lines.append(f'{k} = "{_toml_escape_str(str(v))}"')
2509
- section_lines.append("")
2510
-
2511
- toml_path.parent.mkdir(parents=True, exist_ok=True)
2512
- toml_path.write_text(content + "\n".join(section_lines), encoding="utf-8")
2513
-
2514
-
2515
- def _remove_toml_section(toml_path: Path, section: str) -> bool:
2516
- """Remove a dotted TOML section. Returns True if removed."""
2517
- if not toml_path.exists():
2518
- return False
2519
- content = toml_path.read_text(encoding="utf-8")
2520
- header = f"[{section}]"
2521
-
2522
- lines = content.splitlines()
2523
- new_lines = []
2524
- skip = False
2525
- removed = False
2526
- for line in lines:
2527
- stripped = line.strip()
2528
- if stripped == header:
2529
- skip = True
2530
- removed = True
2531
- continue
2532
- if skip and stripped.startswith("["):
2533
- skip = False
2534
- if not skip:
2535
- new_lines.append(line)
2536
-
2537
- if removed:
2538
- toml_path.write_text("\n".join(new_lines).rstrip() + "\n", encoding="utf-8")
2539
- return removed
2540
-
2541
-
2542
2448
  def _resolve_mcp_profile(ide_name: str | None):
2543
2449
  requested = (ide_name or "").strip().lower()
2544
2450
  if requested and requested != "auto":
cli/tools/edits.py CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  def handle_edits(action: str, file: str, change_type: str, summary: str,
5
5
  lines_changed: str, tags: str, limit: int, since: str,
6
- edit_id: str, tag: str, svc, finalize) -> str:
6
+ edit_id: str, tag: str, svc, finalize, branch: str = "") -> str:
7
7
  """Route c3_edits actions."""
8
8
  ledger = svc.edit_ledger
9
9
  if ledger is None:
@@ -64,12 +64,17 @@ def handle_edits(action: str, file: str, change_type: str, summary: str,
64
64
  file=file or None,
65
65
  limit=limit or 50,
66
66
  since=since or None,
67
+ branch=branch or None,
67
68
  )
68
69
  if not entries:
69
70
  return finalize("c3_edits", {"action": "history"}, "No edits found", "0 edits")
70
- lines = [f"[edits:history] {len(entries)} entries" + (f" for {file}" if file else "")]
71
+ scope = (f" for {file}" if file else "") + (f" on {branch}" if branch else "")
72
+ lines = [f"[edits:history] {len(entries)} entries" + scope]
71
73
  for e in entries:
72
74
  ln = f" {e['timestamp'][:19]} | {e['file']} {e['version']} | {e['change_type']} | {e['summary']}"
75
+ br = (e.get("git") or {}).get("branch")
76
+ if br:
77
+ ln += f" @{br}"
73
78
  if e.get("tags"):
74
79
  ln += f" [{','.join(e['tags'])}]"
75
80
  lines.append(ln)
cli/tools/shell.py CHANGED
@@ -60,7 +60,13 @@ _FILTER_THRESHOLD_LINES = 30
60
60
 
61
61
 
62
62
  def _popen_kwargs() -> dict:
63
- kw: dict = {"stdin": subprocess.DEVNULL}
63
+ # Force UTF-8 in child processes so Unicode output (→, box-drawing, emoji)
64
+ # doesn't crash on Windows' legacy cp1252 console encoding. setdefault so an
65
+ # intentional caller-set encoding still wins.
66
+ env = dict(os.environ)
67
+ env.setdefault("PYTHONUTF8", "1")
68
+ env.setdefault("PYTHONIOENCODING", "utf-8")
69
+ kw: dict = {"stdin": subprocess.DEVNULL, "env": env}
64
70
  if sys.platform == "win32":
65
71
  kw["creationflags"] = subprocess.CREATE_NO_WINDOW
66
72
  return kw
@@ -86,7 +92,7 @@ def _run_sync(cmd: str, cwd: str, timeout: int) -> dict:
86
92
  proc = subprocess.Popen(
87
93
  cmd, shell=True, cwd=cwd,
88
94
  stdout=subprocess.PIPE, stderr=subprocess.PIPE,
89
- text=True, errors="replace",
95
+ text=True, encoding="utf-8", errors="replace",
90
96
  **_popen_kwargs(),
91
97
  )
92
98
  timed_out = False
@@ -133,6 +139,45 @@ def _maybe_refresh_ledger(cmd: str, result: dict, svc) -> list[str]:
133
139
  return []
134
140
 
135
141
 
142
+ # git diagnostics whose output the caller almost always needs verbatim — never
143
+ # auto-filter these, even past the line threshold.
144
+ _GIT_DIAGNOSTIC = re.compile(
145
+ r"^\s*git\s+(status|diff|log|show|branch|stash\s+list)\b", re.IGNORECASE
146
+ )
147
+
148
+
149
+ def _list_root_files(root: Path) -> set[str]:
150
+ try:
151
+ return {e.name for e in root.iterdir() if e.is_file()}
152
+ except OSError:
153
+ return set()
154
+
155
+
156
+ def _sweep_new_ghost_files(root: Path, before: set[str]) -> list[str]:
157
+ """Delete 0-byte 'ghost' files (shell-redirect / metacharacter artifacts —
158
+ e.g. a `>Lnnn` marker or `2>$null` leaking a filename) that appeared in
159
+ *root* during this command. Only files absent from *before* are removed, so
160
+ pre-existing files are never touched. Detection is reused from
161
+ hook_ghost_files so the rules live in one place; this makes c3_shell
162
+ self-clean regardless of whether the external PostToolUse ghost hook is
163
+ wired for this tool."""
164
+ try:
165
+ from cli.hook_ghost_files import scan_ghost_files
166
+ except Exception:
167
+ return []
168
+ swept: list[str] = []
169
+ for g in scan_ghost_files(root):
170
+ name = g.get("name", "")
171
+ if not name or name in before:
172
+ continue
173
+ try:
174
+ Path(g["path"]).unlink()
175
+ swept.append(name)
176
+ except OSError:
177
+ pass
178
+ return swept
179
+
180
+
136
181
  async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
137
182
  log: bool, svc, finalize) -> str:
138
183
  if not cmd or not cmd.strip():
@@ -147,11 +192,17 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
147
192
  work_cwd = cwd or svc.project_path
148
193
  work_cwd = str(Path(work_cwd).resolve())
149
194
 
195
+ ghost_root = Path(work_cwd)
196
+ _ghosts_before = _list_root_files(ghost_root)
197
+
150
198
  result = await asyncio.to_thread(_run_sync, cmd, work_cwd, timeout)
151
199
 
200
+ swept_ghosts = _sweep_new_ghost_files(ghost_root, _ghosts_before)
201
+
152
202
  raw_stdout = result["stdout"]
153
203
  filtered_note = ""
154
- if filter_output and raw_stdout.count("\n") > _FILTER_THRESHOLD_LINES:
204
+ if (filter_output and raw_stdout.count("\n") > _FILTER_THRESHOLD_LINES
205
+ and not _GIT_DIAGNOSTIC.search(cmd)):
155
206
  try:
156
207
  filtered = await asyncio.to_thread(
157
208
  handle_filter,
@@ -201,6 +252,11 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
201
252
  body += f"--- stderr ---\n{result['stderr'].rstrip()}\n"
202
253
  if touched_files:
203
254
  body += f"--- ledger ---\nlogged {len(touched_files)} file(s)\n"
255
+ if swept_ghosts:
256
+ body += (
257
+ f"--- ghost-sweep ---\nremoved {len(swept_ghosts)} stray 0-byte "
258
+ f"file(s): {', '.join(swept_ghosts)}\n"
259
+ )
204
260
 
205
261
  summary = f"shell {status} in {result['duration_ms']}ms"
206
262
  resp_tokens = count_tokens(body) if body else 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.33.0
3
+ Version: 2.35.0
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -245,7 +245,7 @@ C3 exposes 16 tools as a native MCP server. Your IDE calls them directly:
245
245
  | `c3_impact` | Blast-radius analysis before edits to shared symbols |
246
246
  | `c3_delegate` | Offload heavy work to local Ollama / Codex / Gemini / etc. |
247
247
  | `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
248
- | `c3_edits` | Edit-ledger queries + version diffs + restore points |
248
+ | `c3_edits` | Edit-ledger queries + version diffs + restore points + per-branch filter |
249
249
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
250
250
  | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
251
251
 
@@ -363,7 +363,7 @@ Real-world A/B tests: same task, with and without C3 mounted. Reports include to
363
363
 
364
364
  ## Security & privacy
365
365
 
366
- - **All web servers (Hub, per-project UI, Oracle) bind to `127.0.0.1` by default and are guarded against browser-based attacks even on loopback** — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. A malicious web page you visit therefore cannot drive C3's local endpoints. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface in `~/.c3/hub_config.json` (`host`) or Oracle's config (`bind_host`) is opt-in and warned at startup; add externally-facing hostnames/IPs to an `allowed_hosts` list there so the guard permits them.
366
+ - **All web servers (Hub, per-project UI, Oracle) bind to `127.0.0.1` by default and are guarded against browser-based attacks even on loopback** — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. A malicious web page you visit therefore cannot drive C3's local endpoints. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface in `~/.c3/hub_config.json` (`host`) or Oracle's config (`bind_host`) is opt-in and warned at startup; add externally-facing hostnames/IPs to an `allowed_hosts` list there so the guard permits them. _(Cross-origin/CSRF + DNS-rebinding hardening added in v2.33.0.)_
367
367
  - **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`. Even when enabled, request bodies, local variables, and prompts are stripped before sending.
368
368
  - **API keys** for third-party model providers are read from environment variables and never persisted by C3.
369
369
  - See [`SECURITY.md`](SECURITY.md) for the full hardening guide and disclosure policy.
@@ -1,6 +1,6 @@
1
1
  cli/__init__.py,sha256=ec66drCZGNMRU4V6ov0zVhYZph1us12Vn8OvG_LJyRY,22
2
2
  cli/_hook_utils.py,sha256=1_hTA-Wz62xB8jnSAH4C5TfCkrwEP0g2kq_-oRfQLm4,3724
3
- cli/c3.py,sha256=A22d4MQhcVEC-2DdpO7zd7QpQ5o9rDp96UVKubTVr3w,289101
3
+ cli/c3.py,sha256=lHmkT56LCHB7_NRNRXjqP8kXUWuzgfTKN9vevA7uj6M,289101
4
4
  cli/docs.html,sha256=JgtBFUuUkvmYowPREYiGhhcRbB5e2UjkRc00MIF0hsU,143653
5
5
  cli/edits.html,sha256=UjAhoCmBmQ89cklGvJqzC6eyNP2tc8H6T-e01DVkLvE,43418
6
6
  cli/hook_auto_snapshot.py,sha256=amtliVDzKUQr6KBR0pdBA8vXghAV-gKr19jBaJVnP_w,5006
@@ -15,10 +15,10 @@ cli/hook_read.py,sha256=M5l_SU899O72tZe3j4YQJJKNb1-xulvKOj8XZjJzwYU,8021
15
15
  cli/hook_session_stats.py,sha256=a1OKi9kmiXRI2qieY_Uq14xRxdXQTQu9WVzDTUlI0GQ,1897
16
16
  cli/hook_terse_advisor.py,sha256=pD7Bap7OYOKqtYz7cX8nWSRLH7ook-tSD2Ov2MNp_sA,5907
17
17
  cli/hub.html,sha256=Hl-XPZGT1mMiKrbX9c5OsEw6mXEumwIB3vp1WlWaplM,183966
18
- cli/hub_server.py,sha256=srtoCuR-mvxr8nRO0EcTaWj70W87jC9UUQsGrz-cOeQ,62996
18
+ cli/hub_server.py,sha256=L7M3PAQNiRFyqdgL0COXIzIo9lyJTaCZSk-K1I2kZtM,59725
19
19
  cli/mcp_proxy.py,sha256=92htuT-p0j-cDTbyqlIJpGoQ85_Aw7UuB8L_Toi_u20,17511
20
- cli/mcp_server.py,sha256=5cyXOhH_CxJFCpG13AsOEvtdLZAM8_OiI9ZH1xXtZLs,32454
21
- cli/server.py,sha256=Eb7I6-p5CYYbE8jvyt0jnIkK32xEYWI3cir5ygYbtts,123087
20
+ cli/mcp_server.py,sha256=iYUB6rfGjNuiNQP-GecuXyMVa1CEihtu4dV7PhRHWqg,32549
21
+ cli/server.py,sha256=n8CNh444AGuYMnVSSiRK9pirGh84Ap7ZTI8wuRrJCX8,119970
22
22
  cli/ui.html,sha256=xcdt74nlFEXx-0Bx6-Okw-WSVZPAXL0iukxU0ytI6CA,5694
23
23
  cli/ui_legacy.html,sha256=cI8tC6RKmE2NIJOcsu7CY-zT4VznjcbD6NTjxb_fvUY,378460
24
24
  cli/ui_nano.html,sha256=UAwQ6bbTOXAoGq191AZ7slhngR9edJSa3IhqpynveDg,27740
@@ -32,7 +32,7 @@ cli/tools/bitbucket.py,sha256=MBVMnREDhJiUal43cPqLUUPWyS8AGp3v3rNZ291Vkrg,27271
32
32
  cli/tools/compress.py,sha256=hgBQ6jUwvfGRmcC53vJBz_bbGD0E7T85IxD4q53rj4E,8941
33
33
  cli/tools/delegate.py,sha256=zOpa03znY27_y1u7T7wbfgQXPwCDA409z9dJ2ki4esU,46947
34
34
  cli/tools/edit.py,sha256=fVIZzBPe3ixKBxcZFU03ur2XKu9rAlBihga2-tmIuWw,13791
35
- cli/tools/edits.py,sha256=-Tv5eqw_X-dYc9l4kFWr_8vX1TAUb9QNMv0fpy0rXjQ,5304
35
+ cli/tools/edits.py,sha256=8zM01TzLmjm7ULQlCmXOmitlJd84zQHVzE0z7UHJUdA,5520
36
36
  cli/tools/filter.py,sha256=IEjBdKrHxYVCm4cP0Ao6WZkKhbIBi1uI-mLY627zEUw,11503
37
37
  cli/tools/impact.py,sha256=jjWkFTxHu-gBpZZNd2HTdBl22itA6-wwwOZXxk_qBl8,6257
38
38
  cli/tools/memory.py,sha256=OdYBcIEFo4sr5aCG0_uO48uyJ-Kzof7LC2Ou1THGFuc,23317
@@ -40,7 +40,7 @@ cli/tools/project.py,sha256=PKHLGRFZdwBBEgryyV440mybTeQMqnlLgHdfXDnPahw,11868
40
40
  cli/tools/read.py,sha256=2UT2ICjkyUqMWujOHidEhsGuOTORLTt7na2CVdVZwpw,10868
41
41
  cli/tools/search.py,sha256=qB8C3w8yuu59aepvnuJNlzbsirtSEZA8zz4neKlE7Xs,13246
42
42
  cli/tools/session.py,sha256=LIZbmEhNdh6rAsT6Dbpb21UY8xF9oubvpjGwfnXxQK4,4573
43
- cli/tools/shell.py,sha256=vdzt_ak_ryL7tV_1JC3rG5MninjPTEjl5Ot1qLrTxj8,7654
43
+ cli/tools/shell.py,sha256=lTGMpT_YWnAyJzcT-WHMLjuenqq6m-p3v6uCHKCsHWM,9752
44
44
  cli/tools/status.py,sha256=yCHXskXgKzaDhJT6vHYlp3ZU5j89vhVYzf5dQOAR9yQ,12625
45
45
  cli/tools/validate.py,sha256=KJr_YKLHiThgKdPnv-7Uucv2rS3DIoKISNxSy2icw8I,11965
46
46
  cli/ui/api.js,sha256=wI9-lxGitIgZ5R6lqi1PVc2edD0b3TsYwMUGgcNWgfU,1342
@@ -57,16 +57,17 @@ cli/ui/components/memory.js,sha256=v5IsHTxLHpXX4xCsUaZ_UPprZEabdgP4jiWc298iV2U,2
57
57
  cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE,30837
58
58
  cli/ui/components/settings.js,sha256=8LVTV2TQl9tcRXhXbtBEJOCBdiyk-x2QASoVYZUAuEA,71442
59
59
  cli/ui/components/sidebar.js,sha256=cAY_jwYB-o1X_wWn__VXlG4IegVObuE3NmVsuFWqxtg,7417
60
- code_context_control-2.33.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
60
+ code_context_control-2.35.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
61
61
  core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
62
62
  core/config.py,sha256=0RBVni99wqJIxAYU6uweWVOmdI-FJvQ8d3IV5Mp1Muc,12818
63
63
  core/ide.py,sha256=9LzsDVK2LL8RVpL40l6oNGiasZ3D8OCU_9i9A0gJKBo,6876
64
- core/web_security.py,sha256=K7X02ybqcHsk5-FaNIeufjTJE-sbuijjxONpKk8y1Mo,6922
64
+ core/mcp_toml.py,sha256=nFsgDm9j0W1v-o4tBTeEYFuHyxkBNuuMjPhJX-lvfYE,4422
65
+ core/web_security.py,sha256=WkNmoCsSWepV3XduibuQYalEJSIR_cpmumoK9bce9FM,7412
65
66
  oracle/__init__.py,sha256=-OTD7Jh4mUMA4QgPGthPLWXttgZLpkIPhGQ87ZfHBx0,63
66
67
  oracle/config.py,sha256=ErjH6Y_F51jGXpYo_4boGhdIk-AIo3rDH3xDwUGs7B8,3193
67
- oracle/mcp_oracle.py,sha256=gBvQgfDWVs3iMCMK5dyoj3AQF2A204BaqPdsgIpCrvE,6372
68
+ oracle/mcp_oracle.py,sha256=Vts1ugITgvZP_BzKHgQN1nxHNVQNuNAEPdKgVIpRjPU,8133
68
69
  oracle/oracle.html,sha256=KW1jeqmUwvAH2mDlhCLo05nrHW8PfmCYv0iQhL5d74s,185219
69
- oracle/oracle_server.py,sha256=pjVLiElO5mQiBkAetoPqOIicoxguMHTqkO0-38WMOV0,33722
70
+ oracle/oracle_server.py,sha256=qMKLzLoV5cp-cK-l5tc0w24jis2QudNVB7S74eKijGQ,33778
70
71
  oracle/services/__init__.py,sha256=Nb4POd1_YIwLVYsGfr-DiK-iKTelkU0fh9m7wjeLQHA,23
71
72
  oracle/services/api_auth.py,sha256=1PW3pG--1DJb_F6qMhP3gBTYHxxPE2bsHmVmIhC81Y8,3566
72
73
  oracle/services/c3_bridge.py,sha256=Khj2jao2oENe4yFA31Ny0yI3fcV8XBerjsLslt4ns3U,9652
@@ -86,23 +87,24 @@ oracle/services/tool_registry.py,sha256=V7eP-UeacN3T4We_zbJ8NdFCFCKJVSKJa4zfH02L
86
87
  services/__init__.py,sha256=3Kn4cZweLm7at8wFdBdZ-Zwo8hHcnVIsmY5f29nzi2Y,116
87
88
  services/activity_log.py,sha256=YsW8-HBQEFh2vYTlvnzK7doNsR-XEtBbWXJ-324XigU,3370
88
89
  services/agent_base.py,sha256=a-gdSd_jtZtbjXo1WS8CnWCagXgKaGZd5ShcG6s0kT4,4809
89
- services/agents.py,sha256=f4mvmLZ1Awds3RbYjESSZFtheoybHkBb_oagvnMLyaM,67485
90
+ services/agents.py,sha256=iDYqT4iY4Q_KmWYWGKIjp7F1A_F6so9l6n59Qk7mHmI,73275
90
91
  services/auto_memory.py,sha256=v__ZS1e68533_Yv491mZtvuZnheC63q6_uTvWhBw3Lw,14290
91
92
  services/benchmark_dashboard.py,sha256=iR-DnqnoKbqHMJ4d-ZkIvJBYfzwTa7r-jzO6j2BYDfQ,27711
92
93
  services/bitbucket_client.py,sha256=v8xGEcnIEmURvcg38XwmiCGh7-_QnjhAJEb0te_yZzQ,16107
93
94
  services/bitbucket_credentials.py,sha256=2qLA9pQMol4y95y4DJMNBsBBPUsJQCKbLFo2iiCnfvI,7364
94
95
  services/claude_md.py,sha256=iL0vUQw-5lxSQehNPvhlkUmcGPeMSCcZqP4OYG_qoYk,35092
95
96
  services/compressor.py,sha256=uSVyTYfvxFrRYupzyKj-HzkBP0RwARrGYFz_DnMSEaM,25169
96
- services/context_snapshot.py,sha256=upxrxcBUPX7MrOlgUo7oD9rvm2H1SJLK8FI1tgHrAjg,14045
97
+ services/context_snapshot.py,sha256=s_klEr1SJYM9u-anMmnoemsYuIF_KUWBjz1zUo0wPgU,15662
97
98
  services/conversation_store.py,sha256=vPiMiKAE22RCBSSphgGH9Vx-lPV45SmttOwgVVWahL4,33398
98
99
  services/doc_index.py,sha256=kYcE_lQgjgG7CRmqN3Byx7MNmz1JCfm8QsrjH3u7OUI,18614
99
100
  services/e2e_benchmark.py,sha256=kHZnatL27pHT1cC1DFW3SY0B6mNpIFdVns7au48Rp04,132867
100
101
  services/e2e_evaluator.py,sha256=WRIPu6b1SrSQpHESCnIWrC1wsRp1v4UGaaNcFD1KZ5c,17672
101
102
  services/e2e_tasks.py,sha256=Ln5VbGDIcS3NY3aml5ERbgjfjLxEslmRZ8AyaYxpWEo,34524
102
- services/edit_ledger.py,sha256=WKfsRApgZCXz5cKeKC3JVro4j9EPmW9vgmpsZDrqFm8,17961
103
+ services/edit_ledger.py,sha256=R0eUA2jOXY_RUuCMT52wA4hTbgaeuYbGwy_xSMxS64k,18027
103
104
  services/embedding_index.py,sha256=ZccqCH5WWQnqAmPtO1PB5W2N7OzRZARrctDBAtLgPBg,12769
104
105
  services/error_reporting.py,sha256=HZ3ru8i5RLf8nq2R4iRnTs5sm1blUxknSbv5hdxuxs0,4139
105
106
  services/file_memory.py,sha256=GnEbwdWE7TUKUR4PpSgHV7cnLys3Fa2bsLvc-XwuFgI,29188
107
+ services/git_context.py,sha256=lhuIvGDBUTKOPqye-olgJfjv538t-jtRZLBAcs7iVoA,9506
106
108
  services/hub_service.py,sha256=Ta2ExJP1sePxb7zcHooroYXJKsylm5Ea8vQvts6-cAw,21876
107
109
  services/indexer.py,sha256=ZceGqvd1OheN-hvSg4jjjXNcFjCSCgswKf5DmI-xaqA,27044
108
110
  services/memory.py,sha256=uH3hWWUCy8p_0hVuJq-pzp2F5qNRLcVOpaFYmap2VFY,12458
@@ -123,14 +125,14 @@ services/retrieval_broker.py,sha256=9X67VZ_6AkbAzopHuuMFKmP4CGZLnW576kjSKMenBnw,
123
125
  services/router.py,sha256=Cz10nx2fKTbaGn14mSBePWIDrw5rdcs_1JFYXeik084,15626
124
126
  services/runtime.py,sha256=SOUizCDW1FFTDCoaZ1Njozjp25Bhah7lR1f0WYscaw0,11361
125
127
  services/session_benchmark.py,sha256=qw_vtDim1hvFdM8Me5EsgU9pTuJhzRjQmh6m7DDnXWY,98989
126
- services/session_manager.py,sha256=TVG1Jf5FuVSeVrnCKTPXEDnyPp4bjRqDl4bWXP6_Cf4,43190
128
+ services/session_manager.py,sha256=Px7RpTS6zDSuxj2O87o-7tkR8l-faMZxBX1gd5RLHfo,43837
127
129
  services/session_preloader.py,sha256=DsTAXMKVtrX9yu1sEFojYDi9-jkSAj1Ylt9JTy57Dow,9883
128
130
  services/text_index.py,sha256=r3o4CobTG9jAO9PWazgbWYLY9oi_FgEJ3xwEXrF4KM0,2783
129
131
  services/tool_classifier.py,sha256=Fgvq0ZcpnCskwtO8a3YI1MiecPNnw6UbPyJQIUwgfiQ,6512
130
132
  services/transcript_index.py,sha256=VQhvgkSyLVEYamXi_YIbiIhBnd0mqFHZlWG2HQu_1EA,12144
131
133
  services/validation_cache.py,sha256=skFYR7CkSGvFb2gq6dfxOnvjQzz5Boa3jJWT7UfaIhY,5587
132
134
  services/vector_store.py,sha256=o1RdZgRegFWlrr_kgSrY243W4KURmo4gvnP7vrxa2DE,11425
133
- services/version_tracker.py,sha256=Q_2Z2Fw2VkSyWmL9QF2SU9z7Y1w1zQ-80iqX93SsHn0,10130
135
+ services/version_tracker.py,sha256=8yQAcZuJjzq1Efib828FMOjQNIcVQvPQC5KksbWLSUw,9880
134
136
  services/watcher.py,sha256=TT8dvUHw1z7Uc2KCbyynkkN4luns6qxsicc2_cj9PM8,6856
135
137
  services/bench/__init__.py,sha256=WLEJIWJeaUj6FnH2nDO1qWugJDKfOKeM6WvKLSreYjI,231
136
138
  services/bench/external/__init__.py,sha256=XgPS99ztx9igMd6x-1bLykcaePGXctkb6ujQ1MLgKAs,608
@@ -154,8 +156,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
154
156
  tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
155
157
  tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
156
158
  tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
157
- code_context_control-2.33.0.dist-info/METADATA,sha256=nAokxXx43_pIJbf4Wi6scwNarxuEYraKwA3sRK2z2JY,19736
158
- code_context_control-2.33.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
159
- code_context_control-2.33.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
160
- code_context_control-2.33.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
161
- code_context_control-2.33.0.dist-info/RECORD,,
159
+ code_context_control-2.35.0.dist-info/METADATA,sha256=BGKYwuZVthBqtj3BfoOXk7OvsfXi10ys2RX03fu90gw,19822
160
+ code_context_control-2.35.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
161
+ code_context_control-2.35.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
162
+ code_context_control-2.35.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
163
+ code_context_control-2.35.0.dist-info/RECORD,,