code-context-control 2.119.0__py3-none-any.whl → 2.121.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
@@ -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.119.0"
95
+ __version__ = "2.121.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -1570,6 +1570,42 @@ def cmd_shell_eval(args):
1570
1570
  sys.exit(1)
1571
1571
 
1572
1572
 
1573
+ def cmd_map_eval(args):
1574
+ """Run the file-map gold suite and compare it to its baseline.
1575
+
1576
+ Renders the hand-annotated fixtures through the renderer the MCP tool
1577
+ uses and grades symbol recall, signatures, ranges and determinism. Exit
1578
+ status 1 when the baseline is violated (a must_pass case failed, an
1579
+ aggregate fell under its floor or rose over its ceiling, a complete map
1580
+ grew). See docs/map-eval.md.
1581
+ """
1582
+ from services.bench import map_eval as me
1583
+
1584
+ try:
1585
+ report = me.run_suite(args.suite, baseline=args.baseline)
1586
+ except FileNotFoundError as e:
1587
+ raise RuntimeError(str(e))
1588
+
1589
+ if args.update_baseline:
1590
+ path = args.baseline or me.BUNDLED_BASELINES.get(report.suite)
1591
+ if not path:
1592
+ raise RuntimeError(
1593
+ f"suite {report.suite!r} has no bundled baseline; pass --baseline PATH")
1594
+ floors = json.loads(args.floors) if args.floors else None
1595
+ ceilings = json.loads(args.ceilings) if args.ceilings else None
1596
+ me.write_baseline(report, path, floors=floors, ceilings=ceilings)
1597
+ report.baseline_violations, report.baseline_warnings = me.compare_to_baseline(
1598
+ report, me.load_baseline(path))
1599
+ print(f"baseline written: {path}")
1600
+
1601
+ if args.json:
1602
+ print(json.dumps(report.to_dict(), indent=2))
1603
+ else:
1604
+ print(report.render())
1605
+ if report.baseline_violations:
1606
+ sys.exit(1)
1607
+
1608
+
1573
1609
  def _benchmark_extract_preview(full_path: Path, compressor: CodeCompressor, pattern: str = "", max_lines: int = 50) -> str:
1574
1610
  """Approximate c3_filter behavior for local benchmarking without MCP startup."""
1575
1611
  import re as _re
@@ -9261,6 +9297,7 @@ def main():
9261
9297
  "stats": cmd_stats,
9262
9298
  "search-eval": cmd_search_eval,
9263
9299
  "shell-eval": cmd_shell_eval,
9300
+ "map-eval": cmd_map_eval,
9264
9301
  "benchmark": cmd_benchmark,
9265
9302
  "session-benchmark": cmd_session_benchmark,
9266
9303
  "benchmark-e2e": cmd_benchmark_e2e,
cli/commands/parser.py CHANGED
@@ -76,6 +76,19 @@ def build_parser(version: str, parse_cli_ide_arg):
76
76
  help='With --update-baseline: JSON object of metric ceilings, e.g. \'{"bytes_p95": 18432}\'')
77
77
  p_shell_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
78
78
 
79
+ p_map_eval = subparsers.add_parser(
80
+ "map-eval", help="Run the file-map gold suite (docs/map-eval.md)")
81
+ p_map_eval.add_argument("--suite", default="fixture",
82
+ help="'fixture' (hand-annotated sources, CI gate) or a .jsonl path")
83
+ p_map_eval.add_argument("--baseline", default=None, help="Baseline JSON to compare against / write")
84
+ p_map_eval.add_argument("--update-baseline", action="store_true",
85
+ help="Write aggregates + per-case status to the baseline (floors/ceilings are kept)")
86
+ p_map_eval.add_argument("--floors", default=None,
87
+ help='With --update-baseline: JSON object of metric floors, e.g. \'{"symbol_recall_mean": 0.9}\'')
88
+ p_map_eval.add_argument("--ceilings", default=None,
89
+ help='With --update-baseline: JSON object of metric ceilings, e.g. \'{"tokens_p95": 4000}\'')
90
+ p_map_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
91
+
79
92
  p_compress = subparsers.add_parser("compress", help="Compress a file")
80
93
  p_compress.add_argument("file", help="File to compress")
81
94
  p_compress.add_argument("--mode", choices=["map", "dense_map", "smart", "diff"], default="smart")
