Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,13 @@ func (c *CLI) registerCommands() {
Run: c.repair,
}

c.rootCmd.Subcommands["refresh"] = &Command{
Name: "refresh",
Description: "Sync agent worktrees with main branch",
Usage: "multiclaude refresh",
Run: c.refresh,
}

// Claude restart command - for resuming Claude after exit
c.rootCmd.Subcommands["claude"] = &Command{
Name: "claude",
Expand Down Expand Up @@ -4877,6 +4884,34 @@ func (c *CLI) repair(args []string) error {
return nil
}

// refresh triggers an immediate worktree sync for all agents
func (c *CLI) refresh(args []string) error {
// Connect to daemon
client := socket.NewClient(c.paths.DaemonSock)
_, err := client.Send(socket.Request{Command: "ping"})
if err != nil {
return errors.DaemonNotRunning()
}

fmt.Println("Triggering worktree refresh...")

resp, err := client.Send(socket.Request{
Command: "trigger_refresh",
})
if err != nil {
return fmt.Errorf("failed to trigger refresh: %w", err)
}
if !resp.Success {
return fmt.Errorf("refresh failed: %s", resp.Error)
}

fmt.Println("✓ Worktree refresh triggered")
fmt.Println(" Agent worktrees will be synced with main branch in the background.")
fmt.Println(" Agents will receive a notification when their worktree is refreshed.")

return nil
}

// localRepair performs state repair without the daemon running
func (c *CLI) localRepair(verbose bool) error {
// Load state from disk
Expand Down
16 changes: 16 additions & 0 deletions internal/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,9 @@ func (d *Daemon) handleRequest(req socket.Request) socket.Response {
case "spawn_agent":
return d.handleSpawnAgent(req)

case "trigger_refresh":
return d.handleTriggerRefresh(req)

default:
return socket.Response{
Success: false,
Expand Down Expand Up @@ -1147,6 +1150,19 @@ func (d *Daemon) handleTriggerCleanup(req socket.Request) socket.Response {
}
}

// handleTriggerRefresh manually triggers worktree refresh for all agents
func (d *Daemon) handleTriggerRefresh(req socket.Request) socket.Response {
d.logger.Info("Manual worktree refresh triggered")

// Run refresh in background so we can return immediately
go d.refreshWorktrees()

return socket.Response{
Success: true,
Data: "Worktree refresh triggered",
}
}

// handleRepairState repairs state inconsistencies
func (d *Daemon) handleRepairState(req socket.Request) socket.Response {
d.logger.Info("State repair triggered")
Expand Down