# Merge pull request #1699 from entireio/feat/imported-sessions-in-session-list

```
62a79dc→main·

computermode·1w ago·15 files·+609 added/-7 removed

feat(import): show imported sessions in `entire session list`
```

## Changes

15

- cmd/entire/cli
  
    - agent/types
  
      - Mtoken_usage.go+29
  
      - Atoken_usage_test.go+32

- agentimport
  
      - Magentimport.go+75
  
      - Asession_state_test.go+231

- Mresume_picker.go+20
  
    - Mresume_picker_test.go+34

- session
  
      - Aprompt.go+15
  
      - Mstate.go+17
  
      - Mstate_test.go+14

- Msessions.go+12/-1
    - Msessions_test.go+42

- strategy
  
      - Mcleanup.go+6
  
      - Aimported_session_test.go+70
  
      - Mmanual_commit_session.go+9
  
      - Mmanual_commit_types.go+3/-6

```
    15 unmodified lines
    ```

// SubagentTokens contains token usage from spawned subagents (if any)
	SubagentTokens *TokenUsage `json:"subagent_tokens,omitempty"`
	}

// AddTokenUsage returns the sum of a and b, recursing into subagent usage.
	// Either operand may be nil (treated as zero); the result is nil only when both
	// are. Neither input is mutated.
	func AddTokenUsage(a, b *TokenUsage) *TokenUsage {
		if a == nil && b == nil {
			return nil
		}
		sum := &TokenUsage{}
		var aSub, bSub *TokenUsage
		if a != nil {
			sum.InputTokens = a.InputTokens
			sum.CacheCreationTokens = a.CacheCreationTokens
			sum.CacheReadTokens = a.CacheReadTokens
			sum.OutputTokens = a.OutputTokens
			sum.APICallCount = a.APICallCount
			aSub = a.SubagentTokens
		}
		if b != nil {
			sum.InputTokens += b.InputTokens
			sum.CacheCreationTokens += b.CacheCreationTokens
			sum.CacheReadTokens += b.CacheReadTokens
			sum.OutputTokens += b.OutputTokens
			sum.APICallCount += b.APICallCount
			bSub = b.SubagentTokens
		}
		sum.SubagentTokens = AddTokenUsage(aSub, bSub)
		return sum
	}
	```

```go
package types

import "testing"

func TestAddTokenUsage(t *testing.T) {
	t.Parallel()

if got := AddTokenUsage(nil, nil); got != nil {
		t.Errorf("AddTokenUsage(nil, nil) = %+v, want nil", got)
	}

only := &TokenUsage{InputTokens: 3}
	if got := AddTokenUsage(nil, only); got == nil || got.InputTokens != 3 {
		t.Errorf("AddTokenUsage(nil, x) = %+v, want a copy of x", got)
	}
	if got := AddTokenUsage(only, nil); got == only {
		t.Error("AddTokenUsage must not return an input pointer (would alias caller state)")
	}

a := &TokenUsage{InputTokens: 1, OutputTokens: 2, APICallCount: 1, SubagentTokens: &TokenUsage{InputTokens: 10}}
	b := &TokenUsage{InputTokens: 4, OutputTokens: 5, APICallCount: 2, SubagentTokens: &TokenUsage{InputTokens: 20}}
	got := AddTokenUsage(a, b)
	if got.InputTokens != 5 || got.OutputTokens != 7 || got.APICallCount != 3 {
		t.Errorf("top-level sum = %+v", got)
	}
	if got.SubagentTokens == nil || got.SubagentTokens.InputTokens != 30 {
		t.Errorf("subagent sum = %+v, want InputTokens 30", got.SubagentTokens)
	}
	if a.InputTokens != 1 || a.SubagentTokens.InputTokens != 10 {
		t.Error("AddTokenUsage mutated an input")
	}
}
```

```go
package agentimport

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"
	"unicode/utf8"
	
	"github.com/go-git/go-git/v6"
	
	"github.com/entireio/cli/cmd/entire/cli/agent"
	"github.com/entireio/cli/cmd/entire/cli/agent/types"
	"github.com/entireio/cli/cmd/entire/cli/session"
	"github.com/entireio/cli/cmd/entire/cli/strategy"
	"github.com/entireio/cli/cmd/entire/cli/testutil"
)

// fakeImporter is the minimal Importer needed to exercise writeSessionState.
type fakeImporter struct{}

func (fakeImporter) Name() string               { return string(agent.AgentNameClaudeCode) }
func (fakeImporter) AgentType() types.AgentType { return agent.AgentTypeClaudeCode }
func (fakeImporter) Discover(_, _ string, _ time.Time, _ []string) ([]SessionFile, error) {
	return nil, nil
}
func (fakeImporter) SplitTurns(_ SessionFile, _ []byte) ([]Turn, error) { return nil, nil }
```

```go
const (
	// logsOnlyScanLimit is the maximum number of commits to scan for logs-only points.
	logsOnlyScanLimit = 50

// maxLastPromptRunes is the maximum rune length for LastPrompt stored in session state.
	maxLastPromptRunes = 100
)

// truncatePromptForStorage collapses whitespace and truncates a user prompt
// for storage in LastPrompt. It delegates to session.TruncatePromptForStorage
// so imports and live sessions format the field identically.
func truncatePromptForStorage(prompt string) string {
	return stringutil.TruncateRunes(stringutil.CollapseWhitespace(prompt), maxLastPromptRunes, "...")
}
```
