@@ -760,22 +760,19 @@ func decodeCheckpointInfo(
760760 return & metadata , nil
761761}
762762
763- // GetMetadataBranchTree returns the tree object for the entire/checkpoints/v1 branch.
764- func GetMetadataBranchTree (repo * git.Repository ) (* object.Tree , error ) {
765- refName := plumbing .NewBranchReferenceName (paths .MetadataBranchName )
766- ref , err := repo .Reference (refName , true )
763+ // GetMetadataRefTree returns the tree object at the given committed-metadata ref.
764+ func GetMetadataRefTree (repo * git.Repository , ref plumbing.ReferenceName ) (* object.Tree , error ) {
765+ resolvedRef , err := repo .Reference (ref , true )
767766 if err != nil {
768- return nil , fmt .Errorf ("failed to get metadata branch reference : %w" , err )
767+ return nil , fmt .Errorf ("read ref %s : %w" , ref , err )
769768 }
770-
771- commit , err := repo .CommitObject (ref .Hash ())
769+ commit , err := repo .CommitObject (resolvedRef .Hash ())
772770 if err != nil {
773- return nil , fmt .Errorf ("failed to get metadata branch commit : %w" , err )
771+ return nil , fmt .Errorf ("read commit at %s : %w" , ref , err )
774772 }
775-
776773 tree , err := commit .Tree ()
777774 if err != nil {
778- return nil , fmt .Errorf ("failed to get metadata branch tree : %w" , err )
775+ return nil , fmt .Errorf ("read tree at %s : %w" , ref , err )
779776 }
780777 return tree , nil
781778}
@@ -942,28 +939,32 @@ func ReadLatestSessionPromptFromCommittedTree(tree *object.Tree, cpID id.Checkpo
942939
943940// ReadAllSessionPromptsFromTree reads the first prompt for all sessions in a multi-session checkpoint.
944941// Returns a slice of prompts parallel to sessionIDs (oldest to newest).
945- // For single-session checkpoints, returns a slice with just the root prompt.
942+ // For single-session checkpoints, returns a slice with just the session prompt.
946943func ReadAllSessionPromptsFromTree (tree * object.Tree , checkpointPath string , sessionCount int , sessionIDs []string ) []string {
947944 if sessionCount <= 1 || len (sessionIDs ) <= 1 {
948- // Single session - just return the root prompt
949- prompt := ReadSessionPromptFromTree (tree , checkpointPath )
945+ prompt := ReadSessionPromptFromTree (tree , checkpointPath + "/0" )
946+ if prompt == "" {
947+ prompt = ReadSessionPromptFromTree (tree , checkpointPath )
948+ }
950949 if prompt != "" {
951950 return []string {prompt }
952951 }
953952 return nil
954953 }
955954
956- // Multi-session: read prompts from archived folders (0/, 1/, etc.) and root
957955 prompts := make ([]string , len (sessionIDs ))
958956
959- // Read archived session prompts (folders 0, 1, ... N-2 )
960- for i := range sessionCount - 1 {
961- archivedPath := fmt .Sprintf ("%s/%d" , checkpointPath , i )
962- prompts [i ] = ReadSessionPromptFromTree (tree , archivedPath )
957+ sessionLimit := min ( sessionCount , len ( prompts ) )
958+ for i := range sessionLimit {
959+ sessionPath := fmt .Sprintf ("%s/%d" , checkpointPath , i )
960+ prompts [i ] = ReadSessionPromptFromTree (tree , sessionPath )
963961 }
964962
965- // Read the most recent session prompt (at root level)
966- prompts [len (prompts )- 1 ] = ReadSessionPromptFromTree (tree , checkpointPath )
963+ // Older committed metadata stored the latest prompt at the checkpoint root.
964+ latestIndex := sessionLimit - 1
965+ if latestIndex >= 0 && prompts [latestIndex ] == "" {
966+ prompts [latestIndex ] = ReadSessionPromptFromTree (tree , checkpointPath )
967+ }
967968
968969 return prompts
969970}
@@ -1549,73 +1550,6 @@ func collectUntrackedFiles(ctx context.Context) ([]string, error) {
15491550//
15501551// See push_common.go and session_test.go for usage examples.
15511552
1552- // getSessionDescriptionFromTree reads the first line of prompt.txt from a git tree.
1553- // This is the tree-based equivalent of getSessionDescription (which reads from filesystem).
1554- //
1555- // If metadataDir is provided, looks for files at metadataDir/prompt.txt.
1556- // If metadataDir is empty, first tries the root of the tree (for when the tree is already
1557- // the session directory), then falls back to
1558- // searching for .entire/metadata/*/prompt.txt (for full worktree trees).
1559- func getSessionDescriptionFromTree (tree * object.Tree , metadataDir string ) string {
1560- // Helper to read first line from a file in tree
1561- readFirstLine := func (path string ) string {
1562- file , err := tree .File (path )
1563- if err != nil {
1564- return ""
1565- }
1566- content , err := file .Contents ()
1567- if err != nil {
1568- return ""
1569- }
1570- lines := strings .SplitN (content , "\n " , 2 )
1571- if len (lines ) > 0 && lines [0 ] != "" {
1572- return strings .TrimSpace (lines [0 ])
1573- }
1574- return ""
1575- }
1576-
1577- // If metadataDir is provided, look there directly
1578- if metadataDir != "" {
1579- if desc := readFirstLine (metadataDir + "/" + paths .PromptFileName ); desc != "" {
1580- return desc
1581- }
1582- return NoDescription
1583- }
1584-
1585- // No metadataDir provided - first try looking at the root of the tree
1586- // (used when the tree is already the session directory)
1587- if desc := readFirstLine (paths .PromptFileName ); desc != "" {
1588- return desc
1589- }
1590-
1591- // Fall back to searching for .entire/metadata/*/prompt.txt
1592- // (used when the tree is the full worktree)
1593- var desc string
1594- //nolint:errcheck // We ignore errors here as we're just searching for a description
1595- _ = tree .Files ().ForEach (func (f * object.File ) error {
1596- if desc != "" {
1597- return nil // Already found description
1598- }
1599- name := f .Name
1600- if strings .Contains (name , ".entire/metadata/" ) && strings .HasSuffix (name , "/" + paths .PromptFileName ) {
1601- content , err := f .Contents ()
1602- if err != nil {
1603- return nil //nolint:nilerr // Skip files we can't read, continue searching
1604- }
1605- lines := strings .SplitN (content , "\n " , 2 )
1606- if len (lines ) > 0 && lines [0 ] != "" {
1607- desc = strings .TrimSpace (lines [0 ])
1608- }
1609- }
1610- return nil
1611- })
1612-
1613- if desc != "" {
1614- return desc
1615- }
1616- return NoDescription
1617- }
1618-
16191553// GetGitAuthorFromRepo retrieves the git user.name and user.email,
16201554// checking both the repository-local config and the global ~/.gitconfig.
16211555// Delegates to checkpoint.GetGitAuthorFromRepo — this wrapper exists so
0 commit comments