cli/mcp_server.py CHANGED
@@ -85,7 +85,7 @@ def _build_instructions(ide_name: str) -> str:
85
85
  return (
86
86
  "C3 — local code intelligence. Route by goal:\n"
87
87
  " FIND candidates → c3_search\n"
88
- " MAP file shape → c3_compress(mode='map') then READ content → c3_read(symbols=…)\n"
88
+ " MAP a file → c3_read(file_path) with no symbols, then READ → c3_read(symbols=…); batch maps → c3_compress\n"
89
89
  " EDIT code → c3_edit (always; it logs to the ledger automatically)\n"
90
90
  " VALIDATE after every edit → c3_validate\n"
91
91
  " BLAST RADIUS before shared-symbol edits → c3_impact\n"
@@ -583,8 +583,10 @@ async def c3_memory(action: str, query: str = "", fact: str = "",
583
583
  @mcp.tool()
584
584
  async def c3_read(file_path: str, symbols: Any = None, lines: Any = None,
585
585
  include_docstrings: bool = True, ctx: Context = None) -> str:
586
- """READ exact content. Use after c3_compress when you need real source (read-only, plan-mode safe).
587
- file_path: single or comma-separated. symbols: function/class names. lines: int, [start,end], or list of ranges."""
586
+ """READ source, or MAP a file when called with only file_path (read-only, plan-mode safe).
587
+ file_path: single or comma-separated. symbols: names as the map prints them (Class.method ok).
588
+ lines: int, [start,end], or list of ranges. No symbols/lines = one line per symbol with
589
+ signature and [La-Lb] range at ~10% of the file's tokens; then read the symbols you need."""
588
590
  path_err = validate_file_path(file_path)
589
591
  if path_err:
590
592
  return f"[c3_read:error] {path_err}"
@@ -597,10 +599,11 @@ async def c3_read(file_path: str, symbols: Any = None, lines: Any = None,
597
599
 
598
600
 
599
601
  @mcp.tool()
600
- async def c3_compress(file_path: str, mode: str = "smart", ctx: Context = None) -> str:
601
- """MAP file shape — classes/functions/imports at 40-70% tokens (read-only, plan-mode safe).
602
- Use before c3_read to know which symbols to fetch. Modes: map, dense_map, smart, diff, bug_scan, ast.
603
- file_path: single or comma-separated."""
602
+ async def c3_compress(file_path: str, mode: str = "map", ctx: Context = None) -> str:
603
+ """MAP a file — one line per symbol with full signature and [La-Lb] range, ~10% of the
604
+ file's tokens (read-only, plan-mode safe). Same map as c3_read(file_path) with no symbols;
605
+ use this form for a comma-separated batch (up to 10). mode: map (default); other modes
606
+ are legacy."""
604
607
  path_err = validate_file_path(file_path)
605
608
  if path_err:
606
609
  return f"[c3_compress:error] {path_err}"
cli/tools/agent.py CHANGED
@@ -877,11 +877,10 @@ def _parallel_compress(files: list, svc, steps_log: list,
877
877
  maps = {}
878
878
 
879
879
  def compress_one(fp):
880
- full_path = str(Path(svc.project_path) / fp)
881
880
  try:
882
- res = svc.compressor.compress_file(full_path, "map")
883
- if isinstance(res, dict) and res.get("compressed"):
884
- return fp, res["compressed"]
881
+ fmap = svc.file_memory.get_or_build_map(fp.replace("\\", "/"))
882
+ if fmap and not fmap.startswith("[file_map]"):
883
+ return fp, fmap
885
884
  except Exception:
886
885
  pass
887
886
  return fp, None
@@ -936,11 +935,10 @@ def _parallel_validate_and_compress(files: list, svc, steps_log: list):
936
935
  return "validate", fp, "ERROR", str(e)
937
936
 
938
937
  def compress_one(fp):
939
- full_path = str(Path(svc.project_path) / fp)
940
938
  try:
941
- res = svc.compressor.compress_file(full_path, "map")
942
- if isinstance(res, dict) and res.get("compressed"):
943
- return "compress", fp, res["compressed"]
939
+ fmap = svc.file_memory.get_or_build_map(fp.replace("\\", "/"))
940
+ if fmap and not fmap.startswith("[file_map]"):
941
+ return "compress", fp, fmap
944
942
  except Exception:
945
943
  pass
946
944
  return "compress", fp, None
cli/tools/compress.py CHANGED
@@ -1,5 +1,7 @@
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."""
1
+ """c3_compress — the canonical file map (services/file_map.render_map), one file or a batch.
2
+
3
+ mode='map' (default) is the same text c3_read(file_path) serves. The other
4
+ modes (dense_map, smart, diff, bug_scan, ast) are legacy and retire in 2.122.0."""
3
5
 
4
6
  import json
5
7
  import shutil
@@ -14,6 +16,48 @@ from core import count_tokens
14
16
  from services import access_guard
15
17
 
16
18
 
19
+ def map_detail(svc, rel: str, requested_mode: str, *, cache_hit: bool,
20
+ symbols: int = 0, fallback: str = "") -> dict:
21
+ """Telemetry `detail` for a map served from file_memory (C0, 2.120.0).
22
+
23
+ backend names the code path, parser the extractor that built the record
24
+ (tree_sitter | regex | generic, "" for a pre-2.120.0 record), cache_hit
25
+ whether the record was already fresh. `symbols` is how many the caller
26
+ asked for and `fallback` why a read served a map instead of source.
27
+ Flat so telemetry.aggregate_tool_telemetry can fold it without a schema.
28
+ """
29
+ record = None
30
+ try:
31
+ record = svc.file_memory.get(rel)
32
+ except Exception:
33
+ record = None
34
+ if not isinstance(record, dict):
35
+ record = None
36
+ detail = {
37
+ "requested_mode": requested_mode,
38
+ "backend": "file_memory",
39
+ "parser": str((record or {}).get("parser") or ""),
40
+ "cache_hit": bool(cache_hit),
41
+ "sections": len((record or {}).get("sections") or []),
42
+ }
43
+ if symbols:
44
+ detail["symbols"] = int(symbols)
45
+ if fallback:
46
+ detail["fallback"] = fallback
47
+ return detail
48
+
49
+
50
+ def compressor_detail(res: dict, requested_mode: str) -> dict:
51
+ """Telemetry `detail` for a CodeCompressor result (smart/diff/bug_scan…)."""
52
+ backend = "large_fast_path" if res.get("fast_path") else "compressor"
53
+ return {
54
+ "requested_mode": requested_mode,
55
+ "backend": backend,
56
+ "actual_mode": str(res.get("mode") or ""),
57
+ "cache_hit": bool(res.get("cache_hit")),
58
+ }
59
+
60
+
17
61
  def _run_memory_mcp_cli(args: list, cwd: str, timeout: int = 30) -> tuple:
18
62
  """Run codebase-memory-mcp CLI and return (success, output_or_error)."""
19
63
  binary = shutil.which("codebase-memory-mcp")
@@ -150,6 +194,8 @@ def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> s
150
194
  return ("[file_map:error] not found. To create a new file use "
151
195
  "c3_edit(file_path=..., old_string='', new_string=<content>).")
152
196
  rel = str(full.resolve().relative_to(Path(svc.project_path).resolve())).replace("\\", "/")
197
+ # C0 measurement: was the record already fresh before this call?
198
+ cache_hit = not svc.file_memory.needs_update(rel)
153
199
  queued = svc.file_memory.drain_queue()
154
200
  completed = []
155
201
  failed = []
@@ -174,8 +220,14 @@ def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> s
174
220
  raw_tokens = None
175
221
  map_tokens = 0
176
222
  try:
177
- raw_tokens = count_tokens(full.read_text(encoding="utf-8", errors="replace"))
223
+ raw_text = full.read_text(encoding="utf-8", errors="replace")
224
+ raw_tokens = count_tokens(raw_text)
178
225
  map_tokens = count_tokens(res)
226
+ if map_tokens >= raw_tokens and not res.startswith("[file_map]"):
227
+ # A map that costs more than the file is worth nothing
228
+ # (docs/file-map.md § Small files).
229
+ res = f"[compress:{file_path}] whole file — smaller than its map\n" + raw_text
230
+ map_tokens = count_tokens(res)
179
231
  summary = mode
180
232
  except Exception:
181
233
  summary = "mapped"
@@ -183,7 +235,8 @@ def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> s
183
235
  finalize, svc, "c3_compress", {"file_path": file_path, "mode": mode},
184
236
  res, summary,
185
237
  raw_tokens=raw_tokens, optimized_tokens=map_tokens or None,
186
- response_tokens=map_tokens)
238
+ response_tokens=map_tokens,
239
+ detail=map_detail(svc, rel, mode, cache_hit=cache_hit))
187
240
 
188
241
  try:
189
242
  res = svc.compressor.compress_file(str(full), mode)
@@ -197,7 +250,8 @@ def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> s
197
250
  finalize, svc, "c3_compress", {"file_path": file_path},
198
251
  resp + maybe_facts(svc, Path(file_path).name), mode,
199
252
  raw_tokens=res.get('original_tokens'),
200
- optimized_tokens=res.get('compressed_tokens'))
253
+ optimized_tokens=res.get('compressed_tokens'),
254
+ detail=compressor_detail(res, mode))
201
255
 
202
256
 
203
257
  def _compress_batch(paths: list, mode: str, svc, finalize, maybe_facts) -> str:
@@ -288,4 +342,6 @@ def _compress_batch(paths: list, mode: str, svc, finalize, maybe_facts) -> str:
288
342
  {"file_path": ",".join(paths), "mode": mode, "batch": True},
289
343
  body, f"batch {total_ok}/{len(paths)}",
290
344
  raw_tokens=total_raw if measured else None,
291
- optimized_tokens=total_opt if measured else None)
345
+ optimized_tokens=total_opt if measured else None,
346
+ detail={"requested_mode": mode, "backend": "batch",
347
+ "files": len(paths), "ok": total_ok})
cli/tools/read.py CHANGED
@@ -8,6 +8,7 @@ from typing import Any
8
8
 
9
9
  from cli.tools import _grants
10
10
  from cli.tools._helpers import finalize_with_tokens, maybe_related_facts
11
+ from cli.tools.compress import map_detail
11
12
  from core import count_tokens
12
13
  from services import access_guard
13
14
 
@@ -301,16 +302,25 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
301
302
  ranges.extend(main_ranges)
302
303
 
303
304
  if not ranges and symbols:
305
+ map_cached = not svc.file_memory.needs_update(rel_path)
304
306
  file_map = svc.file_memory.get_or_build_map(rel_path)
305
307
  resp = f"[read:{file_path}] symbols not found: {symbols}. Showing file map:\n{file_map}"
306
308
  map_tok = count_tokens(file_map)
307
309
  return finalize_with_tokens(
308
310
  finalize, svc, "c3_read", {"file": file_path, "symbols": symbols},
309
311
  resp, f"{full_file_tokens()}->{map_tok}tok",
310
- raw_tokens=full_file_tokens(), optimized_tokens=map_tok)
312
+ raw_tokens=full_file_tokens(), optimized_tokens=map_tok,
313
+ detail=map_detail(svc, rel_path, "read", cache_hit=map_cached,
314
+ symbols=len(symbols), fallback="symbols_not_found"))
311
315
 
312
316
  if not ranges:
317
+ map_cached = not svc.file_memory.needs_update(rel_path)
313
318
  file_map = svc.file_memory.get_or_build_map(rel_path)
319
+ if count_tokens(file_map) >= full_file_tokens():
320
+ # A map that costs more than the file is worth nothing: serve the
321
+ # file (docs/file-map.md § Small files).
322
+ file_map = (f"[read:{file_path}] whole file — smaller than its map\n"
323
+ + raw_text)
314
324
  resp = (file_map
315
325
  + "\n[map only — pass lines=[start,end] or symbols=[...] for exact source]"
316
326
  + maybe_related_facts(svc, rel_path, top_k=3, context="read"))
@@ -319,7 +329,9 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
319
329
  finalize, svc, "c3_read", {"file": file_path},
320
330
  resp, f"{full_file_tokens()}->{map_tok}tok",
321
331
  raw_tokens=full_file_tokens(), optimized_tokens=map_tok,
322
- response_tokens=map_tok)
332
+ response_tokens=map_tok,
333
+ detail=map_detail(svc, rel_path, "read", cache_hit=map_cached,
334
+ fallback="map_only"))
323
335
  else:
324
336
  # Sort and merge overlapping ranges
325
337
  ranges.sort()
@@ -359,7 +371,16 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
359
371
  resp = final_content + maybe_related_facts(svc, rel_path, top_k=3, context="read")
360
372
  tokens = count_tokens(resp)
361
373
  summary = f"{full_file_tokens()}->{tokens}tok" if tokens < full_file_tokens() else f"{tokens}tok"
374
+ # C0 measurement: what the read asked for and how much source it took.
375
+ read_detail = {
376
+ "backend": "source",
377
+ "symbols": len(symbols) if symbols else 0,
378
+ "by_lines": bool(lines),
379
+ "ranges": len(ranges),
380
+ "lines_served": sum(e - s_ + 1 for s_, e in ranges),
381
+ "file_lines": len(content_lines),
382
+ }
362
383
  return finalize_with_tokens(
363
384
  finalize, svc, "c3_read", {"file": file_path, "symbols": symbols}, resp, summary,
364
385
  raw_tokens=full_file_tokens(), optimized_tokens=tokens,
365
- response_tokens=tokens)
386
+ response_tokens=tokens, detail=read_detail)
cli/tools/search.py CHANGED
@@ -13,6 +13,7 @@ from pathlib import Path
13
13
  from cli.tools._helpers import finalize_with_tokens, show_token_ratios
14
14
  from core import count_tokens
15
15
  from services import access_guard
16
+ from services.file_map import render_map
16
17
  from services.indexer import DEFAULT_CODE_EXTS
17
18
  from services.lexical_index import Filters, doc_kind
18
19
  from services.scanner import SKIP_DIRS, iter_files
@@ -473,21 +474,15 @@ def _first_file_map(rel: str, svc) -> str:
473
474
  watcher_active = (hasattr(svc, "watcher") and svc.watcher._observer.is_alive())
474
475
  if not watcher_active and svc.file_memory.needs_update(rel):
475
476
  svc.file_memory.update(rel)
476
- fmap = svc.file_memory.get_or_build_map(rel)
477
+ record = svc.file_memory.get(rel)
478
+ if not record:
479
+ return ""
480
+ # Same renderer as c3_read/c3_compress, shortened to the cap by
481
+ # dropping symbol lines from the end (docs/file-map.md).
482
+ fmap = render_map(record, max_tokens=_MAP_TOKEN_CAP)
477
483
  if not fmap:
478
484
  return ""
479
- if count_tokens(fmap) <= _MAP_TOKEN_CAP:
480
- return f"\n {fmap.replace(chr(10), chr(10) + ' ')}"
481
- # Truncate large maps: keep first N lines
482
- truncated = []
483
- tok = 0
484
- for fl in fmap.split("\n"):
485
- tok += count_tokens(fl)
486
- if tok > _MAP_TOKEN_CAP:
487
- break
488
- truncated.append(fl)
489
- truncated.append(" [map truncated]")
490
- return f"\n {chr(10).join(truncated).replace(chr(10), chr(10) + ' ')}"
485
+ return f"\n {fmap.replace(chr(10), chr(10) + ' ')}"
491
486
  except Exception:
492
487
  return ""
493
488
 
@@ -720,11 +715,13 @@ def _append_prefetch(resp: str, query: str, top_k: int, svc) -> str:
720
715
  uncached.append(fp)
721
716
 
722
717
  def compress_one(fp):
718
+ # The canonical map from file_memory — the same text c3_read serves
719
+ # (compressor.compress_file never had a "map" mode; it rendered a
720
+ # structure-only summary under that name).
723
721
  try:
724
- full = str(Path(svc.project_path) / fp)
725
- result = svc.compressor.compress_file(full, "map")
726
- if isinstance(result, dict) and result.get("compressed"):
727
- return fp, result["compressed"]
722
+ fmap = svc.file_memory.get_or_build_map(fp.replace("\\", "/"))
723
+ if fmap and not fmap.startswith("[file_map]"):
724
+ return fp, fmap
728
725
  except Exception:
729
726
  pass
730
727
  return fp, None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.119.0
3
+ Version: 2.121.0
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=e48F6FQloFReUIMtmWsih2t54j9SROzAaHtMkEuttDs,20489
3
3
  cli/_shell_writes.py,sha256=XzUNlUDljmg-wZxK03xHnRe36WeQxe4tpO9HKVFwP5o,5090
4
- cli/c3.py,sha256=EG12ysTtVGf1tkXBSgjZpHQfv1jU2z4Xrd_JLgI_-UE,415354
4
+ cli/c3.py,sha256=33z6xHxi3hdsM-zyi4WAM8QGW9rjFuuas5rpc357tMA,416811
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
@@ -23,7 +23,7 @@ cli/hook_terse_advisor.py,sha256=W_zaTfX2akgX-ifuUTsLu2H1atM8XmWt6jpPoeU7Pm0,625
23
23
  cli/hub_server.py,sha256=4BxvRHCGNc87jOtWankOVjQLYNk-GhWI2OY1harC8ro,184548
24
24
  cli/hub_ui.html,sha256=nnGqWhWGCLfNisGUnoAlQFcBr6wPNsq-AEOR7uFtVkE,2942
25
25
  cli/mcp_proxy.py,sha256=r-Qhlie7gCtotex8yQUudCyBLRUK-IW6cNIW5RhBW0o,17648
26
- cli/mcp_server.py,sha256=FWmCNCSxgtX6EsJwT9k248eid13AncggLXZn9ldkP5E,64007
26
+ cli/mcp_server.py,sha256=MC5adrvIoENLBhV3y4OCrgHHySb-EAfqVngx9MZvZOQ,64241
27
27
  cli/progress.py,sha256=qTkNy0howOD3hXraMo4ok3dYTpBW5yG_tenKfF4UDM0,1470
28
28
  cli/server.py,sha256=bsHvKGPXsBJi_MDLiw0IAEq8RWKIG56q72c7OKKTLug,173324
29
29
  cli/ui.html,sha256=xcdt74nlFEXx-0Bx6-Okw-WSVZPAXL0iukxU0ytI6CA,5694
@@ -31,7 +31,7 @@ cli/ui_legacy.html,sha256=cI8tC6RKmE2NIJOcsu7CY-zT4VznjcbD6NTjxb_fvUY,378460
31
31
  cli/ui_nano.html,sha256=UAwQ6bbTOXAoGq191AZ7slhngR9edJSa3IhqpynveDg,27740
32
32
  cli/commands/__init__.py,sha256=0Z8MABNzwSFJGT4Xv9R5AJVR8XxraTsuVTz5b0bShmo,38
33
33
  cli/commands/common.py,sha256=zkxr0zW9KB600BlarJ2VXf7UOp2ak21R6uXZKdGvpyg,14413
34
- cli/commands/parser.py,sha256=TcOxupfwf0sxOEgzE9l8WHyWJiKpwdbXcjq83n7Oiic,64338
34
+ cli/commands/parser.py,sha256=d4nL6_UPeY4_Cb4ecAWjNyZBVvfdO450WFJavA2E9Fc,65353
35
35
  cli/guide/access.html,sha256=BelnEc4p7XgcH_ysTlMXL9ZHCD0O4CPLq3h5rvqPIh8,14790
36
36
  cli/guide/bitbucket.html,sha256=6zmHIv2-G314_HDqMCQV-ZAIy0-co0gaFs0_k2Q1kYc,35491
37
37
  cli/guide/credentials.html,sha256=801vO_cCqG7oHsa73yAGSoBDGZ4mcGsdx6D2uS1dwCQ,58196
@@ -74,11 +74,11 @@ cli/hub_ui/components/topbar.js,sha256=vi23ybRUBrvsOLRR2L3pQem6VdkCde3qGEIKpgizM
74
74
  cli/tools/__init__.py,sha256=HO6eVKzDm1KPqsKTHY6lfIsnFnv3C7Bd9o3Q_V88idg,127
75
75
  cli/tools/_grants.py,sha256=xJwEZWC9r4exq0OuabQy-fFMZFayUYZe0Eub7NS3ikQ,4974
76
76
  cli/tools/_helpers.py,sha256=ER9zMOyxYmNZk72tkJTtRyNA9lGnnV7iHNRqyE1Sb7Q,8060
77
- cli/tools/agent.py,sha256=Fp9XLrOqjSP7_Ihq7VXjYXcGoXjw17-Hx3JMvoOVnhc,48105
77
+ cli/tools/agent.py,sha256=RmEEh5HhCZLvYu0gSRcwA_NENpd4iIYJW3exBzT8kVs,47983
78
78
  cli/tools/artifacts.py,sha256=SjazShDFIzOpAZW7uMv9itBktXnc6pqQKZeaen8GgzI,9379
79
79
  cli/tools/bitbucket.py,sha256=cni8Y1EoiNm9jcHEpzi2dgKFIT1-4ct0WOhpTs7ac3k,35812
80
80
  cli/tools/ci.py,sha256=fQ03RENywS5gqHjH26Fa4YiraBTvchlPcPSnVYwwKBs,19444
81
- cli/tools/compress.py,sha256=RzGsomsxt35E2v3CdX3qUB93v5Hc1Ec6px_CJqd4OC8,12993
81
+ cli/tools/compress.py,sha256=3uvtjH1OWCzM5XKpfth7xRnJjlMxUq-LZkql8KG7SvQ,15362
82
82
  cli/tools/credentials.py,sha256=R8Errpa41vsq0Z_sb7K-fmJxVovzXDYUyniITLrFC24,19033
83
83
  cli/tools/delegate.py,sha256=yA2-ph53Y8XAJMpz7R5LwqXshRRD8bYljgN244RbHWA,62012
84
84
  cli/tools/edit.py,sha256=xnRRM2UUybvGvfSzXzIjWmt6_zNaCbkupiK1z-8K4jE,30127
@@ -92,8 +92,8 @@ cli/tools/locks.py,sha256=FvuNxToU-5ZE2m_C6fTrn1jKERoxR4cbtxNb_b8mXqA,5882
92
92
  cli/tools/memory.py,sha256=yDDRsEngeFcjb6nXUrhRZXuboasXfixJeyltKhDbZD4,24935
93
93
  cli/tools/override.py,sha256=LiZFgoDN-35NXVwldnYrcCzfBl8MhQQ3tKVVkOG5d_o,9217
94
94
  cli/tools/project.py,sha256=MWzi7tBTQ03p_6PavmG9ZLXZHO0IhjKEJNyB0oZWTFc,24248
95
- cli/tools/read.py,sha256=lRnXIwfitEyFXpbBOuZk2EZbh2ICeTDYdTFv6qugfjQ,16509
96
- cli/tools/search.py,sha256=RbtazgTQAhqkr-ut45KlK_m8np2j5zekMW08pXSbw-A,32421
95
+ cli/tools/read.py,sha256=vQP-tfm3Mpx0y2vObPBOUeHsCdANacb_onzYJc0v-m8,17641
96
+ cli/tools/search.py,sha256=BZh3E7YggjCWOC1lJz0YNcRsdDLWsJiEmONtgUW2rEo,32397
97
97
  cli/tools/session.py,sha256=ailQiRqXhi9NcBB3XS3Dv72GEkEZaYivB0bqDlhmgTA,5202
98
98
  cli/tools/shell.py,sha256=Zcsocl8IXeL9DSQNewq_fXECSufTccUdwc-H3S2Alto,58818
99
99
  cli/tools/shell_job.py,sha256=_ilFBL3ulmqx8mwQJFUG6xW5dN-4NHqe0EZfRJL2e-4,16451
@@ -123,7 +123,7 @@ cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE
123
123
  cli/ui/components/settings.js,sha256=ATbAjBlVIwCNpxq7s191b49a_INQV38iwmySqtJLYwY,79066
124
124
  cli/ui/components/sidebar.js,sha256=K2ym2kUgpbyG-EBA_wBIIiqQY8qTatsiBZwzseMWuIQ,9939
125
125
  cli/ui/components/tasks.js,sha256=vyKQ3uwoppMwvdEaHlhWXW4oWcAisx4NveqzMhsYqHo,38438
126
- code_context_control-2.119.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
126
+ code_context_control-2.121.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
127
127
  core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
128
128
  core/codex_patch.py,sha256=CxvT_rQIwPNTRJZj9EHJmx0ZdOeSLxjiixuLI3Z7lPc,2107
129
129
  core/config.py,sha256=YmkcZwedz_lfDM0ZuI_f4xpe98ixPLcSQFcTCHgRiRg,19206
@@ -181,7 +181,7 @@ services/access_telemetry.py,sha256=9pOCLS9LgDtM7Z4cCEyl7osxhj-m3wsPubcXolBKuV4,
181
181
  services/activity_log.py,sha256=PNGeEYlw1Aux-mRU4pKCQdbsSuzLvOg7MYiq-cb4n8g,4473
182
182
  services/agent_base.py,sha256=a-gdSd_jtZtbjXo1WS8CnWCagXgKaGZd5ShcG6s0kT4,4809
183
183
  services/agent_locks.py,sha256=nRAPuRSoet7BG9oOsNyA5WhlNy-UMhpsq6z5ggIPmLA,22421
184
- services/agents.py,sha256=vwfqs8mOlJDXQcGnWOFLPlXnrXraKjiF6lQRsEb0uB4,84469
184
+ services/agents.py,sha256=oKJS6yUxA49RO9cKvUk59QipIxQoYVvEnl1S46nWpPc,83571
185
185
  services/artifact_defs.py,sha256=4bJAcg2maJCtMhY3ub_IxZg49bVg1mD_B5Z4Bn5NF0o,9805
186
186
  services/artifact_store.py,sha256=vCHpOzOcZmR5VF_BxcvIh6G0rPMl07c1W6Wdu2OkVVA,31098
187
187
  services/atomic_json.py,sha256=8-TXLXDv6raPCCjbyU13M-zbJmsnFRp1TsAP4kLG174,5661
@@ -203,7 +203,7 @@ services/circuit_breaker.py,sha256=ES6PpjL40gfDhtK88GeS6GFzsz5EOEEkZsB-DzX_tbw,3
203
203
  services/claude_md.py,sha256=jXvr0orZOkPYrVxEkf67beAj8EKPbB_M99mmxxMsPg4,61217
204
204
  services/codex_integration.py,sha256=dXlaVbQJrIrlZw5hZcDjhZVli3AvumnOTQTkl-_I-rg,7708
205
205
  services/codex_transcript.py,sha256=TtxKiNkZ3vsWpaQRczaIGsA7wd8r24z_65Nnso2BNj0,3658
206
- services/compressor.py,sha256=1K6LzOt7Qg3F50YJAFs2xky_jlrctDf2OqHQQoGuQGU,36022
206
+ services/compressor.py,sha256=oX5Tnn42syY_08_SWukEkRamwTH7qwQ-T6TGIlZNgJY,36148
207
207
  services/context_snapshot.py,sha256=2f_bxY3xX4ZC653ncYno8YSeSTFSavwBjrorytHA0Ns,16879
208
208
  services/conversation_store.py,sha256=RKA0nk09VAI8Ip935kSVlQdF-cQEzFLrgHbZiEJ7G1E,37518
209
209
  services/cred_audit.py,sha256=tdxnRzbB0c8nJ7dqA9HOJrcOeRWivEzq6yhwu6ksmZI,10240
@@ -217,7 +217,8 @@ services/edit_ledger.py,sha256=Tj8Q14o19VHQHpofRHdbZKKcVs17v-ctZ3LOeVTqvdQ,29362
217
217
  services/embedding_index.py,sha256=c85kAkekL7r-liiFEwqi7nJAQr4ZbJA36h0oMdiTurc,25156
218
218
  services/enforcement_policy.py,sha256=bB-lI7EZwWT5MhoNtkBjjixN4h7zAYUtVBWPMJ6aONo,17196
219
219
  services/error_reporting.py,sha256=HZ3ru8i5RLf8nq2R4iRnTs5sm1blUxknSbv5hdxuxs0,4139
220
- services/file_memory.py,sha256=vUvgBBdFC_rvCp9GXfvfojQIr6iSHWTRFrzWG5e0kHs,35048
220
+ services/file_map.py,sha256=t5Ua4abJDuo-EZSX793MWiXg4uMqNAk1KxZrOffIm48,14500
221
+ services/file_memory.py,sha256=AckiClEKJeVJqCPoCTrqkCMDfHruVWhz2UZn3Df_7bU,33788
221
222
  services/git_context.py,sha256=FFdA8Y46op4DYsUnZsXLTqxIjgxb0q_d-hkFTbosC8Q,9518
222
223
  services/hub_service.py,sha256=z2MZ2Rg9NLNXxQ17e05XGF_f6qSTDWLYtoC3WpuQfGU,2634
223
224
  services/index_store.py,sha256=SWHHKQB_wYww1ubtKgkLo5FFEqaWhPbw0OAN8x3gk9Q,16453
@@ -249,7 +250,7 @@ services/override_grants.py,sha256=BQVwD6WCxVORsUaqDWNToIalz2mStnJRMIR-SOxQzuQ,3
249
250
  services/override_policy.py,sha256=VC5H-FETUz4u6f4JM_q5jqT2HIb1MiFzhpdJyuBG72I,22369
250
251
  services/override_requests.py,sha256=H9lSUbfOjkjE1muztaQ58InqqsqhtnKIT-pF2VzvWkg,31148
251
252
  services/override_wake.py,sha256=HjSOXQTDi0irgeMyrTqngL7xLcSOOIgYsVW9yxod4ps,10363
252
- services/parser.py,sha256=0cOOVY_tz_9KKmAr1Qj2_I8NCz1W0bf4xNBwkwdFRJs,58218
253
+ services/parser.py,sha256=4pklWjWICIVohRLghylS727idWCWyrUBWks1Xh4526o,62782
253
254
  services/project_manager.py,sha256=uQh-GUvH5cgV5Ce9XYPINlQeqH6NvNdW8zrNFYRbBkw,37855
254
255
  services/project_runtime.py,sha256=yyftX48BFjq4B2KcR4KGszDAAa4xR6gn6j0SgTyro1s,11603
255
256
  services/protocol.py,sha256=CWZ0BWWd-jPui-11hZlvGgkNk18gMFhhLWbp-BP35Kk,12861
@@ -270,7 +271,7 @@ services/shell_jobs.py,sha256=p95Sr_lCA04ZkZh3UezeIxxw72_ClDzASaH-T9CV8CA,48581
270
271
  services/shell_output.py,sha256=lLvENKqS9N7-hsVw9M7fWUXhBVPaaGRmU9dRx3Vr4Dk,42558
271
272
  services/subprojects.py,sha256=pjGbuWLqC81QxYMai9ZbNxmTJTuwzM7QNiyAqeZG-Yg,41218
272
273
  services/task_store.py,sha256=QoyhLcAyd-JZxn1nMfnZ11tTLgFqY-xwmlx1q8w_1p8,49477
273
- services/telemetry.py,sha256=pz4KviB8V29HaLZwm1OOcmqWn2GdQbk__UgwNI4x2v0,20597
274
+ services/telemetry.py,sha256=nueiwm8rR-OjTInBt0G4wAr7Qit5nUI92I5B2EIowZE,26128
274
275
  services/text_index.py,sha256=r3o4CobTG9jAO9PWazgbWYLY9oi_FgEJ3xwEXrF4KM0,2783
275
276
  services/time_tracker.py,sha256=sZNz8QAYpWhCBwfmvopVyxpMb8H-CrBT25C0_VOT1LY,11056
276
277
  services/tool_classifier.py,sha256=Fgvq0ZcpnCskwtO8a3YI1MiecPNnw6UbPyJQIUwgfiQ,6512
@@ -280,6 +281,7 @@ services/vector_store.py,sha256=satc4MJanC1Wsu_iveMCUXG6K2fd0Ke87JSyy2BMikw,1304
280
281
  services/watcher.py,sha256=xsMlXy4VxX5_CXGQDfmOeZrvlU42S2mGubZgTheCS_s,7859
281
282
  services/win_subprocess.py,sha256=nt8Uwc2PrqsRW3-jcViEsoKj56GudW8TV3CQwryx8y4,4271
282
283
  services/bench/__init__.py,sha256=WLEJIWJeaUj6FnH2nDO1qWugJDKfOKeM6WvKLSreYjI,231
284
+ services/bench/map_eval.py,sha256=i0M3hBJQM9wXX4dMB_2LjVKoFtXzFUKapoqjGB_8tcE,43456
283
285
  services/bench/search_eval.py,sha256=HjVDoIs_uTvNhbT_YjhNjCPEweUG5goaUDaipOcjuF4,29234
284
286
  services/bench/shell_eval.py,sha256=YW4qFO6JwmHuv-7_aaQG4QcDpXqnSEZ5uqFDigzTo_8,26723
285
287
  services/bench/external/__init__.py,sha256=XgPS99ztx9igMd6x-1bLykcaePGXctkb6ujQ1MLgKAs,608
@@ -303,8 +305,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
303
305
  tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
304
306
  tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
305
307
  tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
306
- code_context_control-2.119.0.dist-info/METADATA,sha256=vC05A__3lkThii-29HtPfZDyyodXmQ5k1F8X9WSHqzA,27067
307
- code_context_control-2.119.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
308
- code_context_control-2.119.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
309
- code_context_control-2.119.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
310
- code_context_control-2.119.0.dist-info/RECORD,,
308
+ code_context_control-2.121.0.dist-info/METADATA,sha256=bLL-hxMFWw55dYOgBSwJqDy_Uq73ZXh1ZUmievzSMOU,27067
309
+ code_context_control-2.121.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
310
+ code_context_control-2.121.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
311
+ code_context_control-2.121.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
312
+ code_context_control-2.121.0.dist-info/RECORD,,
services/agents.py CHANGED
@@ -923,29 +923,10 @@ class FileMemoryAgent(BackgroundAgent):
923
923
  completed = []
924
924
  failed = []
925
925
  for rel_path in files_to_process:
926
- ai_summary = None
927
-
928
- # Generate AI summary if available
929
- if self.ai_available:
930
- record = self.file_memory.get(rel_path)
931
- section_names = ""
932
- if record:
933
- names = [s.get("name", "") for s in record.get("sections", [])
934
- if s.get("type") not in ("import", "decorator")]
935
- section_names = ", ".join(names[:10])
936
-
937
- if section_names:
938
- ai_summary = self._ai_generate(
939
- f"File: {rel_path}\n"
940
- f"Symbols: {section_names}\n\n"
941
- f"Describe the purpose of this file and its main symbols in 1-2 concise sentences. "
942
- f"Focus on what they do, not how they are implemented.",
943
- system="You are a senior architect summarizing code for an AI assistant. "
944
- "Be technical, concise, and highlight the main responsibilities of the symbols.",
945
- max_tokens=100,
946
- )
947
-
948
- result = self.file_memory.update(rel_path, ai_summary=ai_summary)
926
+ # No generated summary: it was produced from symbol names alone
927
+ # and half of the stored ones were cut mid-sentence (2026-09-06).
928
+ # The map carries symbols and ranges only (docs/file-map.md).
929
+ result = self.file_memory.update(rel_path)
949
930
  if result:
950
931
  updated_count += 1
951
932
  completed.append(rel_path)