adl-toolkit 0.0.0-stage → 0.1.1
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.
- package/INSTALL_TOOLKIT.md +163 -0
- package/README.md +269 -2
- package/adl_drift/__init__.py +6 -0
- package/adl_drift/cli/__init__.py +1 -0
- package/adl_drift/cli/commands.py +993 -0
- package/adl_drift/cli/main.py +744 -0
- package/adl_drift/cortex/__init__.py +1 -0
- package/adl_drift/cortex/embeddings.py +96 -0
- package/adl_drift/cortex/memory.py +1749 -0
- package/adl_drift/cortex/patterns.py +89 -0
- package/adl_drift/cortex/telemetry.py +192 -0
- package/adl_drift/detectors/__init__.py +1 -0
- package/adl_drift/detectors/async_patterns.py +115 -0
- package/adl_drift/detectors/base.py +121 -0
- package/adl_drift/detectors/config.py +122 -0
- package/adl_drift/detectors/data_access.py +128 -0
- package/adl_drift/detectors/decorators.py +122 -0
- package/adl_drift/detectors/dynamic_patterns.py +260 -0
- package/adl_drift/detectors/errors.py +134 -0
- package/adl_drift/detectors/imports.py +132 -0
- package/adl_drift/detectors/logging_patterns.py +108 -0
- package/adl_drift/detectors/routes.py +257 -0
- package/adl_drift/detectors/security.py +236 -0
- package/adl_drift/detectors/taint.py +406 -0
- package/adl_drift/detectors/tests.py +95 -0
- package/adl_drift/detectors/type_conventions.py +81 -0
- package/adl_drift/graph/__init__.py +1 -0
- package/adl_drift/graph/builder.py +2670 -0
- package/adl_drift/graph/cfg.py +461 -0
- package/adl_drift/graph/cluster.py +40 -0
- package/adl_drift/graph/edges.py +86 -0
- package/adl_drift/graph/node.py +90 -0
- package/adl_drift/harness/__init__.py +10 -0
- package/adl_drift/harness/setup.py +832 -0
- package/adl_drift/harness/skills/drift-antigravity.md +19 -0
- package/adl_drift/harness/skills/drift-generic.md +19 -0
- package/adl_drift/harness/skills/drift.md +25 -0
- package/adl_drift/harness/watch.py +84 -0
- package/adl_drift/lang/__init__.py +8 -0
- package/adl_drift/lang/base.py +464 -0
- package/adl_drift/lang/java/__init__.py +6 -0
- package/adl_drift/lang/java/backend.py +97 -0
- package/adl_drift/lang/java/cfg.py +1424 -0
- package/adl_drift/lang/java/config.py +707 -0
- package/adl_drift/lang/java/detectors/__init__.py +29 -0
- package/adl_drift/lang/java/detectors/additional.py +445 -0
- package/adl_drift/lang/java/detectors/base.py +154 -0
- package/adl_drift/lang/java/detectors/data_access.py +148 -0
- package/adl_drift/lang/java/detectors/imports.py +53 -0
- package/adl_drift/lang/java/detectors/routes.py +159 -0
- package/adl_drift/lang/java/detectors/security.py +386 -0
- package/adl_drift/lang/java/detectors/tests.py +74 -0
- package/adl_drift/lang/java/extractor.py +582 -0
- package/adl_drift/lang/java/ids.py +99 -0
- package/adl_drift/lang/java/parser.py +49 -0
- package/adl_drift/lang/java/resolution/__init__.py +1 -0
- package/adl_drift/lang/java/resolution/constants.py +1619 -0
- package/adl_drift/lang/java/resolution/constructors.py +278 -0
- package/adl_drift/lang/java/resolution/context.py +305 -0
- package/adl_drift/lang/java/resolution/dispatch.py +540 -0
- package/adl_drift/lang/java/resolution/functional.py +1318 -0
- package/adl_drift/lang/java/resolution/generated.py +95 -0
- package/adl_drift/lang/java/resolution/model.py +153 -0
- package/adl_drift/lang/java/resolution/orchestration.py +866 -0
- package/adl_drift/lang/java/resolution/overloads.py +1275 -0
- package/adl_drift/lang/java/resolution/scopes.py +1111 -0
- package/adl_drift/lang/java/resolution/types.py +2947 -0
- package/adl_drift/lang/java/resolver.py +1401 -0
- package/adl_drift/lang/java/scopes.py +69 -0
- package/adl_drift/lang/java/taint.py +500 -0
- package/adl_drift/lang/java/type_provenance.py +342 -0
- package/adl_drift/lang/python/__init__.py +8 -0
- package/adl_drift/lang/python/backend.py +94 -0
- package/adl_drift/lang/python/cfg.py +537 -0
- package/adl_drift/lang/python/extractor.py +454 -0
- package/adl_drift/lang/python/parser.py +41 -0
- package/adl_drift/lang/python/resolver.py +1789 -0
- package/adl_drift/lang/python/taint.py +365 -0
- package/adl_drift/lang/registry.py +117 -0
- package/adl_drift/parser/__init__.py +1 -0
- package/adl_drift/parser/cache.py +38 -0
- package/adl_drift/parser/core.py +33 -0
- package/adl_drift/parser/extractor.py +17 -0
- package/adl_drift/parser/literal_eval.py +326 -0
- package/adl_drift/scanner/__init__.py +1 -0
- package/adl_drift/scanner/discovery.py +338 -0
- package/adl_drift/scanner/incremental.py +261 -0
- package/adl_drift/scanner/parallel.py +224 -0
- package/adl_drift/server/__init__.py +1 -0
- package/adl_drift/server/handlers.py +2849 -0
- package/adl_drift/server/mcp_server.py +127 -0
- package/adl_drift/server/mcp_stdio.py +335 -0
- package/adl_drift/server/protocol.py +71 -0
- package/adl_drift/server/static/index.html +696 -0
- package/adl_drift/server/web.py +350 -0
- package/adl_drift/utils/__init__.py +1 -0
- package/adl_drift/utils/config.py +77 -0
- package/adl_drift/utils/fswalk.py +52 -0
- package/adl_drift/utils/types.py +345 -0
- package/bin/adl-drift.mjs +35 -0
- package/bin/adl-toolkit.mjs +488 -0
- package/package.json +29 -4
- package/pyproject.toml +49 -0
- package/scripts/install_toolkit.py +3584 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# ADL Toolkit — User Guide
|
|
2
|
+
|
|
3
|
+
ADL Toolkit connects a code graph tool to your AI assistants. Choose ADL-Drift,
|
|
4
|
+
CodeGraph, Git Nexus, or Graphify, and optionally add Caveman and Ponytail.
|
|
5
|
+
|
|
6
|
+
Use two commands to manage your setup:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx adl-toolkit install
|
|
10
|
+
npx adl-toolkit uninstall
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Follow the steps below to install the toolkit, start using it, and remove it when needed.
|
|
14
|
+
|
|
15
|
+
## First-time checklist
|
|
16
|
+
|
|
17
|
+
Before you start, install:
|
|
18
|
+
|
|
19
|
+
- Node.js **22.20+ within the 22.x series, or 24.11+**.
|
|
20
|
+
- npm and npx, included with Node.js.
|
|
21
|
+
- Python **3.11+** and Git.
|
|
22
|
+
- At least one supported AI assistant: Codex, Claude Code, Cursor, or Antigravity.
|
|
23
|
+
|
|
24
|
+
Open a terminal and check:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node --version
|
|
28
|
+
npm --version
|
|
29
|
+
git --version
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Check Python with `python3 --version` on Linux, macOS, or WSL, or
|
|
33
|
+
`py -3 --version` / `python --version` on Windows.
|
|
34
|
+
On Windows, use `npm.cmd` and `npx.cmd` if PowerShell blocks npm or npx scripts.
|
|
35
|
+
After installing or upgrading a prerequisite, reopen your terminal.
|
|
36
|
+
|
|
37
|
+
## 1. Install
|
|
38
|
+
|
|
39
|
+
Open a terminal in the project you want your AI assistant to explore, then run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx adl-toolkit install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If npm asks to download `adl-toolkit`, confirm to continue.
|
|
46
|
+
|
|
47
|
+
### Linux and macOS
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd /path/to/my-project
|
|
51
|
+
npx adl-toolkit install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Running on Windows (PowerShell or CMD)
|
|
55
|
+
|
|
56
|
+
Use Windows Node.js and Python:
|
|
57
|
+
|
|
58
|
+
```powershell
|
|
59
|
+
cd "C:\work\my-project"
|
|
60
|
+
npx.cmd adl-toolkit install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In CMD, use `cd /d` when changing drives.
|
|
64
|
+
|
|
65
|
+
### Running from WSL
|
|
66
|
+
|
|
67
|
+
Use Linux Node.js, npm, and Python inside WSL when your AI assistant also runs there:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cd /mnt/e/work/my-project
|
|
71
|
+
npx adl-toolkit install
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If your assistant runs on Windows, follow the Windows instructions instead.
|
|
75
|
+
For mixed Windows/Linux tool errors, see [WSL recovery](windows_installation.md#recovery-in-wsl).
|
|
76
|
+
|
|
77
|
+
### Choose your setup
|
|
78
|
+
|
|
79
|
+
The installer walks you through these choices:
|
|
80
|
+
|
|
81
|
+
1. **Graph tool:** select ADL-Drift, CodeGraph, Git Nexus, or Graphify.
|
|
82
|
+
2. **Optional plugins:** select Caveman for concise agent responses, Ponytail for minimal coding changes, both, or neither.
|
|
83
|
+
3. **AI assistants:** select one or more assistants, or choose **Select all**.
|
|
84
|
+
4. **Project directory:** confirm the project you want to analyze.
|
|
85
|
+
5. **Graph index:** keep **Yes (recommended)** to build the index during installation. Large projects may take longer.
|
|
86
|
+
6. **Review:** check your selections and confirm **Install now?**.
|
|
87
|
+
|
|
88
|
+
Use **↑/↓** to move, **Space** to toggle selections, **Enter** to save and continue,
|
|
89
|
+
**←** to return to the previous step, and **Ctrl+C** to cancel.
|
|
90
|
+
|
|
91
|
+
Wait for **Installation complete.** Follow any next steps printed by the installer.
|
|
92
|
+
Reopen your terminal if it reports PATH changes, then restart your selected AI assistants.
|
|
93
|
+
|
|
94
|
+
## 2. Use the toolkit
|
|
95
|
+
|
|
96
|
+
Open the same project in one of the assistants you selected during installation.
|
|
97
|
+
Start a new conversation and ask it to use your selected graph tool. For example:
|
|
98
|
+
|
|
99
|
+
> Use the code graph to explain this project's main modules and entry points.
|
|
100
|
+
|
|
101
|
+
> Find the callers of this function and show which parts of the project a change could affect.
|
|
102
|
+
|
|
103
|
+
If you skipped indexing, run the graph build command printed after installation first.
|
|
104
|
+
To refresh the index after changing your code, use that tool's graph build command again.
|
|
105
|
+
|
|
106
|
+
Selected Caveman and Ponytail plugins are activated through the project's agent instructions.
|
|
107
|
+
To disable one, ask your assistant not to use it, or remove it through the uninstall menu.
|
|
108
|
+
|
|
109
|
+
## 3. Uninstall
|
|
110
|
+
|
|
111
|
+
Open a terminal in the project where you installed the toolkit:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx adl-toolkit uninstall
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
On Windows, use `npx.cmd adl-toolkit uninstall`.
|
|
118
|
+
|
|
119
|
+
1. Confirm the **Project directory**.
|
|
120
|
+
2. Choose **Entire managed installation**, or remove selected plugins or AI assistant connections when those options are available.
|
|
121
|
+
3. For a full uninstall, choose whether to remove generated index data. The default **No** keeps it.
|
|
122
|
+
4. Review the summary and select **Remove** to confirm. **Cancel** is selected by default.
|
|
123
|
+
|
|
124
|
+
Removing selected plugins or assistant connections keeps the shared graph runtime.
|
|
125
|
+
To switch graph tools, uninstall the current managed installation, then run
|
|
126
|
+
`npx adl-toolkit install` and select the new tool.
|
|
127
|
+
|
|
128
|
+
If uninstall reports that a file was changed and retained, review the reported file
|
|
129
|
+
before retrying. If it cannot find your installation, check that you selected the original project directory.
|
|
130
|
+
|
|
131
|
+
## Everyday commands
|
|
132
|
+
|
|
133
|
+
Install and uninstall are the main commands. For troubleshooting or maintenance,
|
|
134
|
+
run these advanced commands from your project directory:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Inspect installation files
|
|
138
|
+
npx adl-toolkit status
|
|
139
|
+
|
|
140
|
+
# Check installation health, including ADL-Drift's live MCP connection
|
|
141
|
+
npx adl-toolkit doctor
|
|
142
|
+
|
|
143
|
+
# Restore missing managed configuration and instructions
|
|
144
|
+
npx adl-toolkit repair
|
|
145
|
+
|
|
146
|
+
# Upgrade the managed graph runtime
|
|
147
|
+
npx adl-toolkit update
|
|
148
|
+
|
|
149
|
+
# Show all commands and options
|
|
150
|
+
npx adl-toolkit --help
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Update upgrades the runtime; it does not replace the graph build command used to refresh your index.
|
|
154
|
+
On Windows, use `npx.cmd` for these commands too.
|
|
155
|
+
|
|
156
|
+
## If something fails
|
|
157
|
+
|
|
158
|
+
- **npm or npx is missing:** install or repair Node.js, then reopen your terminal.
|
|
159
|
+
- **Python cannot be found:** check its version and PATH. If needed, set `ADL_TOOLKIT_PYTHON` to your Python executable path.
|
|
160
|
+
- **An installation step fails:** open the full audit log at the path printed by the installer, then retry the reported command.
|
|
161
|
+
- **Your assistant cannot connect:** restart it in the installed project and run `npx adl-toolkit doctor`. For ADL-Drift, keep the failing checks and server traceback when reporting the issue.
|
|
162
|
+
- **Configuration is missing:** run `npx adl-toolkit repair`, then restart your assistant.
|
|
163
|
+
- **Windows or WSL cannot launch the command:** see [Windows recovery](windows_installation.md#recovery-in-native-windows) or [WSL recovery](windows_installation.md#recovery-in-wsl).
|
package/README.md
CHANGED
|
@@ -1,3 +1,270 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ADL Drift
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ADL Drift indexes and analyzes Python and Java source code with a pure-Python runtime.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
**Connect a graph tool to your AI assistants with ADL Toolkit.**
|
|
8
|
+
Check the [prerequisites](INSTALL_TOOLKIT.md#first-time-checklist),
|
|
9
|
+
then open a terminal in your project and run:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx adl-toolkit install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Choose your graph tool, optional plugins, and AI assistants in the menu.
|
|
16
|
+
Confirm your project, build the index, then restart your assistants to start using the graph.
|
|
17
|
+
|
|
18
|
+
To remove the setup or selected components, run:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx adl-toolkit uninstall
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
On Windows, use `npx.cmd`. Follow the [ADL Toolkit user guide](INSTALL_TOOLKIT.md)
|
|
25
|
+
for the full installation, usage, and uninstall walkthrough, including
|
|
26
|
+
[advanced commands](INSTALL_TOOLKIT.md#everyday-commands) and troubleshooting.
|
|
27
|
+
|
|
28
|
+
**Using ADL Drift from an AI agent (Claude Code / Cursor / Antigravity / Codex VS
|
|
29
|
+
Code)?**
|
|
30
|
+
|
|
31
|
+
For Claude, Cursor, or Antigravity:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install -e . && adl-drift mcp setup
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then verify with `adl-drift mcp doctor`. Full guide (harness vs MCP-only,
|
|
38
|
+
CI gate, watch mode, troubleshooting): **[SETUP.md](SETUP.md)**.
|
|
39
|
+
|
|
40
|
+
Codex VS Code is included: setup writes its trusted-project
|
|
41
|
+
`.codex/config.toml` entry. Use the full [VS Code demo](DEMO_HAPPYCASE_VSCODE.md)
|
|
42
|
+
for a walkthrough.
|
|
43
|
+
|
|
44
|
+
For a Java/JUnit 5 indexing demo, including the reproducible cold-scan and
|
|
45
|
+
incremental-correctness commands, see [DEMO_JAVA_JUNIT.md](DEMO_JAVA_JUNIT.md).
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 1. Scan the project — this now also builds and persists the graph
|
|
49
|
+
adl-drift -p adl_drift scan adl_drift
|
|
50
|
+
|
|
51
|
+
# 2. Run graph stats (first time builds + stores)
|
|
52
|
+
adl-drift -p adl_drift graph
|
|
53
|
+
|
|
54
|
+
# 3. Run it again — should be instant because it loads from SQLite
|
|
55
|
+
adl-drift -p adl_drift graph
|
|
56
|
+
|
|
57
|
+
# 4. Impact queries are also cached
|
|
58
|
+
adl-drift -p adl_drift impact add_knowledge
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Command Reference
|
|
62
|
+
|
|
63
|
+
> Full plain-language reference with every option, output-column explanations, and workflows: **[COMMANDS.md](COMMANDS.md)**.
|
|
64
|
+
|
|
65
|
+
Global option (goes **before** the command): `--project, -p <dir>` — project root (default `.`). Example: `adl-drift -p adl_drift scan adl_drift`.
|
|
66
|
+
|
|
67
|
+
| Command | What it does | Options |
|
|
68
|
+
|---------|--------------|---------|
|
|
69
|
+
| `adl-drift scan [PATH]` | Scan files/directories for patterns; also builds + persists the call graph | `-c, --category <name>` filter to one category (e.g. `security`) · `-f, --format table\|json\|github` · `-i, --incremental` only re-parse changed files · `--more-info` beginner-friendly output (see below) · `--full` show all rows with `--more-info` |
|
|
70
|
+
| `adl-drift patterns` | List every stored pattern with its ID and approval state | — |
|
|
71
|
+
| `adl-drift approve <id>` | Mark a pattern as approved ("this is intentional, stop flagging it") | — |
|
|
72
|
+
| `adl-drift gate` | CI gate — exits 1 if unapproved patterns exist | `--json` machine contract: `{violations, new_patterns, scan_errors, high_security}`; exits 1 only on HIGH security findings or scan errors |
|
|
73
|
+
| `adl-drift graph` | Call-graph statistics: node/edge counts by type, entry points | — |
|
|
74
|
+
| `adl-drift impact <symbol>` | Blast radius: who calls `<symbol>`, directly and transitively. Accepts qualified (`pkg.mod.Class.method`) or simple names | `-f, --format tree\|table\|json` (default `tree`) · `--include-initializers` counts Java `<init>`/`<clinit>` contexts in caller totals |
|
|
75
|
+
| `adl-drift viz` | Interactive graph visualization in the browser (live-updates on file save) | `--host` (default `127.0.0.1`) · `--port` (default `8765`) |
|
|
76
|
+
| `adl-drift learn <topic> [text...]` | Store tribal knowledge (no text → opens `$EDITOR`, or pipe via stdin) | — |
|
|
77
|
+
| `adl-drift why <topic>` | Retrieve tribal knowledge for a topic | — |
|
|
78
|
+
| `adl-drift server` | MCP server over HTTP/SSE | `--port` (default `3000`) |
|
|
79
|
+
| `adl-drift mcp serve` | MCP server over stdio (Claude Code / Cursor / Claude Desktop / Antigravity / Codex VS Code) | — |
|
|
80
|
+
| `adl-drift mcp setup` | Auto-configure MCP clients: writes `.mcp.json` / `.cursor/mcp.json` / `.codex/config.toml` / `~/.gemini/config/mcp_config.json` + installs skill files (merge, never clobber) | `--claude` · `--cursor` · `--antigravity` · `--codex` · `--print` dry run |
|
|
81
|
+
| `adl-drift mcp doctor` | Verify wiring: config → interpreter → SDK → live stdio handshake → tool list | — |
|
|
82
|
+
| `adl-drift watch` | Keep the index fresh: hash-based polling + incremental rescans | `--interval <s>` (default 2) |
|
|
83
|
+
|
|
84
|
+
### `scan --more-info` (easy mode)
|
|
85
|
+
|
|
86
|
+
Beginner-friendly report: summary line (`Scanned 59 files · 847 findings · 4 security (3 HIGH, 1 MEDIUM)`), per-category counts, a plain-language **What was found** column, color-coded **Severity**, confidence as words, and the first 50 rows with a footer hint (`--full` lifts the cap).
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
adl-drift -p . scan . --more-info
|
|
90
|
+
adl-drift -p . scan . --more-info --full # all rows
|
|
91
|
+
adl-drift -p . scan . --more-info -c security # one category
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Reference: Categories, Types & Values
|
|
95
|
+
|
|
96
|
+
### Pattern categories (the `Category` column in scan output)
|
|
97
|
+
|
|
98
|
+
| Category | What it covers |
|
|
99
|
+
|----------|----------------|
|
|
100
|
+
| `ROUTES` | Web endpoints from Flask/FastAPI/Django and Spring MVC/JAX-RS |
|
|
101
|
+
| `ERRORS` | Python error handling: broad/empty handlers and custom exception classes |
|
|
102
|
+
| `DATA_ACCESS` | Python ORM/raw SQL plus JDBC, JPA/Hibernate, Spring Data, and MyBatis operations |
|
|
103
|
+
| `DECORATORS` | Python decorators and Java annotations used for framework behavior |
|
|
104
|
+
| `ASYNC` | Python async/await patterns and Java asynchronous APIs |
|
|
105
|
+
| `IMPORTS` | Python and Java imports with language-appropriate classification |
|
|
106
|
+
| `SECURITY` | Risky execution, SQL construction, deserialization, crypto, reflection, secrets, and production assertions — carries a **Severity** |
|
|
107
|
+
| `TESTS` | pytest/unittest and JUnit/TestNG tests, fixtures, and lifecycle methods |
|
|
108
|
+
| `CONFIG` | Environment/config reads and constant conventions |
|
|
109
|
+
| `LOGGING` | Console and logger calls, including inefficient message construction |
|
|
110
|
+
| `TYPES` | Python annotation coverage and Java raw/nullability type conventions |
|
|
111
|
+
|
|
112
|
+
### Scan table columns
|
|
113
|
+
|
|
114
|
+
| Column | Meaning |
|
|
115
|
+
|--------|---------|
|
|
116
|
+
| `Object` | The concrete thing the finding is about — the function, decorator, imported module, env-var key, etc. Empty when the finding has no single symbol (e.g. a bare `except:`) |
|
|
117
|
+
| `Severity` | Security/logging findings only: `HIGH` (red — fix or justify), `MEDIUM` (yellow — review), `LOW` (dim — informational) |
|
|
118
|
+
| `Confidence` | How sure the detector is. Numeric `0–1` in the default table; words in `--more-info`: **Certain** ≥ 0.85, **Likely** ≥ 0.6, **Guess** below |
|
|
119
|
+
| `Line` | 1-indexed line in the file |
|
|
120
|
+
|
|
121
|
+
### Graph node types (`adl-drift graph`, viz UI)
|
|
122
|
+
|
|
123
|
+
| Node type | Meaning | Viz shape |
|
|
124
|
+
|-----------|---------|-----------|
|
|
125
|
+
| `MODULE` | One `.py` or `.java` file (`pkg.sub.mod`) | rounded box, dark |
|
|
126
|
+
| `CLASS` | Class definition | diamond, grey |
|
|
127
|
+
| `FUNCTION` | Function or method | dot, emerald |
|
|
128
|
+
| `VARIABLE` | Module-level constant or `self.X` attribute defined in `__init__` | dot |
|
|
129
|
+
|
|
130
|
+
Node IDs are dotted qualified names — `module.Class.method` — relative to the detected project root.
|
|
131
|
+
|
|
132
|
+
### Graph edge types
|
|
133
|
+
|
|
134
|
+
| Edge | Meaning | Emitted confidence |
|
|
135
|
+
|------|---------|--------------------|
|
|
136
|
+
| `CONTAINS` | Module contains class/function; class contains methods | 1.0 |
|
|
137
|
+
| `CALLS` | Function A calls function B | 0.3–0.95 by resolution strategy (see below) |
|
|
138
|
+
| `AWAITS` | The call is awaited (`await f()`) — coexists with `CALLS` | same as the call |
|
|
139
|
+
| `IMPORTS` | Module imports another module | 1.0 |
|
|
140
|
+
| `INHERITS` | Class extends a base class | 1.0 |
|
|
141
|
+
| `DECORATED_BY` | Symbol wrapped by a decorator function | 1.0 |
|
|
142
|
+
| `REFERENCES` | Function reads a variable/constant (`return MAX_RETRIES`, `self.db`) | 0.85–0.95 |
|
|
143
|
+
| `TYPE_OF` | Function has a parameter annotated with a class (`def f(s: Service)`) | 1.0 |
|
|
144
|
+
| `RETURNS` | Function's return annotation is a class (`-> Service`) | 1.0 |
|
|
145
|
+
|
|
146
|
+
`CALLS` confidence by how the call was resolved: `0.95` `self.x()` on own class · `0.9` same-module name · `0.85` via import / inherited method / `super()` / type-annotated receiver · `0.75` chained call (`lib.Db.query()`) · `0.6` unique global name · `0.3–0.5` guessed by attribute name. The viz draws ≥ 0.85 solid, 0.6–0.85 dashed, < 0.6 faint.
|
|
147
|
+
|
|
148
|
+
**Blast radius** (`adl-drift impact`) follows incoming `CALLS`, `REFERENCES`, `TYPE_OF`, and `RETURNS` edges — so changing a constant reports every function that reads it, and changing a class reports every function annotated with it, plus their callers transitively. Synthetic Java field/initializer-block contexts (`<init>`/`<clinit>`) are reported in separate initializer fields by default; pass `--include-initializers` to include them in the ordinary caller totals.
|
|
149
|
+
|
|
150
|
+
### Symbol kinds (internal `Symbol.kind`)
|
|
151
|
+
|
|
152
|
+
`function` (incl. methods — enclosing class recorded in `parent`) · `class` · `variable` (module-level assignment) · `attribute` (`self.X = ...` in `__init__`).
|
|
153
|
+
|
|
154
|
+
## Node ID Collision & Project Root Detection
|
|
155
|
+
|
|
156
|
+
In large codebases and monorepos, multiple packages can contain files with the same relative path (e.g. `backend/api/users.py` and `frontend/api/users.py`). ADL Drift automatically detects your project root by looking for `pyproject.toml`, `.git`, `setup.py`, or `setup.cfg` and computes fully-qualified module names relative to that root. This prevents symbols from overwriting each other in the call graph.
|
|
157
|
+
|
|
158
|
+
### How it works
|
|
159
|
+
|
|
160
|
+
- **Detection**: `CallGraphBuilder.find_project_root()` walks up the directory tree from the scan target until it finds a root marker.
|
|
161
|
+
- **Module naming**: `_path_to_module()` strips the project root prefix from every file path, so `/repo/backend/api/users.py` becomes `backend.api.users` instead of a truncated heuristic.
|
|
162
|
+
- **Fallback**: If no project root is found, ADL Drift falls back to the last 3 path components for backward compatibility.
|
|
163
|
+
|
|
164
|
+
### Verifying the fix
|
|
165
|
+
|
|
166
|
+
Run the collision test to see the before/after behavior:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pytest tests/test_graph.py::TestCallGraphBuilder::test_no_node_id_collision_with_project_root -v
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Or inspect the graph in a real project and confirm that nested packages produce distinct node IDs:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
adl-drift -p . graph
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Test scripts
|
|
179
|
+
|
|
180
|
+
These are the exact scripts used during development to verify the collision fix.
|
|
181
|
+
|
|
182
|
+
**1. Full collision demo (shows old vs new behavior side-by-side)**
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from pathlib import Path
|
|
186
|
+
import tempfile
|
|
187
|
+
from adl_drift.parser.core import PythonParser
|
|
188
|
+
from adl_drift.parser.extractor import SymbolExtractor
|
|
189
|
+
from adl_drift.graph.builder import CallGraphBuilder
|
|
190
|
+
|
|
191
|
+
with tempfile.TemporaryDirectory() as td:
|
|
192
|
+
root = Path(td)
|
|
193
|
+
# Paths where the last 3 components are IDENTICAL — old code collides here
|
|
194
|
+
(root / 'services' / 'backend' / 'api' / 'v1').mkdir(parents=True)
|
|
195
|
+
(root / 'services' / 'frontend' / 'api' / 'v1').mkdir(parents=True)
|
|
196
|
+
(root / 'pyproject.toml').write_text('[project]\n')
|
|
197
|
+
|
|
198
|
+
(root / 'services' / 'backend' / 'api' / 'v1' / 'users.py').write_text('def list(): pass\n')
|
|
199
|
+
(root / 'services' / 'frontend' / 'api' / 'v1' / 'users.py').write_text('def list(): pass\n')
|
|
200
|
+
|
|
201
|
+
parser = PythonParser()
|
|
202
|
+
extractor = SymbolExtractor(parser)
|
|
203
|
+
r1 = extractor.extract(root / 'services' / 'backend' / 'api' / 'v1' / 'users.py')
|
|
204
|
+
r2 = extractor.extract(root / 'services' / 'frontend' / 'api' / 'v1' / 'users.py')
|
|
205
|
+
|
|
206
|
+
# OLD: last-3 heuristic collapses both files into api.v1.users
|
|
207
|
+
old = CallGraphBuilder(project_root=None)
|
|
208
|
+
old.add_file_result(r1)
|
|
209
|
+
old.add_file_result(r2)
|
|
210
|
+
print('OLD nodes:', sorted(old._nodes))
|
|
211
|
+
print('OLD count :', len(old._nodes), '(should be 4, is 2 -> COLLISION)')
|
|
212
|
+
|
|
213
|
+
# NEW: full relative path from project root
|
|
214
|
+
new = CallGraphBuilder(project_root=root)
|
|
215
|
+
new.add_file_result(r1)
|
|
216
|
+
new.add_file_result(r2)
|
|
217
|
+
print('NEW nodes:', sorted(new._nodes))
|
|
218
|
+
print('NEW count :', len(new._nodes), '(4 -> DISTINCT)')
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Expected output:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
OLD nodes: ['api.v1.users', 'api.v1.users.list']
|
|
225
|
+
OLD count : 2 (should be 4, is 2 -> COLLISION)
|
|
226
|
+
NEW nodes: ['services.backend.api.v1.users', 'services.backend.api.v1.users.list',
|
|
227
|
+
'services.frontend.api.v1.users', 'services.frontend.api.v1.users.list']
|
|
228
|
+
NEW count : 4 (4 -> DISTINCT)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**2. Quick live-project check**
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from pathlib import Path
|
|
235
|
+
from adl_drift.cli.commands import DriftCommands
|
|
236
|
+
|
|
237
|
+
cmd = DriftCommands(Path('.'))
|
|
238
|
+
stats = cmd.graph_stats()
|
|
239
|
+
print('Nodes by type:', stats.get('node_types'))
|
|
240
|
+
print('Total nodes :', stats.get('total_nodes'))
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**3. Unit test (also in `tests/test_graph.py`)**
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
def test_no_node_id_collision_with_project_root(self, tmp_path):
|
|
247
|
+
"""P0.2: Files with same relative path in different subtrees must have unique node IDs."""
|
|
248
|
+
backend = tmp_path / "backend" / "api"
|
|
249
|
+
frontend = tmp_path / "frontend" / "api"
|
|
250
|
+
backend.mkdir(parents=True)
|
|
251
|
+
frontend.mkdir(parents=True)
|
|
252
|
+
|
|
253
|
+
(backend / "users.py").write_text("def get_users(): pass\n")
|
|
254
|
+
(frontend / "users.py").write_text("def get_users(): pass\n")
|
|
255
|
+
|
|
256
|
+
(tmp_path / "pyproject.toml").write_text("[project]\n")
|
|
257
|
+
|
|
258
|
+
extractor = SymbolExtractor(PythonParser())
|
|
259
|
+
result1 = extractor.extract(backend / "users.py")
|
|
260
|
+
result2 = extractor.extract(frontend / "users.py")
|
|
261
|
+
|
|
262
|
+
builder = CallGraphBuilder(project_root=tmp_path)
|
|
263
|
+
builder.add_file_result(result1)
|
|
264
|
+
builder.add_file_result(result2)
|
|
265
|
+
|
|
266
|
+
assert "backend.api.users" in builder._nodes
|
|
267
|
+
assert "frontend.api.users" in builder._nodes
|
|
268
|
+
assert "backend.api.users.get_users" in builder._nodes
|
|
269
|
+
assert "frontend.api.users.get_users" in builder._nodes
|
|
270
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line interface."""
|