compass-code 0.1.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.
- compass_cli/__init__.py +0 -0
- compass_cli/commands/__init__.py +0 -0
- compass_cli/commands/ingest.py +310 -0
- compass_cli/commands/mcp.py +25 -0
- compass_cli/commands/query.py +181 -0
- compass_cli/commands/serve.py +123 -0
- compass_cli/commands/setup.py +171 -0
- compass_cli/display.py +231 -0
- compass_cli/errors.py +30 -0
- compass_cli/main.py +54 -0
- compass_cli/progress.py +191 -0
- compass_cli/result_views.py +389 -0
- compass_cli/types.py +41 -0
- compass_code-0.1.0.dist-info/METADATA +72 -0
- compass_code-0.1.0.dist-info/RECORD +137 -0
- compass_code-0.1.0.dist-info/WHEEL +4 -0
- compass_code-0.1.0.dist-info/entry_points.txt +2 -0
- compass_core/__init__.py +1 -0
- compass_core/contract/__init__.py +6 -0
- compass_core/contract/errors.py +116 -0
- compass_core/contract/models.py +204 -0
- compass_core/contract/params.py +99 -0
- compass_core/contract/results.py +370 -0
- compass_core/contract/serialize.py +59 -0
- compass_core/contract/types.py +76 -0
- compass_core/errors.py +148 -0
- compass_core/graph/__init__.py +0 -0
- compass_core/graph/db.py +205 -0
- compass_core/graph/schema.py +165 -0
- compass_core/graph/stored_ids.py +133 -0
- compass_core/graph/writer.py +482 -0
- compass_core/index/__init__.py +1 -0
- compass_core/index/freshness.py +55 -0
- compass_core/index/locate.py +155 -0
- compass_core/index/metadata.py +107 -0
- compass_core/ir/__init__.py +0 -0
- compass_core/ir/graph.py +65 -0
- compass_core/ir/models.py +75 -0
- compass_core/languages/__init__.py +1 -0
- compass_core/languages/base.py +26 -0
- compass_core/languages/python/__init__.py +6 -0
- compass_core/languages/python/extractor.py +670 -0
- compass_core/languages/python/import_resolver.py +107 -0
- compass_core/languages/registry.py +89 -0
- compass_core/logger.py +42 -0
- compass_core/phases/__init__.py +0 -0
- compass_core/phases/base.py +58 -0
- compass_core/phases/discovery.py +167 -0
- compass_core/phases/parse.py +80 -0
- compass_core/phases/persistence.py +33 -0
- compass_core/phases/pipeline.py +152 -0
- compass_core/phases/resolution.py +572 -0
- compass_core/phases/symbol_table.py +36 -0
- compass_core/phases/validation.py +76 -0
- compass_core/progress.py +45 -0
- compass_core/py.typed +0 -0
- compass_core/query/__init__.py +1 -0
- compass_core/query/cypher.py +92 -0
- compass_core/query/detail.py +241 -0
- compass_core/query/graph_map.py +127 -0
- compass_core/query/impact.py +273 -0
- compass_core/query/impact_walk.py +352 -0
- compass_core/query/overview.py +221 -0
- compass_core/query/references.py +235 -0
- compass_core/query/rows.py +378 -0
- compass_core/query/search.py +183 -0
- compass_core/query/status.py +49 -0
- compass_core/query/walk_queries.py +202 -0
- compass_core/render.py +408 -0
- compass_core/settings.py +61 -0
- compass_core/shared_types.py +78 -0
- compass_mcp/__init__.py +0 -0
- compass_mcp/guide.py +45 -0
- compass_mcp/py.typed +0 -0
- compass_mcp/server.py +261 -0
- compass_server/__init__.py +5 -0
- compass_server/errors.py +84 -0
- compass_server/main.py +42 -0
- compass_server/py.typed +0 -0
- compass_server/routers/__init__.py +0 -0
- compass_server/routers/query.py +182 -0
- compass_server/settings.py +37 -0
- compass_server/static/404.html +1 -0
- compass_server/static/_next/static/chunks/1629039a.eed2a06658ec4f9c.js +1 -0
- compass_server/static/_next/static/chunks/1ff282bf-bb7c483245264fc9.js +1 -0
- compass_server/static/_next/static/chunks/223.f881a22f446259bf.js +508 -0
- compass_server/static/_next/static/chunks/51fa5c19.6396973222c9d6fd.js +485 -0
- compass_server/static/_next/static/chunks/556.443c1682b6b20128.js +1 -0
- compass_server/static/_next/static/chunks/684-1aa0170f59baf77e.js +1 -0
- compass_server/static/_next/static/chunks/92e71660.3a42d4f70d017951.js +342 -0
- compass_server/static/_next/static/chunks/937-8692224bb6d1b605.js +1 -0
- compass_server/static/_next/static/chunks/app/_not-found/page-2c96ddf295eb6a86.js +1 -0
- compass_server/static/_next/static/chunks/app/layout-4bd0ba4a7d18aff9.js +1 -0
- compass_server/static/_next/static/chunks/app/page-5376a0a98bbd1faa.js +1 -0
- compass_server/static/_next/static/chunks/framework-96dcd958cfe08bd4.js +1 -0
- compass_server/static/_next/static/chunks/main-6dee8e626b16731a.js +1 -0
- compass_server/static/_next/static/chunks/main-app-460e8bc670818718.js +1 -0
- compass_server/static/_next/static/chunks/pages/_app-638a3e7363f92b80.js +1 -0
- compass_server/static/_next/static/chunks/pages/_error-6a72dbbb45cae743.js +1 -0
- compass_server/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- compass_server/static/_next/static/chunks/webpack-597057bf48ce4111.js +1 -0
- compass_server/static/_next/static/css/1b0fbfd8dd653f37.css +3 -0
- compass_server/static/_next/static/ctUZeD9K7jQUgLqmBas2L/_buildManifest.js +1 -0
- compass_server/static/_next/static/ctUZeD9K7jQUgLqmBas2L/_ssgManifest.js +1 -0
- compass_server/static/_next/static/media/0086f8992871c45b-s.woff2 +0 -0
- compass_server/static/_next/static/media/034d78ad42e9620c-s.woff2 +0 -0
- compass_server/static/_next/static/media/03b436aa846269de-s.woff2 +0 -0
- compass_server/static/_next/static/media/0484562807a97172-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/08aedeceaf1dcd57-s.woff2 +0 -0
- compass_server/static/_next/static/media/0aa834ed78bf6d07-s.woff2 +0 -0
- compass_server/static/_next/static/media/29a4aea02fdee119-s.woff2 +0 -0
- compass_server/static/_next/static/media/29e7bbdce9332268-s.woff2 +0 -0
- compass_server/static/_next/static/media/36008747766f78c6-s.woff2 +0 -0
- compass_server/static/_next/static/media/39969fcf98a3026e-s.woff2 +0 -0
- compass_server/static/_next/static/media/4de1fea1a954a5b6-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/5c0c2bcbaa4149ca-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/67957d42bae0796d-s.woff2 +0 -0
- compass_server/static/_next/static/media/6d38f9d4e0f4772b-s.woff2 +0 -0
- compass_server/static/_next/static/media/6d664cce900333ee-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/886030b0b59bc5a7-s.woff2 +0 -0
- compass_server/static/_next/static/media/8888a3826f4a3af4-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/939c4f875ee75fbb-s.woff2 +0 -0
- compass_server/static/_next/static/media/a1386beebedccca4-s.woff2 +0 -0
- compass_server/static/_next/static/media/ab00a911ac2adf48-s.woff2 +0 -0
- compass_server/static/_next/static/media/b957ea75a84b6ea7-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/bb3ef058b751a6ad-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/c3bc380753a8436c-s.woff2 +0 -0
- compass_server/static/_next/static/media/cce080f35d014443-s.woff2 +0 -0
- compass_server/static/_next/static/media/db911767852bc875-s.woff2 +0 -0
- compass_server/static/_next/static/media/eafabf029ad39a43-s.p.woff2 +0 -0
- compass_server/static/_next/static/media/f10b8e9d91f3edcb-s.woff2 +0 -0
- compass_server/static/_next/static/media/f911b923c6adde36-s.woff2 +0 -0
- compass_server/static/_next/static/media/fe0777f1195381cb-s.woff2 +0 -0
- compass_server/static/index.html +1 -0
- compass_server/static/index.txt +25 -0
- compass_server/web_bundle.py +27 -0
- compass_server/web_limits.py +48 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Typed read/write of ``.compass/metadata.json``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from datetime import UTC, datetime
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from compass_core.errors import IndexIncompatibleError
|
|
13
|
+
from compass_core.shared_types import Language
|
|
14
|
+
|
|
15
|
+
SCHEMA_VERSION = 2
|
|
16
|
+
"""Graph schema written by this version of compass; indexes in any other version are
|
|
17
|
+
rejected and must be rebuilt with ``compass ingest``.
|
|
18
|
+
|
|
19
|
+
History: 1 stored internal ids (``py::app.models::User``); 2 stores public ids
|
|
20
|
+
(``app/models.py::User``) and a ``qualified_name`` on classes and functions.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
25
|
+
class IndexMetadata:
|
|
26
|
+
"""Facts recorded about an index at ingest time.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
indexed_commit: Git HEAD commit at ingest, or ``None`` if unknown.
|
|
30
|
+
indexed_at: Ingest time (timezone-aware).
|
|
31
|
+
schema_version: Metadata/index schema version; pre-v1 files count as 1.
|
|
32
|
+
grammar_versions: Installed grammar package version per language.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
``{"indexed_commit": "abc", "indexed_at": 1788431823, "grammar_versions":
|
|
36
|
+
{"python": "0.25.0"}}`` loads as ``IndexMetadata(indexed_commit="abc",
|
|
37
|
+
indexed_at=datetime(..., tzinfo=UTC), schema_version=2,
|
|
38
|
+
grammar_versions={Language.PYTHON: "0.25.0"})``.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
indexed_commit: str | None
|
|
42
|
+
indexed_at: datetime
|
|
43
|
+
schema_version: int
|
|
44
|
+
grammar_versions: Mapping[Language, str]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def save_metadata(path: Path, meta: IndexMetadata) -> None:
|
|
48
|
+
"""Atomically write ``meta`` to ``path`` as JSON.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
path: Destination ``metadata.json``; parent directories are created.
|
|
52
|
+
meta: Metadata to store. ``indexed_at`` is stored as epoch seconds.
|
|
53
|
+
"""
|
|
54
|
+
payload = {
|
|
55
|
+
"schema_version": meta.schema_version,
|
|
56
|
+
"indexed_commit": meta.indexed_commit,
|
|
57
|
+
"indexed_at": int(meta.indexed_at.timestamp()),
|
|
58
|
+
"grammar_versions": {lang.value: v for lang, v in meta.grammar_versions.items()},
|
|
59
|
+
}
|
|
60
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
tmp = path.with_name(f"{path.name}.{os.getpid()}.tmp")
|
|
62
|
+
try:
|
|
63
|
+
tmp.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
64
|
+
os.replace(tmp, path)
|
|
65
|
+
except BaseException:
|
|
66
|
+
tmp.unlink(missing_ok=True)
|
|
67
|
+
raise
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def load_metadata(path: Path) -> IndexMetadata:
|
|
71
|
+
"""Read metadata from ``path``.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
path: Path to ``metadata.json``.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The parsed metadata. A missing ``schema_version`` counts as 1.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
IndexIncompatibleError: If the file is unreadable, malformed, has an unknown
|
|
81
|
+
language, or its ``schema_version`` is not ``SCHEMA_VERSION``.
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
85
|
+
schema_version = raw.get("schema_version", 1)
|
|
86
|
+
if isinstance(schema_version, bool) or not isinstance(schema_version, int):
|
|
87
|
+
raise ValueError(f"invalid schema_version {schema_version!r}")
|
|
88
|
+
if schema_version != SCHEMA_VERSION:
|
|
89
|
+
raise IndexIncompatibleError(
|
|
90
|
+
f"The index at {path.parent} uses schema version {schema_version}; this "
|
|
91
|
+
f"compass reads version {SCHEMA_VERSION}. Run `compass ingest` to rebuild it."
|
|
92
|
+
)
|
|
93
|
+
indexed_at = raw["indexed_at"]
|
|
94
|
+
if isinstance(indexed_at, bool) or not isinstance(indexed_at, int | float):
|
|
95
|
+
raise ValueError(f"invalid indexed_at {indexed_at!r}")
|
|
96
|
+
commit = raw.get("indexed_commit")
|
|
97
|
+
return IndexMetadata(
|
|
98
|
+
indexed_commit=None if commit is None else str(commit),
|
|
99
|
+
indexed_at=datetime.fromtimestamp(indexed_at, UTC),
|
|
100
|
+
schema_version=schema_version,
|
|
101
|
+
grammar_versions={
|
|
102
|
+
Language(lang): str(v) for lang, v in raw.get("grammar_versions", {}).items()
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
except (OSError, KeyError, ValueError, TypeError, AttributeError, OverflowError) as exc:
|
|
106
|
+
# JSONDecodeError is a ValueError subclass.
|
|
107
|
+
raise IndexIncompatibleError(f"Unreadable index metadata at {path}: {exc}") from exc
|
|
File without changes
|
compass_core/ir/graph.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Resolved call/import/inheritance graph — Phase 3 output, Phase 5 input.
|
|
2
|
+
|
|
3
|
+
Edge shapes are kept as four distinct dataclasses (not collapsed into one
|
|
4
|
+
generic Edge type) because call_resolver's 10 prioritized resolution rules
|
|
5
|
+
carry different fields per edge kind (external edges have no callee_id,
|
|
6
|
+
only a full_ref + library) and collapsing would lose that without gaining
|
|
7
|
+
anything — this mirrors resolver/models.py exactly, just relocated.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
|
|
14
|
+
from compass_core.ir.models import ParsedFile
|
|
15
|
+
from compass_core.shared_types import CallType, UnlinkedCall
|
|
16
|
+
|
|
17
|
+
CONFIDENCE: dict[CallType | UnlinkedCall, float] = {
|
|
18
|
+
CallType.DIRECT_IMPORT: 1.0,
|
|
19
|
+
CallType.MODULE_ATTR: 0.9,
|
|
20
|
+
CallType.RE_EXPORT: 0.8,
|
|
21
|
+
CallType.MRO: 0.8,
|
|
22
|
+
UnlinkedCall.WILDCARD: 0.6,
|
|
23
|
+
UnlinkedCall.DYNAMIC: 0.0,
|
|
24
|
+
UnlinkedCall.CIRCULAR: 0.0,
|
|
25
|
+
UnlinkedCall.EXTERNAL: 0.0,
|
|
26
|
+
UnlinkedCall.UNRESOLVED: 0.0,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(slots=True)
|
|
31
|
+
class CallEdge:
|
|
32
|
+
caller_id: str
|
|
33
|
+
callee_id: str
|
|
34
|
+
call_type: CallType
|
|
35
|
+
confidence: float
|
|
36
|
+
line: int = 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(slots=True)
|
|
40
|
+
class ExternalCallEdge:
|
|
41
|
+
caller_id: str
|
|
42
|
+
full_ref: str
|
|
43
|
+
library: str
|
|
44
|
+
line: int = 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(slots=True)
|
|
48
|
+
class ImportEdge:
|
|
49
|
+
from_path: str
|
|
50
|
+
to_path: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(slots=True)
|
|
54
|
+
class InheritEdge:
|
|
55
|
+
child_id: str
|
|
56
|
+
parent_id: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class ResolvedGraph:
|
|
61
|
+
files: list[ParsedFile] = field(default_factory=list)
|
|
62
|
+
call_edges: list[CallEdge] = field(default_factory=list)
|
|
63
|
+
external_call_edges: list[ExternalCallEdge] = field(default_factory=list)
|
|
64
|
+
import_edges: list[ImportEdge] = field(default_factory=list)
|
|
65
|
+
inherit_edges: list[InheritEdge] = field(default_factory=list)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Language-agnostic IR — the seam below which no phase may know a specific language.
|
|
2
|
+
|
|
3
|
+
Definition covers class/function/method (var/interface/struct are future
|
|
4
|
+
kinds, added when a language that needs them is registered — do not add
|
|
5
|
+
unused kinds speculatively).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from compass_core.shared_types import CallType, DefinitionKind, Language, UnlinkedCall
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(slots=True)
|
|
16
|
+
class Definition:
|
|
17
|
+
id: str # namespaced, e.g. "py::pkg.mod::Foo" or "py::pkg.mod::Foo.bar"
|
|
18
|
+
kind: DefinitionKind
|
|
19
|
+
name: str
|
|
20
|
+
file_path: str
|
|
21
|
+
line_start: int
|
|
22
|
+
line_end: int
|
|
23
|
+
source: str
|
|
24
|
+
docstring: str | None
|
|
25
|
+
bases: list[str] # populated for CLASS only
|
|
26
|
+
parent_id: str | None # populated for METHOD only (id of owning CLASS Definition)
|
|
27
|
+
signature: str | None # populated for FUNCTION/METHOD only
|
|
28
|
+
decorators: list[str]
|
|
29
|
+
raw_calls: list[str] # populated for FUNCTION/METHOD only
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(slots=True)
|
|
33
|
+
class ImportStatement:
|
|
34
|
+
module: str
|
|
35
|
+
names: list[str]
|
|
36
|
+
alias: str | None
|
|
37
|
+
is_relative: bool
|
|
38
|
+
is_from: bool
|
|
39
|
+
line: int
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(slots=True)
|
|
43
|
+
class CallSite:
|
|
44
|
+
callee_name: str
|
|
45
|
+
receiver_expr: str | None
|
|
46
|
+
line: int
|
|
47
|
+
enclosing_definition_id: str | None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class ParsedFile:
|
|
52
|
+
path: str
|
|
53
|
+
language: Language
|
|
54
|
+
module_name: str
|
|
55
|
+
content_hash: str
|
|
56
|
+
definitions: list[Definition]
|
|
57
|
+
imports: list[ImportStatement]
|
|
58
|
+
call_sites: list[CallSite]
|
|
59
|
+
degraded: bool = False
|
|
60
|
+
error: str | None = None # human-readable reason when degraded=True
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(slots=True)
|
|
64
|
+
class CallResult:
|
|
65
|
+
"""Outcome of resolving one raw call string (Phase 3 / resolution.py).
|
|
66
|
+
|
|
67
|
+
Relocated from resolver/call_resolver.py::CallResult, same shape, since
|
|
68
|
+
it's a shared IR-adjacent type this phase produces internally.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
raw: str
|
|
72
|
+
target_id: str | None # Definition.id if resolved internally
|
|
73
|
+
call_type: CallType | UnlinkedCall
|
|
74
|
+
confidence: float
|
|
75
|
+
external_library: str | None = None # set only for EXTERNAL calls
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from compass_core.languages import python as _python # noqa: F401
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Plugin contracts. Every language extractor/import resolver must satisfy
|
|
2
|
+
these Protocols — enforced by mypy --strict in CI (Task 16), not just at
|
|
3
|
+
review time."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Protocol, runtime_checkable
|
|
9
|
+
|
|
10
|
+
from compass_core.ir.models import ParsedFile
|
|
11
|
+
from compass_core.shared_types import Language
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class LanguageExtractor(Protocol):
|
|
16
|
+
language_id: Language
|
|
17
|
+
file_extensions: set[str]
|
|
18
|
+
|
|
19
|
+
def parse(self, source: bytes, file_path: Path) -> ParsedFile: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@runtime_checkable
|
|
23
|
+
class ImportResolver(Protocol):
|
|
24
|
+
language_id: Language
|
|
25
|
+
|
|
26
|
+
def resolve(self, files: list[ParsedFile]) -> dict[str, dict[str, str | None]]: ...
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from compass_core.languages import registry
|
|
2
|
+
from compass_core.languages.python.extractor import PythonExtractor
|
|
3
|
+
from compass_core.languages.python.import_resolver import PythonImportResolver
|
|
4
|
+
|
|
5
|
+
registry.register_extractor(PythonExtractor())
|
|
6
|
+
registry.register_import_resolver(PythonImportResolver())
|