|
8 | 8 |
|
9 | 9 | from pygls import uris |
10 | 10 |
|
| 11 | +from codeflash.code_utils.git_utils import create_git_worktrees, create_worktree_root_dir, remove_git_worktrees |
11 | 12 | from codeflash.either import is_successful |
12 | 13 | from codeflash.lsp.server import CodeflashLanguageServer, CodeflashLanguageServerProtocol |
13 | 14 |
|
@@ -292,3 +293,116 @@ def perform_function_optimization( # noqa: PLR0911 |
292 | 293 | "extra": f"Speedup: {speedup:.2f}x faster", |
293 | 294 | "optimization": optimized_source, |
294 | 295 | } |
| 296 | + |
| 297 | + |
| 298 | +@dataclass |
| 299 | +class WorktreeParams: |
| 300 | + functionName: str # noqa: N815 |
| 301 | + candidateId: str # noqa: N815 |
| 302 | + gitRoot: str # noqa: N815 |
| 303 | + |
| 304 | + |
| 305 | +@server.feature("codeflash/createWorktree") |
| 306 | +def create_worktree(server: CodeflashLanguageServer, params: WorktreeParams) -> dict[str, str]: |
| 307 | + """Create git worktrees for optimization suggestions using CLI's existing infrastructure.""" |
| 308 | + server.show_message_log( |
| 309 | + f"Creating worktree for function: {params.functionName}, candidate: {params.candidateId}", "Info" |
| 310 | + ) |
| 311 | + |
| 312 | + try: |
| 313 | + module_root = Path(params.gitRoot) |
| 314 | + |
| 315 | + # Create worktree root directory |
| 316 | + git_root, worktree_root_dir = create_worktree_root_dir(module_root) |
| 317 | + |
| 318 | + if not git_root or not worktree_root_dir: |
| 319 | + server.show_message_log("Not in a git repository, worktree creation skipped", "Warning") |
| 320 | + return { |
| 321 | + "functionName": params.functionName, |
| 322 | + "candidateId": params.candidateId, |
| 323 | + "status": "error", |
| 324 | + "message": "Not in a git repository", |
| 325 | + } |
| 326 | + |
| 327 | + # Create git worktrees (creates N_CANDIDATES + 1 worktrees) |
| 328 | + worktree_root, worktrees = create_git_worktrees(git_root, worktree_root_dir, module_root) |
| 329 | + |
| 330 | + if not worktrees: |
| 331 | + server.show_message_log("Failed to create git worktrees", "Error") |
| 332 | + return { |
| 333 | + "functionName": params.functionName, |
| 334 | + "candidateId": params.candidateId, |
| 335 | + "status": "error", |
| 336 | + "message": "Failed to create git worktrees", |
| 337 | + } |
| 338 | + |
| 339 | + # Store worktree info for later cleanup (use public attribute instead of private) |
| 340 | + if not hasattr(server, "worktree_registry"): |
| 341 | + server.worktree_registry = {} |
| 342 | + |
| 343 | + server.worktree_registry[params.candidateId] = { |
| 344 | + "worktree_root": worktree_root, |
| 345 | + "worktrees": worktrees, |
| 346 | + "function_name": params.functionName, |
| 347 | + } |
| 348 | + |
| 349 | + # For now, return the first worktree (original) - in a full implementation, |
| 350 | + # you'd assign specific worktrees to specific optimization candidates |
| 351 | + primary_worktree_path = str(worktrees[0]) if worktrees else str(worktree_root) |
| 352 | + |
| 353 | + server.show_message_log( |
| 354 | + f"Successfully created worktrees for {params.functionName}, primary at: {primary_worktree_path}", "Info" |
| 355 | + ) |
| 356 | + |
| 357 | + return { |
| 358 | + "functionName": params.functionName, |
| 359 | + "candidateId": params.candidateId, |
| 360 | + "status": "success", |
| 361 | + "worktreePath": primary_worktree_path, |
| 362 | + "message": f"Created {len(worktrees)} worktrees", |
| 363 | + } |
| 364 | + |
| 365 | + except Exception as e: |
| 366 | + server.show_message_log(f"Error creating worktree: {e!s}", "Error") |
| 367 | + return { |
| 368 | + "functionName": params.functionName, |
| 369 | + "candidateId": params.candidateId, |
| 370 | + "status": "error", |
| 371 | + "message": f"Error creating worktree: {e!s}", |
| 372 | + } |
| 373 | + |
| 374 | + |
| 375 | +@server.feature("codeflash/removeWorktree") |
| 376 | +def remove_worktree(server: CodeflashLanguageServer, params: WorktreeParams) -> dict[str, str]: |
| 377 | + """Remove git worktrees for a specific optimization candidate.""" |
| 378 | + server.show_message_log(f"Removing worktree for candidate: {params.candidateId}", "Info") |
| 379 | + |
| 380 | + if not hasattr(server, "worktree_registry") or params.candidateId not in server.worktree_registry: |
| 381 | + server.show_message_log(f"No worktree found for candidate: {params.candidateId}", "Warning") |
| 382 | + return {"candidateId": params.candidateId, "status": "warning", "message": "No worktree found for candidate"} |
| 383 | + |
| 384 | + try: |
| 385 | + worktree_info = server.worktree_registry[params.candidateId] |
| 386 | + worktree_root = worktree_info["worktree_root"] |
| 387 | + worktrees = worktree_info["worktrees"] |
| 388 | + function_name = worktree_info["function_name"] |
| 389 | + |
| 390 | + # Use CLI's existing cleanup function |
| 391 | + remove_git_worktrees(worktree_root, worktrees) |
| 392 | + |
| 393 | + # Remove from registry |
| 394 | + del server.worktree_registry[params.candidateId] |
| 395 | + |
| 396 | + server.show_message_log( |
| 397 | + f"Successfully removed worktrees for {function_name} (candidate: {params.candidateId})", "Info" |
| 398 | + ) |
| 399 | + |
| 400 | + except Exception as e: |
| 401 | + server.show_message_log(f"Error removing worktree: {e!s}", "Error") |
| 402 | + return {"candidateId": params.candidateId, "status": "error", "message": f"Error removing worktree: {e!s}"} |
| 403 | + else: |
| 404 | + return { |
| 405 | + "candidateId": params.candidateId, |
| 406 | + "status": "success", |
| 407 | + "message": f"Successfully removed worktrees for {function_name}", |
| 408 | + } |
0 commit comments