codegraph-brain 0.23.0__py3-none-any.whl → 0.23.2__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.
- cgis/api/mcp_server.py +6 -2
- cgis/cli.py +68 -39
- cgis/query/context/audit.py +86 -8
- cgis/query/render/graph_json.py +22 -8
- {codegraph_brain-0.23.0.dist-info → codegraph_brain-0.23.2.dist-info}/METADATA +1 -1
- {codegraph_brain-0.23.0.dist-info → codegraph_brain-0.23.2.dist-info}/RECORD +9 -9
- {codegraph_brain-0.23.0.dist-info → codegraph_brain-0.23.2.dist-info}/WHEEL +0 -0
- {codegraph_brain-0.23.0.dist-info → codegraph_brain-0.23.2.dist-info}/entry_points.txt +0 -0
- {codegraph_brain-0.23.0.dist-info → codegraph_brain-0.23.2.dist-info}/licenses/LICENSE +0 -0
cgis/api/mcp_server.py
CHANGED
|
@@ -966,8 +966,9 @@ def cgis_audit_reachability(
|
|
|
966
966
|
str | None,
|
|
967
967
|
Field(
|
|
968
968
|
description="Only audit sources at or under this FQN prefix, matched on whole "
|
|
969
|
-
"dot-segments
|
|
970
|
-
"
|
|
969
|
+
"dot-segments. A selection matching no source is an error naming the "
|
|
970
|
+
"whole-segment prefixes it may have meant. Combined with from_type when both "
|
|
971
|
+
"are given."
|
|
971
972
|
),
|
|
972
973
|
] = None,
|
|
973
974
|
depth: Annotated[
|
|
@@ -986,6 +987,9 @@ def cgis_audit_reachability(
|
|
|
986
987
|
one is required. Returns JSON ``{target, covered, gaps}`` where each gap carries
|
|
987
988
|
``fqn``/``file``/``line``. Generalizes to validators, event tracking, or
|
|
988
989
|
service-layer-boundary rules by pointing ``target`` at the required node.
|
|
990
|
+
|
|
991
|
+
A selection that matches no source returns a ❌ message, not an empty
|
|
992
|
+
``{covered: [], gaps: []}`` that would read as a passing audit (#467).
|
|
989
993
|
"""
|
|
990
994
|
if blank := _blank_fqn_error(target):
|
|
991
995
|
return blank
|
cgis/cli.py
CHANGED
|
@@ -20,6 +20,7 @@ style tags you wrote yourself and pure numbers need no escaping.
|
|
|
20
20
|
|
|
21
21
|
import dataclasses
|
|
22
22
|
import json as _json
|
|
23
|
+
from collections.abc import Callable
|
|
23
24
|
from enum import StrEnum
|
|
24
25
|
from pathlib import Path
|
|
25
26
|
|
|
@@ -42,7 +43,7 @@ from cgis.query.analysis.analyzer import AnalyzerEngine
|
|
|
42
43
|
from cgis.query.analysis.anomaly import AnomalyType, ArchitecturalAnomaly
|
|
43
44
|
from cgis.query.analysis.health import HealthScorer
|
|
44
45
|
from cgis.query.analysis.suggest_service import SuggestReport, report_to_dict, suggest_packages
|
|
45
|
-
from cgis.query.context.audit import ReachabilityAudit, audit_reachability
|
|
46
|
+
from cgis.query.context.audit import NoAuditSourcesError, ReachabilityAudit, audit_reachability
|
|
46
47
|
from cgis.query.context.context_service import build_context
|
|
47
48
|
from cgis.query.context.orphans import OrphanReport, find_orphan_classes
|
|
48
49
|
from cgis.query.drift.drift import DriftReport, FitQuality
|
|
@@ -318,6 +319,40 @@ def _resolve_cli_fqn(store: SQLiteStore, target: str, kind: str) -> str:
|
|
|
318
319
|
return resolution.resolved
|
|
319
320
|
|
|
320
321
|
|
|
322
|
+
def _tree_neighbours(
|
|
323
|
+
store: SQLiteStore,
|
|
324
|
+
edges: list[Edge],
|
|
325
|
+
neighbour_of: Callable[[Edge], str],
|
|
326
|
+
*,
|
|
327
|
+
allowed_edge_types: frozenset[EdgeType] | None,
|
|
328
|
+
show_external: bool,
|
|
329
|
+
min_confidence: float | None,
|
|
330
|
+
) -> list[tuple[str, Node | None]]:
|
|
331
|
+
"""The neighbours one tree level shows: filtered, in edge order, each id once.
|
|
332
|
+
|
|
333
|
+
One entry per neighbour, not per edge: two call sites are separate edges to the
|
|
334
|
+
same node, and a tree row shows neither line nor edge type to tell them apart
|
|
335
|
+
(#463). A neighbour absent from the store (an unresolved target) comes back with
|
|
336
|
+
``None``, and is dropped with the non-INTERNAL ones when ``show_external`` is off.
|
|
337
|
+
"""
|
|
338
|
+
if allowed_edge_types is not None:
|
|
339
|
+
edges = [e for e in edges if e.type in allowed_edge_types]
|
|
340
|
+
if min_confidence is not None:
|
|
341
|
+
edges = [e for e in edges if e.confidence >= min_confidence]
|
|
342
|
+
ids = list(dict.fromkeys(neighbour_of(e) for e in edges))
|
|
343
|
+
nodes = {n.id: n for n in store.get_nodes(ids)}
|
|
344
|
+
return [
|
|
345
|
+
(node_id, nodes.get(node_id))
|
|
346
|
+
for node_id in ids
|
|
347
|
+
if show_external or _is_internal(nodes.get(node_id))
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _is_internal(node: Node | None) -> bool:
|
|
352
|
+
"""True for a stored node from the ingested repository."""
|
|
353
|
+
return node is not None and node.namespace == NodeNamespace.INTERNAL
|
|
354
|
+
|
|
355
|
+
|
|
321
356
|
def build_trace_tree(
|
|
322
357
|
store: SQLiteStore,
|
|
323
358
|
current_id: str,
|
|
@@ -333,21 +368,15 @@ def build_trace_tree(
|
|
|
333
368
|
if current_depth >= max_depth:
|
|
334
369
|
return
|
|
335
370
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if not show_external and (
|
|
347
|
-
target_node is None or target_node.namespace != NodeNamespace.INTERNAL
|
|
348
|
-
):
|
|
349
|
-
continue
|
|
350
|
-
|
|
371
|
+
callees = _tree_neighbours(
|
|
372
|
+
store,
|
|
373
|
+
store.get_outgoing_edges(current_id),
|
|
374
|
+
lambda edge: edge.target,
|
|
375
|
+
allowed_edge_types=allowed_edge_types,
|
|
376
|
+
show_external=show_external,
|
|
377
|
+
min_confidence=min_confidence,
|
|
378
|
+
)
|
|
379
|
+
for target_id, target_node in callees:
|
|
351
380
|
if target_node:
|
|
352
381
|
label = (
|
|
353
382
|
f"[bold green]{target_node.type.value}[/bold green] "
|
|
@@ -470,21 +499,15 @@ def build_impact_tree(
|
|
|
470
499
|
if current_depth >= max_depth:
|
|
471
500
|
return
|
|
472
501
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if not show_external and (
|
|
484
|
-
source_node is None or source_node.namespace != NodeNamespace.INTERNAL
|
|
485
|
-
):
|
|
486
|
-
continue
|
|
487
|
-
|
|
502
|
+
callers = _tree_neighbours(
|
|
503
|
+
store,
|
|
504
|
+
store.get_incoming_edges(current_id),
|
|
505
|
+
lambda edge: edge.source,
|
|
506
|
+
allowed_edge_types=allowed_edge_types,
|
|
507
|
+
show_external=show_external,
|
|
508
|
+
min_confidence=min_confidence,
|
|
509
|
+
)
|
|
510
|
+
for source_id, source_node in callers:
|
|
488
511
|
if source_node:
|
|
489
512
|
label = (
|
|
490
513
|
f"[bold magenta]{source_node.type.value}[/bold magenta] "
|
|
@@ -1445,7 +1468,7 @@ def audit(
|
|
|
1445
1468
|
help="Only audit nodes of this type (e.g. ROUTE_HANDLER, API_ENDPOINT).",
|
|
1446
1469
|
),
|
|
1447
1470
|
from_prefix: str | None = typer.Option(
|
|
1448
|
-
None, "--from-prefix", help="Only audit nodes
|
|
1471
|
+
None, "--from-prefix", help="Only audit nodes under this FQN prefix (whole dot-segments)."
|
|
1449
1472
|
),
|
|
1450
1473
|
db: str = typer.Option(_DEFAULT_DB, "--db", "-d", help=_DEFAULT_DB_HELP),
|
|
1451
1474
|
depth: int = typer.Option(
|
|
@@ -1487,13 +1510,19 @@ def audit(
|
|
|
1487
1510
|
|
|
1488
1511
|
with SQLiteStore(db) as store:
|
|
1489
1512
|
resolved = _resolve_checkpoint(store, target)
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1513
|
+
try:
|
|
1514
|
+
result = audit_reachability(
|
|
1515
|
+
store,
|
|
1516
|
+
target_fqn=resolved,
|
|
1517
|
+
from_type=from_type,
|
|
1518
|
+
from_prefix=from_prefix,
|
|
1519
|
+
max_depth=depth,
|
|
1520
|
+
)
|
|
1521
|
+
except NoAuditSourcesError as exc:
|
|
1522
|
+
# Exit 2 like a bad selector: exit 0 here let a typo'd prefix pass a CI gate (#467).
|
|
1523
|
+
# stderr, like _resolve_checkpoint: `--format json` stdout stays a clean payload.
|
|
1524
|
+
err_console.print(f"[bold red]❌ {escape(str(exc))}[/bold red]")
|
|
1525
|
+
raise typer.Exit(code=2) from exc
|
|
1497
1526
|
|
|
1498
1527
|
if output_format == OutputFormat.JSON:
|
|
1499
1528
|
typer.echo(_json.dumps(dataclasses.asdict(result), indent=2))
|
cgis/query/context/audit.py
CHANGED
|
@@ -51,29 +51,100 @@ class ReachabilityAudit:
|
|
|
51
51
|
gaps: list[NodeRef]
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
class NoAuditSourcesError(ValueError):
|
|
55
|
+
"""The selectors matched no source to audit, so there is no result to report (#467).
|
|
56
|
+
|
|
57
|
+
Raised instead of returning empty ``covered``/``gaps``: callers — and CI gates
|
|
58
|
+
reading ``gaps == []`` — would otherwise take an audit of nothing for a clean one.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_SUGGESTION_LIMIT = 5
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _describe_selection(from_type: NodeType | None, from_prefix: str | None) -> str:
|
|
66
|
+
"""Render the selectors the way a caller passed them, for the error message."""
|
|
67
|
+
parts = []
|
|
68
|
+
if from_type is not None:
|
|
69
|
+
parts.append(f"from_type={from_type.value}")
|
|
70
|
+
if from_prefix is not None:
|
|
71
|
+
parts.append(f"from_prefix={from_prefix!r}")
|
|
72
|
+
return " and ".join(parts)
|
|
73
|
+
|
|
74
|
+
|
|
54
75
|
def _prefix_matches(fqn: str, prefix: str) -> bool:
|
|
55
76
|
"""Dot-boundary prefix match — ``app.routes`` matches ``app.routes.x``, not ``app.routesX``."""
|
|
56
77
|
return fqn == prefix or fqn.startswith(f"{prefix}.")
|
|
57
78
|
|
|
58
79
|
|
|
80
|
+
def _is_candidate(node: Node, from_type: NodeType | None, target_fqn: str) -> bool:
|
|
81
|
+
"""An INTERNAL node of the requested type that is not the checkpoint — a possible source."""
|
|
82
|
+
return (
|
|
83
|
+
node.namespace == NodeNamespace.INTERNAL
|
|
84
|
+
and (from_type is None or node.type == from_type)
|
|
85
|
+
and node.id != target_fqn
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
59
89
|
def _select_sources(
|
|
60
|
-
|
|
90
|
+
nodes: list[Node], target_fqn: str, from_type: NodeType | None, from_prefix: str | None
|
|
61
91
|
) -> list[Node]:
|
|
62
92
|
"""Select INTERNAL source nodes by node type and/or dot-boundary FQN prefix (AND-combined).
|
|
63
93
|
|
|
64
94
|
Restricted to INTERNAL nodes so the audit never flags stdlib/third-party
|
|
65
95
|
code, and the prefix is boundary-aware so a name overlap (``app.routesX``)
|
|
66
|
-
can't sneak into an ``app.routes`` selection.
|
|
96
|
+
can't sneak into an ``app.routes`` selection. The checkpoint is never its
|
|
97
|
+
own source.
|
|
67
98
|
"""
|
|
68
99
|
return [
|
|
69
100
|
node
|
|
70
|
-
for node in
|
|
71
|
-
if node
|
|
72
|
-
and (from_type is None or node.type == from_type)
|
|
101
|
+
for node in nodes
|
|
102
|
+
if _is_candidate(node, from_type, target_fqn)
|
|
73
103
|
and (from_prefix is None or _prefix_matches(node.id, from_prefix))
|
|
74
104
|
]
|
|
75
105
|
|
|
76
106
|
|
|
107
|
+
def _empty_selection_hint(
|
|
108
|
+
nodes: list[Node], target_fqn: str, from_type: NodeType | None, from_prefix: str | None
|
|
109
|
+
) -> str:
|
|
110
|
+
"""Explain an empty selection: the whole-segment prefix meant, or what the prefix does hold.
|
|
111
|
+
|
|
112
|
+
Suggestions come from the same candidates ``_select_sources`` would accept, so
|
|
113
|
+
every suggested prefix selects at least one source. That also means the input
|
|
114
|
+
is never offered back: a candidate completing to ``from_prefix`` would itself
|
|
115
|
+
have been selected. A trailing dot is dropped first: ``app.routes.`` meant
|
|
116
|
+
``app.routes``.
|
|
117
|
+
"""
|
|
118
|
+
if from_prefix is None:
|
|
119
|
+
return ""
|
|
120
|
+
stem = from_prefix.rstrip(".")
|
|
121
|
+
suggestions: set[str] = set()
|
|
122
|
+
for node in nodes:
|
|
123
|
+
if _is_candidate(node, from_type, target_fqn) and node.id.startswith(stem):
|
|
124
|
+
next_dot = node.id.find(".", len(stem))
|
|
125
|
+
suggestions.add(node.id if next_dot == -1 else node.id[:next_dot])
|
|
126
|
+
if suggestions:
|
|
127
|
+
listing = ", ".join(sorted(suggestions)[:_SUGGESTION_LIMIT])
|
|
128
|
+
return f"Prefixes match whole dot-segments; did you mean: {listing}?"
|
|
129
|
+
under = [
|
|
130
|
+
n for n in nodes if n.namespace == NodeNamespace.INTERNAL and _prefix_matches(n.id, stem)
|
|
131
|
+
]
|
|
132
|
+
if under and all(n.id == target_fqn for n in under):
|
|
133
|
+
return "Only the checkpoint itself is under that prefix, and it is never its own source."
|
|
134
|
+
if under and from_type is not None:
|
|
135
|
+
return f"There are nodes under that prefix, but none of type {from_type.value}."
|
|
136
|
+
return ""
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _no_sources_error(
|
|
140
|
+
nodes: list[Node], target_fqn: str, from_type: NodeType | None, from_prefix: str | None
|
|
141
|
+
) -> NoAuditSourcesError:
|
|
142
|
+
"""Build the error for an empty selection, with a hint when one can be given."""
|
|
143
|
+
msg = f"No sources matched {_describe_selection(from_type, from_prefix)} — nothing was audited."
|
|
144
|
+
hint = _empty_selection_hint(nodes, target_fqn, from_type, from_prefix)
|
|
145
|
+
return NoAuditSourcesError(f"{msg} {hint}" if hint else msg)
|
|
146
|
+
|
|
147
|
+
|
|
77
148
|
def _ref(node: Node) -> NodeRef:
|
|
78
149
|
"""Build a located reference from a node."""
|
|
79
150
|
return NodeRef(fqn=node.id, file=node.file_path, line=node.start_line)
|
|
@@ -112,11 +183,20 @@ def audit_reachability(
|
|
|
112
183
|
already-injected instance — so a dependency-injected collaborator looks like
|
|
113
184
|
a gap. Target the specific method (or the constructor) when auditing "does X
|
|
114
185
|
use this collaborator".
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
NoAuditSourcesError: The selectors match no source other than the checkpoint
|
|
189
|
+
itself. An empty ``covered``/``gaps`` pair would read as a passing audit.
|
|
115
190
|
"""
|
|
116
191
|
from_prefix = from_prefix.strip() or None if from_prefix is not None else None
|
|
117
192
|
if from_type is None and from_prefix is None:
|
|
118
193
|
msg = "audit_reachability requires from_type or a non-empty from_prefix to select sources."
|
|
119
194
|
raise ValueError(msg)
|
|
195
|
+
nodes = store.get_all_nodes()
|
|
196
|
+
# Select before traversing: an empty selection has nothing to prove.
|
|
197
|
+
sources = _select_sources(nodes, target_fqn, from_type, from_prefix)
|
|
198
|
+
if not sources:
|
|
199
|
+
raise _no_sources_error(nodes, target_fqn, from_type, from_prefix)
|
|
120
200
|
engine = QueryEngine(store)
|
|
121
201
|
# `is not None`, not `or`: an explicit empty frozenset (no-traversal, target-only)
|
|
122
202
|
# is a valid intent and must not be overridden by the enforcement default.
|
|
@@ -127,8 +207,6 @@ def audit_reachability(
|
|
|
127
207
|
reaching = {node.id for node in upstream_nodes}
|
|
128
208
|
covered: list[NodeRef] = []
|
|
129
209
|
gaps: list[NodeRef] = []
|
|
130
|
-
for source in sorted(
|
|
131
|
-
if source.id == target_fqn:
|
|
132
|
-
continue
|
|
210
|
+
for source in sorted(sources, key=lambda n: n.id):
|
|
133
211
|
(covered if source.id in reaching else gaps).append(_ref(source))
|
|
134
212
|
return ReachabilityAudit(target=target_fqn, covered=covered, gaps=gaps)
|
cgis/query/render/graph_json.py
CHANGED
|
@@ -28,6 +28,10 @@ def graph_to_json(
|
|
|
28
28
|
``coverage`` is the traversal's local resolution coverage (#201). A
|
|
29
29
|
structure query follows no calls and passes none, so the key is omitted
|
|
30
30
|
rather than reported as a zero it did not measure.
|
|
31
|
+
|
|
32
|
+
Edges are one per distinct ``(src, type, dst)``, as in the Mermaid view: two
|
|
33
|
+
call sites to the same function are separate graph edges, but without a line
|
|
34
|
+
number the payload would state the same fact twice (#463).
|
|
31
35
|
"""
|
|
32
36
|
payload: dict[str, Any] = {
|
|
33
37
|
"root": root,
|
|
@@ -40,16 +44,26 @@ def graph_to_json(
|
|
|
40
44
|
}
|
|
41
45
|
for node in nodes
|
|
42
46
|
],
|
|
43
|
-
"edges":
|
|
44
|
-
|
|
47
|
+
"edges": _distinct_edges(edges),
|
|
48
|
+
}
|
|
49
|
+
if coverage is not None:
|
|
50
|
+
payload["coverage"] = coverage.model_dump()
|
|
51
|
+
return payload
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _distinct_edges(edges: list[Edge]) -> list[dict[str, Any]]:
|
|
55
|
+
"""Collapse edges sharing ``(src, type, dst)``, first-seen order, highest confidence kept."""
|
|
56
|
+
distinct: dict[tuple[str, str, str], dict[str, Any]] = {}
|
|
57
|
+
for edge in edges:
|
|
58
|
+
key = (edge.source, edge.type.value, edge.target)
|
|
59
|
+
seen = distinct.get(key)
|
|
60
|
+
if seen is None:
|
|
61
|
+
distinct[key] = {
|
|
45
62
|
"src": edge.source,
|
|
46
63
|
"dst": edge.target,
|
|
47
64
|
"type": edge.type.value,
|
|
48
65
|
"confidence": edge.confidence,
|
|
49
66
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if coverage is not None:
|
|
54
|
-
payload["coverage"] = coverage.model_dump()
|
|
55
|
-
return payload
|
|
67
|
+
elif edge.confidence > seen["confidence"]:
|
|
68
|
+
seen["confidence"] = edge.confidence
|
|
69
|
+
return list(distinct.values())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: codegraph-brain
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Semantic code graph for AI agents — deterministic FQN resolution, impact analysis and architectural drift gates, exposed over MCP.
|
|
5
5
|
Project-URL: Homepage, https://github.com/zaebee/codegraph-brain
|
|
6
6
|
Project-URL: Repository, https://github.com/zaebee/codegraph-brain
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
cgis/__init__.py,sha256=3QdRGRHRQHrjQYXrPCo1uCZKcx5C-f098rpT21gq3RU,271
|
|
2
2
|
cgis/__main__.py,sha256=w9qXbHyKaCVxkdm7i_NDSc-Mz07ivIoaAAVFGvs3Plo,326
|
|
3
|
-
cgis/cli.py,sha256=
|
|
3
|
+
cgis/cli.py,sha256=tLUfKUyEFG0LtU3xRrsBvyGOw0i08MKb7q1tJaCq1Ws,71133
|
|
4
4
|
cgis/pipeline.py,sha256=c-z6MJb9H06hWZQfvVwGQL2PUN3k0-Am-PCAHfMK0nQ,17048
|
|
5
5
|
cgis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
cgis/api/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
cgis/api/__init__.py,sha256=wvFZK6oZspFGmonBz2rDg1aXxK7DHuE87or_w_cwY28,91
|
|
8
|
-
cgis/api/mcp_server.py,sha256=
|
|
8
|
+
cgis/api/mcp_server.py,sha256=M2lq_Eo8UO0H47yTrbyBvSPzsp8sKH01jQ4B2HWH1dg,44602
|
|
9
9
|
cgis/core/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
cgis/core/coverage.py,sha256=AmeZ_mij5Q382MAqtUmDRmJ_lHLPsV73k0_zksaWc6c,2469
|
|
11
11
|
cgis/core/freshness.py,sha256=s1ahMqizX5jRo5Sj6T-2YfNq1d-jsRqisfne5m4yagw,1395
|
|
@@ -60,7 +60,7 @@ cgis/query/analysis/cohesion.py,sha256=o_xXGbFqD0RgRSHxbsIBD-B3Spmtxv-RCy1MbB_IG
|
|
|
60
60
|
cgis/query/analysis/health.py,sha256=3eZokxeH_be7l7MNuLoLpRIZZ5B3N0DoA1TKMDAkjBs,4989
|
|
61
61
|
cgis/query/analysis/suggest_service.py,sha256=K_eJsfP54QGRSI3rBFB1Y94G-asP30EBZoVUlr1wkm8,10059
|
|
62
62
|
cgis/query/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
|
-
cgis/query/context/audit.py,sha256=
|
|
63
|
+
cgis/query/context/audit.py,sha256=U8ZPvFxTFwsXKTbZzXaE9GKEZ6RSD_xCGFciF1sMqHk,9566
|
|
64
64
|
cgis/query/context/context_service.py,sha256=V0YtJaImgs7cwihejaBzKaOWa8Iax1T2OGrC-W6HbWs,5849
|
|
65
65
|
cgis/query/context/orphans.py,sha256=-28Jc7CqXXQIlH81LGlQihLtlIQLO0UK20DuEn3ZAuI,8064
|
|
66
66
|
cgis/query/context/prompt.py,sha256=H38K0MN_PBaBdK-1nmN1873rOwADVvVYmcxKECLQkLU,8222
|
|
@@ -75,7 +75,7 @@ cgis/query/drift/ontology_init.py,sha256=cWcr_UjUJRV9w8MGZITt4m6kvQ3asbKLZaN402E
|
|
|
75
75
|
cgis/query/drift/quotient.py,sha256=4tV29yk07VYfbrAo7PIrWQ4BagZ0T6nItWP_8Macx_4,2711
|
|
76
76
|
cgis/query/drift/triads.py,sha256=OoGxSAsU9QzHP2MboYkXJ3Jg7PyoE9tO6BfX65fwyYQ,6150
|
|
77
77
|
cgis/query/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
-
cgis/query/render/graph_json.py,sha256=
|
|
78
|
+
cgis/query/render/graph_json.py,sha256=Wxu0_4oxa7o6IKvjTnJbPgV-Hlcl211DDi_UwFjABH0,2622
|
|
79
79
|
cgis/query/render/mermaid.py,sha256=OfvAIdqcqfCS8vvDdWTovGe9dYbLu_DEhRmjmDv8bEc,10749
|
|
80
80
|
cgis/query/render/metrics.py,sha256=23iEdj29_Cry5VlLvDHgLM8f3_CewARgxllkPgEg3nI,18179
|
|
81
81
|
cgis/resolver/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -87,8 +87,8 @@ cgis/resolver/symbols.py,sha256=A88dOb7ciEfWaS4KCK0Ho4cBC2IZisNrBfYp-f1LFYs,1254
|
|
|
87
87
|
cgis/resolver/uplift.py,sha256=Hkye1q-kI-gKO6GIBYv3gUZj1AC0-_mkpoIpmwVsG4g,9591
|
|
88
88
|
cgis/storage/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
89
|
cgis/storage/sqlite_store.py,sha256=tlkg9kbiAFm0rth7ndsRPyv3cjDCj3dpvs7Pp_FTBno,45671
|
|
90
|
-
codegraph_brain-0.23.
|
|
91
|
-
codegraph_brain-0.23.
|
|
92
|
-
codegraph_brain-0.23.
|
|
93
|
-
codegraph_brain-0.23.
|
|
94
|
-
codegraph_brain-0.23.
|
|
90
|
+
codegraph_brain-0.23.2.dist-info/METADATA,sha256=Ul_KuCONXckwgxLZ6rE6LxtefLk-IQVyDmsJVKGhw9E,11771
|
|
91
|
+
codegraph_brain-0.23.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
92
|
+
codegraph_brain-0.23.2.dist-info/entry_points.txt,sha256=mWajEQlAoWuiLyCQdD1TvvguloKQFmzKb52-g9PB_R4,123
|
|
93
|
+
codegraph_brain-0.23.2.dist-info/licenses/LICENSE,sha256=1X36nOG5VocDaEGzAZqIv7uawy_7sWlFoiwECwx5aBI,1065
|
|
94
|
+
codegraph_brain-0.23.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|