codecompass-mcp 3.1.0__tar.gz → 3.2.0__tar.gz
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.
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/PKG-INFO +1 -1
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/PKG-INFO +1 -1
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/graph/code_graph_client.py +42 -7
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/main.py +21 -7
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/pyproject.toml +1 -1
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_accuracy_fixes.py +12 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/LICENSE +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/README.md +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/SOURCES.txt +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/dependency_links.txt +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/entry_points.txt +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/requires.txt +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/top_level.txt +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/config.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/graph/__init__.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/graph/cli.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/graph/code_query_cli.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/graph/setup.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/__init__.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/chunker.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/code_normalizer.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/code_parser.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/description_enricher.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/entity_resolver.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/file_watcher.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/graph_writer.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/hierarchy_builder.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/reader_agent.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/ingestion/source_context.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/mcp_server.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/models/__init__.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/models/code_types.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/models/types.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/setup.cfg +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_batch_impact.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_blast_radius.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_code_parser.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_description_enricher.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_ingestion.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_lit_css_parser.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_mcp_server.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/tests/test_php_parser.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/utils/__init__.py +0 -0
- {codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/utils/formatting.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecompass-mcp
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Structural code context for AI coding agents — a local code knowledge graph for blast radius, impact, deps, dead code, and flow tracing
|
|
5
5
|
Author: CodeCompass contributors
|
|
6
6
|
License: MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecompass-mcp
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Structural code context for AI coding agents — a local code knowledge graph for blast radius, impact, deps, dead code, and flow tracing
|
|
5
5
|
Author: CodeCompass contributors
|
|
6
6
|
License: MIT
|
|
@@ -60,18 +60,30 @@ def _strip_code_ext(path: str) -> str:
|
|
|
60
60
|
return path
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def _import_resolves_to(import_str: str, from_file: str, target_file: str
|
|
63
|
+
def _import_resolves_to(import_str: str, from_file: str, target_file: str,
|
|
64
|
+
psr4: dict[str, str] | None = None) -> bool:
|
|
64
65
|
"""True if `import_str` written in `from_file` refers to `target_file`.
|
|
65
66
|
|
|
66
67
|
Resolves relative CommonJS/ESM specifiers (`./response`, `../lib/response`,
|
|
67
|
-
with an implicit `/index`)
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
with an implicit `/index`), dotted module names (`lib.response`), and — via a
|
|
69
|
+
composer PSR-4 map — PHP namespaces (`GuzzleHttp.Client` → `src/Client.php`)
|
|
70
|
+
against the target's extension-stripped path. Package imports never match a
|
|
71
|
+
project file and return False.
|
|
70
72
|
"""
|
|
71
73
|
if not import_str or not target_file:
|
|
72
74
|
return False
|
|
73
75
|
target_base = _strip_code_ext(target_file).replace("\\", "/")
|
|
74
76
|
|
|
77
|
+
# PSR-4 (PHP): namespace prefix -> directory, from composer.json autoload.
|
|
78
|
+
if psr4:
|
|
79
|
+
for prefix, directory in psr4.items():
|
|
80
|
+
pfx = prefix + "."
|
|
81
|
+
if import_str.startswith(pfx):
|
|
82
|
+
rest = import_str[len(pfx):].replace(".", "/")
|
|
83
|
+
base = f"{directory.rstrip('/')}/{rest}".replace("\\", "/")
|
|
84
|
+
if base == target_base:
|
|
85
|
+
return True
|
|
86
|
+
|
|
75
87
|
if import_str.startswith("."):
|
|
76
88
|
from_dir = os.path.dirname(from_file)
|
|
77
89
|
resolved = os.path.normpath(os.path.join(from_dir, import_str)).replace("\\", "/")
|
|
@@ -931,10 +943,33 @@ class LocalGraphClient:
|
|
|
931
943
|
|
|
932
944
|
return results, target_file
|
|
933
945
|
|
|
946
|
+
def _psr4(self) -> dict[str, str]:
|
|
947
|
+
"""PHP composer PSR-4 map: dotted namespace prefix -> source directory
|
|
948
|
+
(e.g. {'GuzzleHttp': 'src/'}), so `use GuzzleHttp\\Client` resolves to a
|
|
949
|
+
file. Read once from composer.json at the repo root; empty if none."""
|
|
950
|
+
if hasattr(self, "_psr4_cache"):
|
|
951
|
+
return self._psr4_cache
|
|
952
|
+
m: dict[str, str] = {}
|
|
953
|
+
repo = os.path.dirname(os.path.dirname(self.storage_path))
|
|
954
|
+
try:
|
|
955
|
+
with open(os.path.join(repo, "composer.json")) as f:
|
|
956
|
+
data = json.load(f)
|
|
957
|
+
for key in ("autoload", "autoload-dev"):
|
|
958
|
+
for ns, path in (data.get(key, {}).get("psr-4", {}) or {}).items():
|
|
959
|
+
prefix = ns.rstrip("\\").replace("\\", ".")
|
|
960
|
+
paths = path if isinstance(path, list) else [path]
|
|
961
|
+
if prefix and paths:
|
|
962
|
+
m[prefix] = paths[0]
|
|
963
|
+
except Exception:
|
|
964
|
+
pass
|
|
965
|
+
self._psr4_cache = m
|
|
966
|
+
return m
|
|
967
|
+
|
|
934
968
|
def _direct_importers(self, target_file: str) -> list[str]:
|
|
935
969
|
"""Source files with an IMPORTS edge whose module string resolves to
|
|
936
|
-
target_file. Handles
|
|
937
|
-
(`lib.response`)
|
|
970
|
+
target_file. Handles relative (`./response`), dotted-module
|
|
971
|
+
(`lib.response`), and PHP PSR-4 namespace (`GuzzleHttp\\Client`) spellings."""
|
|
972
|
+
psr4 = self._psr4()
|
|
938
973
|
importers: list[str] = []
|
|
939
974
|
for _u, v, data in self.graph.edges(data=True):
|
|
940
975
|
if data.get("type") != "IMPORTS":
|
|
@@ -943,7 +978,7 @@ class LocalGraphClient:
|
|
|
943
978
|
if not from_file:
|
|
944
979
|
continue
|
|
945
980
|
import_str = self.graph.nodes[v].get("name", "")
|
|
946
|
-
if _import_resolves_to(import_str, from_file, target_file):
|
|
981
|
+
if _import_resolves_to(import_str, from_file, target_file, psr4):
|
|
947
982
|
importers.append(from_file)
|
|
948
983
|
return sorted(set(importers))
|
|
949
984
|
|
|
@@ -26,8 +26,10 @@ _CODECOMPASS_START = "<!-- codecompass-code-graph-start -->"
|
|
|
26
26
|
_CODECOMPASS_END = "<!-- codecompass-code-graph-end -->"
|
|
27
27
|
_CODECOMPASS_READ_INSTRUCTION = (
|
|
28
28
|
"Orient through the code graph first: start from an entry point, see what's "
|
|
29
|
-
"there, then trace its flow and dependencies —
|
|
30
|
-
"
|
|
29
|
+
"there, then trace its flow and dependencies — never use `cat`, `grep`, or "
|
|
30
|
+
"`rg` to search or read code content. Use the `codecompass query` commands "
|
|
31
|
+
"below for discovery and tracing, then read only the specific slices the "
|
|
32
|
+
"graph points you to."
|
|
31
33
|
)
|
|
32
34
|
|
|
33
35
|
|
|
@@ -324,6 +326,7 @@ def ingest_code(repo_path: str, normalize: bool = False, dump_triples: str | Non
|
|
|
324
326
|
def _register_project_agents_md(repo_path: str) -> None:
|
|
325
327
|
"""Write or update the Code graph section in the project's AGENTS.md."""
|
|
326
328
|
block = f"""{_CODECOMPASS_START}
|
|
329
|
+
<!-- This file must stay byte-for-byte identical to its counterpart in pi-package/templates/. Run scripts/check-pi-package-sync.sh to verify. -->
|
|
327
330
|
## Code graph
|
|
328
331
|
|
|
329
332
|
**{_CODECOMPASS_READ_INSTRUCTION}**
|
|
@@ -360,8 +363,18 @@ All commands default to the current directory — run them from the project root
|
|
|
360
363
|
3. **Read** the specific slice the graph pointed you to (Read tool / `sed -n`),
|
|
361
364
|
not the whole file.
|
|
362
365
|
|
|
363
|
-
4. **Edit** —
|
|
364
|
-
|
|
366
|
+
4. **Edit** — before editing, verify the target fully so you don't break callers or dependents:
|
|
367
|
+
- Run `--deps <file>` to understand what the file relies on.
|
|
368
|
+
- Run `--flow <entry_symbol> --format json` (or `--flow-summary <entry_symbol>`) to trace the logic end-to-end.
|
|
369
|
+
- Run `--impact <symbol>` for every symbol you plan to change.
|
|
370
|
+
- Run `--blast-radius <file>` for every file you plan to change.
|
|
371
|
+
- Read the specific slices the graph identified.
|
|
372
|
+
- Then make the smallest correct change.
|
|
373
|
+
|
|
374
|
+
After any code change (edits, additions, deletions, renames, refactors), re-ingest so the graph stays current:
|
|
375
|
+
```bash
|
|
376
|
+
codecompass ingest-code
|
|
377
|
+
```
|
|
365
378
|
|
|
366
379
|
### Reading the results
|
|
367
380
|
|
|
@@ -403,8 +416,9 @@ scripts). Results are split into "likely dead" and (with `--include-entrypoints`
|
|
|
403
416
|
"possible entry points".
|
|
404
417
|
|
|
405
418
|
This is STATIC analysis: dynamic dispatch, reflection, and string-based
|
|
406
|
-
invocation are invisible. Treat every result as a candidate —
|
|
407
|
-
|
|
419
|
+
invocation are invisible. Treat every result as a candidate — use
|
|
420
|
+
`codecompass query --grep <name>` or `--search <name>` to confirm it is truly
|
|
421
|
+
unused before deleting it.
|
|
408
422
|
|
|
409
423
|
### Project notes: `overview.md`, `memory.md`, `learnings.md`
|
|
410
424
|
|
|
@@ -432,7 +446,7 @@ doc → `memory.md`; code-comment warning to the next person → `learnings.md`.
|
|
|
432
446
|
|
|
433
447
|
### When to re-ingest
|
|
434
448
|
|
|
435
|
-
- After
|
|
449
|
+
- After every code change: edits, additions, deletions, renames, refactors
|
|
436
450
|
- After major refactors (moved functions, renamed classes)
|
|
437
451
|
- If query results look stale or incomplete
|
|
438
452
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "codecompass-mcp"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.2.0"
|
|
4
4
|
description = "Structural code context for AI coding agents — a local code knowledge graph for blast radius, impact, deps, dead code, and flow tracing"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -339,6 +339,18 @@ def test_python_public_method_marked_exported():
|
|
|
339
339
|
assert by_name.get("_private") is False, "underscore method is not exported"
|
|
340
340
|
|
|
341
341
|
|
|
342
|
+
def test_php_psr4_import_resolution():
|
|
343
|
+
from graph.code_graph_client import _import_resolves_to
|
|
344
|
+
psr4 = {"GuzzleHttp": "src/", "GuzzleHttp.Tests": "tests/"}
|
|
345
|
+
assert _import_resolves_to("GuzzleHttp.Client", "src/Pool.php", "src/Client.php", psr4)
|
|
346
|
+
assert _import_resolves_to("GuzzleHttp.Handler.CurlFactory", "src/x.php",
|
|
347
|
+
"src/Handler/CurlFactory.php", psr4)
|
|
348
|
+
assert _import_resolves_to("GuzzleHttp.Tests.ClientTest", "src/x.php",
|
|
349
|
+
"tests/ClientTest.php", psr4)
|
|
350
|
+
assert not _import_resolves_to("GuzzleHttp.Client", "src/Pool.php", "src/Other.php", psr4)
|
|
351
|
+
assert not _import_resolves_to("Vendor.Lib.Thing", "src/x.php", "src/Client.php", psr4)
|
|
352
|
+
|
|
353
|
+
|
|
342
354
|
def test_inheritance_super_resolution_all_langs():
|
|
343
355
|
cases = [
|
|
344
356
|
(".py", "class Command:\n def invoke(self, c): pass\n"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codecompass_mcp-3.1.0 → codecompass_mcp-3.2.0}/codecompass_mcp.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|