node-walk 0.1.1__tar.gz → 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.
- node_walk-0.2.0/CHANGELOG.md +80 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/PKG-INFO +29 -4
- {node_walk-0.1.1 → node_walk-0.2.0}/README.md +28 -3
- node_walk-0.2.0/plans/traversable-graph.md +351 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/pyproject.toml +9 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/__init__.py +1 -1
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/cli/main.py +35 -0
- node_walk-0.2.0/src/node_walk/web/__init__.py +3 -0
- node_walk-0.2.0/src/node_walk/web/app.js +704 -0
- node_walk-0.2.0/src/node_walk/web/index.html +157 -0
- node_walk-0.2.0/src/node_walk/web/server.py +337 -0
- node_walk-0.2.0/src/node_walk/web/style.css +555 -0
- node_walk-0.2.0/tests/test_web_server.py +246 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/.github/workflows/ci.yml +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/.github/workflows/release.yml +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/.gitignore +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/LICENSE +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/plans/plan.md +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/base.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/python/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/python/analyzer.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/python/scope.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/python/visitor.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/analysis/python_analyzer.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/cli/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/indexer.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/ir/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/ir/enums.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/ir/models.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/query/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/query/engine.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/query/tree_formatter.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/storage/__init__.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/storage/base.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/storage/repository.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/storage/schema.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/src/node_walk/storage/sqlite_store.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/fixtures/nested_project/base.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/fixtures/nested_project/impl.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/fixtures/simple_project/services.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/test_ir.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/test_python_analyzer.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/test_query_engine.py +0 -0
- {node_walk-0.1.1 → node_walk-0.2.0}/tests/test_storage.py +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **node-walk** will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [0.2.0] - 2026-08-23
|
|
15
|
+
### Added
|
|
16
|
+
- **`node-walk serve` command**: Launches an embedded local HTTP server (`localhost:7777` by default) and auto-opens the browser to the interactive graph explorer. Accepts `--port`, `--host`, and `--no-open` flags.
|
|
17
|
+
- **Graph Explorer UI** (`src/node_walk/web/`): A single-page browser application (no build step, no npm) that renders the full code graph using Cytoscape.js (CDN):
|
|
18
|
+
- Force-directed layout with manual drag support.
|
|
19
|
+
- Nodes coloured and shaped by `SymbolKind`; edges styled and coloured by `RelationshipType`.
|
|
20
|
+
- Click node → highlight it and direct neighbours + show detail panel (name, kind, file, lines, signature, docstring, source snippet).
|
|
21
|
+
- Double-click node → lazy 1-hop neighbour expansion via `/api/neighbors`.
|
|
22
|
+
- Right-click context menu: expand neighbours, focus subtree, hide node, reset focus.
|
|
23
|
+
- Debounced search bar backed by `/api/search` → centres and selects the top match.
|
|
24
|
+
- Filter panel (checkboxes) to show/hide nodes by `SymbolKind` and edges by `RelationshipType`; `CONTAINS` edges hidden by default.
|
|
25
|
+
- Tooltip on hover for nodes and edges.
|
|
26
|
+
- Fit-to-viewport and re-layout buttons.
|
|
27
|
+
- Status bar showing visible node/edge counts and selected symbol name.
|
|
28
|
+
- **Web API** (`src/node_walk/web/server.py`): Zero-dependency HTTP server (Python `http.server`) exposing:
|
|
29
|
+
- `GET /api/graph[?kinds=…&rels=…]` — full graph for initial render, with optional kind/relationship filters.
|
|
30
|
+
- `GET /api/symbol/{id}` — symbol detail including source snippet, caller/callee counts.
|
|
31
|
+
- `GET /api/neighbors/{id}[?direction=out|in|both&rels=…]` — 1-hop neighbours for lazy canvas expansion.
|
|
32
|
+
- `GET /api/search?q=…` — fuzzy symbol search (reuses `QueryEngine.find_symbol`).
|
|
33
|
+
- `GET /api/stats` — graph statistics.
|
|
34
|
+
- **API tests** (`tests/test_web_server.py`): Full test suite covering all five endpoints (schema validation, filter params, 404 handling, score ranges) plus a full smoke round-trip and static file serving tests.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- **`pyproject.toml`**: Added `force-include` entries so `index.html`, `style.css`, and `app.js` are bundled in the installed wheel.
|
|
38
|
+
- **`node-walk help`**: Added "Browser Explorer" section listing the `serve` command.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## [0.1.1] - 2026-08-20
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
- **Dotted-Path Symbol Search**: Support searching for scoped symbols (e.g. `ModelAdapter.chat`, `UserService.create_user`) matching child symbols within parents without needing full module paths.
|
|
45
|
+
- **Fuzzy / Typo Matching**: Added `difflib.SequenceMatcher` fallback across symbols to handle typos (e.g. `ModelAdpater.chat`, `creat_user`), returning match scores and `(fuzzy)` indicators.
|
|
46
|
+
- **Graph Visualizations**: Added ASCII tree, Graphviz DOT (`.dot`), and Mermaid diagram formatters in `tree_formatter.py`.
|
|
47
|
+
- **`graph` Command**: Added `node-walk graph <symbol>` for general BFS neighborhood exploration with customizable direction (`out`, `in`, `both`) and format (`tree`, `dot`, `mermaid`, `table`).
|
|
48
|
+
- **Formatting Options**: Added `--format` / `-f` (`tree`, `dot`, `mermaid`, `table`) and `--output` / `-o` flags to `trace` and `blast-radius` commands.
|
|
49
|
+
- **Automated Versioning in CI**: Updated GitHub Actions release workflow with dynamic version resolution (tag triggers or `patch`/`minor`/`major` dispatch inputs).
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- **Branding**: Renamed project and CLI binaries from `CodeGraph` to `node-walk`.
|
|
53
|
+
- **Packaging**: Switched `pyproject.toml` to dynamic versioning via Hatchling reading from `src/node_walk/__init__.py`.
|
|
54
|
+
- **CLI Resolution**: Auto-select top candidate when an unambiguous high-confidence match is found instead of prompting unnecessarily.
|
|
55
|
+
- **Documentation**: Updated `README.md` to reflect all currently supported features, traversal modes, and CLI commands.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## [0.1.0] - 2026-08-20
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
- **Tree-sitter Python Analyzer**: High-speed AST analysis extracting files, classes, methods, functions, constants, variables, fields, docstrings, signatures, and call sites.
|
|
63
|
+
- **Language-Independent Code IR**: Pydantic v2 data models for `Symbol`, `Relationship`, `FileInfo`, `SourceLocation`, and `AnalysisResult`.
|
|
64
|
+
- **Typed Semantic Relationships**: Support for `CONTAINS`, `IMPORTS`, `CALLS`, `REFERENCES`, `EXTENDS`, `IMPLEMENTS`, and `OVERRIDES`.
|
|
65
|
+
- **SQLite Storage Backend**: Local SQLite database with WAL mode, foreign keys, and 10 query indexes.
|
|
66
|
+
- **Recursive CTE Query Engine**: In-database bounded graph traversals (`walk`, `trace`, `blast_radius`) using recursive SQL CTEs.
|
|
67
|
+
- **Rich CLI**: Typer-based command-line interface with custom themed tables and syntax highlighting:
|
|
68
|
+
- `index`: Analyze and index a codebase.
|
|
69
|
+
- `find`: Search symbols by name or qualified name.
|
|
70
|
+
- `definition`: Show symbol definition and metadata.
|
|
71
|
+
- `source`: Extract and display the exact source code block of any symbol.
|
|
72
|
+
- `callers` & `callees`: Discover direct upstream and downstream call sites.
|
|
73
|
+
- `refs`: Locate symbol references.
|
|
74
|
+
- `implementations`: Find concrete classes extending or implementing interfaces/ABCs.
|
|
75
|
+
- `imports`: Inspect imported modules and symbols.
|
|
76
|
+
- `trace`: Follow outgoing dependency chains.
|
|
77
|
+
- `blast-radius`: Follow incoming dependent chains.
|
|
78
|
+
- `stats`: Display database statistics and symbol/relationship breakdowns.
|
|
79
|
+
- `export`: Export the complete semantic graph to JSON.
|
|
80
|
+
- `help`: Custom command cheat sheet.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: node-walk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Semantic code intelligence — local-first graph of your codebase for humans and LLMs
|
|
5
5
|
Author: CodeGraph Contributors
|
|
6
6
|
License: MIT
|
|
@@ -38,8 +38,9 @@ Local-first · Lightweight · Fast indexing · SQLite backed · CLI & Visualizat
|
|
|
38
38
|
- **Smart Symbol Search**: Find symbols by simple name (`chat`), qualified dotted path (`ModelAdapter.chat`), or fuzzy typo matching (`ModelAdpater.chat`).
|
|
39
39
|
- **Exact Source Retrieval**: View definitions, signatures, and exact source ranges instantly.
|
|
40
40
|
- **Relationship Navigation**: Find callers, callees, references, class implementations / ABCs, and imports.
|
|
41
|
-
- **Graph Traversal & Visualization**: Trace outgoing call chains and incoming blast radiuses rendered
|
|
42
|
-
- **
|
|
41
|
+
- **Graph Traversal & Visualization**: Trace outgoing call chains and incoming blast radiuses rendered in terminal (ASCII tree), exported to Graphviz (`.dot`), or generated as Mermaid diagrams.
|
|
42
|
+
- **Browser Graph Explorer**: `node-walk serve` launches a local interactive Cytoscape.js graph — click nodes, expand neighbours, search symbols, filter by kind/relationship, and inspect source — all without leaving the browser.
|
|
43
|
+
- **Lightweight & Self-Contained**: Pure Python + Tree-sitter + SQLite + stdlib `http.server`. Zero external database services, cloud dependencies, or build steps.
|
|
43
44
|
|
|
44
45
|
---
|
|
45
46
|
|
|
@@ -111,7 +112,25 @@ node-walk blast-radius UserService.create_user --format tree
|
|
|
111
112
|
node-walk graph ModelAdapter --depth 3 --format tree
|
|
112
113
|
```
|
|
113
114
|
|
|
114
|
-
### 5.
|
|
115
|
+
### 5. Browser Graph Explorer
|
|
116
|
+
```bash
|
|
117
|
+
# Launch the interactive graph explorer in your browser
|
|
118
|
+
node-walk serve # default: http://localhost:7777
|
|
119
|
+
node-walk serve --port 8888 # custom port
|
|
120
|
+
node-walk serve --no-open # start server only, don't auto-open
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The explorer visualises **all** symbols and relationships as a force-directed interactive graph:
|
|
124
|
+
|
|
125
|
+
| Action | Result |
|
|
126
|
+
|---|---|
|
|
127
|
+
| Click node | Highlight node + direct neighbours; open detail panel |
|
|
128
|
+
| Double-click node | Lazy-expand 1-hop neighbours from the server |
|
|
129
|
+
| Right-click node | Context menu: expand, focus subtree, hide, reset |
|
|
130
|
+
| Search bar | Debounced fuzzy search → centre + select result |
|
|
131
|
+
| Filter panel | Toggle visibility by SymbolKind / RelationshipType |
|
|
132
|
+
|
|
133
|
+
### 6. Utilities
|
|
115
134
|
```bash
|
|
116
135
|
# Show database statistics (symbol kinds, relationship counts)
|
|
117
136
|
node-walk stats
|
|
@@ -147,3 +166,9 @@ pytest tests/ -v
|
|
|
147
166
|
## Graph Storage & Lifecycle
|
|
148
167
|
|
|
149
168
|
The generated graph is stored in `.node_walk/graph.db` inside your indexed repository. It is disposable and can be re-indexed at any time with `node-walk index .`.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Changelog
|
|
173
|
+
|
|
174
|
+
See [CHANGELOG.md](file:///c:/Users/nshri/Github/CodeGraph/CHANGELOG.md) for full release history and notes.
|
|
@@ -14,8 +14,9 @@ Local-first · Lightweight · Fast indexing · SQLite backed · CLI & Visualizat
|
|
|
14
14
|
- **Smart Symbol Search**: Find symbols by simple name (`chat`), qualified dotted path (`ModelAdapter.chat`), or fuzzy typo matching (`ModelAdpater.chat`).
|
|
15
15
|
- **Exact Source Retrieval**: View definitions, signatures, and exact source ranges instantly.
|
|
16
16
|
- **Relationship Navigation**: Find callers, callees, references, class implementations / ABCs, and imports.
|
|
17
|
-
- **Graph Traversal & Visualization**: Trace outgoing call chains and incoming blast radiuses rendered
|
|
18
|
-
- **
|
|
17
|
+
- **Graph Traversal & Visualization**: Trace outgoing call chains and incoming blast radiuses rendered in terminal (ASCII tree), exported to Graphviz (`.dot`), or generated as Mermaid diagrams.
|
|
18
|
+
- **Browser Graph Explorer**: `node-walk serve` launches a local interactive Cytoscape.js graph — click nodes, expand neighbours, search symbols, filter by kind/relationship, and inspect source — all without leaving the browser.
|
|
19
|
+
- **Lightweight & Self-Contained**: Pure Python + Tree-sitter + SQLite + stdlib `http.server`. Zero external database services, cloud dependencies, or build steps.
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -87,7 +88,25 @@ node-walk blast-radius UserService.create_user --format tree
|
|
|
87
88
|
node-walk graph ModelAdapter --depth 3 --format tree
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
### 5.
|
|
91
|
+
### 5. Browser Graph Explorer
|
|
92
|
+
```bash
|
|
93
|
+
# Launch the interactive graph explorer in your browser
|
|
94
|
+
node-walk serve # default: http://localhost:7777
|
|
95
|
+
node-walk serve --port 8888 # custom port
|
|
96
|
+
node-walk serve --no-open # start server only, don't auto-open
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The explorer visualises **all** symbols and relationships as a force-directed interactive graph:
|
|
100
|
+
|
|
101
|
+
| Action | Result |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Click node | Highlight node + direct neighbours; open detail panel |
|
|
104
|
+
| Double-click node | Lazy-expand 1-hop neighbours from the server |
|
|
105
|
+
| Right-click node | Context menu: expand, focus subtree, hide, reset |
|
|
106
|
+
| Search bar | Debounced fuzzy search → centre + select result |
|
|
107
|
+
| Filter panel | Toggle visibility by SymbolKind / RelationshipType |
|
|
108
|
+
|
|
109
|
+
### 6. Utilities
|
|
91
110
|
```bash
|
|
92
111
|
# Show database statistics (symbol kinds, relationship counts)
|
|
93
112
|
node-walk stats
|
|
@@ -123,3 +142,9 @@ pytest tests/ -v
|
|
|
123
142
|
## Graph Storage & Lifecycle
|
|
124
143
|
|
|
125
144
|
The generated graph is stored in `.node_walk/graph.db` inside your indexed repository. It is disposable and can be re-indexed at any time with `node-walk index .`.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Changelog
|
|
149
|
+
|
|
150
|
+
See [CHANGELOG.md](file:///c:/Users/nshri/Github/CodeGraph/CHANGELOG.md) for full release history and notes.
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Traversable Graph — Feature Plan
|
|
2
|
+
|
|
3
|
+
**Interactive browser-based code graph visualization for node-walk.**
|
|
4
|
+
|
|
5
|
+
Light-touch MVP first, iterate from user feedback.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Goal
|
|
10
|
+
|
|
11
|
+
Let a developer **see and click through** their code graph in a browser — starting from any symbol, expanding neighbors on click, reading source on hover — rather than only navigating via terminal commands.
|
|
12
|
+
|
|
13
|
+
The graph is **local-only**: a tiny embedded HTTP server reads the same `.node_walk/graph.db` that the CLI already produces. No cloud, no build step, no bundler.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. What the MVP Does
|
|
18
|
+
|
|
19
|
+
| Capability | Detail |
|
|
20
|
+
|---|---|
|
|
21
|
+
| **Launch from CLI** | `node-walk serve` starts a local HTTP server (default `localhost:7777`) and opens the browser. |
|
|
22
|
+
| **Full graph overview** | On load, render all symbols + relationships from the indexed repo. Nodes are colored by `SymbolKind`, edges by `RelationshipType`. |
|
|
23
|
+
| **Click to focus** | Click a node → highlight it and its direct neighbors, dim everything else. |
|
|
24
|
+
| **Expand / collapse** | Double-click a node → run a 1-hop walk from that node and add newly discovered neighbors to the canvas (lazy expansion). |
|
|
25
|
+
| **Node detail panel** | Select a node → side panel shows: qualified name, kind, file, line range, signature, docstring preview. |
|
|
26
|
+
| **Search bar** | Type a symbol name → fuzzy match (reuses `find_symbol` logic server-side) → center the graph on the result. |
|
|
27
|
+
| **Layout** | Force-directed layout (Cytoscape.js `cose`) with manual drag. |
|
|
28
|
+
| **Edge labels** | Edges show relationship type (`CALLS`, `IMPORTS`, `EXTENDS`, etc.). |
|
|
29
|
+
| **Filter panel** | Checkboxes to show/hide by SymbolKind and RelationshipType. |
|
|
30
|
+
|
|
31
|
+
### What the MVP Does NOT Do
|
|
32
|
+
|
|
33
|
+
- No live re-indexing (user must `node-walk index` first).
|
|
34
|
+
- No edit-in-place or "go to file in editor" integration.
|
|
35
|
+
- No multi-repo or remote graphs.
|
|
36
|
+
- No persistence of layout state between sessions.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. Architecture
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
┌────────────────────────────────┐
|
|
44
|
+
│ Browser │
|
|
45
|
+
│ ┌──────────────────────────┐ │
|
|
46
|
+
│ │ Single-Page HTML/JS/CSS │ │
|
|
47
|
+
│ │ Cytoscape.js (CDN) │ │
|
|
48
|
+
│ └──────────┬───────────────┘ │
|
|
49
|
+
│ │ fetch /api/* │
|
|
50
|
+
└─────────────┼──────────────────┘
|
|
51
|
+
│ HTTP (localhost)
|
|
52
|
+
┌─────────────┼──────────────────┐
|
|
53
|
+
│ node-walk serve │
|
|
54
|
+
│ ┌──────────┴───────────────┐ │
|
|
55
|
+
│ │ Python HTTP server │ │
|
|
56
|
+
│ │ (aiohttp or stdlib) │ │
|
|
57
|
+
│ │ JSON API endpoints │ │
|
|
58
|
+
│ └──────────┬───────────────┘ │
|
|
59
|
+
│ │ │
|
|
60
|
+
│ ┌──────────┴───────────────┐ │
|
|
61
|
+
│ │ QueryEngine │ │
|
|
62
|
+
│ │ SQLiteGraphStore │ │
|
|
63
|
+
│ │ (.node_walk/graph.db) │ │
|
|
64
|
+
│ └──────────────────────────┘ │
|
|
65
|
+
└────────────────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Zero new Python dependencies for MVP.** The HTTP server uses Python's built-in `http.server` module. The frontend loads Cytoscape.js from CDN. All HTML/CSS/JS is served from a single bundled directory inside the package.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 4. Backend — API Endpoints
|
|
73
|
+
|
|
74
|
+
All endpoints return JSON. The server is a thin wrapper around `QueryEngine`.
|
|
75
|
+
|
|
76
|
+
### `GET /api/graph`
|
|
77
|
+
|
|
78
|
+
Returns the full graph (all symbols + relationships) for initial render.
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"nodes": [
|
|
83
|
+
{
|
|
84
|
+
"id": "uuid",
|
|
85
|
+
"name": "chat",
|
|
86
|
+
"qualified_name": "jarvis.model.base.ModelAdapter.chat",
|
|
87
|
+
"kind": "METHOD",
|
|
88
|
+
"file_path": "src/jarvis/model/base.py",
|
|
89
|
+
"start_line": 42,
|
|
90
|
+
"end_line": 58,
|
|
91
|
+
"signature": "(self, messages: list[ChatMessage]) -> str",
|
|
92
|
+
"docstring": "Send messages to the model and return response.",
|
|
93
|
+
"parent_id": "uuid-of-ModelAdapter"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"edges": [
|
|
97
|
+
{
|
|
98
|
+
"id": "uuid",
|
|
99
|
+
"source": "source-symbol-uuid",
|
|
100
|
+
"target": "target-symbol-uuid",
|
|
101
|
+
"type": "CALLS",
|
|
102
|
+
"resolution": "resolved"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"stats": {
|
|
106
|
+
"total_nodes": 127,
|
|
107
|
+
"total_edges": 304
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Query params:**
|
|
113
|
+
- `?kinds=CLASS,METHOD,FUNCTION` — filter node kinds (default: all)
|
|
114
|
+
- `?rels=CALLS,IMPORTS,EXTENDS` — filter edge types (default: all)
|
|
115
|
+
|
|
116
|
+
### `GET /api/symbol/{id}`
|
|
117
|
+
|
|
118
|
+
Returns full detail for a single symbol (definition, source snippet).
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"symbol": { /* same shape as node above */ },
|
|
123
|
+
"source_lines": ["def chat(self, ...):", " ..."],
|
|
124
|
+
"callers_count": 3,
|
|
125
|
+
"callees_count": 5,
|
|
126
|
+
"refs_count": 8
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `GET /api/neighbors/{id}`
|
|
131
|
+
|
|
132
|
+
Returns 1-hop neighbors of a symbol (for lazy expand on double-click).
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"nodes": [ /* new nodes not already on canvas */ ],
|
|
137
|
+
"edges": [ /* edges connecting to/from the expanded node */ ]
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Query params:**
|
|
142
|
+
- `?direction=out|in|both` (default: `both`)
|
|
143
|
+
- `?rels=CALLS,IMPORTS` (default: all)
|
|
144
|
+
|
|
145
|
+
### `GET /api/search?q=<query>`
|
|
146
|
+
|
|
147
|
+
Fuzzy symbol search. Returns top matches with scores.
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"results": [
|
|
152
|
+
{
|
|
153
|
+
"id": "uuid",
|
|
154
|
+
"qualified_name": "pkg.ModelAdapter.chat",
|
|
155
|
+
"kind": "METHOD",
|
|
156
|
+
"score": 0.95
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `GET /api/stats`
|
|
163
|
+
|
|
164
|
+
Returns graph statistics (reuses `QueryEngine.stats()`).
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 5. Frontend — Single-Page App
|
|
169
|
+
|
|
170
|
+
### Technology
|
|
171
|
+
|
|
172
|
+
| Component | Choice | Rationale |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| Graph rendering | **Cytoscape.js** (CDN) | Mature, performant, supports cola/cose layouts, built-in selection/expansion APIs. |
|
|
175
|
+
| Styling | Vanilla CSS | Zero build step. Dark theme by default. |
|
|
176
|
+
| HTTP | `fetch()` | No framework needed. |
|
|
177
|
+
|
|
178
|
+
### Files
|
|
179
|
+
|
|
180
|
+
All frontend files live under `src/node_walk/web/`:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
src/node_walk/web/
|
|
184
|
+
├── index.html # Single-page shell
|
|
185
|
+
├── style.css # Dark theme, layout, panels
|
|
186
|
+
└── app.js # Cytoscape init, API calls, interaction handlers
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### UI Layout
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
193
|
+
│ ┌─────────────────────────────────────────┐ ┌───────────┐ │
|
|
194
|
+
│ │ Search bar │ │ Filters │ │
|
|
195
|
+
│ └─────────────────────────────────────────┘ └───────────┘ │
|
|
196
|
+
│ ┌─────────────────────────────────────────┐ ┌───────────┐ │
|
|
197
|
+
│ │ │ │ Detail │ │
|
|
198
|
+
│ │ │ │ Panel │ │
|
|
199
|
+
│ │ Cytoscape Canvas │ │ │ │
|
|
200
|
+
│ │ (interactive graph) │ │ - Name │ │
|
|
201
|
+
│ │ │ │ - Kind │ │
|
|
202
|
+
│ │ │ │ - File │ │
|
|
203
|
+
│ │ │ │ - Lines │ │
|
|
204
|
+
│ │ │ │ - Source │ │
|
|
205
|
+
│ └─────────────────────────────────────────┘ └───────────┘ │
|
|
206
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
207
|
+
│ │ Status bar: node count · edge count · index path │ │
|
|
208
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
209
|
+
└───────────────────────────────────────────────────────────────┘
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Interactions
|
|
213
|
+
|
|
214
|
+
| User Action | Behavior |
|
|
215
|
+
|---|---|
|
|
216
|
+
| **Click node** | Select → highlight it + direct neighbors. Show detail panel. |
|
|
217
|
+
| **Double-click node** | Lazy expand: fetch `/api/neighbors/{id}`, add new nodes/edges, re-layout locally. |
|
|
218
|
+
| **Right-click node** | Context menu: "Trace from here", "Blast radius", "Hide node", "Focus subtree". |
|
|
219
|
+
| **Hover node** | Tooltip with qualified name + kind. |
|
|
220
|
+
| **Hover edge** | Tooltip with relationship type. |
|
|
221
|
+
| **Search** | Debounced keystroke → `GET /api/search?q=...` → highlight + center on top match. |
|
|
222
|
+
| **Filter checkboxes** | Toggle visibility of SymbolKind / RelationshipType categories. |
|
|
223
|
+
| **Drag node** | Manual positioning (disables auto-layout for that node). |
|
|
224
|
+
| **Scroll** | Zoom in/out. |
|
|
225
|
+
| **Fit button** | Reset viewport to fit all visible nodes. |
|
|
226
|
+
|
|
227
|
+
### Node Styling (by SymbolKind)
|
|
228
|
+
|
|
229
|
+
| Kind | Shape | Color |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| CLASS | Round rectangle | `#4FC3F7` (blue) |
|
|
232
|
+
| INTERFACE | Diamond | `#7E57C2` (purple) |
|
|
233
|
+
| FUNCTION | Ellipse | `#66BB6A` (green) |
|
|
234
|
+
| METHOD | Ellipse | `#FFA726` (orange) |
|
|
235
|
+
| MODULE / FILE | Rectangle | `#AB47BC` (violet) |
|
|
236
|
+
| CONSTANT | Small rectangle | `#FFEE58` (yellow) |
|
|
237
|
+
| VARIABLE / FIELD | Small ellipse | `#BDBDBD` (grey) |
|
|
238
|
+
|
|
239
|
+
### Edge Styling (by RelationshipType)
|
|
240
|
+
|
|
241
|
+
| Type | Style | Color |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| CALLS | Solid arrow | `#42A5F5` (blue) |
|
|
244
|
+
| IMPORTS | Dashed arrow | `#AB47BC` (purple) |
|
|
245
|
+
| EXTENDS | Bold arrow | `#66BB6A` (green) |
|
|
246
|
+
| IMPLEMENTS | Dashed arrow | `#26A69A` (teal) |
|
|
247
|
+
| REFERENCES | Dotted arrow | `#9E9E9E` (grey) |
|
|
248
|
+
| CONTAINS | Dotted, thin | `#E0E0E0` (light grey) |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 6. Implementation Plan
|
|
253
|
+
|
|
254
|
+
### Phase 1: Backend API (server.py)
|
|
255
|
+
|
|
256
|
+
**New file:** `src/node_walk/web/server.py`
|
|
257
|
+
|
|
258
|
+
1. Create a `http.server.HTTPServer` subclass that:
|
|
259
|
+
- Serves static files from `src/node_walk/web/` for `/`, `/style.css`, `/app.js`.
|
|
260
|
+
- Routes `/api/*` requests to handler functions.
|
|
261
|
+
- Opens `SQLiteGraphStore` + `QueryEngine` on startup.
|
|
262
|
+
2. Implement API handlers:
|
|
263
|
+
- `handle_graph()` → serialize all symbols + relationships to JSON.
|
|
264
|
+
- `handle_symbol(id)` → serialize symbol detail + source snippet.
|
|
265
|
+
- `handle_neighbors(id)` → 1-hop walk, serialize incremental nodes/edges.
|
|
266
|
+
- `handle_search(q)` → `find_symbol()`, serialize matches.
|
|
267
|
+
- `handle_stats()` → `stats()`, serialize.
|
|
268
|
+
3. Add `serve` command to CLI (`main.py`):
|
|
269
|
+
```python
|
|
270
|
+
@app.command()
|
|
271
|
+
def serve(
|
|
272
|
+
port: int = 7777,
|
|
273
|
+
no_open: bool = False,
|
|
274
|
+
):
|
|
275
|
+
"""Launch the interactive graph explorer in your browser."""
|
|
276
|
+
```
|
|
277
|
+
4. Auto-open `http://localhost:{port}` in the default browser via `webbrowser.open()`.
|
|
278
|
+
|
|
279
|
+
### Phase 2: Frontend (index.html + style.css + app.js)
|
|
280
|
+
|
|
281
|
+
**New files:** `src/node_walk/web/index.html`, `style.css`, `app.js`
|
|
282
|
+
|
|
283
|
+
1. **index.html**: Minimal shell — imports Cytoscape.js from CDN, links `style.css` and `app.js`.
|
|
284
|
+
2. **style.css**: Dark theme, layout grid (graph canvas + side panel), search bar, filter panel, status bar.
|
|
285
|
+
3. **app.js**:
|
|
286
|
+
- On load: `fetch('/api/graph')` → feed nodes/edges to Cytoscape.
|
|
287
|
+
- Node click → fetch `/api/symbol/{id}` → populate detail panel.
|
|
288
|
+
- Node double-click → fetch `/api/neighbors/{id}` → add to graph, run local layout.
|
|
289
|
+
- Search input → debounced fetch `/api/search` → center + highlight.
|
|
290
|
+
- Filter checkboxes → toggle element visibility via `cy.elements().filter(...)`.
|
|
291
|
+
|
|
292
|
+
### Phase 3: CLI Integration
|
|
293
|
+
|
|
294
|
+
1. Add `serve` command to `main.py`.
|
|
295
|
+
2. Include `src/node_walk/web/` in the package build (`pyproject.toml` package data).
|
|
296
|
+
3. Update `README.md` and `CHANGELOG.md`.
|
|
297
|
+
|
|
298
|
+
### Phase 4: Tests
|
|
299
|
+
|
|
300
|
+
1. **Backend API tests** (`tests/test_web_server.py`):
|
|
301
|
+
- Spin up server in a thread, hit each endpoint, assert JSON schema.
|
|
302
|
+
- Test search endpoint with fuzzy queries.
|
|
303
|
+
- Test neighbors endpoint returns incremental data.
|
|
304
|
+
2. **Smoke test**: Index a fixture repo, start server, verify `/api/graph` returns valid JSON with expected node/edge counts.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 7. File Manifest
|
|
309
|
+
|
|
310
|
+
| File | Status | Purpose |
|
|
311
|
+
|---|---|---|
|
|
312
|
+
| `src/node_walk/web/__init__.py` | NEW | Package marker |
|
|
313
|
+
| `src/node_walk/web/server.py` | NEW | HTTP server + API handlers |
|
|
314
|
+
| `src/node_walk/web/index.html` | NEW | Single-page HTML shell |
|
|
315
|
+
| `src/node_walk/web/style.css` | NEW | Dark theme + layout |
|
|
316
|
+
| `src/node_walk/web/app.js` | NEW | Cytoscape.js graph logic |
|
|
317
|
+
| `src/node_walk/cli/main.py` | MODIFY | Add `serve` command |
|
|
318
|
+
| `pyproject.toml` | MODIFY | Include `web/` in package data |
|
|
319
|
+
| `tests/test_web_server.py` | NEW | API endpoint tests |
|
|
320
|
+
| `README.md` | MODIFY | Document `serve` command |
|
|
321
|
+
| `CHANGELOG.md` | MODIFY | Add traversable graph entry |
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 8. Post-MVP Improvements (Later)
|
|
326
|
+
|
|
327
|
+
These are explicitly **not** in the MVP scope, but worth tracking:
|
|
328
|
+
|
|
329
|
+
| Improvement | Description |
|
|
330
|
+
|---|---|
|
|
331
|
+
| **Compound nodes** | Nest methods inside class nodes (Cytoscape.js compound node support). |
|
|
332
|
+
| **Trace overlay** | Click "Trace" → highlight the full call chain path with animated edges. |
|
|
333
|
+
| **Blast radius heatmap** | Color nodes by blast-radius depth (red = close, blue = far). |
|
|
334
|
+
| **"Open in editor" link** | `vscode://file/{path}:{line}` deep-links from the detail panel. |
|
|
335
|
+
| **Layout persistence** | Save/restore node positions to `.node_walk/layout.json`. |
|
|
336
|
+
| **Incremental re-index** | Watch file changes, re-index modified files, push updates to connected browser via WebSocket. |
|
|
337
|
+
| **Performance: virtual rendering** | For repos with >5k symbols, use Cytoscape.js `webgl` renderer or cluster nodes by module. |
|
|
338
|
+
| **Minimap** | Small overview panel for orientation on large graphs. |
|
|
339
|
+
| **Dark/light toggle** | Theme switcher. |
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 9. Constraints & Decisions
|
|
344
|
+
|
|
345
|
+
| Decision | Rationale |
|
|
346
|
+
|---|---|
|
|
347
|
+
| **stdlib `http.server`** over Flask/FastAPI | Zero new dependencies, consistent with "lightweight" philosophy. MVP doesn't need async, middleware, or routing frameworks. |
|
|
348
|
+
| **Cytoscape.js from CDN** | No npm/bundler build step. Single HTML file can load it. Cytoscape is the most mature JS graph library with built-in layouts, selection, and expansion. |
|
|
349
|
+
| **All frontend in 3 files** | Keeps it dead simple. No React, no Vite, no TypeScript. If the MVP proves valuable, we can graduate to a proper SPA later. |
|
|
350
|
+
| **Full graph on initial load** | For repos up to ~2-3k symbols this is fine (Cytoscape handles 5k+ nodes). For larger repos, Phase 2 can add pagination or module-level clustering. |
|
|
351
|
+
| **CONTAINS edges hidden by default** | They dominate the graph and add visual clutter. Users can toggle them on via the filter panel. |
|
|
@@ -44,6 +44,15 @@ path = "src/node_walk/__init__.py"
|
|
|
44
44
|
[tool.hatch.build.targets.wheel]
|
|
45
45
|
packages = ["src/node_walk"]
|
|
46
46
|
|
|
47
|
+
[tool.hatch.build.targets.wheel.shared-data]
|
|
48
|
+
# Include all static web assets in the installed package
|
|
49
|
+
"src/node_walk/web" = "node_walk/web"
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
52
|
+
"src/node_walk/web/index.html" = "node_walk/web/index.html"
|
|
53
|
+
"src/node_walk/web/style.css" = "node_walk/web/style.css"
|
|
54
|
+
"src/node_walk/web/app.js" = "node_walk/web/app.js"
|
|
55
|
+
|
|
47
56
|
[tool.pytest.ini_options]
|
|
48
57
|
testpaths = ["tests"]
|
|
49
58
|
pythonpath = ["src"]
|
|
@@ -629,11 +629,46 @@ def show_help() -> None:
|
|
|
629
629
|
table.add_row("stats", "Show database statistics (file, symbol, edge counts).")
|
|
630
630
|
table.add_row("export", "Export the entire semantic graph as JSON.")
|
|
631
631
|
|
|
632
|
+
table.add_section()
|
|
633
|
+
table.add_row("[bold white]Browser Explorer[/bold white]", "")
|
|
634
|
+
table.add_row("serve", "Launch the interactive graph explorer in your browser.")
|
|
635
|
+
|
|
632
636
|
console.print(table)
|
|
633
637
|
console.print("\n[dim]To see options for any command, run: [bold]node-walk <command> --help[/bold][/dim]")
|
|
634
638
|
|
|
635
639
|
|
|
636
640
|
|
|
641
|
+
@app.command()
|
|
642
|
+
def serve(
|
|
643
|
+
port: Annotated[int, typer.Option("--port", "-p", help="Port to listen on.")] = 7777,
|
|
644
|
+
host: Annotated[str, typer.Option("--host", help="Host to bind to.")] = "localhost",
|
|
645
|
+
no_open: Annotated[bool, typer.Option("--no-open", help="Do not open the browser automatically.")] = False,
|
|
646
|
+
) -> None:
|
|
647
|
+
"""Launch the interactive graph explorer in your browser."""
|
|
648
|
+
db = _find_db()
|
|
649
|
+
if db is None:
|
|
650
|
+
err_console.print(
|
|
651
|
+
"[red]No .node_walk/graph.db found.[/red] "
|
|
652
|
+
"Run [bold]node-walk index <path>[/bold] first."
|
|
653
|
+
)
|
|
654
|
+
raise typer.Exit(1)
|
|
655
|
+
|
|
656
|
+
url = f"http://{host}:{port}"
|
|
657
|
+
console.print(
|
|
658
|
+
Panel(
|
|
659
|
+
f"[bold cyan]Graph explorer[/bold cyan] starting at [bold]{url}[/bold]\n"
|
|
660
|
+
f"[dim]DB:[/dim] {db}\n"
|
|
661
|
+
"[dim]Press Ctrl+C to stop.[/dim]",
|
|
662
|
+
title="node-walk serve",
|
|
663
|
+
border_style="cyan",
|
|
664
|
+
)
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
from node_walk.web.server import start_server
|
|
668
|
+
|
|
669
|
+
start_server(db, host=host, port=port, open_browser=not no_open, block=True)
|
|
670
|
+
|
|
671
|
+
|
|
637
672
|
# ---------------------------------------------------------------------------
|
|
638
673
|
# Entry point
|
|
639
674
|
# ---------------------------------------------------------------------------
|