feat: Add PR creation via gh CLI and improve git operations (#57)

This commit is contained in:
João Salavisa
2026-01-20 02:33:58 +00:00
committed by GitHub
parent 6ec8b31e6b
commit 086c7c4bac
17 changed files with 2225 additions and 107 deletions
+164
View File
@@ -0,0 +1,164 @@
# Git Operations for Worktrees
This document describes the architecture for Git operations (Pull, Push, Rebase, Merge) on worktrees in Kandev.
## Overview
Git operations are executed **in agentctl**, not in the backend. This ensures consistent behavior whether running locally or in Docker/remote environments. The backend acts as a proxy, forwarding requests from the frontend WebSocket to agentctl's HTTP API.
## Supported Operations
| Operation | Direction | Description |
|-----------|-----------|-------------|
| **Pull** | Remote → Worktree | Fetch and merge changes from remote for the worktree's branch |
| **Push** | Worktree → Remote | Push local commits to remote |
| **Rebase** | Base → Worktree | Rebase worktree branch onto base branch (rewrites history) |
| **Merge** | Base → Worktree | Merge base branch into worktree branch (creates merge commit) |
| **Abort** | — | Abort an in-progress merge or rebase |
## Architecture
### Request Flow
```
Frontend UI (Git Actions Dropdown)
│
▼
WebSocket Client
│ worktree.pull / worktree.push / worktree.rebase / worktree.merge
▼
Backend WebSocket Gateway
│
▼
Git Handlers (internal/agent/handlers/git_handlers.go)
│ GetExecutionBySessionID(sessionID)
▼
Lifecycle Manager → AgentExecution → agentctl.Client
│
│ HTTP POST /api/v1/git/<operation>
▼
agentctl HTTP API (server/api/git.go)
│
▼
Git Command Execution (server/process/git.go)
│ exec.Command("git", ...) in worktree directory
▼
HTTP Response → Backend Handler → WebSocket Response → Frontend
```
### Notification Flow (Git Status Updates)
After any git operation, the workspace state changes. Updates flow through the event bus:
```
agentctl WorkspaceTracker (detects git status change)
│ workspace stream: git_status message
▼
Backend StreamManager (OnGitStatus callback)
│
▼
EventPublisher.PublishGitStatus()
│
▼
Event Bus
│
▼
TaskNotificationBridge
│
▼
Hub.BroadcastToSession(sessionID)
│
▼
Frontend WebSocket → Zustand Store update
```
## agentctl API
### Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/v1/git/pull` | Pull from remote |
| POST | `/api/v1/git/push` | Push to remote |
| POST | `/api/v1/git/rebase` | Rebase onto base branch |
| POST | `/api/v1/git/merge` | Merge base branch in |
| POST | `/api/v1/git/abort` | Abort merge/rebase |
### Request/Response Format
**Pull Request:**
```json
{ "rebase": false }
```
**Push Request:**
```json
{ "force": false, "set_upstream": true }
```
**Rebase/Merge Request:**
```json
{ "base_branch": "main" }
```
**Abort Request:**
```json
{ "operation": "merge" }
```
**Response (all operations):**
```json
{
"success": true,
"operation": "pull",
"output": "Already up to date.",
"error": null,
"conflict_files": []
}
```
## Locking
A per-instance mutex in agentctl prevents concurrent git operations on the same worktree. If an operation is already running, new requests return HTTP 409 Conflict.
## Conflict Handling
- **Rebase conflicts**: Automatically aborted (`git rebase --abort`), conflict files returned
- **Merge conflicts**: Left in place for user/agent resolution, conflict files returned
- **Abort endpoint**: Allows manual abort of conflicted merge/rebase
## Frontend Integration
### WebSocket Actions
- `worktree.pull` - Pull from remote
- `worktree.push` - Push to remote
- `worktree.rebase` - Rebase onto base
- `worktree.merge` - Merge base branch
- `worktree.abort` - Abort operation
### Hook Usage
```typescript
const { pull, push, rebase, merge, isLoading, error } = useGitOperations(sessionId);
// In component
<Button onClick={() => pull()} disabled={isLoading}>Pull</Button>
```
## Files
### agentctl
- `server/api/git.go` - HTTP handlers
- `server/process/git.go` - Git command execution
- `client/git.go` - Client methods
### Backend
- `internal/agent/handlers/git_handlers.go` - WebSocket handlers
- `pkg/websocket/actions.go` - Action constants
### Frontend
- `lib/types/backend.ts` - TypeScript types
- `lib/ws/actions/git.ts` - WebSocket action functions
- `lib/hooks/useGitOperations.ts` - React hook