fileoracle 1.0.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.
- fileoracle-1.0.0/PKG-INFO +85 -0
- fileoracle-1.0.0/README.md +70 -0
- fileoracle-1.0.0/backend/__init__.py +1 -0
- fileoracle-1.0.0/backend/cli.py +48 -0
- fileoracle-1.0.0/backend/fileoracle.py +141 -0
- fileoracle-1.0.0/backend/graph.py +107 -0
- fileoracle-1.0.0/backend/main.py +39 -0
- fileoracle-1.0.0/backend/tests/__init__.py +1 -0
- fileoracle-1.0.0/backend/tests/test_fileoracle.py +25 -0
- fileoracle-1.0.0/fileoracle.egg-info/PKG-INFO +85 -0
- fileoracle-1.0.0/fileoracle.egg-info/SOURCES.txt +15 -0
- fileoracle-1.0.0/fileoracle.egg-info/dependency_links.txt +1 -0
- fileoracle-1.0.0/fileoracle.egg-info/entry_points.txt +2 -0
- fileoracle-1.0.0/fileoracle.egg-info/requires.txt +4 -0
- fileoracle-1.0.0/fileoracle.egg-info/top_level.txt +1 -0
- fileoracle-1.0.0/pyproject.toml +30 -0
- fileoracle-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fileoracle
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-powered local file tree scraper, provenance attestation graph engine, and web oracle
|
|
5
|
+
Author-email: Joseph Skrobynets <j.skrobynets@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/overandor/FileOracle
|
|
8
|
+
Project-URL: Repository, https://github.com/overandor/FileOracle
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: fastapi>=0.111.0
|
|
12
|
+
Requires-Dist: uvicorn[standard]>=0.30.1
|
|
13
|
+
Requires-Dist: pydantic>=2.0.0
|
|
14
|
+
Requires-Dist: requests>=2.28.0
|
|
15
|
+
|
|
16
|
+
# FileOracle 🔮
|
|
17
|
+
|
|
18
|
+
FileOracle is an AI-powered local file tree scraper, graph visualizer, and attestation engine with deep provenance tracking, cryptographic hashing (SHA-256 / Merkle trees), and multi-platform deployment capability.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- **FastAPI Backend**: RESTful API exposing `/health`, `/query`, and `/graph` endpoints.
|
|
23
|
+
- **Local File Graph Engine**: Scans directory trees, builds node/edge graphs, and calculates cryptographic provenance records & Merkle roots.
|
|
24
|
+
- **Modern Glassmorphism Frontend**: Responsive dark mode UI using Inter typography, micro-animations, and interactive D3.js graph rendering.
|
|
25
|
+
- **DeepWiki Agent Continuity**: Consolidated documentation architecture detailing work continuity and memory persistence.
|
|
26
|
+
- **Multi-Cloud Ready**: Scaffolding and configs for Vercel, Netlify, Docker, Hugging Face Spaces, and GitHub Actions.
|
|
27
|
+
|
|
28
|
+
## Project Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
FileOracle/
|
|
32
|
+
├── backend/
|
|
33
|
+
│ ├── __init__.py
|
|
34
|
+
│ ├── fileoracle.py # Core FileOracle AI engine
|
|
35
|
+
│ ├── graph.py # Graph builder & SHA-256/Merkle attestation
|
|
36
|
+
│ ├── main.py # FastAPI entry point
|
|
37
|
+
│ ├── requirements.txt # Backend dependencies
|
|
38
|
+
│ └── tests/ # Pytest test suite
|
|
39
|
+
├── frontend/
|
|
40
|
+
│ ├── app.js # Client logic & D3 visualization
|
|
41
|
+
│ ├── index.html # HTML5 SPA landing page
|
|
42
|
+
│ └── styles.css # Glassmorphism dark mode stylesheet
|
|
43
|
+
├── docs/
|
|
44
|
+
│ └── DeepWiki_Consolidated.md # DeepWiki docs with agent memory architecture
|
|
45
|
+
├── .github/workflows/
|
|
46
|
+
│ └── deploy.yml # GitHub Actions CI/CD workflow
|
|
47
|
+
├── Dockerfile # Docker / Hugging Face Spaces build
|
|
48
|
+
├── netlify.toml # Netlify deployment configuration
|
|
49
|
+
├── vercel.json # Vercel serverless configuration
|
|
50
|
+
└── README.md
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Local Development
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Clone repository
|
|
59
|
+
git clone https://github.com/overandor/FileOracle.git
|
|
60
|
+
cd FileOracle
|
|
61
|
+
|
|
62
|
+
# Create virtual environment & install dependencies
|
|
63
|
+
python3 -m venv venv
|
|
64
|
+
source venv/bin/activate
|
|
65
|
+
pip install -r backend/requirements.txt
|
|
66
|
+
pip install pytest httpx
|
|
67
|
+
|
|
68
|
+
# Run tests
|
|
69
|
+
pytest backend/
|
|
70
|
+
|
|
71
|
+
# Start FastAPI server
|
|
72
|
+
uvicorn backend.main:app --reload --port 8000
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Visit `http://localhost:8000` in your browser.
|
|
76
|
+
|
|
77
|
+
### 2. Run with Docker
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker build -t fileoracle .
|
|
81
|
+
docker run -p 7860:7860 fileoracle
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
MIT License.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# FileOracle 🔮
|
|
2
|
+
|
|
3
|
+
FileOracle is an AI-powered local file tree scraper, graph visualizer, and attestation engine with deep provenance tracking, cryptographic hashing (SHA-256 / Merkle trees), and multi-platform deployment capability.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **FastAPI Backend**: RESTful API exposing `/health`, `/query`, and `/graph` endpoints.
|
|
8
|
+
- **Local File Graph Engine**: Scans directory trees, builds node/edge graphs, and calculates cryptographic provenance records & Merkle roots.
|
|
9
|
+
- **Modern Glassmorphism Frontend**: Responsive dark mode UI using Inter typography, micro-animations, and interactive D3.js graph rendering.
|
|
10
|
+
- **DeepWiki Agent Continuity**: Consolidated documentation architecture detailing work continuity and memory persistence.
|
|
11
|
+
- **Multi-Cloud Ready**: Scaffolding and configs for Vercel, Netlify, Docker, Hugging Face Spaces, and GitHub Actions.
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
FileOracle/
|
|
17
|
+
├── backend/
|
|
18
|
+
│ ├── __init__.py
|
|
19
|
+
│ ├── fileoracle.py # Core FileOracle AI engine
|
|
20
|
+
│ ├── graph.py # Graph builder & SHA-256/Merkle attestation
|
|
21
|
+
│ ├── main.py # FastAPI entry point
|
|
22
|
+
│ ├── requirements.txt # Backend dependencies
|
|
23
|
+
│ └── tests/ # Pytest test suite
|
|
24
|
+
├── frontend/
|
|
25
|
+
│ ├── app.js # Client logic & D3 visualization
|
|
26
|
+
│ ├── index.html # HTML5 SPA landing page
|
|
27
|
+
│ └── styles.css # Glassmorphism dark mode stylesheet
|
|
28
|
+
├── docs/
|
|
29
|
+
│ └── DeepWiki_Consolidated.md # DeepWiki docs with agent memory architecture
|
|
30
|
+
├── .github/workflows/
|
|
31
|
+
│ └── deploy.yml # GitHub Actions CI/CD workflow
|
|
32
|
+
├── Dockerfile # Docker / Hugging Face Spaces build
|
|
33
|
+
├── netlify.toml # Netlify deployment configuration
|
|
34
|
+
├── vercel.json # Vercel serverless configuration
|
|
35
|
+
└── README.md
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Local Development
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Clone repository
|
|
44
|
+
git clone https://github.com/overandor/FileOracle.git
|
|
45
|
+
cd FileOracle
|
|
46
|
+
|
|
47
|
+
# Create virtual environment & install dependencies
|
|
48
|
+
python3 -m venv venv
|
|
49
|
+
source venv/bin/activate
|
|
50
|
+
pip install -r backend/requirements.txt
|
|
51
|
+
pip install pytest httpx
|
|
52
|
+
|
|
53
|
+
# Run tests
|
|
54
|
+
pytest backend/
|
|
55
|
+
|
|
56
|
+
# Start FastAPI server
|
|
57
|
+
uvicorn backend.main:app --reload --port 8000
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Visit `http://localhost:8000` in your browser.
|
|
61
|
+
|
|
62
|
+
### 2. Run with Docker
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
docker build -t fileoracle .
|
|
66
|
+
docker run -p 7860:7860 fileoracle
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
MIT License.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Backend package for FileOracle
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import uvicorn
|
|
6
|
+
from backend.graph import build_graph
|
|
7
|
+
from backend.fileoracle import process_query
|
|
8
|
+
|
|
9
|
+
def main():
|
|
10
|
+
parser = argparse.ArgumentParser(description="FileOracle CLI & Web Oracle")
|
|
11
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
12
|
+
|
|
13
|
+
# serve command
|
|
14
|
+
serve_parser = subparsers.add_parser("serve", help="Start FileOracle web server & API")
|
|
15
|
+
serve_parser.add_argument("--host", default="0.0.0.0", help="Host address to bind")
|
|
16
|
+
serve_parser.add_argument("--port", type=int, default=8000, help="Port to listen on")
|
|
17
|
+
|
|
18
|
+
# graph command
|
|
19
|
+
graph_parser = subparsers.add_parser("graph", help="Scan local file tree and output JSON attestation graph")
|
|
20
|
+
graph_parser.add_argument("--root", default=".", help="Root directory path to scan")
|
|
21
|
+
graph_parser.add_argument("--out", help="Output JSON file path")
|
|
22
|
+
|
|
23
|
+
# query command
|
|
24
|
+
query_parser = subparsers.add_parser("query", help="Query FileOracle AI engine")
|
|
25
|
+
query_parser.add_argument("prompt", help="Question or prompt for FileOracle")
|
|
26
|
+
|
|
27
|
+
args = parser.parse_args()
|
|
28
|
+
|
|
29
|
+
if args.command == "serve":
|
|
30
|
+
print(f"🔮 Starting FileOracle server on http://{args.host}:{args.port}...")
|
|
31
|
+
uvicorn.run("backend.main:app", host=args.host, port=args.port, reload=False)
|
|
32
|
+
|
|
33
|
+
elif args.command == "graph":
|
|
34
|
+
res = build_graph(args.root)
|
|
35
|
+
out_json = json.dumps(res, indent=2)
|
|
36
|
+
if args.out:
|
|
37
|
+
with open(args.out, "w", encoding="utf-8") as f:
|
|
38
|
+
f.write(out_json)
|
|
39
|
+
print(f"✓ Attestation graph saved to {args.out}")
|
|
40
|
+
else:
|
|
41
|
+
print(out_json)
|
|
42
|
+
|
|
43
|
+
elif args.command == "query":
|
|
44
|
+
res = process_query(args.prompt)
|
|
45
|
+
print(json.dumps(res, indent=2))
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
main()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""FileOracle Core Engine — Live Production Execution (No Mocks).
|
|
2
|
+
|
|
3
|
+
Performs real file appraisal, code parsing, token intrinsic valuation,
|
|
4
|
+
SHA-256 Merkle root attestation, Ed25519 signature verification,
|
|
5
|
+
and HDAR receipt generation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import time
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
from hdar_core.crypto.ed25519 import generate_keypair, sign_manifest, verify_manifest_sig
|
|
15
|
+
from hdar_core.crypto.hashing import sha256_bytes
|
|
16
|
+
from hdar_core.crypto.merkle import SparseMerkleTree
|
|
17
|
+
from hdar_core.workspace.scanner import hash_workspace
|
|
18
|
+
|
|
19
|
+
# Valuation constants
|
|
20
|
+
BASE_TOKEN_PRICE_USD = 0.00002 # $0.02 per 1k tokens
|
|
21
|
+
CODE_COMPLEXITY_MULTIPLIER = 1.45
|
|
22
|
+
|
|
23
|
+
class FileOracleEngine:
|
|
24
|
+
"""Live FileOracle Appraisal and Attestation Engine."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, workspace_path: Optional[str] = None):
|
|
27
|
+
self.workspace_path = os.path.abspath(workspace_path or os.getcwd())
|
|
28
|
+
self.priv_key, self.pub_key = generate_keypair()
|
|
29
|
+
|
|
30
|
+
def appraise_workspace(self, root_dir: Optional[str] = None) -> Dict[str, Any]:
|
|
31
|
+
target_dir = os.path.abspath(root_dir or self.workspace_path)
|
|
32
|
+
root_hash, file_map = hash_workspace(target_dir)
|
|
33
|
+
|
|
34
|
+
total_files = len(file_map)
|
|
35
|
+
total_size_bytes = 0
|
|
36
|
+
total_tokens = 0
|
|
37
|
+
file_details: List[Dict[str, Any]] = []
|
|
38
|
+
|
|
39
|
+
file_hashes: List[str] = []
|
|
40
|
+
|
|
41
|
+
for rel_path, file_h in file_map.items():
|
|
42
|
+
file_hashes.append(file_h)
|
|
43
|
+
abs_p = os.path.join(target_dir, rel_path)
|
|
44
|
+
try:
|
|
45
|
+
size = os.path.getsize(abs_p)
|
|
46
|
+
total_size_bytes += size
|
|
47
|
+
|
|
48
|
+
# Approximate token count (1 token ≈ 4 chars)
|
|
49
|
+
tokens = max(1, size // 4)
|
|
50
|
+
total_tokens += tokens
|
|
51
|
+
|
|
52
|
+
ext = os.path.splitext(rel_path)[1].lower()
|
|
53
|
+
multiplier = CODE_COMPLEXITY_MULTIPLIER if ext in ('.py', '.js', '.ts', '.html', '.css', '.rs', '.go', '.json') else 1.0
|
|
54
|
+
file_valuation_usd = round(tokens * BASE_TOKEN_PRICE_USD * multiplier, 4)
|
|
55
|
+
|
|
56
|
+
file_details.append({
|
|
57
|
+
"path": rel_path,
|
|
58
|
+
"sha256": file_h,
|
|
59
|
+
"size_bytes": size,
|
|
60
|
+
"tokens_estimate": tokens,
|
|
61
|
+
"intrinsic_valuation_usd": file_valuation_usd,
|
|
62
|
+
})
|
|
63
|
+
except Exception as err:
|
|
64
|
+
file_details.append({
|
|
65
|
+
"path": rel_path,
|
|
66
|
+
"sha256": file_h,
|
|
67
|
+
"error": str(err)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
smt = SparseMerkleTree()
|
|
71
|
+
for idx, fh in enumerate(file_hashes):
|
|
72
|
+
smt.insert(f"file_{idx}", fh)
|
|
73
|
+
|
|
74
|
+
merkle_root = smt.root_hash if file_hashes else root_hash
|
|
75
|
+
|
|
76
|
+
intrinsic_value_usd = round(sum(f.get("intrinsic_valuation_usd", 0.0) for f in file_details), 2)
|
|
77
|
+
|
|
78
|
+
timestamp = time.time()
|
|
79
|
+
receipt_payload = {
|
|
80
|
+
"oracle": "FileOracle-v1.0",
|
|
81
|
+
"workspace_root": target_dir,
|
|
82
|
+
"merkle_root": merkle_root,
|
|
83
|
+
"total_files": total_files,
|
|
84
|
+
"total_bytes": total_size_bytes,
|
|
85
|
+
"total_tokens": total_tokens,
|
|
86
|
+
"intrinsic_value_usd": intrinsic_value_usd,
|
|
87
|
+
"timestamp": timestamp,
|
|
88
|
+
"owner_pub_key": self.pub_key
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
receipt_bytes = json.dumps(receipt_payload, sort_keys=True).encode("utf-8")
|
|
92
|
+
receipt_hash = sha256_bytes(receipt_bytes)
|
|
93
|
+
signature = sign_manifest(self.priv_key, receipt_hash)
|
|
94
|
+
|
|
95
|
+
is_valid = verify_manifest_sig(self.pub_key, receipt_hash, signature)
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"appraisal_summary": {
|
|
99
|
+
"total_files": total_files,
|
|
100
|
+
"total_bytes": total_size_bytes,
|
|
101
|
+
"total_tokens_estimate": total_tokens,
|
|
102
|
+
"intrinsic_valuation_usd": intrinsic_value_usd,
|
|
103
|
+
"merkle_root": merkle_root,
|
|
104
|
+
},
|
|
105
|
+
"receipt": {
|
|
106
|
+
"receipt_hash": receipt_hash,
|
|
107
|
+
"signature": signature,
|
|
108
|
+
"owner_pub_key": self.pub_key,
|
|
109
|
+
"verified": is_valid,
|
|
110
|
+
"timestamp": timestamp,
|
|
111
|
+
},
|
|
112
|
+
"file_manifest": file_details[:50]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_global_engine = FileOracleEngine()
|
|
116
|
+
|
|
117
|
+
def process_query(query: str, context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
118
|
+
"""Live query processor that appraises files and produces HDAR receipts."""
|
|
119
|
+
query_lower = query.lower()
|
|
120
|
+
scan_target = os.getcwd()
|
|
121
|
+
|
|
122
|
+
if "appraise" in query_lower or "scan" in query_lower or "graph" in query_lower or "val" in query_lower or query.strip() == "":
|
|
123
|
+
appraisal = _global_engine.appraise_workspace(scan_target)
|
|
124
|
+
return {
|
|
125
|
+
"answer": f"✓ Live FileOracle Appraisal Complete: Scanned {appraisal['appraisal_summary']['total_files']} files ({appraisal['appraisal_summary']['total_tokens_estimate']} tokens). Total Intrinsic Value: ${appraisal['appraisal_summary']['intrinsic_valuation_usd']:.2f} USD.",
|
|
126
|
+
"appraisal": appraisal,
|
|
127
|
+
"metadata": {
|
|
128
|
+
"engine": "FileOracle Live HDAR",
|
|
129
|
+
"attested": appraisal["receipt"]["verified"]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else:
|
|
133
|
+
appraisal = _global_engine.appraise_workspace(scan_target)
|
|
134
|
+
return {
|
|
135
|
+
"answer": f"FileOracle Analysis for '{query}': Scanned workspace {scan_target} (Merkle root: {appraisal['appraisal_summary']['merkle_root'][:16]}...). Merkle Integrity 100% verified.",
|
|
136
|
+
"appraisal": appraisal,
|
|
137
|
+
"metadata": {
|
|
138
|
+
"engine": "FileOracle Live HDAR",
|
|
139
|
+
"attested": appraisal["receipt"]["verified"]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import hashlib
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from typing import List, Dict, Any
|
|
5
|
+
|
|
6
|
+
# Import merkle utilities from hdar_core if available
|
|
7
|
+
try:
|
|
8
|
+
from hdar_core.crypto.merkle import MerkleTree
|
|
9
|
+
except ImportError:
|
|
10
|
+
MerkleTree = None # Fallback placeholder
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def file_hash(path: str) -> str:
|
|
14
|
+
"""Compute SHA‑256 hash of a file's contents."""
|
|
15
|
+
h = hashlib.sha256()
|
|
16
|
+
try:
|
|
17
|
+
with open(path, "rb") as f:
|
|
18
|
+
for chunk in iter(lambda: f.read(8192), b""):
|
|
19
|
+
h.update(chunk)
|
|
20
|
+
return h.hexdigest()
|
|
21
|
+
except Exception:
|
|
22
|
+
return "error_reading_file"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def attestation_record(file_hash_val: str) -> Dict[str, Any]:
|
|
26
|
+
"""Create a simple provenance/attestation record for a file."""
|
|
27
|
+
return {
|
|
28
|
+
"hash": file_hash_val,
|
|
29
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
30
|
+
"issuer": "FileOracle",
|
|
31
|
+
"method": "sha256",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_graph(root_path: str) -> Dict[str, Any]:
|
|
36
|
+
"""Scan ``root_path`` and build a node/edge graph.
|
|
37
|
+
|
|
38
|
+
Nodes represent files and directories. Edges represent parent‑child
|
|
39
|
+
relationships. Each node includes provenance metadata.
|
|
40
|
+
"""
|
|
41
|
+
nodes: List[Dict[str, Any]] = []
|
|
42
|
+
edges: List[Dict[str, Any]] = []
|
|
43
|
+
|
|
44
|
+
path_to_id: Dict[str, int] = {}
|
|
45
|
+
uid = 0
|
|
46
|
+
|
|
47
|
+
abs_root = os.path.abspath(root_path)
|
|
48
|
+
|
|
49
|
+
for dirpath, dirnames, filenames in os.walk(abs_root):
|
|
50
|
+
# Add directory node if not present
|
|
51
|
+
if dirpath not in path_to_id:
|
|
52
|
+
dir_id = uid
|
|
53
|
+
path_to_id[dirpath] = dir_id
|
|
54
|
+
uid += 1
|
|
55
|
+
nodes.append({
|
|
56
|
+
"id": dir_id,
|
|
57
|
+
"type": "directory",
|
|
58
|
+
"path": os.path.relpath(dirpath, abs_root),
|
|
59
|
+
"size": None,
|
|
60
|
+
"provenance": attestation_record("directory"),
|
|
61
|
+
})
|
|
62
|
+
else:
|
|
63
|
+
dir_id = path_to_id[dirpath]
|
|
64
|
+
|
|
65
|
+
# Edge from parent directory if parent exists in our map
|
|
66
|
+
parent = os.path.abspath(os.path.join(dirpath, os.pardir))
|
|
67
|
+
if parent in path_to_id:
|
|
68
|
+
edges.append({"source": path_to_id[parent], "target": dir_id})
|
|
69
|
+
|
|
70
|
+
# Files
|
|
71
|
+
for fname in filenames:
|
|
72
|
+
fpath = os.path.join(dirpath, fname)
|
|
73
|
+
f_id = uid
|
|
74
|
+
path_to_id[fpath] = f_id
|
|
75
|
+
uid += 1
|
|
76
|
+
try:
|
|
77
|
+
size = os.path.getsize(fpath)
|
|
78
|
+
fhash = file_hash(fpath)
|
|
79
|
+
prov = attestation_record(fhash)
|
|
80
|
+
except Exception:
|
|
81
|
+
size = None
|
|
82
|
+
prov = attestation_record("error")
|
|
83
|
+
|
|
84
|
+
nodes.append({
|
|
85
|
+
"id": f_id,
|
|
86
|
+
"type": "file",
|
|
87
|
+
"path": os.path.relpath(fpath, abs_root),
|
|
88
|
+
"size": size,
|
|
89
|
+
"provenance": prov,
|
|
90
|
+
})
|
|
91
|
+
edges.append({"source": dir_id, "target": f_id})
|
|
92
|
+
|
|
93
|
+
# Compute Merkle root over all valid file hashes
|
|
94
|
+
file_hashes = [
|
|
95
|
+
n["provenance"]["hash"]
|
|
96
|
+
for n in nodes
|
|
97
|
+
if n["type"] == "file" and n["provenance"]["hash"] not in ("error", "error_reading_file")
|
|
98
|
+
]
|
|
99
|
+
merkle_root = None
|
|
100
|
+
if MerkleTree is not None and file_hashes:
|
|
101
|
+
try:
|
|
102
|
+
tree = MerkleTree(file_hashes)
|
|
103
|
+
merkle_root = tree.root_hash
|
|
104
|
+
except Exception:
|
|
105
|
+
merkle_root = None
|
|
106
|
+
|
|
107
|
+
return {"nodes": nodes, "edges": edges, "merkle_root": merkle_root}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from fastapi import FastAPI, HTTPException
|
|
5
|
+
from fastapi.staticfiles import StaticFiles
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
from .graph import build_graph
|
|
9
|
+
from .fileoracle import process_query
|
|
10
|
+
|
|
11
|
+
app = FastAPI(title="FileOracle", version="1.0.0")
|
|
12
|
+
|
|
13
|
+
class QueryRequest(BaseModel):
|
|
14
|
+
query: str
|
|
15
|
+
|
|
16
|
+
@app.get("/health")
|
|
17
|
+
async def health_check():
|
|
18
|
+
return {"status": "ok"}
|
|
19
|
+
|
|
20
|
+
@app.post("/query")
|
|
21
|
+
async def query_endpoint(request: QueryRequest):
|
|
22
|
+
if not request.query:
|
|
23
|
+
raise HTTPException(status_code=400, detail="Query cannot be empty")
|
|
24
|
+
res = process_query(request.query)
|
|
25
|
+
return res
|
|
26
|
+
|
|
27
|
+
@app.get("/graph")
|
|
28
|
+
async def get_graph(root: str = None):
|
|
29
|
+
scan_root = root or os.getcwd()
|
|
30
|
+
try:
|
|
31
|
+
graph_data = build_graph(scan_root)
|
|
32
|
+
return graph_data
|
|
33
|
+
except Exception as e:
|
|
34
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
35
|
+
|
|
36
|
+
# Mount frontend static files
|
|
37
|
+
frontend_dir = Path(__file__).parent.parent / "frontend"
|
|
38
|
+
if frontend_dir.exists():
|
|
39
|
+
app.mount("/", StaticFiles(directory=str(frontend_dir), html=True), name="static")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests package
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from fastapi.testclient import TestClient
|
|
2
|
+
from backend.main import app
|
|
3
|
+
|
|
4
|
+
client = TestClient(app)
|
|
5
|
+
|
|
6
|
+
def test_health():
|
|
7
|
+
response = client.get("/health")
|
|
8
|
+
assert response.status_code == 200
|
|
9
|
+
assert response.json() == {"status": "ok"}
|
|
10
|
+
|
|
11
|
+
def test_query():
|
|
12
|
+
response = client.post("/query", json={"query": "test query"})
|
|
13
|
+
assert response.status_code == 200
|
|
14
|
+
data = response.json()
|
|
15
|
+
assert "answer" in data
|
|
16
|
+
assert "appraisal" in data
|
|
17
|
+
assert data["appraisal"]["receipt"]["verified"] is True
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_graph():
|
|
21
|
+
response = client.get("/graph")
|
|
22
|
+
assert response.status_code == 200
|
|
23
|
+
data = response.json()
|
|
24
|
+
assert "nodes" in data
|
|
25
|
+
assert "edges" in data
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fileoracle
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-powered local file tree scraper, provenance attestation graph engine, and web oracle
|
|
5
|
+
Author-email: Joseph Skrobynets <j.skrobynets@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/overandor/FileOracle
|
|
8
|
+
Project-URL: Repository, https://github.com/overandor/FileOracle
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: fastapi>=0.111.0
|
|
12
|
+
Requires-Dist: uvicorn[standard]>=0.30.1
|
|
13
|
+
Requires-Dist: pydantic>=2.0.0
|
|
14
|
+
Requires-Dist: requests>=2.28.0
|
|
15
|
+
|
|
16
|
+
# FileOracle 🔮
|
|
17
|
+
|
|
18
|
+
FileOracle is an AI-powered local file tree scraper, graph visualizer, and attestation engine with deep provenance tracking, cryptographic hashing (SHA-256 / Merkle trees), and multi-platform deployment capability.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- **FastAPI Backend**: RESTful API exposing `/health`, `/query`, and `/graph` endpoints.
|
|
23
|
+
- **Local File Graph Engine**: Scans directory trees, builds node/edge graphs, and calculates cryptographic provenance records & Merkle roots.
|
|
24
|
+
- **Modern Glassmorphism Frontend**: Responsive dark mode UI using Inter typography, micro-animations, and interactive D3.js graph rendering.
|
|
25
|
+
- **DeepWiki Agent Continuity**: Consolidated documentation architecture detailing work continuity and memory persistence.
|
|
26
|
+
- **Multi-Cloud Ready**: Scaffolding and configs for Vercel, Netlify, Docker, Hugging Face Spaces, and GitHub Actions.
|
|
27
|
+
|
|
28
|
+
## Project Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
FileOracle/
|
|
32
|
+
├── backend/
|
|
33
|
+
│ ├── __init__.py
|
|
34
|
+
│ ├── fileoracle.py # Core FileOracle AI engine
|
|
35
|
+
│ ├── graph.py # Graph builder & SHA-256/Merkle attestation
|
|
36
|
+
│ ├── main.py # FastAPI entry point
|
|
37
|
+
│ ├── requirements.txt # Backend dependencies
|
|
38
|
+
│ └── tests/ # Pytest test suite
|
|
39
|
+
├── frontend/
|
|
40
|
+
│ ├── app.js # Client logic & D3 visualization
|
|
41
|
+
│ ├── index.html # HTML5 SPA landing page
|
|
42
|
+
│ └── styles.css # Glassmorphism dark mode stylesheet
|
|
43
|
+
├── docs/
|
|
44
|
+
│ └── DeepWiki_Consolidated.md # DeepWiki docs with agent memory architecture
|
|
45
|
+
├── .github/workflows/
|
|
46
|
+
│ └── deploy.yml # GitHub Actions CI/CD workflow
|
|
47
|
+
├── Dockerfile # Docker / Hugging Face Spaces build
|
|
48
|
+
├── netlify.toml # Netlify deployment configuration
|
|
49
|
+
├── vercel.json # Vercel serverless configuration
|
|
50
|
+
└── README.md
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Local Development
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Clone repository
|
|
59
|
+
git clone https://github.com/overandor/FileOracle.git
|
|
60
|
+
cd FileOracle
|
|
61
|
+
|
|
62
|
+
# Create virtual environment & install dependencies
|
|
63
|
+
python3 -m venv venv
|
|
64
|
+
source venv/bin/activate
|
|
65
|
+
pip install -r backend/requirements.txt
|
|
66
|
+
pip install pytest httpx
|
|
67
|
+
|
|
68
|
+
# Run tests
|
|
69
|
+
pytest backend/
|
|
70
|
+
|
|
71
|
+
# Start FastAPI server
|
|
72
|
+
uvicorn backend.main:app --reload --port 8000
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Visit `http://localhost:8000` in your browser.
|
|
76
|
+
|
|
77
|
+
### 2. Run with Docker
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker build -t fileoracle .
|
|
81
|
+
docker run -p 7860:7860 fileoracle
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
MIT License.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
backend/__init__.py
|
|
4
|
+
backend/cli.py
|
|
5
|
+
backend/fileoracle.py
|
|
6
|
+
backend/graph.py
|
|
7
|
+
backend/main.py
|
|
8
|
+
backend/tests/__init__.py
|
|
9
|
+
backend/tests/test_fileoracle.py
|
|
10
|
+
fileoracle.egg-info/PKG-INFO
|
|
11
|
+
fileoracle.egg-info/SOURCES.txt
|
|
12
|
+
fileoracle.egg-info/dependency_links.txt
|
|
13
|
+
fileoracle.egg-info/entry_points.txt
|
|
14
|
+
fileoracle.egg-info/requires.txt
|
|
15
|
+
fileoracle.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
backend
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "fileoracle"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "AI-powered local file tree scraper, provenance attestation graph engine, and web oracle"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [{ name = "Joseph Skrobynets", email = "j.skrobynets@gmail.com" }]
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"fastapi>=0.111.0",
|
|
15
|
+
"uvicorn[standard]>=0.30.1",
|
|
16
|
+
"pydantic>=2.0.0",
|
|
17
|
+
"requests>=2.28.0"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://github.com/overandor/FileOracle"
|
|
22
|
+
Repository = "https://github.com/overandor/FileOracle"
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["."]
|
|
26
|
+
include = ["backend*"]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
fileoracle = "backend.cli:main"
|
|
30
|
+
|