srcodex 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.
Files changed (52) hide show
  1. srcodex/__init__.py +0 -0
  2. srcodex/backend/__init__.py +0 -0
  3. srcodex/backend/chat.py +79 -0
  4. srcodex/backend/main.py +98 -0
  5. srcodex/backend/services/__init__.py +0 -0
  6. srcodex/backend/services/claude_service.py +754 -0
  7. srcodex/backend/services/config_loader.py +113 -0
  8. srcodex/backend/services/file_access_tools.py +279 -0
  9. srcodex/backend/services/file_tree.py +480 -0
  10. srcodex/backend/services/graph_tools.py +874 -0
  11. srcodex/backend/services/logger_setup.py +91 -0
  12. srcodex/backend/services/session_manager.py +81 -0
  13. srcodex/backend/services/status_tracker.py +91 -0
  14. srcodex/cli.py +255 -0
  15. srcodex/core/__init__.py +0 -0
  16. srcodex/core/config.py +113 -0
  17. srcodex/core/logger.py +23 -0
  18. srcodex/indexer/__init__.py +0 -0
  19. srcodex/indexer/cscope_client.py +183 -0
  20. srcodex/indexer/ctags_compat.py +223 -0
  21. srcodex/indexer/ctags_parser.py +456 -0
  22. srcodex/indexer/explorer.py +135 -0
  23. srcodex/indexer/field_access_analyzer.py +436 -0
  24. srcodex/indexer/indexer.py +664 -0
  25. srcodex/indexer/reference_ingestor.py +293 -0
  26. srcodex/indexer/reference_resolver.py +544 -0
  27. srcodex/tui/__init__.py +0 -0
  28. srcodex/tui/app.py +103 -0
  29. srcodex/tui/app.tcss +24 -0
  30. srcodex/tui/components/__init__.py +0 -0
  31. srcodex/tui/components/bars/__init__.py +0 -0
  32. srcodex/tui/components/bars/chat_header.py +48 -0
  33. srcodex/tui/components/bars/code_tab_bar.py +157 -0
  34. srcodex/tui/components/bars/footer_bar.py +128 -0
  35. srcodex/tui/components/bars/left_tab.py +54 -0
  36. srcodex/tui/components/logger.py +57 -0
  37. srcodex/tui/components/panels/__init__.py +0 -0
  38. srcodex/tui/components/panels/chat_panel.py +523 -0
  39. srcodex/tui/components/panels/code_panel.py +229 -0
  40. srcodex/tui/components/panels/side_panel.py +128 -0
  41. srcodex/tui/components/views/__init__.py +0 -0
  42. srcodex/tui/components/views/explorer_view.py +20 -0
  43. srcodex/tui/components/views/search_view.py +148 -0
  44. srcodex/tui/components/widgets/__init__.py +0 -0
  45. srcodex/tui/components/widgets/file_browser.py +16 -0
  46. srcodex/tui/components/widgets/find_box.py +85 -0
  47. srcodex-0.2.0.dist-info/METADATA +170 -0
  48. srcodex-0.2.0.dist-info/RECORD +52 -0
  49. srcodex-0.2.0.dist-info/WHEEL +5 -0
  50. srcodex-0.2.0.dist-info/entry_points.txt +2 -0
  51. srcodex-0.2.0.dist-info/licenses/LICENSE +21 -0
  52. srcodex-0.2.0.dist-info/top_level.txt +1 -0
