ruth-code 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- frontend/dist/assets/geist-mono-cyrillic-400-normal-BPBWmzPh.woff +0 -0
- frontend/dist/assets/geist-mono-cyrillic-400-normal-Ce5q_31Z.woff2 +0 -0
- frontend/dist/assets/geist-mono-cyrillic-500-normal-CJBLNVQT.woff2 +0 -0
- frontend/dist/assets/geist-mono-cyrillic-500-normal-mNhfPmgl.woff +0 -0
- frontend/dist/assets/geist-mono-cyrillic-600-normal-CGND36d7.woff2 +0 -0
- frontend/dist/assets/geist-mono-cyrillic-600-normal-DrylrLu6.woff +0 -0
- frontend/dist/assets/geist-mono-cyrillic-700-normal-DH5Q319x.woff +0 -0
- frontend/dist/assets/geist-mono-cyrillic-700-normal-VCNRadI3.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-400-normal-CoULgQGM.woff +0 -0
- frontend/dist/assets/geist-mono-latin-400-normal-LC9RFr9I.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-500-normal-D3o2eNa9.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-500-normal-DOxI7kZ4.woff +0 -0
- frontend/dist/assets/geist-mono-latin-600-normal-DQQBcVN0.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-600-normal-DsVeri3b.woff +0 -0
- frontend/dist/assets/geist-mono-latin-700-normal-D6izGJRP.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-700-normal-QGw08Lff.woff +0 -0
- frontend/dist/assets/geist-mono-latin-ext-400-normal-Cgks_Qgx.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-ext-400-normal-CxNRRMGd.woff +0 -0
- frontend/dist/assets/geist-mono-latin-ext-500-normal-CQcGuCNt.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-ext-500-normal-diTenJ8L.woff +0 -0
- frontend/dist/assets/geist-mono-latin-ext-600-normal-CJwYYto2.woff2 +0 -0
- frontend/dist/assets/geist-mono-latin-ext-600-normal-EvIRCXgu.woff +0 -0
- frontend/dist/assets/geist-mono-latin-ext-700-normal-BX9f1BHp.woff +0 -0
- frontend/dist/assets/geist-mono-latin-ext-700-normal-YOllDaLV.woff2 +0 -0
- frontend/dist/assets/index-AEO_WTHY.js +59 -0
- frontend/dist/assets/index-JUssvikZ.css +1 -0
- frontend/dist/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- frontend/dist/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- frontend/dist/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- frontend/dist/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-700-normal-DrXBdSj3.woff +0 -0
- frontend/dist/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- frontend/dist/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- frontend/dist/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- frontend/dist/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- frontend/dist/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff +0 -0
- frontend/dist/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- frontend/dist/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- frontend/dist/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- frontend/dist/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- frontend/dist/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- frontend/dist/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- frontend/dist/assets/inter-greek-700-normal-BUv2fZ6O.woff +0 -0
- frontend/dist/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- frontend/dist/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- frontend/dist/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- frontend/dist/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- frontend/dist/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- frontend/dist/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- frontend/dist/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- frontend/dist/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff +0 -0
- frontend/dist/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- frontend/dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- frontend/dist/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- frontend/dist/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- frontend/dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- frontend/dist/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- frontend/dist/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- frontend/dist/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- frontend/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- frontend/dist/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- frontend/dist/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- frontend/dist/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- frontend/dist/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- frontend/dist/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- frontend/dist/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- frontend/dist/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- frontend/dist/assets/inter-latin-ext-700-normal-TidjK2hL.woff +0 -0
- frontend/dist/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- frontend/dist/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- frontend/dist/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- frontend/dist/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- frontend/dist/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- frontend/dist/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- frontend/dist/assets/inter-vietnamese-700-normal-BZaoP0fm.woff +0 -0
- frontend/dist/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- frontend/dist/favicon.svg +1 -0
- frontend/dist/icons.svg +24 -0
- frontend/dist/index.html +15 -0
- frontend/dist/logo.svg +1 -0
- ruth/__init__.py +3 -0
- ruth/annotations/__init__.py +1 -0
- ruth/annotations/complexity.py +128 -0
- ruth/annotations/coverage.py +106 -0
- ruth/cli.py +167 -0
- ruth/graph/__init__.py +1 -0
- ruth/graph/engine.py +383 -0
- ruth/parser/__init__.py +1 -0
- ruth/parser/discovery.py +226 -0
- ruth/parser/symbols.py +656 -0
- ruth/server.py +162 -0
- ruth_code-0.1.0.dist-info/METADATA +106 -0
- ruth_code-0.1.0.dist-info/RECORD +102 -0
- ruth_code-0.1.0.dist-info/WHEEL +4 -0
- ruth_code-0.1.0.dist-info/entry_points.txt +2 -0
- ruth_code-0.1.0.dist-info/licenses/LICENSE +21 -0
ruth/server.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Ruth FastAPI server — serves the React frontend and WebSocket API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import asyncio
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
|
11
|
+
from fastapi.staticfiles import StaticFiles
|
|
12
|
+
from fastapi.responses import FileResponse, HTMLResponse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Path to the built frontend assets
|
|
16
|
+
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConnectionManager:
|
|
20
|
+
"""Manages active WebSocket connections and broadcasts graph updates."""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.active_connections: list[WebSocket] = []
|
|
24
|
+
|
|
25
|
+
async def connect(self, websocket: WebSocket):
|
|
26
|
+
await websocket.accept()
|
|
27
|
+
self.active_connections.append(websocket)
|
|
28
|
+
|
|
29
|
+
def disconnect(self, websocket: WebSocket):
|
|
30
|
+
if websocket in self.active_connections:
|
|
31
|
+
self.active_connections.remove(websocket)
|
|
32
|
+
|
|
33
|
+
async def send_message(self, websocket: WebSocket, message: dict[str, Any]):
|
|
34
|
+
await websocket.send_json(message)
|
|
35
|
+
|
|
36
|
+
async def broadcast(self, message: dict[str, Any]):
|
|
37
|
+
for connection in self.active_connections:
|
|
38
|
+
try:
|
|
39
|
+
await connection.send_json(message)
|
|
40
|
+
except Exception:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
manager = ConnectionManager()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _build_graph(project_root: Path) -> dict[str, Any]:
|
|
48
|
+
"""Build the full code graph by running the parser → graph → annotation pipeline."""
|
|
49
|
+
from ruth.parser.discovery import discover_files
|
|
50
|
+
from ruth.graph.engine import build_graph
|
|
51
|
+
from ruth.annotations.coverage import load_coverage
|
|
52
|
+
|
|
53
|
+
# Phase 1: Discover files
|
|
54
|
+
discovery = discover_files(project_root)
|
|
55
|
+
|
|
56
|
+
# Phase 2: Build graph from discovered files
|
|
57
|
+
graph = build_graph(discovery, project_root, granularity="module")
|
|
58
|
+
|
|
59
|
+
# Phase 3: Overlay coverage data if available
|
|
60
|
+
coverage_data = load_coverage(project_root)
|
|
61
|
+
if coverage_data:
|
|
62
|
+
for node in graph["nodes"]:
|
|
63
|
+
rel_path = node["data"]["filePath"]
|
|
64
|
+
if rel_path in coverage_data:
|
|
65
|
+
node["data"]["annotations"]["coverage"] = coverage_data[rel_path]
|
|
66
|
+
|
|
67
|
+
return graph
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def create_app(project_path: str = ".") -> FastAPI:
|
|
71
|
+
"""Create the FastAPI application with WebSocket and static file serving."""
|
|
72
|
+
|
|
73
|
+
app = FastAPI(
|
|
74
|
+
title="Ruth",
|
|
75
|
+
description="Interactive Codebase Topology Visualizer",
|
|
76
|
+
version="0.1.0",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
project_root = Path(project_path).resolve()
|
|
80
|
+
|
|
81
|
+
# Cache the graph to avoid re-parsing on every request
|
|
82
|
+
_graph_cache: dict[str, Any] = {}
|
|
83
|
+
|
|
84
|
+
def get_graph(force_refresh: bool = False) -> dict[str, Any]:
|
|
85
|
+
if force_refresh or not _graph_cache:
|
|
86
|
+
result = _build_graph(project_root)
|
|
87
|
+
_graph_cache.clear()
|
|
88
|
+
_graph_cache.update(result)
|
|
89
|
+
return _graph_cache
|
|
90
|
+
|
|
91
|
+
@app.websocket("/ws")
|
|
92
|
+
async def websocket_endpoint(websocket: WebSocket):
|
|
93
|
+
await manager.connect(websocket)
|
|
94
|
+
try:
|
|
95
|
+
# Send initial full graph on connection
|
|
96
|
+
graph = get_graph(force_refresh=True)
|
|
97
|
+
await manager.send_message(websocket, {
|
|
98
|
+
"type": "full_graph",
|
|
99
|
+
"payload": graph,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
# Keep connection alive and listen for client messages
|
|
103
|
+
while True:
|
|
104
|
+
data = await websocket.receive_text()
|
|
105
|
+
msg = json.loads(data)
|
|
106
|
+
|
|
107
|
+
if msg.get("type") == "refresh":
|
|
108
|
+
graph = get_graph(force_refresh=True)
|
|
109
|
+
await manager.send_message(websocket, {
|
|
110
|
+
"type": "full_graph",
|
|
111
|
+
"payload": graph,
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
except WebSocketDisconnect:
|
|
115
|
+
manager.disconnect(websocket)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
try:
|
|
118
|
+
await manager.send_message(websocket, {
|
|
119
|
+
"type": "error",
|
|
120
|
+
"payload": {"message": str(e)},
|
|
121
|
+
})
|
|
122
|
+
except Exception:
|
|
123
|
+
pass
|
|
124
|
+
manager.disconnect(websocket)
|
|
125
|
+
|
|
126
|
+
@app.get("/api/health")
|
|
127
|
+
async def health():
|
|
128
|
+
return {
|
|
129
|
+
"status": "ok",
|
|
130
|
+
"project": project_root.name,
|
|
131
|
+
"connections": len(manager.active_connections),
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@app.get("/api/graph")
|
|
135
|
+
async def get_graph_api():
|
|
136
|
+
return get_graph()
|
|
137
|
+
|
|
138
|
+
# Serve the built React frontend
|
|
139
|
+
if FRONTEND_DIR.exists():
|
|
140
|
+
# Serve static assets (JS, CSS, etc.)
|
|
141
|
+
app.mount("/assets", StaticFiles(directory=FRONTEND_DIR / "assets"), name="assets")
|
|
142
|
+
|
|
143
|
+
@app.get("/{full_path:path}")
|
|
144
|
+
async def serve_spa(full_path: str):
|
|
145
|
+
"""Serve the SPA — all non-API routes return index.html."""
|
|
146
|
+
file_path = FRONTEND_DIR / full_path
|
|
147
|
+
if file_path.is_file():
|
|
148
|
+
return FileResponse(file_path)
|
|
149
|
+
return FileResponse(FRONTEND_DIR / "index.html")
|
|
150
|
+
else:
|
|
151
|
+
@app.get("/")
|
|
152
|
+
async def no_frontend():
|
|
153
|
+
return HTMLResponse(
|
|
154
|
+
"<html><body style='background:#07070d;color:#e8e8f0;font-family:sans-serif;"
|
|
155
|
+
"display:flex;align-items:center;justify-content:center;height:100vh'>"
|
|
156
|
+
"<div style='text-align:center'>"
|
|
157
|
+
"<h1 style='color:#2dd4bf'>◈ Ruth</h1>"
|
|
158
|
+
"<p>Frontend not built. Run <code>npm run build</code> in the frontend/ directory.</p>"
|
|
159
|
+
"</div></body></html>"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return app
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ruth-code
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interactive codebase topology visualizer — Google Maps for your repo
|
|
5
|
+
Project-URL: Homepage, https://github.com/kossisoroyce/ruth
|
|
6
|
+
Project-URL: Repository, https://github.com/kossisoroyce/ruth
|
|
7
|
+
Project-URL: Issues, https://github.com/kossisoroyce/ruth/issues
|
|
8
|
+
Author: Electric Sheep Africa
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: architecture,code-analysis,code-quality,codebase,dependency-graph,developer-tools,topology,visualization
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: click>=8.1.0
|
|
27
|
+
Requires-Dist: fastapi>=0.110.0
|
|
28
|
+
Requires-Dist: rich>=13.0
|
|
29
|
+
Requires-Dist: tree-sitter>=0.21.0
|
|
30
|
+
Requires-Dist: uvicorn[standard]>=0.27.0
|
|
31
|
+
Requires-Dist: watchfiles>=0.21.0
|
|
32
|
+
Requires-Dist: websockets>=12.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# Ruth
|
|
39
|
+
|
|
40
|
+
**Google Maps for your codebase.**
|
|
41
|
+
|
|
42
|
+
Ruth parses your codebase, builds a dependency graph, detects landmarks (entry points, orchestrators, hubs), overlays code quality metrics, and renders it as an explorable visual map in the browser.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install ruth-code
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ruth serve ./your-project
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Open `http://localhost:4150` and explore.
|
|
57
|
+
|
|
58
|
+
## What You Get
|
|
59
|
+
|
|
60
|
+
**Landmarks & Points of Interest** — Ruth auto-detects the key files in your codebase:
|
|
61
|
+
- **Entry Points** — `main.py`, `index.ts`, `cli.py` — where execution begins
|
|
62
|
+
- **Orchestrators** — files that import many modules, wiring your app together
|
|
63
|
+
- **Hubs** — core dependencies imported by everyone
|
|
64
|
+
- **Islands** — disconnected files that may be dead code
|
|
65
|
+
|
|
66
|
+
**Dependency Path Tracing** — Click two nodes to trace the import chain between them, like getting directions on a map.
|
|
67
|
+
|
|
68
|
+
**Traffic Lanes** — Import edges scale in thickness based on how heavily two files are connected.
|
|
69
|
+
|
|
70
|
+
**Overlays** — Switch between views like map layers:
|
|
71
|
+
- **Complexity** — cyclomatic complexity heatmap (green to red)
|
|
72
|
+
- **Security** — vulnerability overlay (Semgrep/OSV integration)
|
|
73
|
+
- **Coverage** — test coverage mapping (lcov/coverage.json)
|
|
74
|
+
|
|
75
|
+
**Multi-Language** — Python, TypeScript, JavaScript, Rust, Go, Java, Ruby, C/C++.
|
|
76
|
+
|
|
77
|
+
**Live** — WebSocket-powered real-time updates. Edit a file, see the graph change.
|
|
78
|
+
|
|
79
|
+
## Commands
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Start the visualization dashboard
|
|
83
|
+
ruth serve /path/to/project
|
|
84
|
+
|
|
85
|
+
# Analyze and output graph as JSON
|
|
86
|
+
ruth analyze /path/to/project -o graph.json
|
|
87
|
+
|
|
88
|
+
# Quick project scan
|
|
89
|
+
ruth scan /path/to/project
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Keyboard Shortcuts
|
|
93
|
+
|
|
94
|
+
| Key | Action |
|
|
95
|
+
|-----|--------|
|
|
96
|
+
| `Cmd+K` | Command palette — search and jump to any node |
|
|
97
|
+
| `/` | Focus search filter |
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
- Python 3.10+
|
|
102
|
+
- Node.js (for development only — the frontend is pre-built)
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT — Electric Sheep Africa
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
ruth/__init__.py,sha256=ADsEjmcD2_bq8Q7JLPxzEIoiukHqYlh9Xg0Am2QgAj0,80
|
|
2
|
+
ruth/cli.py,sha256=2UicJIPWPMBNskfYQrZUnSVNbduY9oLZTv4UPIzvxcI,6165
|
|
3
|
+
ruth/server.py,sha256=M6I-rj1aA5VCi-ibplJG8U_Gm4T5dRUHcVAZtibpIjw,5479
|
|
4
|
+
ruth/annotations/__init__.py,sha256=8RItmI9XfNL5gT0rKK60NjNKXhBJBWhmYJdxAhtprh0,89
|
|
5
|
+
ruth/annotations/complexity.py,sha256=-ByKJI_GOLO8f93jg9oZMJUlT59R0_5VB1yEnsfnEf8,3924
|
|
6
|
+
ruth/annotations/coverage.py,sha256=Lz8ID1CSyOcG5jH4sJo7qgMgrpuZwfAcLIXWO-kGaI8,3122
|
|
7
|
+
ruth/graph/__init__.py,sha256=9gbE3xk8dsq9ds9sLt7sI2LyK5XS6GLTLfvhhs0OlvU,80
|
|
8
|
+
ruth/graph/engine.py,sha256=w9tPrlyxvV6iERe1AnAAH5vyLn5qKcIhbGhFH946ghI,14903
|
|
9
|
+
ruth/parser/__init__.py,sha256=tEWo5apUg6FbM3VW8fl_R2DwCU0ETPPBH_wamrRm8hU,82
|
|
10
|
+
ruth/parser/discovery.py,sha256=4k96rMCe7BnPi_-xU2NhkaBS1XBVB0Ed1Ralnzj4LbM,6533
|
|
11
|
+
ruth/parser/symbols.py,sha256=K1sIr7CJJin7Q5fvWDUkJV9ZxUNxbJh1rW20KmBZRmA,25821
|
|
12
|
+
frontend/dist/favicon.svg,sha256=YbyaFh3lgkgojmkFQl1xgPBiTChlAHuX12P9rBIEOmY,9522
|
|
13
|
+
frontend/dist/icons.svg,sha256=tF-lBhlc_N70BrqfDHezbdwafCJAQJJuxwq8L96nuTo,5031
|
|
14
|
+
frontend/dist/index.html,sha256=MsYEQTkvVTXR9KSMlSdzGDeU-BsuscTJLeWDnCaFcOI,676
|
|
15
|
+
frontend/dist/logo.svg,sha256=HYlVpsdhdNoCa2KyPaPgGtJqL-Jc7iPS4TZeZxabg7c,992958
|
|
16
|
+
frontend/dist/assets/geist-mono-cyrillic-400-normal-BPBWmzPh.woff,sha256=npeQXwZj6rknvKpytOW4RL-pgK2j-JT_kgUux-0tjAM,7164
|
|
17
|
+
frontend/dist/assets/geist-mono-cyrillic-400-normal-Ce5q_31Z.woff2,sha256=JZtj2aLc30Sbc_RmJOQJ3h1ipRE06ITT9K8SQnNs3hA,5460
|
|
18
|
+
frontend/dist/assets/geist-mono-cyrillic-500-normal-CJBLNVQT.woff2,sha256=dljAM01TXLFrh6SxHBa7OzP72_szFgiQJOS2OW0giNg,5664
|
|
19
|
+
frontend/dist/assets/geist-mono-cyrillic-500-normal-mNhfPmgl.woff,sha256=hhBzau5iR6o4L-WJkWpoQGafhFwKnCx1MJyo3iZfzlo,7352
|
|
20
|
+
frontend/dist/assets/geist-mono-cyrillic-600-normal-CGND36d7.woff2,sha256=buXbsAa-lEHAyYgLInFJXGKN8OJwSc4X7Owgc4zUtwk,5680
|
|
21
|
+
frontend/dist/assets/geist-mono-cyrillic-600-normal-DrylrLu6.woff,sha256=GEQI9Ec1cPqIG36617YCpwHDulf5qEbWcMZsDcg93s0,7356
|
|
22
|
+
frontend/dist/assets/geist-mono-cyrillic-700-normal-DH5Q319x.woff,sha256=KaexsnbbEQbVSw1mGupCd4sm8nFnjUgZ_I0LoQ3tmAY,7328
|
|
23
|
+
frontend/dist/assets/geist-mono-cyrillic-700-normal-VCNRadI3.woff2,sha256=ouPOBzfukA3I_l6knvkjqLShYY7qhwMbiVBFxixXszo,5792
|
|
24
|
+
frontend/dist/assets/geist-mono-latin-400-normal-CoULgQGM.woff,sha256=ryoG_GlAq_81MFqWzk4vacKTQQYzm0iLjLhcpvE23_8,19168
|
|
25
|
+
frontend/dist/assets/geist-mono-latin-400-normal-LC9RFr9I.woff2,sha256=YW43ylmir-vjBnUXc6U4uT9aLZqQ_T_JfOczIcuTr1E,14712
|
|
26
|
+
frontend/dist/assets/geist-mono-latin-500-normal-D3o2eNa9.woff2,sha256=mklHZPh8LhHSQAG5EGAL0hkiMFVMCQoN3GboIhsy884,15304
|
|
27
|
+
frontend/dist/assets/geist-mono-latin-500-normal-DOxI7kZ4.woff,sha256=8btiwq_E0RlxzhQhXvsSsBL2zUKlcBYZNfshNujc4m4,19640
|
|
28
|
+
frontend/dist/assets/geist-mono-latin-600-normal-DQQBcVN0.woff2,sha256=iLS5tI4HRnwkZjCWOaReYu0-PeIqSO5kDQR1ITdOPXw,15264
|
|
29
|
+
frontend/dist/assets/geist-mono-latin-600-normal-DsVeri3b.woff,sha256=FKxmaTc2TrEf4upF7mEQxYU0b1SwLwnKQvim7S72i5Q,19608
|
|
30
|
+
frontend/dist/assets/geist-mono-latin-700-normal-D6izGJRP.woff2,sha256=6ya9no9ryfW2y3aSoEbaQ_Em7ds6CAM1YuprbfHWv68,15300
|
|
31
|
+
frontend/dist/assets/geist-mono-latin-700-normal-QGw08Lff.woff,sha256=vQQgU2H63chA_bFF_kdFosAwcr4RW_RXOoAb2dMx1Xw,19632
|
|
32
|
+
frontend/dist/assets/geist-mono-latin-ext-400-normal-Cgks_Qgx.woff2,sha256=f0pdPBzfilvI3rR7hWBqVIbVFZ1C66BIuulYPE0IXNA,6424
|
|
33
|
+
frontend/dist/assets/geist-mono-latin-ext-400-normal-CxNRRMGd.woff,sha256=n3OiV2YLlgX9P64Y7sc_GBPaXU4GY49ffSsVV1BTAYU,8744
|
|
34
|
+
frontend/dist/assets/geist-mono-latin-ext-500-normal-CQcGuCNt.woff2,sha256=onRpwOPaPl7vHKC5v-qThVgejSHUboD3XaQNjUryOlg,6500
|
|
35
|
+
frontend/dist/assets/geist-mono-latin-ext-500-normal-diTenJ8L.woff,sha256=9DEGx6ENrVHTcHqvb9qZf3B6bsgN0hcpfzHNbIbEsBA,8856
|
|
36
|
+
frontend/dist/assets/geist-mono-latin-ext-600-normal-CJwYYto2.woff2,sha256=vAr8fiX7_6yjrOG7wQVBWZ6m6B-DFg4fWlMWj6xW7yQ,6496
|
|
37
|
+
frontend/dist/assets/geist-mono-latin-ext-600-normal-EvIRCXgu.woff,sha256=Q12HiDr37dpOlmW65CBVV2Lj9Cr-NUqie39YNYVJFRI,8860
|
|
38
|
+
frontend/dist/assets/geist-mono-latin-ext-700-normal-BX9f1BHp.woff,sha256=5YskHT-Hh6AhVl2iF-aoIbI8LHWnxSQ9WUGXgI73xtI,8852
|
|
39
|
+
frontend/dist/assets/geist-mono-latin-ext-700-normal-YOllDaLV.woff2,sha256=SvXmr1pWFNoUmO521DxBSx1Pw5i-a0MiheNKDbg1yPU,6456
|
|
40
|
+
frontend/dist/assets/index-AEO_WTHY.js,sha256=cr_IZ-A-H62UBcQB3YRPJvNwmuQKOGJRpG9U6UUiV24,526550
|
|
41
|
+
frontend/dist/assets/index-JUssvikZ.css,sha256=QOVkNHAvCSWX8jo4r_vPtgkjg4gSP_mQQLKSPEEGAtA,44512
|
|
42
|
+
frontend/dist/assets/inter-cyrillic-400-normal-HOLc17fK.woff,sha256=bkQabJR4gxj6ArbQpjOqKe6-J7acZWfrHlm07caO1w4,9780
|
|
43
|
+
frontend/dist/assets/inter-cyrillic-400-normal-obahsSVq.woff2,sha256=8LtYZFnOjwmyOChQQPF-Pp6VOLLFp6rgd1GU4zw2w8M,7712
|
|
44
|
+
frontend/dist/assets/inter-cyrillic-500-normal-BasfLYem.woff2,sha256=t3qG7Baq3BV_SpnoiY1xzXXqJkdT2b3xP5YvjDmIy7A,7900
|
|
45
|
+
frontend/dist/assets/inter-cyrillic-500-normal-CxZf_p3X.woff,sha256=W-GOA0V4HLiComd5hRhVPA6RUXT8cHMatfCFymS6Hrw,9940
|
|
46
|
+
frontend/dist/assets/inter-cyrillic-600-normal-4D_pXhcN.woff,sha256=zBkO0bZOtlCkrX6Xx6Zoy4s0rNnEx_e_Q3LAy6zTV5U,9936
|
|
47
|
+
frontend/dist/assets/inter-cyrillic-600-normal-CWCymEST.woff2,sha256=bCo3-Cpna81EG3NeTizaTtuIc6BZq5w2KoTwcR8lcEE,7972
|
|
48
|
+
frontend/dist/assets/inter-cyrillic-700-normal-CjBOestx.woff2,sha256=WReHHTzJcNjOGVEBy_ZcH2jslIAi62BwAwNCu37fs7s,7904
|
|
49
|
+
frontend/dist/assets/inter-cyrillic-700-normal-DrXBdSj3.woff,sha256=crbapJFz5TECfYomDvEo4UKhZYEcq2oode7-DDxY-g4,9912
|
|
50
|
+
frontend/dist/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2,sha256=71cvkYeovgGNnZwsa3fB9ssq9BmfAvwWwpLqEKslosw,10232
|
|
51
|
+
frontend/dist/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff,sha256=XLLxzAk2-JpCzq409aVyAkjcW4EUwSscM6fS7wGptrk,13336
|
|
52
|
+
frontend/dist/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2,sha256=HC25LTzZsjfKfJwHr1VtVC8o3tHbVM1Dgs93ZQHFKR8,10432
|
|
53
|
+
frontend/dist/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff,sha256=4lDAWuvPSZceCyX0dpkt1GPCjAKS67IE2dtUL7UGbKc,13452
|
|
54
|
+
frontend/dist/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff,sha256=pQcyhUCUQ_RlPIWN5YxdwL_C_TPmDYdHOINF58WrGrM,13464
|
|
55
|
+
frontend/dist/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2,sha256=UJ_KnFlWT5qEb6abxkf5sFD8Eavxyfbz2nH7LV7UJb0,10484
|
|
56
|
+
frontend/dist/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2,sha256=pGuZeBFwlx4smah_9-6fXPkKnfzRgXXhvmMAIB0DASM,10496
|
|
57
|
+
frontend/dist/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff,sha256=Dz1L4r1wGPePo0hKX26djOVnaJQmZDuEpH6Mq7keXxY,13408
|
|
58
|
+
frontend/dist/assets/inter-greek-400-normal-B4URO6DV.woff2,sha256=wV3dAKmSe1b1xlWkH5dveb2EiiDM6R_BQid1GHKhzCc,7776
|
|
59
|
+
frontend/dist/assets/inter-greek-400-normal-q2sYcFCs.woff,sha256=va6dKHKejGhYfV1U4hbXcaQNemgA6CRYam4vVwwvEN8,9924
|
|
60
|
+
frontend/dist/assets/inter-greek-500-normal-BIZE56-Y.woff2,sha256=zBl9edM6NhWgR7quhfTRlX9vmLiJgxNljhYLHVGbG28,7920
|
|
61
|
+
frontend/dist/assets/inter-greek-500-normal-Xzm54t5V.woff,sha256=htVaSxucvO1-YedtXUTPSdC9HIFNPfLeZ7cTarT9zs4,9980
|
|
62
|
+
frontend/dist/assets/inter-greek-600-normal-BZpKdvQh.woff,sha256=CQsk4i_E3fQUUNE73sgcinSAi5_H7a-N8GyQmxd6iZI,10032
|
|
63
|
+
frontend/dist/assets/inter-greek-600-normal-plRanbMR.woff2,sha256=nFqJf52fz-YNkGMddmrmK0vx7ddmM_p6Sy-Mh-A2eJs,7944
|
|
64
|
+
frontend/dist/assets/inter-greek-700-normal-BUv2fZ6O.woff,sha256=UzaPU9X8QzgdzEXIUzuiR2-AM3E2MTUl-W3L3HNmFqU,9980
|
|
65
|
+
frontend/dist/assets/inter-greek-700-normal-C3JjAnD8.woff2,sha256=c3xskc1gNy0w5lQAlq2oPInJtGE810cuM2a_LgetmfE,7920
|
|
66
|
+
frontend/dist/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2,sha256=6t7dnhPCWCQwqfsVGeuGFS_au0g6b2bZD42KUul3obc,5264
|
|
67
|
+
frontend/dist/assets/inter-greek-ext-400-normal-KugGGMne.woff,sha256=Tytvkt3-zogS55d01EYhiqbgdz_4wtMRMP4r3CO9ItA,7064
|
|
68
|
+
frontend/dist/assets/inter-greek-ext-500-normal-2j5mBUwD.woff,sha256=yF0RvecZEIzJpPb1sAgIf2w2STtHOVWA1PUzYYKw8Mc,7192
|
|
69
|
+
frontend/dist/assets/inter-greek-ext-500-normal-C4iEst2y.woff2,sha256=dansk4Ojt6e_fPuU9k7fONnP3F9_-gy-0nM2J6bkQm0,5428
|
|
70
|
+
frontend/dist/assets/inter-greek-ext-600-normal-B8X0CLgF.woff,sha256=78eqnM5cUF3YzExNrwAkf6gF83vNqWB5I5ujNYqyffs,7212
|
|
71
|
+
frontend/dist/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2,sha256=OZ-U11qnNAPkDiNT6MDMdcOPc2KmyiY7OwLZcjFX_-U,5432
|
|
72
|
+
frontend/dist/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff,sha256=sm7WTJE1p1CtWAuSFSvt7vkHcedOGPb3dZptetsPG10,7216
|
|
73
|
+
frontend/dist/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2,sha256=t7JzLryYGzClRj_8hQQHZJ26QeYlruEkzGMpPaRUdik,5444
|
|
74
|
+
frontend/dist/assets/inter-latin-400-normal-C38fXH4l.woff2,sha256=iQmQSrbIcuuZQJNIKoiijsos2VkS17b-zXIQOw3Aftw,23664
|
|
75
|
+
frontend/dist/assets/inter-latin-400-normal-CyCys3Eg.woff,sha256=4g-gtP0t0m5NFLOsPMkiUJw6Y_pekQ6QxhRUSqBC3UU,30696
|
|
76
|
+
frontend/dist/assets/inter-latin-500-normal-BL9OpVg8.woff,sha256=m0LBCNpIte1VowcugV_-4tJxVi5sDdaZiRDo-cCeCj0,31284
|
|
77
|
+
frontend/dist/assets/inter-latin-500-normal-Cerq10X2.woff2,sha256=83efHvzMS9zfnAoCq5W_a9CS7QnEjAjO3HJYie3R0Z8,24272
|
|
78
|
+
frontend/dist/assets/inter-latin-600-normal-CiBQ2DWP.woff,sha256=apyzpQm07q8St92mxKrKw-hdB_QgG_TdcW4zLmkrh70,31260
|
|
79
|
+
frontend/dist/assets/inter-latin-600-normal-LgqL8muc.woff2,sha256=-aBuec06KiCVHA8OKPZt0ObT_ac5EdZAohJcj8t48ho,24452
|
|
80
|
+
frontend/dist/assets/inter-latin-700-normal-BLAVimhd.woff,sha256=fF7VZVcw3jN3BNP8lGKFFc1-PY0yNohxcJv1asA5fno,31320
|
|
81
|
+
frontend/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2,sha256=b1ZAn9PWS7hffQcLziB0nbLWa21jzsWGzCLRx2G-JJE,24356
|
|
82
|
+
frontend/dist/assets/inter-latin-ext-400-normal-77YHD8bZ.woff,sha256=Iq6DYPutJNKvfGyYmKNGyIF3Tch_fPlL0mLEitWNcRY,47560
|
|
83
|
+
frontend/dist/assets/inter-latin-ext-400-normal-C1nco2VV.woff2,sha256=Z0Sn9QnrxqsiCmzU6nfomK3wFPA9iNzaXUXYqf7vtOk,35000
|
|
84
|
+
frontend/dist/assets/inter-latin-ext-500-normal-BxGbmqWO.woff,sha256=MNKQPOl_ionqDpwIO0LLi_l-e7tWB-fwA1KBXxnLDVs,48492
|
|
85
|
+
frontend/dist/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2,sha256=LG-8QtMVUovrBsEJbfRUh79BhsS3i4ER0SyclR-KzKI,36024
|
|
86
|
+
frontend/dist/assets/inter-latin-ext-600-normal-CIVaiw4L.woff,sha256=Iv8gphcGdPuWN8KgciJ76GMDu27FK4KbnXB3QF9xlqY,48668
|
|
87
|
+
frontend/dist/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2,sha256=5L32ewzRXKnhhFCSdb6V25QhldPMKxf2oEUvKt910L8,36260
|
|
88
|
+
frontend/dist/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2,sha256=FD-VBPE3cBKqPjnJDENU70KcsElLmsDhQ38ageVBIjY,36244
|
|
89
|
+
frontend/dist/assets/inter-latin-ext-700-normal-TidjK2hL.woff,sha256=F2HtujIBQYDeqz274_cVbGTvbzS8djE7oxziJ_yf85E,48632
|
|
90
|
+
frontend/dist/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff,sha256=VKpC0yW839Yj7LnqxKXjxkIMY9e4bp2FRftHn2U761c,6500
|
|
91
|
+
frontend/dist/assets/inter-vietnamese-400-normal-DMkecbls.woff2,sha256=VHrZ_a6wrkNIf0uKAuR8NlU8DAy3PIqpj5O3thX2tV0,4972
|
|
92
|
+
frontend/dist/assets/inter-vietnamese-500-normal-DOriooB6.woff2,sha256=RONqpajxITACmim7DmaV0CYrZ0Rs4yHoeLH7VhYrXeY,5112
|
|
93
|
+
frontend/dist/assets/inter-vietnamese-500-normal-mJboJaSs.woff,sha256=GKSgn3UWcc2JKdfGbo_n2CC1EcNuUc9gR__Oq4juxKQ,6596
|
|
94
|
+
frontend/dist/assets/inter-vietnamese-600-normal-BuLX-rYi.woff,sha256=JKAee9lHru-Rro97jt6yP62vXO2jSmEM5i0rva6lfoM,6640
|
|
95
|
+
frontend/dist/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2,sha256=GuuUrp2wUqSi_m8wRvkoz_H9vXq9-HCpoBwTyub666U,5100
|
|
96
|
+
frontend/dist/assets/inter-vietnamese-700-normal-BZaoP0fm.woff,sha256=QSAjqy9BMzs3PixusqPrq4Bv3dYQAV0q6M1PQxTHupI,6632
|
|
97
|
+
frontend/dist/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2,sha256=X6-jgpoW2epaw6Z8UeVBhjUxInkLYEo-Nh-WyrGI2os,5104
|
|
98
|
+
ruth_code-0.1.0.dist-info/METADATA,sha256=vVdYG1_IsLP-sMdBZ9Cy-PTGNlfUGNWYNhZGujfWd7c,3473
|
|
99
|
+
ruth_code-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
100
|
+
ruth_code-0.1.0.dist-info/entry_points.txt,sha256=OUOEjN_vTYnRswfFUO85zRtxWta0OtAPeIbbHkRVVkM,38
|
|
101
|
+
ruth_code-0.1.0.dist-info/licenses/LICENSE,sha256=xcti2_uJQmSN1XNbBTAqkLakLRC_ohS1Eye00zW1s0E,1078
|
|
102
|
+
ruth_code-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Electric Sheep Africa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|