feat(import): discover repo transcripts with one-month lookback · Entire
feat(import): discover repo transcripts with one-month lookback
b3021b4→main·
computermode·3w ago·2 files·+114 added/-0 removed
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Sessions
487abe46ddadView transcript
[?
Implement Claude History Import FeatureClaude Code·Opus 4.8·3 steps](/content/gh/entireio/cli/session/897809d4-ecab-4dc6-aa21-97661cb62607#timeline-487abe46ddad/index.html)
Changes
2
cmd/entire/cli/importclaude
Adiscover.go+59
Adiscover_test.go+55
package importclaude
import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"time"
"github.com/entireio/cli/cmd/entire/cli/agent/claudecode"
)
// LookbackDays bounds how far back import reaches. Fixed this pass (no --since).
const LookbackDays = 30
// DiscoverSessions returns absolute paths of Claude transcript files for the
// repo modified within the lookback window. overridePath replaces the default
// ~/.claude/projects/<slug> dir. sessionFilter, when non-empty, keeps only
// files whose stem (name without .jsonl) matches one of the entries.
func DiscoverSessions(repoRoot, overridePath string, now time.Time, sessionFilter []string) ([]string, error) {
dir := overridePath
if dir == "" {
ag := &claudecode.ClaudeCodeAgent{}
d, err := ag.GetSessionDir(repoRoot)
if err != nil {
return nil, fmt.Errorf("resolve claude session dir: %w", err)
}
dir = d
}
entries, err := os.ReadDir(dir)
if err != nil {
if os.IsNotExist(err) {
return nil, nil // no transcripts for this repo
}
return nil, fmt.Errorf("read claude session dir: %w", err)
}
cutoff := now.AddDate(0, 0, -LookbackDays)
var out []string
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".jsonl") {
continue
}
stem := strings.TrimSuffix(e.Name(), ".jsonl")
if len(sessionFilter) > 0 && !slices.Contains(sessionFilter, stem) {
continue
}
info, err := e.Info()
if err != nil {
continue
}
if info.ModTime().Before(cutoff) {
continue
}
out = append(out, filepath.Join(dir, e.Name()))
}
slices.Sort(out)
return out, nil
}
Acmd/entire/cli/importclaude/discover.go+59
package importclaude
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestDiscoverSessions_LookbackAndFilter(t *testing.T) {
t.Parallel()
dir := t.TempDir()
now := time.Date(2026, 6, 25, 12, 0, 0, 0, time.UTC)
writeAged := func(name string, age time.Duration) {
p := filepath.Join(dir, name)
if err := os.WriteFile(p, []byte("{}\n"), 0o644); err != nil {
t.Fatal(err)
}
mt := now.Add(-age)
if err := os.Chtimes(p, mt, mt); err != nil {
t.Fatal(err)
}
}
writeAged("recent.jsonl", 5*24*time.Hour)
writeAged("old.jsonl", 60*24*time.Hour)
writeAged("skip.txt", 1*time.Hour)
got, err := DiscoverSessions("", dir, now, nil)
if err != nil {
t.Fatal(err)
}
if len(got) != 1 || filepath.Base(got[0]) != "recent.jsonl" {
t.Fatalf("lookback filter wrong: %v", got)
}
writeAged("abc123.jsonl", 1*24*time.Hour)
got, err = DiscoverSessions("", dir, now, []string{"abc123"})
if err != nil {
t.Fatal(err)
}
if len(got) != 1 || filepath.Base(got[0]) != "abc123.jsonl" {
t.Fatalf("session filter wrong: %v", got)
}
}
func TestDiscoverSessions_MissingDirIsEmpty(t *testing.T) {
t.Parallel()
got, err := DiscoverSessions("", filepath.Join(t.TempDir(), "does-not-exist"), time.Now(), nil)
if err != nil {
t.Fatalf("missing dir should not error: %v", err)
}
if len(got) != 0 {
t.Fatalf("expected empty, got %v", got)
}
}
Acmd/entire/cli/importclaude/discover_test.go+55