srcodex/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,79 @@
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ from .services.claude_service import ClaudeService
4
+ from .services.logger_setup import setup_backend_logging
5
+ from fastapi.responses import StreamingResponse
6
+ import json
7
+ import logging
8
+
9
+
10
+ setup_backend_logging()
11
+ logger = logging.getLogger(__name__)
12
+
13
+ app = FastAPI()
14
+
15
+ try:
16
+ claude_service = ClaudeService()
17
+ except ValueError as e:
18
+ print(f"Warning: {e}")
19
+ claude_service = None
20
+
21
+ class ChatRequest(BaseModel):
22
+ """Request body for chat endpoint"""
23
+ message: str
24
+ conversation_history: list = []
25
+
26
+ class ChatResponse(BaseModel):
27
+ """Response body for chat endpoint"""
28
+ response: str
29
+
30
+ @app.post("/api/chat", response_model=ChatResponse)
31
+ async def chat(request: ChatRequest):
32
+ """
33
+ Chat endpoint - sends message to Claude and returns response
34
+ Example:
35
+ POST /api/chat
36
+ {"message": "What does functionX do?"}
37
+
38
+ Returns:
39
+ {"response": "FunctionX is a function that..."}
40
+ """
41
+ if not claude_service:
42
+ raise HTTPException(status_code=500, detail="Claude service not initialized - check API key")
43
+
44
+ if not request.message.strip():
45
+ raise HTTPException(status_code=400, detail="Message cannot be empty")
46
+
47
+ try:
48
+ logger.info(f"Chat request: {request.message[:100]}...")
49
+ response = claude_service.send_message_with_tools(request.message, request.conversation_history)
50
+ logger.info(f"Chat response: {len(response)} chars")
51
+ return ChatResponse(response=response)
52
+ except Exception as e:
53
+ logger.error(f"Claude API error: {str(e)}")
54
+ raise HTTPException(status_code=500, detail=f"Claude API error: {str(e)}")
55
+
56
+ @app.post("/api/chat/stream")
57
+ async def chat_stream(request: ChatRequest):
58
+ """
59
+ Streaming chat endpoint - streams Claude's response in real-time
60
+
61
+ Streams newline-delimited JSON objects:
62
+ - Text chunks: {"type": "text", "content": "..."}
63
+ - Token metadata: {"type": "tokens", "input": 1234, "output": 56, "total": 1290}
64
+ """
65
+ if not claude_service:
66
+ raise HTTPException(status_code=500, detail="Claude service not initialized")
67
+
68
+ if not request.message.strip():
69
+ raise HTTPException(status_code=400, detail="Message cannot be empty")
70
+
71
+ try:
72
+ def generate():
73
+ for chunk in claude_service.stream_message_with_tools(request.message, request.conversation_history):
74
+ # Stream as newline-delimited JSON
75
+ yield json.dumps(chunk) + "\n"
76
+
77
+ return StreamingResponse(generate(), media_type="application/x-ndjson")
78
+ except Exception as e:
79
+ raise HTTPException(status_code=500, detail=f"Claude API error: {str(e)}")
@@ -0,0 +1,98 @@
1
+ """
2
+ srcodex Backend - Semantic Graph API
3
+ """
4
+
5
+ from fastapi import FastAPI
6
+ from pathlib import Path
7
+ from typing import Dict, List, Any
8
+ import sys
9
+ sys.path.insert(0, str(Path(__file__).parent))
10
+ from services.file_tree import FileTreeService
11
+ DB_PATH = Path(__file__).parent.parent / "data" / "pmfw_main.db" ##Database path
12
+
13
+ app = FastAPI(title="srcodex API", version="0.1.0")
14
+ file_tree_service = FileTreeService(str(DB_PATH))
15
+
16
+ @app.get("/")
17
+ async def root() -> Dict[str, str]:
18
+ """ API Root, returns basic information """
19
+ return {
20
+ "name": "srcodex API",
21
+ "version": "0.1.0"
22
+ }
23
+
24
+ @app.get("/projects/{project_id}/root")
25
+ async def get_project_root(project_id: str) -> Dict[str, Any]:
26
+ """
27
+ Get Project root metadata
28
+ Example: GET /projects/pmfw_main/root
29
+ """
30
+ if project_id != Path(DB_PATH).stem:
31
+ return {"error": f"Project '{project_id}' not found!"}, 404
32
+
33
+ return file_tree_service.get_root()
34
+
35
+ @app.get("/projects/{project_id}/children")
36
+ def get_children(project_id: str, path: str = "") -> List[Dict[str, Any]]:
37
+ """
38
+ Get Immediate children of a directory.
39
+ Examples:
40
+ GET /projects/pmfw_main/children?path=
41
+ → Returns root children: [mp1/, mpccx/, common/, test/]
42
+ GET /projects/pmfw_main/children?path=mp1/src/app/
43
+ → Returns contents of mp1/src/app/
44
+ """
45
+ if project_id != Path(DB_PATH).stem:
46
+ return {"error": f"Project '{project_id}' not found!"}, 404
47
+
48
+ return file_tree_service.get_children(path)
49
+
50
+ @app.get("/projects/{project_id}/search/files")
51
+ def search_file(project_id: str, q: str = "") -> List[Dict[str, Any]]:
52
+ """
53
+ Search for files by name or path (like Ctrl+P in VSCode).
54
+ Examples:
55
+ GET /projects/pmfw_main/search/files?q=msg
56
+ → Returns files matching "msg": [msg.c, msg.h, ...]
57
+ GET /projects/pmfw_main/search/files?q=app/pow
58
+ → Returns files in "app" matching "pow": [mp1/src/app/power.c, ...]
59
+ """
60
+ if project_id != Path(DB_PATH).stem:
61
+ return {"error": f"Project '{project_id}' not found!"}, 404
62
+
63
+ return file_tree_service.search_file(q)
64
+
65
+ @app.get("/projects/{project_id}/search/symbols")
66
+ def search_symbol_global(project_id: str, q: str = "") -> List[Dict[str, Any]]:
67
+ """
68
+ Search for symbols globally across entire codebase (like Ctrl+Shift+F in VSCode).
69
+ Examples:
70
+ GET /projects/pmfw_main/search/symbols?q=voltage
71
+ → Returns all voltage-related symbols (variables, macros, structs, ...)
72
+ GET /projects/pmfw_main/search/symbols?q=Init
73
+ → Returns all initialization functions
74
+ """
75
+ if project_id != Path(DB_PATH).stem:
76
+ return {"error": f"Project '{project_id}' not found!"}, 404
77
+
78
+ return file_tree_service.search_symbol_global(q)
79
+
80
+ @app.get("/projects/{project_id}/files/{file_path:path}/symbols")
81
+ def search_symbol_infile(project_id: str, file_path: str, q: str = "") -> List[Dict[str, Any]]:
82
+ """
83
+ Search symbols within a specific file (like Ctrl+F in VSCode on open file).
84
+ Examples:
85
+ GET /projects/pmfw_main/files/mp1/src/app/msg.c/symbols?q=Isr
86
+ → Returns all symbols matching "Isr" in msg.c: [IsrHostMsg, IsrBiosMsg, ...]
87
+ GET /projects/pmfw_main/files/mp1/src/app/power.c/symbols?q=Init
88
+ → Returns all Init functions in power.c
89
+ """
90
+ if project_id != Path(DB_PATH).stem:
91
+ return {"error": f"Project '{project_id}' not found!"}, 404
92
+
93
+ return file_tree_service.search_symbol_infile(q, file_path)
94
+
95
+ if __name__ == "__main__":
96
+ import uvicorn
97
+ uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
98
+
File without changes