Files
ClaudeProjectManager/project_manager.py
Claude Project Manager 4dab418f2f Initial commit
2025-07-09 22:10:42 +02:00

228 Zeilen
9.0 KiB
Python

"""
Project Manager Module
Handles project storage, loading, and management
"""
import json
import os
from datetime import datetime
from typing import List, Dict, Optional
import uuid
from utils.logger import logger
class Project:
def __init__(self, name: str, path: str, project_id: str = None):
self.id = project_id or str(uuid.uuid4())
self.name = name
self.path = path
self.created_at = datetime.now().isoformat()
self.last_accessed = datetime.now().isoformat()
self.readme_path = os.path.join(path, "CLAUDE_PROJECT_README.md")
self.description = ""
self.tags = []
self.gitea_repo = None # Format: "owner/repo_name" or None if not linked
def to_dict(self) -> Dict:
"""Convert project to dictionary for JSON storage"""
return {
'id': self.id,
'name': self.name,
'path': self.path,
'created_at': self.created_at,
'last_accessed': self.last_accessed,
'readme_path': self.readme_path,
'description': self.description,
'tags': self.tags,
'gitea_repo': self.gitea_repo
}
@classmethod
def from_dict(cls, data: Dict) -> 'Project':
"""Create project from dictionary"""
project = cls(data['name'], data['path'], data['id'])
project.created_at = data.get('created_at', datetime.now().isoformat())
project.last_accessed = data.get('last_accessed', datetime.now().isoformat())
project.readme_path = data.get('readme_path', os.path.join(data['path'], "CLAUDE_PROJECT_README.md"))
project.description = data.get('description', '')
project.tags = data.get('tags', [])
project.gitea_repo = data.get('gitea_repo', None)
return project
def update_last_accessed(self):
"""Update last accessed timestamp"""
self.last_accessed = datetime.now().isoformat()
class ProjectManager:
def __init__(self, data_file: str = "data/projects.json"):
self.data_file = data_file
self.projects: Dict[str, Project] = {}
self.vps_project = None
self.admin_panel_project = None
self.activity_server_project = None
self._ensure_data_dir()
self.load_projects()
self._initialize_vps_project()
self._initialize_admin_panel_project()
self._initialize_activity_server_project()
def _ensure_data_dir(self):
"""Ensure data directory exists"""
data_dir = os.path.dirname(self.data_file)
if data_dir and not os.path.exists(data_dir):
os.makedirs(data_dir)
def _initialize_vps_project(self):
"""Initialize the permanent VPS project"""
vps_id = "vps-permanent"
if vps_id not in self.projects:
self.vps_project = Project(
name="VPS Server",
path="claude-dev@91.99.192.14",
project_id=vps_id
)
self.vps_project.description = "Remote VPS Server with Claude"
self.vps_project.tags = ["vps", "remote", "server"]
self.projects[vps_id] = self.vps_project
self.save_projects()
else:
self.vps_project = self.projects[vps_id]
def _initialize_admin_panel_project(self):
"""Initialize the permanent Admin Panel project"""
admin_id = "admin-panel-permanent"
if admin_id not in self.projects:
self.admin_panel_project = Project(
name="Admin Panel",
path="/opt/v2-Docker",
project_id=admin_id
)
self.admin_panel_project.description = "V2 Docker Admin Panel"
self.admin_panel_project.tags = ["admin", "docker", "v2"]
self.projects[admin_id] = self.admin_panel_project
self.save_projects()
else:
self.admin_panel_project = self.projects[admin_id]
def _initialize_activity_server_project(self):
"""Initialize the permanent Activity Server project"""
activity_id = "activity-server-permanent"
if activity_id not in self.projects:
self.activity_server_project = Project(
name="Activity Server",
path="/home/claude-dev/cpm-activity-server",
project_id=activity_id
)
self.activity_server_project.description = "CPM Activity Server"
self.activity_server_project.tags = ["activity", "server", "cpm"]
self.projects[activity_id] = self.activity_server_project
self.save_projects()
else:
self.activity_server_project = self.projects[activity_id]
def load_projects(self):
"""Load projects from JSON file"""
logger.info("Loading projects from file")
if os.path.exists(self.data_file):
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
for proj_data in data.get('projects', []):
project = Project.from_dict(proj_data)
self.projects[project.id] = project
except Exception as e:
print(f"Error loading projects: {e}")
self.projects = {}
def save_projects(self):
"""Save projects to JSON file"""
logger.debug("Saving projects to file")
try:
data = {
'projects': [proj.to_dict() for proj in self.projects.values()],
'last_updated': datetime.now().isoformat()
}
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"Error saving projects: {e}")
def add_project(self, name: str, path: str) -> Project:
"""Add new project"""
logger.info(f"Adding project: {name} at {path}")
# Check if project with same path already exists
for project in self.projects.values():
if project.path == path and project.id != "vps-permanent":
# Update existing project
project.name = name
project.update_last_accessed()
self.save_projects()
return project
# Create new project
project = Project(name, path)
self.projects[project.id] = project
self.save_projects()
return project
def remove_project(self, project_id: str) -> bool:
"""Remove project by ID"""
logger.info(f"Removing project with ID: {project_id}")
if project_id in self.projects and project_id not in ["vps-permanent", "admin-panel-permanent"]:
del self.projects[project_id]
self.save_projects()
return True
return False
def get_project(self, project_id: str) -> Optional[Project]:
"""Get project by ID"""
return self.projects.get(project_id)
def get_all_projects(self) -> List[Project]:
"""Get all projects sorted alphabetically by name"""
projects = list(self.projects.values())
# Sort alphabetically, but keep VPS projects first
vps = [p for p in projects if p.id == "vps-permanent"]
admin = [p for p in projects if p.id == "admin-panel-permanent"]
activity = [p for p in projects if p.id == "activity-server-permanent"]
others = [p for p in projects if p.id not in ["vps-permanent", "admin-panel-permanent", "activity-server-permanent"]]
others.sort(key=lambda p: p.name.lower()) # Sort alphabetically by name (case-insensitive)
return vps + admin + activity + others
def update_project(self, project_id: str, **kwargs):
"""Update project properties"""
project = self.get_project(project_id)
if project:
for key, value in kwargs.items():
if hasattr(project, key):
setattr(project, key, value)
self.save_projects()
def search_projects(self, query: str) -> List[Project]:
"""Search projects by name, path, or tags"""
query = query.lower()
results = []
for project in self.projects.values():
if (query in project.name.lower() or
query in project.path.lower() or
any(query in tag.lower() for tag in project.tags)):
results.append(project)
return results
# Test the module
if __name__ == "__main__":
# Create manager
manager = ProjectManager("test_projects.json")
# Add test projects
proj1 = manager.add_project("Test Project 1", "C:\\Users\\test\\project1")
proj2 = manager.add_project("Test Project 2", "C:\\Users\\test\\project2")
# List all projects
print("All projects:")
for project in manager.get_all_projects():
print(f"- {project.name} ({project.path})")
# Clean up test file
import os
if os.path.exists("test_projects.json"):
os.remove("test_projects.json")