enforce-cpg 0.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.
- enforce_cpg-0.2.0/.github/workflows/ci.yml +12 -0
- enforce_cpg-0.2.0/.github/workflows/release.yml +41 -0
- enforce_cpg-0.2.0/.gitignore +8 -0
- enforce_cpg-0.2.0/LICENSE +85 -0
- enforce_cpg-0.2.0/MANIFEST.in +3 -0
- enforce_cpg-0.2.0/NOTICE +9 -0
- enforce_cpg-0.2.0/PKG-INFO +141 -0
- enforce_cpg-0.2.0/README.md +117 -0
- enforce_cpg-0.2.0/assets/logo.svg +39 -0
- enforce_cpg-0.2.0/assets/mark.svg +38 -0
- enforce_cpg-0.2.0/assets/social-preview.png +0 -0
- enforce_cpg-0.2.0/assets/social-preview.svg +48 -0
- enforce_cpg-0.2.0/docs/grammar-notes.md +163 -0
- enforce_cpg-0.2.0/docs/superpowers/plans/2026-07-24-enforce-cpg.md +1917 -0
- enforce_cpg-0.2.0/docs/superpowers/specs/2026-07-24-enforce-cpg-design.md +266 -0
- enforce_cpg-0.2.0/docs/superpowers/specs/2026-07-25-pypi-release-design.md +60 -0
- enforce_cpg-0.2.0/docs/vanilla-extraction.md +86 -0
- enforce_cpg-0.2.0/enforce-cpg.example.toml +16 -0
- enforce_cpg-0.2.0/pyproject.toml +46 -0
- enforce_cpg-0.2.0/scripts/parse_coverage.py +33 -0
- enforce_cpg-0.2.0/scripts/regression.sh +60 -0
- enforce_cpg-0.2.0/src/enforce_cpg/__init__.py +12 -0
- enforce_cpg-0.2.0/src/enforce_cpg/cli.py +93 -0
- enforce_cpg-0.2.0/src/enforce_cpg/config.py +34 -0
- enforce_cpg-0.2.0/src/enforce_cpg/discovery.py +46 -0
- enforce_cpg-0.2.0/src/enforce_cpg/doctor.py +103 -0
- enforce_cpg-0.2.0/src/enforce_cpg/extract.py +333 -0
- enforce_cpg-0.2.0/src/enforce_cpg/index.py +63 -0
- enforce_cpg-0.2.0/src/enforce_cpg/ingest.py +105 -0
- enforce_cpg-0.2.0/src/enforce_cpg/mcp_server.py +257 -0
- enforce_cpg-0.2.0/src/enforce_cpg/model.py +27 -0
- enforce_cpg-0.2.0/src/enforce_cpg/nodetypes.py +50 -0
- enforce_cpg-0.2.0/src/enforce_cpg/parser.py +28 -0
- enforce_cpg-0.2.0/src/enforce_cpg/query.py +226 -0
- enforce_cpg-0.2.0/src/enforce_cpg/resolve.py +208 -0
- enforce_cpg-0.2.0/src/enforce_cpg/store.py +133 -0
- enforce_cpg-0.2.0/tests/fixtures/mini/modA/4_World/Animal.c +4 -0
- enforce_cpg-0.2.0/tests/fixtures/mini/modB/4_World/Animal.c +5 -0
- enforce_cpg-0.2.0/tests/fixtures/mini/vanilla/3_Game/Animal.c +6 -0
- enforce_cpg-0.2.0/tests/test_attribution_artifacts.py +25 -0
- enforce_cpg-0.2.0/tests/test_audit.py +68 -0
- enforce_cpg-0.2.0/tests/test_cli.py +39 -0
- enforce_cpg-0.2.0/tests/test_config.py +23 -0
- enforce_cpg-0.2.0/tests/test_discovery.py +35 -0
- enforce_cpg-0.2.0/tests/test_doctor.py +61 -0
- enforce_cpg-0.2.0/tests/test_extract.py +64 -0
- enforce_cpg-0.2.0/tests/test_incremental.py +65 -0
- enforce_cpg-0.2.0/tests/test_ingest.py +85 -0
- enforce_cpg-0.2.0/tests/test_mcp_server.py +98 -0
- enforce_cpg-0.2.0/tests/test_override.py +86 -0
- enforce_cpg-0.2.0/tests/test_parser.py +18 -0
- enforce_cpg-0.2.0/tests/test_query.py +189 -0
- enforce_cpg-0.2.0/tests/test_resolve.py +39 -0
- enforce_cpg-0.2.0/tests/test_resolve_perf.py +62 -0
- enforce_cpg-0.2.0/tests/test_smoke.py +14 -0
- enforce_cpg-0.2.0/tests/test_store.py +26 -0
- enforce_cpg-0.2.0/tests/test_store_concurrency.py +39 -0
- enforce_cpg-0.2.0/tests/test_vanilla_present.py +14 -0
- enforce_cpg-0.2.0/uv.lock +797 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/checkout@v4
|
|
8
|
+
- uses: astral-sh/setup-uv@v5
|
|
9
|
+
- run: uv python install 3.12
|
|
10
|
+
- run: uv sync --dev
|
|
11
|
+
- run: uv run ruff check src tests
|
|
12
|
+
- run: uv run pytest -v
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Publish enforce-cpg to PyPI on a version tag. Pure-Python: one wheel + sdist.
|
|
2
|
+
# The grammar (tree-sitter-enforce) must already be on PyPI so the clean-venv
|
|
3
|
+
# smoke install below can resolve it.
|
|
4
|
+
name: pypi-release
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
workflow_dispatch: {}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: astral-sh/setup-uv@v5
|
|
17
|
+
- run: uv build
|
|
18
|
+
- name: smoke-test the built wheel in a clean venv (resolves deps from PyPI)
|
|
19
|
+
run: |
|
|
20
|
+
python -m venv /tmp/smoke
|
|
21
|
+
/tmp/smoke/bin/pip install --upgrade pip
|
|
22
|
+
/tmp/smoke/bin/pip install dist/*.whl
|
|
23
|
+
/tmp/smoke/bin/enforce-cpg --version
|
|
24
|
+
/tmp/smoke/bin/python -c "from enforce_cpg import parser; t = parser.parse(b'class A{}'); assert not t.root_node.has_error; print('grammar+parse OK')"
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist/*
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
if: ${{ github.event_name == 'push' }} # only tag pushes reach here; dispatch = build+smoke only
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/download-artifact@v4
|
|
36
|
+
with:
|
|
37
|
+
name: dist
|
|
38
|
+
path: dist
|
|
39
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
40
|
+
with:
|
|
41
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Attribution Assurance License (AAL)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tommyz4
|
|
4
|
+
https://github.com/tommyz4/enforce-cpg
|
|
5
|
+
|
|
6
|
+
The following is the full, official text of the Open Source Initiative (OSI)
|
|
7
|
+
approved Attribution Assurance License (SPDX identifier: AAL), as published
|
|
8
|
+
at https://opensource.org/license/aal, with the license's own attribution
|
|
9
|
+
fields filled in for this project: Author = tommyz4; Professional
|
|
10
|
+
Identification = enforce-cpg maintainer; URL = https://github.com/tommyz4/enforce-cpg.
|
|
11
|
+
|
|
12
|
+
--------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2026 tommyz4
|
|
15
|
+
|
|
16
|
+
tommyz4, enforce-cpg maintainer * https://github.com/tommyz4/enforce-cpg
|
|
17
|
+
|
|
18
|
+
"enforce-cpg: Code Property Graph MCP server for DayZ Enforce Script"
|
|
19
|
+
|
|
20
|
+
All Rights Reserved
|
|
21
|
+
|
|
22
|
+
ATTRIBUTION ASSURANCE LICENSE (adapted from the original BSD license)
|
|
23
|
+
|
|
24
|
+
Redistribution and use in source and binary forms, with or without
|
|
25
|
+
modification, are permitted provided that the conditions below are met.
|
|
26
|
+
|
|
27
|
+
These conditions require a modest attribution to tommyz4 (the "Author"), who
|
|
28
|
+
hopes that its promotional value may help justify the thousands of dollars in
|
|
29
|
+
otherwise billable time invested in writing this and other freely available,
|
|
30
|
+
open-source software.
|
|
31
|
+
|
|
32
|
+
1. Redistributions of source code, in whole or part and with or without
|
|
33
|
+
modification (the "Code"), must prominently display this GPG-signed text in
|
|
34
|
+
verifiable form.
|
|
35
|
+
|
|
36
|
+
2. Redistributions of the Code in binary form must be accompanied by this
|
|
37
|
+
GPG-signed text in any documentation and, each time the resulting executable
|
|
38
|
+
program or a program dependent thereon is launched, a prominent display
|
|
39
|
+
(e.g., splash screen or banner text) of the Author's attribution
|
|
40
|
+
information, which includes:
|
|
41
|
+
|
|
42
|
+
(a) Name ("tommyz4"),
|
|
43
|
+
|
|
44
|
+
(b) Professional identification ("enforce-cpg maintainer"), and
|
|
45
|
+
|
|
46
|
+
(c) URL ("https://github.com/tommyz4/enforce-cpg").
|
|
47
|
+
|
|
48
|
+
3. Neither the name nor any trademark of the Author may be used to endorse
|
|
49
|
+
or promote products derived from this software without specific prior
|
|
50
|
+
written permission.
|
|
51
|
+
|
|
52
|
+
4. Users are entirely responsible, to the exclusion of the Author and any
|
|
53
|
+
other persons, for compliance with
|
|
54
|
+
|
|
55
|
+
(1) regulations set by owners or administrators of employed equipment,
|
|
56
|
+
|
|
57
|
+
(2) licensing terms of any other software, and
|
|
58
|
+
|
|
59
|
+
(3) local regulations regarding use, including those regarding import,
|
|
60
|
+
export, and use of encryption software.
|
|
61
|
+
|
|
62
|
+
THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
63
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
64
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
65
|
+
EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY DIRECT,
|
|
66
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
67
|
+
(INCLUDING, BUT NOT LIMITED TO, EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK
|
|
68
|
+
ACCESS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
69
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
70
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
71
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
72
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
73
|
+
|
|
74
|
+
--End of License
|
|
75
|
+
|
|
76
|
+
Originally written by Edwin A. Suominen for licensing his PRIVARIA secure
|
|
77
|
+
networking software (see www.privaria.org). The author, who is not an
|
|
78
|
+
attorney, places this license template into the public domain along with a
|
|
79
|
+
complete disclaimer of any warranty or responsibility for its content or
|
|
80
|
+
legal efficacy. You may use or modify the language freely, but entirely at
|
|
81
|
+
your own risk.
|
|
82
|
+
|
|
83
|
+
--------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
Source: https://opensource.org/license/aal (fetched 2026-07-24).
|
enforce_cpg-0.2.0/NOTICE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
enforce-cpg
|
|
2
|
+
Copyright (c) 2026 tommyz4
|
|
3
|
+
https://github.com/tommyz4/enforce-cpg
|
|
4
|
+
|
|
5
|
+
This product includes software developed by tommyz4.
|
|
6
|
+
Licensed under the Attribution Assurance License (AAL).
|
|
7
|
+
|
|
8
|
+
Attribution Notice (must be displayed per AAL clause):
|
|
9
|
+
enforce-cpg — © 2026 tommyz4 — https://github.com/tommyz4/enforce-cpg
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: enforce-cpg
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Code Property Graph MCP server for DayZ Enforce Script
|
|
5
|
+
Project-URL: Homepage, https://github.com/tommyz4/enforce-cpg
|
|
6
|
+
Project-URL: Repository, https://github.com/tommyz4/enforce-cpg
|
|
7
|
+
Project-URL: Issues, https://github.com/tommyz4/enforce-cpg/issues
|
|
8
|
+
Author: tommyz4
|
|
9
|
+
License-Expression: AAL
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: code-property-graph,dayz,enforce,enfusion,mcp,tree-sitter
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Attribution Assurance License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
18
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: mcp>=1.2
|
|
21
|
+
Requires-Dist: tree-sitter-enforce>=0.4
|
|
22
|
+
Requires-Dist: tree-sitter>=0.25
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="assets/logo.svg" alt="enforce-cpg — Code Property Graph for Enforce Script" width="460">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<h1 align="center">enforce-cpg</h1>
|
|
30
|
+
|
|
31
|
+
A Code Property Graph (CPG) MCP server for **DayZ Enforce Script**.
|
|
32
|
+
|
|
33
|
+
It parses Enforce Script (`.c`) source across a vanilla/base layer and any
|
|
34
|
+
number of mod layers, builds a graph of declarations, inheritance,
|
|
35
|
+
overrides, and calls, and exposes that graph over the [Model Context
|
|
36
|
+
Protocol](https://modelcontextprotocol.io) so an AI coding assistant (e.g.
|
|
37
|
+
Claude Code) can answer real DayZ-modding questions: "what overrides
|
|
38
|
+
`Speak` on `Animal`?", "who calls this method?", "what breaks if I change
|
|
39
|
+
this field?" — across a real, multi-mod, load-order-dependent codebase,
|
|
40
|
+
without ever crashing on a bad file or an unresolved reference.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install enforce-cpg # or: uvx enforce-cpg --version
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
No compiler needed — the Enforce grammar ships as prebuilt wheels
|
|
49
|
+
([`tree-sitter-enforce`](https://pypi.org/project/tree-sitter-enforce/)).
|
|
50
|
+
|
|
51
|
+
Or, from a local checkout:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv sync
|
|
55
|
+
uv run enforce-cpg --version
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Configure
|
|
59
|
+
|
|
60
|
+
Point `enforce-cpg` at your vanilla scripts and mod source trees with an
|
|
61
|
+
`enforce-cpg.toml` file (see `enforce-cpg.example.toml`):
|
|
62
|
+
|
|
63
|
+
```toml
|
|
64
|
+
[project]
|
|
65
|
+
name = "my-server"
|
|
66
|
+
db_path = ".enforce-cpg/index.db"
|
|
67
|
+
|
|
68
|
+
# ORDERED: earlier = loaded first = base precedence. This IS your -mod= order.
|
|
69
|
+
[[sources]]
|
|
70
|
+
name = "vanilla"
|
|
71
|
+
kind = "core"
|
|
72
|
+
path = "/path/to/vanilla_scripts"
|
|
73
|
+
|
|
74
|
+
[[sources]]
|
|
75
|
+
name = "MyMod"
|
|
76
|
+
kind = "mod"
|
|
77
|
+
path = "/path/to/MyMod/Scripts"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Load-order warning:** the order of `[[sources]]` in this file *is* the
|
|
81
|
+
override precedence used to resolve `Animal.Speak`-style method stacks —
|
|
82
|
+
it must mirror your server's real `-mod=` load order. A source listed
|
|
83
|
+
earlier is treated as the base that later sources override; get this
|
|
84
|
+
wrong and `resolve_method` / `get_inheritance` will report the wrong
|
|
85
|
+
override winner.
|
|
86
|
+
|
|
87
|
+
Build (or rebuild) the index:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run enforce-cpg index --config enforce-cpg.toml --full
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Tools
|
|
94
|
+
|
|
95
|
+
Once registered with an MCP client, enforce-cpg exposes 12 tools:
|
|
96
|
+
|
|
97
|
+
| Tool | Description |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `reindex` | Rebuild the code property graph index. `full=true` forces a from-scratch rebuild; otherwise only changed files are re-indexed. |
|
|
100
|
+
| `find_symbol` | Find declarations of a symbol by name (optionally filtered by kind). |
|
|
101
|
+
| `find_references` | Find references to a symbol by name (optionally filtered by kind; declaration sites excluded by default). |
|
|
102
|
+
| `find_callers` | Find callers of a class method, transitively up to the given depth. |
|
|
103
|
+
| `resolve_method` | Resolve a method call to its override stack across the source layers (core -> mods), in resolution order, flagging cut chains. |
|
|
104
|
+
| `get_inheritance` | Get the inheritance chain for a class, optionally scoped to a method. |
|
|
105
|
+
| `impact_of_change` | Estimate the blast radius of changing a class member. |
|
|
106
|
+
| `get_overview` | Get a structural overview of a file or a class. |
|
|
107
|
+
| `audit_overrides` | Corpus-wide override audit: every modded layer that overrides without `super`, silently disabling earlier layers. |
|
|
108
|
+
| `mod_surface` | Every method a given source overrides that another source also defines — the mod's footprint on the shared hierarchy. |
|
|
109
|
+
| `doctor` | Setup + index-health report: sources resolved, per-source parse coverage, missing-vanilla warning, diagnostics, unresolved hotspots. |
|
|
110
|
+
| `ingest` | Register a source from an extracted directory (always) or a `.pbo` (de-rapified if a tool is available), copied under `.enforce-cpg/sources/` with the `[[sources]]` entry added. |
|
|
111
|
+
|
|
112
|
+
The same surface is available on the CLI (`enforce-cpg find-symbol`,
|
|
113
|
+
`… audit`, `… mod-surface --source <name>`, `… doctor`,
|
|
114
|
+
`… ingest <path> --name <n> --kind core|mod`, …).
|
|
115
|
+
|
|
116
|
+
Every tool degrades honestly instead of crashing: an unresolved symbol or
|
|
117
|
+
a missing argument returns `{"results": [], "note": "..."}` rather than an
|
|
118
|
+
exception, so a single bad query never takes down the server.
|
|
119
|
+
|
|
120
|
+
## Register with Claude Code
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
claude mcp add enforce-cpg -- uvx enforce-cpg-mcp
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The server reads its config from the `ENFORCE_CPG_CONFIG` environment
|
|
127
|
+
variable (defaults to `enforce-cpg.toml` in the working directory), so
|
|
128
|
+
set that to your project's config path when registering.
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
enforce-cpg is licensed under the **Attribution Assurance License (AAL)**,
|
|
133
|
+
an OSI-approved open-source license. The full license text is in
|
|
134
|
+
[`LICENSE`](./LICENSE); the required attribution notice is in
|
|
135
|
+
[`NOTICE`](./NOTICE).
|
|
136
|
+
|
|
137
|
+
Attribution notice (must be displayed per the AAL's attribution clause):
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
enforce-cpg — © 2026 tommyz4 — https://github.com/tommyz4/enforce-cpg
|
|
141
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.svg" alt="enforce-cpg — Code Property Graph for Enforce Script" width="460">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">enforce-cpg</h1>
|
|
6
|
+
|
|
7
|
+
A Code Property Graph (CPG) MCP server for **DayZ Enforce Script**.
|
|
8
|
+
|
|
9
|
+
It parses Enforce Script (`.c`) source across a vanilla/base layer and any
|
|
10
|
+
number of mod layers, builds a graph of declarations, inheritance,
|
|
11
|
+
overrides, and calls, and exposes that graph over the [Model Context
|
|
12
|
+
Protocol](https://modelcontextprotocol.io) so an AI coding assistant (e.g.
|
|
13
|
+
Claude Code) can answer real DayZ-modding questions: "what overrides
|
|
14
|
+
`Speak` on `Animal`?", "who calls this method?", "what breaks if I change
|
|
15
|
+
this field?" — across a real, multi-mod, load-order-dependent codebase,
|
|
16
|
+
without ever crashing on a bad file or an unresolved reference.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install enforce-cpg # or: uvx enforce-cpg --version
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
No compiler needed — the Enforce grammar ships as prebuilt wheels
|
|
25
|
+
([`tree-sitter-enforce`](https://pypi.org/project/tree-sitter-enforce/)).
|
|
26
|
+
|
|
27
|
+
Or, from a local checkout:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync
|
|
31
|
+
uv run enforce-cpg --version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Configure
|
|
35
|
+
|
|
36
|
+
Point `enforce-cpg` at your vanilla scripts and mod source trees with an
|
|
37
|
+
`enforce-cpg.toml` file (see `enforce-cpg.example.toml`):
|
|
38
|
+
|
|
39
|
+
```toml
|
|
40
|
+
[project]
|
|
41
|
+
name = "my-server"
|
|
42
|
+
db_path = ".enforce-cpg/index.db"
|
|
43
|
+
|
|
44
|
+
# ORDERED: earlier = loaded first = base precedence. This IS your -mod= order.
|
|
45
|
+
[[sources]]
|
|
46
|
+
name = "vanilla"
|
|
47
|
+
kind = "core"
|
|
48
|
+
path = "/path/to/vanilla_scripts"
|
|
49
|
+
|
|
50
|
+
[[sources]]
|
|
51
|
+
name = "MyMod"
|
|
52
|
+
kind = "mod"
|
|
53
|
+
path = "/path/to/MyMod/Scripts"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Load-order warning:** the order of `[[sources]]` in this file *is* the
|
|
57
|
+
override precedence used to resolve `Animal.Speak`-style method stacks —
|
|
58
|
+
it must mirror your server's real `-mod=` load order. A source listed
|
|
59
|
+
earlier is treated as the base that later sources override; get this
|
|
60
|
+
wrong and `resolve_method` / `get_inheritance` will report the wrong
|
|
61
|
+
override winner.
|
|
62
|
+
|
|
63
|
+
Build (or rebuild) the index:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv run enforce-cpg index --config enforce-cpg.toml --full
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Tools
|
|
70
|
+
|
|
71
|
+
Once registered with an MCP client, enforce-cpg exposes 12 tools:
|
|
72
|
+
|
|
73
|
+
| Tool | Description |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `reindex` | Rebuild the code property graph index. `full=true` forces a from-scratch rebuild; otherwise only changed files are re-indexed. |
|
|
76
|
+
| `find_symbol` | Find declarations of a symbol by name (optionally filtered by kind). |
|
|
77
|
+
| `find_references` | Find references to a symbol by name (optionally filtered by kind; declaration sites excluded by default). |
|
|
78
|
+
| `find_callers` | Find callers of a class method, transitively up to the given depth. |
|
|
79
|
+
| `resolve_method` | Resolve a method call to its override stack across the source layers (core -> mods), in resolution order, flagging cut chains. |
|
|
80
|
+
| `get_inheritance` | Get the inheritance chain for a class, optionally scoped to a method. |
|
|
81
|
+
| `impact_of_change` | Estimate the blast radius of changing a class member. |
|
|
82
|
+
| `get_overview` | Get a structural overview of a file or a class. |
|
|
83
|
+
| `audit_overrides` | Corpus-wide override audit: every modded layer that overrides without `super`, silently disabling earlier layers. |
|
|
84
|
+
| `mod_surface` | Every method a given source overrides that another source also defines — the mod's footprint on the shared hierarchy. |
|
|
85
|
+
| `doctor` | Setup + index-health report: sources resolved, per-source parse coverage, missing-vanilla warning, diagnostics, unresolved hotspots. |
|
|
86
|
+
| `ingest` | Register a source from an extracted directory (always) or a `.pbo` (de-rapified if a tool is available), copied under `.enforce-cpg/sources/` with the `[[sources]]` entry added. |
|
|
87
|
+
|
|
88
|
+
The same surface is available on the CLI (`enforce-cpg find-symbol`,
|
|
89
|
+
`… audit`, `… mod-surface --source <name>`, `… doctor`,
|
|
90
|
+
`… ingest <path> --name <n> --kind core|mod`, …).
|
|
91
|
+
|
|
92
|
+
Every tool degrades honestly instead of crashing: an unresolved symbol or
|
|
93
|
+
a missing argument returns `{"results": [], "note": "..."}` rather than an
|
|
94
|
+
exception, so a single bad query never takes down the server.
|
|
95
|
+
|
|
96
|
+
## Register with Claude Code
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
claude mcp add enforce-cpg -- uvx enforce-cpg-mcp
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The server reads its config from the `ENFORCE_CPG_CONFIG` environment
|
|
103
|
+
variable (defaults to `enforce-cpg.toml` in the working directory), so
|
|
104
|
+
set that to your project's config path when registering.
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
enforce-cpg is licensed under the **Attribution Assurance License (AAL)**,
|
|
109
|
+
an OSI-approved open-source license. The full license text is in
|
|
110
|
+
[`LICENSE`](./LICENSE); the required attribution notice is in
|
|
111
|
+
[`NOTICE`](./NOTICE).
|
|
112
|
+
|
|
113
|
+
Attribution notice (must be displayed per the AAL's attribution clause):
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
enforce-cpg — © 2026 tommyz4 — https://github.com/tommyz4/enforce-cpg
|
|
117
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg width="560" height="160" viewBox="0 0 560 160" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="enforce-cpg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="tileL" x1="0" y1="0" x2="160" y2="160" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#0C1524"/>
|
|
5
|
+
<stop offset="1" stop-color="#111F33"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="chainL" x1="52" y1="118" x2="116" y2="42" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="#64748B"/>
|
|
9
|
+
<stop offset="0.55" stop-color="#38BDF8"/>
|
|
10
|
+
<stop offset="1" stop-color="#22D3EE"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<radialGradient id="glowL" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(114 44) scale(34)">
|
|
13
|
+
<stop stop-color="#22D3EE" stop-opacity="0.55"/>
|
|
14
|
+
<stop offset="1" stop-color="#22D3EE" stop-opacity="0"/>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<!-- mark -->
|
|
19
|
+
<g>
|
|
20
|
+
<rect x="2" y="2" width="156" height="156" rx="36" fill="url(#tileL)" stroke="#1E2E45" stroke-width="2"/>
|
|
21
|
+
<path d="M52 116 L30 128" stroke="#2A3B55" stroke-width="3" stroke-linecap="round"/>
|
|
22
|
+
<path d="M82 82 L128 100" stroke="#2A3B55" stroke-width="3" stroke-linecap="round"/>
|
|
23
|
+
<circle cx="28" cy="130" r="6" fill="#243349" stroke="#33475F" stroke-width="2"/>
|
|
24
|
+
<circle cx="132" cy="102" r="7" fill="#243349" stroke="#33475F" stroke-width="2"/>
|
|
25
|
+
<path d="M52 114 L82 82 L114 46" stroke="url(#chainL)" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
26
|
+
<circle cx="114" cy="44" r="30" fill="url(#glowL)"/>
|
|
27
|
+
<circle cx="50" cy="116" r="13" fill="#1B2A40" stroke="#475569" stroke-width="3"/>
|
|
28
|
+
<circle cx="82" cy="82" r="13" fill="#F59E0B" stroke="#FBBF24" stroke-width="2"/>
|
|
29
|
+
<circle cx="114" cy="44" r="16" fill="#22D3EE" stroke="#A5F3FC" stroke-width="2.5"/>
|
|
30
|
+
</g>
|
|
31
|
+
|
|
32
|
+
<!-- wordmark -->
|
|
33
|
+
<g font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', 'Cascadia Code', Menlo, Consolas, monospace">
|
|
34
|
+
<text x="196" y="82" font-size="46" font-weight="700" letter-spacing="-1">
|
|
35
|
+
<tspan fill="#E2E8F0">enforce</tspan><tspan fill="#22D3EE">-cpg</tspan>
|
|
36
|
+
</text>
|
|
37
|
+
<text x="198" y="112" font-size="17.5" font-weight="500" letter-spacing="0.5" fill="#7C8CA5">Code Property Graph for Enforce Script</text>
|
|
38
|
+
</g>
|
|
39
|
+
</svg>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<svg width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="enforce-cpg mark">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="tile" x1="0" y1="0" x2="160" y2="160" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#0C1524"/>
|
|
5
|
+
<stop offset="1" stop-color="#111F33"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="chain" x1="52" y1="118" x2="116" y2="42" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="#64748B"/>
|
|
9
|
+
<stop offset="0.55" stop-color="#38BDF8"/>
|
|
10
|
+
<stop offset="1" stop-color="#22D3EE"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<radialGradient id="glow" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(114 44) scale(34)">
|
|
13
|
+
<stop stop-color="#22D3EE" stop-opacity="0.55"/>
|
|
14
|
+
<stop offset="1" stop-color="#22D3EE" stop-opacity="0"/>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<rect x="2" y="2" width="156" height="156" rx="36" fill="url(#tile)" stroke="#1E2E45" stroke-width="2"/>
|
|
19
|
+
|
|
20
|
+
<!-- faint satellite edges (references / callers) -> gives the graph feel -->
|
|
21
|
+
<path d="M52 116 L30 128" stroke="#2A3B55" stroke-width="3" stroke-linecap="round"/>
|
|
22
|
+
<path d="M82 82 L128 100" stroke="#2A3B55" stroke-width="3" stroke-linecap="round"/>
|
|
23
|
+
<circle cx="28" cy="130" r="6" fill="#243349" stroke="#33475F" stroke-width="2"/>
|
|
24
|
+
<circle cx="132" cy="102" r="7" fill="#243349" stroke="#33475F" stroke-width="2"/>
|
|
25
|
+
|
|
26
|
+
<!-- the override stack: base -> modded -> resolved (main chain) -->
|
|
27
|
+
<path d="M52 114 L82 82 L114 46" stroke="url(#chain)" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
28
|
+
|
|
29
|
+
<!-- glow behind the resolved node -->
|
|
30
|
+
<circle cx="114" cy="44" r="30" fill="url(#glow)"/>
|
|
31
|
+
|
|
32
|
+
<!-- base node (vanilla / lowest precedence) -->
|
|
33
|
+
<circle cx="50" cy="116" r="13" fill="#1B2A40" stroke="#475569" stroke-width="3"/>
|
|
34
|
+
<!-- modded layer node -->
|
|
35
|
+
<circle cx="82" cy="82" r="13" fill="#F59E0B" stroke="#FBBF24" stroke-width="2"/>
|
|
36
|
+
<!-- resolved / effective node (top of stack) -->
|
|
37
|
+
<circle cx="114" cy="44" r="16" fill="#22D3EE" stroke="#A5F3FC" stroke-width="2.5"/>
|
|
38
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<svg width="1280" height="640" viewBox="0 0 1280 640" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1280" y2="640" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#070D18"/>
|
|
5
|
+
<stop offset="1" stop-color="#0E1B2E"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="tileS" x1="0" y1="0" x2="220" y2="220" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="#0C1524"/><stop offset="1" stop-color="#111F33"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="chainS" x1="70" y1="162" x2="158" y2="58" gradientUnits="userSpaceOnUse">
|
|
11
|
+
<stop stop-color="#64748B"/><stop offset="0.55" stop-color="#38BDF8"/><stop offset="1" stop-color="#22D3EE"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<radialGradient id="glowS" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(156 60) scale(46)">
|
|
14
|
+
<stop stop-color="#22D3EE" stop-opacity="0.5"/><stop offset="1" stop-color="#22D3EE" stop-opacity="0"/>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
<radialGradient id="halo" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(340 300) scale(520)">
|
|
17
|
+
<stop stop-color="#123049" stop-opacity="0.6"/><stop offset="1" stop-color="#123049" stop-opacity="0"/>
|
|
18
|
+
</radialGradient>
|
|
19
|
+
</defs>
|
|
20
|
+
|
|
21
|
+
<rect width="1280" height="640" fill="url(#bg)"/>
|
|
22
|
+
<circle cx="340" cy="300" r="520" fill="url(#halo)"/>
|
|
23
|
+
|
|
24
|
+
<!-- mark, scaled up and centered-left -->
|
|
25
|
+
<g transform="translate(150 150) scale(1.36)">
|
|
26
|
+
<rect x="2" y="2" width="216" height="216" rx="50" fill="url(#tileS)" stroke="#1E2E45" stroke-width="2.5"/>
|
|
27
|
+
<path d="M70 160 L40 178" stroke="#2A3B55" stroke-width="4" stroke-linecap="round"/>
|
|
28
|
+
<path d="M112 112 L176 138" stroke="#2A3B55" stroke-width="4" stroke-linecap="round"/>
|
|
29
|
+
<circle cx="38" cy="180" r="8" fill="#243349" stroke="#33475F" stroke-width="2.5"/>
|
|
30
|
+
<circle cx="180" cy="140" r="9" fill="#243349" stroke="#33475F" stroke-width="2.5"/>
|
|
31
|
+
<path d="M70 158 L112 112 L156 64" stroke="url(#chainS)" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
|
|
32
|
+
<circle cx="156" cy="60" r="42" fill="url(#glowS)"/>
|
|
33
|
+
<circle cx="68" cy="160" r="18" fill="#1B2A40" stroke="#475569" stroke-width="4"/>
|
|
34
|
+
<circle cx="112" cy="112" r="18" fill="#F59E0B" stroke="#FBBF24" stroke-width="2.5"/>
|
|
35
|
+
<circle cx="156" cy="60" r="22" fill="#22D3EE" stroke="#A5F3FC" stroke-width="3"/>
|
|
36
|
+
</g>
|
|
37
|
+
|
|
38
|
+
<g font-family="ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace">
|
|
39
|
+
<text x="530" y="270" font-size="82" font-weight="700" letter-spacing="-2"><tspan fill="#E8EEF6">enforce</tspan><tspan fill="#22D3EE">-cpg</tspan></text>
|
|
40
|
+
<text x="534" y="330" font-size="30" font-weight="500" fill="#93A3BC">Code Property Graph MCP server for DayZ Enforce Script</text>
|
|
41
|
+
</g>
|
|
42
|
+
|
|
43
|
+
<!-- feature line -->
|
|
44
|
+
<g font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif">
|
|
45
|
+
<text x="534" y="420" font-size="25" fill="#5D7290">resolve modded-override chains · call graph · inheritance · impact</text>
|
|
46
|
+
<text x="534" y="470" font-size="21" font-weight="600" fill="#6B7F9C">AAL-licensed · pip / uvx · tree-sitter</text>
|
|
47
|
+
</g>
|
|
48
|
+
</svg>
|