From 695474282d1375f7ecd915ace92f838ca868eece Mon Sep 17 00:00:00 2001 From: Ashesh Goplani Date: Mon, 30 Mar 2026 18:32:25 +0800 Subject: [PATCH] fix: preserve group sort_order when saving session data saveSessionData() used NewGroupTree() which reconstructs groups from scratch, losing stored sort_order values. Changed to accept stored group data and use NewGroupTreeWithGroups() to preserve ordering. Fixes #464 Committed by Ashesh Goplani --- cmd/agent-deck/launch_cmd.go | 2 +- cmd/agent-deck/session_cmd.go | 19 +++++++++---------- cmd/agent-deck/try_cmd.go | 8 ++++---- cmd/agent-deck/worktree_cmd.go | 10 +++++----- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/cmd/agent-deck/launch_cmd.go b/cmd/agent-deck/launch_cmd.go index d0aa10fa2..6132d90b2 100644 --- a/cmd/agent-deck/launch_cmd.go +++ b/cmd/agent-deck/launch_cmd.go @@ -341,7 +341,7 @@ func handleLaunch(profile string, args []string) { newInstance.PostStartSync(3 * time.Second) // Save again with updated state (session ID, tmux name) - if err := saveSessionData(storage, instances); err != nil { + if err := saveSessionData(storage, instances, groups); err != nil { out.Error(fmt.Sprintf("failed to save session state: %v", err), ErrCodeInvalidOperation) os.Exit(1) } diff --git a/cmd/agent-deck/session_cmd.go b/cmd/agent-deck/session_cmd.go index 90b7e209f..6c93214bd 100644 --- a/cmd/agent-deck/session_cmd.go +++ b/cmd/agent-deck/session_cmd.go @@ -150,7 +150,7 @@ func handleSessionStart(profile string, args []string) { initialMessage := mergeFlags(*message, *messageShort) // Load sessions - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(err.Error(), ErrCodeNotFound) os.Exit(1) @@ -196,7 +196,7 @@ func handleSessionStart(profile string, args []string) { inst.PostStartSync(3 * time.Second) // Save updated state - if err := saveSessionData(storage, instances); err != nil { + if err := saveSessionData(storage, instances, groups); err != nil { out.Error(fmt.Sprintf("failed to save session state: %v", err), ErrCodeInvalidOperation) os.Exit(1) } @@ -247,7 +247,7 @@ func handleSessionStop(profile string, args []string) { out := NewCLIOutput(*jsonOutput, quietMode) // Load sessions - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(err.Error(), ErrCodeNotFound) os.Exit(1) @@ -283,7 +283,7 @@ func handleSessionStop(profile string, args []string) { } // Save updated state - if err := saveSessionData(storage, instances); err != nil { + if err := saveSessionData(storage, instances, groups); err != nil { out.Error(fmt.Sprintf("failed to save session state: %v", err), ErrCodeInvalidOperation) os.Exit(1) } @@ -321,7 +321,7 @@ func handleSessionRestart(profile string, args []string) { out := NewCLIOutput(*jsonOutput, quietMode) // Load sessions - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(err.Error(), ErrCodeNotFound) os.Exit(1) @@ -354,7 +354,7 @@ func handleSessionRestart(profile string, args []string) { } // Save updated state - if err := saveSessionData(storage, instances); err != nil { + if err := saveSessionData(storage, instances, groups); err != nil { out.Error(fmt.Sprintf("failed to save session state: %v", err), ErrCodeInvalidOperation) os.Exit(1) } @@ -982,10 +982,9 @@ func loadSessionData(profile string) (*session.Storage, []*session.Instance, []* return storage, instances, groupsData, nil } -// saveSessionData saves session data with groups -func saveSessionData(storage *session.Storage, instances []*session.Instance) error { - // Rebuild group tree from instances - groupTree := session.NewGroupTree(instances) +// saveSessionData saves session data with groups, preserving stored group metadata (sort_order). +func saveSessionData(storage *session.Storage, instances []*session.Instance, groups []*session.GroupData) error { + groupTree := session.NewGroupTreeWithGroups(instances, groups) return storage.SaveWithGroups(instances, groupTree) } diff --git a/cmd/agent-deck/try_cmd.go b/cmd/agent-deck/try_cmd.go index 3ce6f55d0..ae2d2c240 100644 --- a/cmd/agent-deck/try_cmd.go +++ b/cmd/agent-deck/try_cmd.go @@ -110,7 +110,7 @@ func handleTry(profile string, args []string) { } // Create and start session - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(err.Error(), ErrCodeInvalidOperation) os.Exit(1) @@ -127,7 +127,7 @@ func handleTry(profile string, args []string) { } inst.PostStartSync(3 * time.Second) // Save updated state with session ID - _ = saveSessionData(storage, instances) + _ = saveSessionData(storage, instances, groups) } out.Print( fmt.Sprintf("Session: %s (%s)\nPath: %s\n", inst.Title, inst.ID[:8], exp.Path), @@ -156,7 +156,7 @@ func handleTry(profile string, args []string) { instances = append(instances, newInst) // Save using helper (rebuilds group tree including "experiments" group from instance) - if err := saveSessionData(storage, instances); err != nil { + if err := saveSessionData(storage, instances, groups); err != nil { out.Error(err.Error(), ErrCodeInvalidOperation) os.Exit(1) } @@ -169,7 +169,7 @@ func handleTry(profile string, args []string) { // Capture session ID and re-save (first save at line above was before Start) newInst.PostStartSync(3 * time.Second) - _ = saveSessionData(storage, instances) + _ = saveSessionData(storage, instances, groups) action := "Created" if !created { diff --git a/cmd/agent-deck/worktree_cmd.go b/cmd/agent-deck/worktree_cmd.go index f2c6b9e22..824da6971 100644 --- a/cmd/agent-deck/worktree_cmd.go +++ b/cmd/agent-deck/worktree_cmd.go @@ -304,7 +304,7 @@ func handleWorktreeCleanup(profile string, args []string) { out := NewCLIOutput(*jsonOutput, false) // Load sessions - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(fmt.Sprintf("failed to load sessions: %v", err), ErrCodeNotFound) os.Exit(1) @@ -459,8 +459,8 @@ func handleWorktreeCleanup(profile string, args []string) { } } - // Save updated session data (uses existing saveSessionData which rebuilds GroupTree) - if err := saveSessionData(storage, remaining); err != nil { + // Save updated session data + if err := saveSessionData(storage, remaining, groups); err != nil { out.Error(fmt.Sprintf("failed to save session data: %v", err), ErrCodeInvalidOperation) os.Exit(1) } @@ -523,7 +523,7 @@ func handleWorktreeFinish(profile string, args []string) { } // Load sessions - storage, instances, _, err := loadSessionData(profile) + storage, instances, groups, err := loadSessionData(profile) if err != nil { out.Error(fmt.Sprintf("failed to load sessions: %v", err), ErrCodeInvalidOperation) os.Exit(1) @@ -668,7 +668,7 @@ func handleWorktreeFinish(profile string, args []string) { remaining = append(remaining, i) } } - if err := saveSessionData(storage, remaining); err != nil { + if err := saveSessionData(storage, remaining, groups); err != nil { out.Error(fmt.Sprintf("failed to save session data: %v", err), ErrCodeInvalidOperation) os.Exit(1) }