feat: Add remote sync for project clones
Fetch remote changes before agents start working so they build on up-to-date code. Adds ProjectSyncManager with git fetch + ff-only merge of defaultBranch, integrated into phase dispatch to sync before branch creation. - Schema: lastFetchedAt column on projects table (migration 0029) - Events: project:synced, project:sync_failed - Phase dispatch: sync all linked projects before creating branches - tRPC: syncProject, syncAllProjects, getProjectSyncStatus - CLI: cw project sync [name] --all, cw project status [name] - Frontend: sync button + ahead/behind badge on projects settings
This commit is contained in:
@@ -53,8 +53,27 @@ Worktrees stored in `.cw-worktrees/` subdirectory of the repo. Each agent gets a
|
||||
- `ensureProjectClone(project, workspaceRoot)` — Idempotent: checks if clone exists, clones if not
|
||||
- `getProjectCloneDir(name, id)` — Canonical path: `repos/<sanitized-name>-<id>/`
|
||||
|
||||
### ProjectSyncManager (`apps/server/git/remote-sync.ts`)
|
||||
|
||||
Fetches remote changes for project clones and fast-forwards the local `defaultBranch`. Safe to run with active worktrees — only updates remote-tracking refs and the base branch (never checked out directly by any worktree).
|
||||
|
||||
**Constructor**: `ProjectSyncManager(projectRepository, workspaceRoot, eventBus?)`
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `syncProject(projectId)` | `git fetch origin` + `git merge --ff-only origin/<defaultBranch>`, updates `lastFetchedAt` |
|
||||
| `syncAllProjects()` | Sync all registered projects sequentially |
|
||||
| `getSyncStatus(projectId)` | Returns `{ ahead, behind, lastFetchedAt }` via `rev-list --left-right --count` |
|
||||
| `getInitiativeDivergence(projectId, branch)` | Ahead/behind between `defaultBranch` and an initiative branch |
|
||||
|
||||
**Sync flow during phase dispatch**: `dispatchNextPhase()` syncs all linked project clones *before* creating initiative/phase branches, so branches fork from up-to-date remote state. Sync is best-effort — failures are logged but don't block dispatch.
|
||||
|
||||
**CLI**: `cw project sync [name] --all`, `cw project status [name]`
|
||||
|
||||
**tRPC**: `syncProject`, `syncAllProjects`, `getProjectSyncStatus`
|
||||
|
||||
### Events Emitted
|
||||
`worktree:created`, `worktree:removed`, `worktree:merged`, `worktree:conflict`
|
||||
`worktree:created`, `worktree:removed`, `worktree:merged`, `worktree:conflict`, `project:synced`, `project:sync_failed`
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user