synap-git 0.2.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.
- synap_git/__init__.py +5 -0
- synap_git/api/__init__.py +5 -0
- synap_git/api/app.py +111 -0
- synap_git/api/static/index.html +615 -0
- synap_git/cli/__init__.py +3 -0
- synap_git/cli/__main__.py +4 -0
- synap_git/cli/main.py +1174 -0
- synap_git/config.py +169 -0
- synap_git/diagnostics/__init__.py +0 -0
- synap_git/diagnostics/logger.py +82 -0
- synap_git/diagnostics/tracing.py +71 -0
- synap_git/embeddings/__init__.py +0 -0
- synap_git/git/__init__.py +11 -0
- synap_git/git/state.py +139 -0
- synap_git/indexer/__init__.py +0 -0
- synap_git/indexer/daemon.py +143 -0
- synap_git/indexer/engine.py +327 -0
- synap_git/indexer/scanner.py +463 -0
- synap_git/indexer/wiki.py +78 -0
- synap_git/mcp/__init__.py +5 -0
- synap_git/mcp/server.py +232 -0
- synap_git/parser/__init__.py +0 -0
- synap_git/parser/registry.py +209 -0
- synap_git/provider/anthropic.py +86 -0
- synap_git/provider/base.py +44 -0
- synap_git/provider/factory.py +101 -0
- synap_git/provider/gemini.py +98 -0
- synap_git/provider/mock.py +66 -0
- synap_git/provider/ollama.py +98 -0
- synap_git/provider/openai.py +90 -0
- synap_git/py.typed +1 -0
- synap_git/retrieval/__init__.py +0 -0
- synap_git/retrieval/engine.py +258 -0
- synap_git/retrieval/memory.py +123 -0
- synap_git/storage/__init__.py +3 -0
- synap_git/storage/sqlite.py +575 -0
- synap_git/utils/__init__.py +0 -0
- synap_git/utils/serialization.py +68 -0
- synap_git-0.2.0.dist-info/METADATA +251 -0
- synap_git-0.2.0.dist-info/RECORD +43 -0
- synap_git-0.2.0.dist-info/WHEEL +4 -0
- synap_git-0.2.0.dist-info/entry_points.txt +2 -0
- synap_git-0.2.0.dist-info/licenses/LICENSE.md +201 -0
synap_git/__init__.py
ADDED
synap_git/api/app.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from fastapi import FastAPI, HTTPException
|
|
9
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
10
|
+
from fastapi.responses import HTMLResponse, StreamingResponse
|
|
11
|
+
from fastapi.staticfiles import StaticFiles
|
|
12
|
+
|
|
13
|
+
from synap_git.indexer.engine import SynapRuntime
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_app(runtime: SynapRuntime) -> FastAPI:
|
|
17
|
+
app = FastAPI(
|
|
18
|
+
title="Synap Context Diagnostics",
|
|
19
|
+
description="Deterministic structural context infrastructure for AI coding agents.",
|
|
20
|
+
version="0.2.0",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
app.add_middleware(
|
|
24
|
+
CORSMiddleware,
|
|
25
|
+
allow_origins=["*"],
|
|
26
|
+
allow_credentials=True,
|
|
27
|
+
allow_methods=["*"],
|
|
28
|
+
allow_headers=["*"],
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Serve static UI files
|
|
32
|
+
static_dir = Path(__file__).parent / "static"
|
|
33
|
+
static_dir.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
|
35
|
+
|
|
36
|
+
@app.get("/", response_class=HTMLResponse)
|
|
37
|
+
async def get_index() -> str:
|
|
38
|
+
index_file = static_dir / "index.html"
|
|
39
|
+
if index_file.exists():
|
|
40
|
+
return index_file.read_text(encoding="utf-8")
|
|
41
|
+
return "<h1>Synap Diagnostic UI is ready.</h1>"
|
|
42
|
+
|
|
43
|
+
@app.get("/api/v1/status")
|
|
44
|
+
async def get_status() -> dict[str, Any]:
|
|
45
|
+
try:
|
|
46
|
+
status = runtime.status()
|
|
47
|
+
from synap_git.cli.main import _read_daemon_heartbeat
|
|
48
|
+
|
|
49
|
+
daemon_info = _read_daemon_heartbeat(Path(status.repository_path))
|
|
50
|
+
return {
|
|
51
|
+
"repository_path": status.repository_path,
|
|
52
|
+
"branch": status.branch,
|
|
53
|
+
"git_commit": status.git_commit,
|
|
54
|
+
"active_commit": status.active_commit,
|
|
55
|
+
"symbols": status.symbols,
|
|
56
|
+
"files": status.files,
|
|
57
|
+
"mode": status.mode,
|
|
58
|
+
"daemon": daemon_info,
|
|
59
|
+
}
|
|
60
|
+
except Exception as exc:
|
|
61
|
+
raise HTTPException(status_code=500, detail=str(exc))
|
|
62
|
+
|
|
63
|
+
@app.get("/api/v1/trace/latest")
|
|
64
|
+
async def get_latest_trace() -> dict[str, Any]:
|
|
65
|
+
try:
|
|
66
|
+
return runtime.trace_store.get_latest()
|
|
67
|
+
except Exception as exc:
|
|
68
|
+
raise HTTPException(status_code=500, detail=str(exc))
|
|
69
|
+
|
|
70
|
+
@app.get("/api/v1/events")
|
|
71
|
+
async def get_events() -> StreamingResponse:
|
|
72
|
+
from collections.abc import AsyncGenerator
|
|
73
|
+
|
|
74
|
+
async def event_generator() -> AsyncGenerator[str, None]:
|
|
75
|
+
while True:
|
|
76
|
+
status = runtime.status()
|
|
77
|
+
yield f"data: {json.dumps(status.__dict__)}\n\n"
|
|
78
|
+
await asyncio.sleep(2)
|
|
79
|
+
|
|
80
|
+
return StreamingResponse(event_generator(), media_type="text/event-stream")
|
|
81
|
+
|
|
82
|
+
@app.get("/wiki/{filepath:path}")
|
|
83
|
+
async def get_wiki_page(filepath: str) -> dict[str, Any]:
|
|
84
|
+
wiki_path = runtime.wiki.wiki_dir / f"{filepath}.md"
|
|
85
|
+
if wiki_path.exists():
|
|
86
|
+
return {"status": "ok", "content": wiki_path.read_text(encoding="utf-8")}
|
|
87
|
+
return {"status": "error", "message": "Wiki not found"}
|
|
88
|
+
|
|
89
|
+
@app.get("/api/v1/memory")
|
|
90
|
+
async def get_memory_page() -> dict[str, Any]:
|
|
91
|
+
approved = runtime.store.get_lessons("approved")
|
|
92
|
+
pending = runtime.store.get_lessons("pending")
|
|
93
|
+
return {"status": "ok", "approved": approved, "pending": pending}
|
|
94
|
+
|
|
95
|
+
@app.get("/api/v1/cost")
|
|
96
|
+
async def get_cost_page() -> dict[str, Any]:
|
|
97
|
+
with runtime.store.connect() as conn:
|
|
98
|
+
rows = conn.execute("SELECT * FROM llm_calls ORDER BY created_at DESC").fetchall()
|
|
99
|
+
calls = [dict(r) for r in rows]
|
|
100
|
+
return {"status": "ok", "calls": calls}
|
|
101
|
+
|
|
102
|
+
@app.get("/api/v1/checkpoints")
|
|
103
|
+
async def get_checkpoints_page() -> dict[str, Any]:
|
|
104
|
+
with runtime.store.connect() as conn:
|
|
105
|
+
rows = conn.execute(
|
|
106
|
+
"SELECT * FROM checkpoints ORDER BY created_at DESC LIMIT 20"
|
|
107
|
+
).fetchall()
|
|
108
|
+
cps = [dict(r) for r in rows]
|
|
109
|
+
return {"status": "ok", "checkpoints": cps}
|
|
110
|
+
|
|
111
|
+
return app
|