veza/scripts/sync-cursor.py

301 lines
9.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Script de synchronisation pour Cursor AI
Génère automatiquement le contexte et les prompts optimisés
"""
import json
import yaml
import os
from pathlib import Path
from datetime import datetime
import subprocess
import sys
class CursorSync:
def __init__(self):
self.project_root = Path.cwd()
self.cursor_config = self.project_root / ".cursor"
self.veza_config = self.project_root / ".veza"
def load_architecture(self):
"""Charge les informations d'architecture"""
try:
with open(self.project_root / "docs/arch/current.mmd", "r") as f:
return {
"type": "mermaid",
"content": f.read()
}
except FileNotFoundError:
return {
"type": "hexagonal",
"description": "Architecture hexagonale avec core backend et features modulaires"
}
def scan_features(self):
"""Scanne toutes les features du projet"""
features = {}
# Core backend
if (self.project_root / "veza-backend-api").exists():
features["core"] = {
"status": "stable",
"version": "1.0.0",
"location": "veza-backend-api/",
"language": "go"
}
# Chat server
if (self.project_root / "veza-chat-server").exists():
features["chat-server"] = {
"status": "stable",
"version": "1.0.0",
"location": "veza-chat-server/",
"language": "rust"
}
# Stream server
if (self.project_root / "veza-stream-server").exists():
features["stream-server"] = {
"status": "stable",
"version": "1.0.0",
"location": "veza-stream-server/",
"language": "rust"
}
# Documentation
if (self.project_root / "veza-docs").exists():
features["docs"] = {
"status": "stable",
"version": "1.0.0",
"location": "veza-docs/",
"language": "javascript"
}
return features
def load_contracts(self):
"""Charge les contrats d'interface"""
contracts = {}
contracts_dir = self.project_root / "veza-backend-api/internal/core/contracts"
if contracts_dir.exists():
for contract_file in contracts_dir.glob("*.go"):
contracts[contract_file.stem] = {
"file": str(contract_file.relative_to(self.project_root)),
"type": "interface"
}
return contracts
def analyze_dependencies(self):
"""Analyse les dépendances du projet"""
dependencies = {}
# Go dependencies
go_mod = self.project_root / "veza-backend-api/go.mod"
if go_mod.exists():
dependencies["go"] = {
"file": "veza-backend-api/go.mod",
"framework": "gin"
}
# Rust dependencies
for rust_project in ["veza-chat-server", "veza-stream-server"]:
cargo_toml = self.project_root / rust_project / "Cargo.toml"
if cargo_toml.exists():
dependencies[rust_project] = {
"file": f"{rust_project}/Cargo.toml",
"language": "rust"
}
return dependencies
def load_tasks(self):
"""Charge les tâches en cours"""
tasks = []
# Vérifier s'il y a des branches en cours
try:
result = subprocess.run(
["git", "branch", "--show-current"],
capture_output=True,
text=True,
cwd=self.project_root
)
if result.returncode == 0:
current_branch = result.stdout.strip()
if current_branch != "main" and current_branch != "develop":
tasks.append({
"type": "feature_development",
"name": f"Working on branch: {current_branch}",
"status": "in_progress"
})
except:
pass
return tasks
def load_validation_rules(self):
"""Charge les règles de validation"""
return [
"version_compatibility",
"interface_contracts",
"event_consistency",
"commit_format",
"test_coverage"
]
def generate_context_file(self):
"""Génère un fichier de contexte pour Cursor AI"""
context = {
"project": "Veza",
"architecture": self.load_architecture(),
"features": self.scan_features(),
"contracts": self.load_contracts(),
"dependencies": self.analyze_dependencies(),
"current_tasks": self.load_tasks(),
"validation_rules": self.load_validation_rules(),
"last_updated": datetime.now().isoformat()
}
self.cursor_config.mkdir(exist_ok=True)
with open(self.cursor_config / "context.json", "w") as f:
json.dump(context, f, indent=2)
print(f"✅ Context file generated: {self.cursor_config / 'context.json'}")
def create_implementation_prompt(self):
"""Crée un prompt optimisé pour l'implémentation"""
return """
En tant qu'assistant Cursor AI pour le projet Veza:
1. TOUJOURS vérifier la compatibilité avec le core avant d'implémenter
2. RESPECTER les contrats définis dans internal/core/contracts/
3. SUIVRE la structure modulaire dans features/
4. UTILISER les types et interfaces du core
5. GÉNÉRER les tests en parallèle de l'implémentation
6. DOCUMENTER chaque fonction publique
7. VALIDER avec le script check-compatibility.sh
8. SUIVRE le format de commit: [SCOPE][TYPE] Description
Contexte actuel: {context}
Feature en cours: {current_feature}
Dépendances: {dependencies}
Architecture: Hexagonale avec core immutable
Patterns: Repository, Service, Handler
Validation: Tests unitaires + intégration obligatoires
"""
def create_testing_prompt(self):
"""Crée un prompt optimisé pour les tests"""
return """
Pour les tests dans Veza:
1. TOUJOURS tester les contrats d'interface
2. COUVRIR les cas d'erreur et edge cases
3. UTILISER testify pour Go, built-in pour Rust
4. MOCKER les dépendances externes
5. TESTER l'intégration entre features
6. VALIDER la compatibilité des versions
Scope: {scope}
Feature: {feature}
Framework: {framework}
"""
def create_compatibility_prompt(self):
"""Crée un prompt pour la vérification de compatibilité"""
return """
Vérification de compatibilité Veza:
1. VÉRIFIER les versions des dépendances
2. CONTRÔLER les interfaces exposées
3. VALIDER les événements publiés/souscrits
4. TESTER l'intégration entre modules
5. DOCUMENTER les changements breaking
Features: {features}
Contracts: {contracts}
Events: {events}
"""
def create_documentation_prompt(self):
"""Crée un prompt pour la documentation"""
return """
Documentation Veza:
1. DOCUMENTER toutes les interfaces publiques
2. EXPLIQUER les patterns d'architecture
3. FOURNIR des exemples d'utilisation
4. MAINTENIR la cohérence avec l'architecture
5. METTRE À JOUR les diagrammes si nécessaire
Type: {doc_type}
Scope: {scope}
Format: Markdown
"""
def generate_prompts(self):
"""Génère des prompts optimisés pour Cursor"""
prompts = {
"implementation": self.create_implementation_prompt(),
"testing": self.create_testing_prompt(),
"compatibility": self.create_compatibility_prompt(),
"documentation": self.create_documentation_prompt()
}
self.cursor_config.mkdir(exist_ok=True)
with open(self.cursor_config / "prompts.yaml", "w") as f:
yaml.dump(prompts, f, default_flow_style=False)
print(f"✅ Prompts generated: {self.cursor_config / 'prompts.yaml'}")
def update_manifest(self):
"""Met à jour le manifeste des features"""
if not self.veza_config.exists():
self.veza_config.mkdir(exist_ok=True)
manifest_file = self.veza_config / "feature-manifest.yaml"
if not manifest_file.exists():
# Créer un manifeste de base
base_manifest = {
"version": "1.0.0",
"last_updated": datetime.now().isoformat(),
"features": self.scan_features(),
"compatibility_matrix": {},
"validation_rules": self.load_validation_rules()
}
with open(manifest_file, "w") as f:
yaml.dump(base_manifest, f, default_flow_style=False)
print(f"✅ Base manifest created: {manifest_file}")
else:
print(f" Manifest already exists: {manifest_file}")
def sync_all(self):
"""Synchronise tout le contexte Cursor"""
print("🔄 Synchronizing Cursor AI context...")
self.generate_context_file()
self.generate_prompts()
self.update_manifest()
print("✅ Cursor AI synchronization completed!")
def main():
"""Fonction principale"""
try:
sync = CursorSync()
sync.sync_all()
except Exception as e:
print(f"❌ Error during synchronization: {e}")
sys.exit(1)
if __name__ == "__main__":
main()