resolve

package
v0.5.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package resolve turns a discovered session file into the project it belongs to. It peeks the file header for the working directory, then resolves that directory's git origin remote to a canonical project key. A folder with no usable git remote is standalone, and a folder that no longer exists on disk is orphaned. Operational Git failures are retried briefly and returned as errors if they persist, so they cannot be mistaken for definitive repository state or retained in the project cache. A file is skipped only when its header carries no recognizable session signature, so an arbitrary *.jsonl that merely shares the suffix (a tool-output log, an event feed) under a custom extra_root is rejected rather than ingested as a junk session.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type GitRunner

type GitRunner func(ctx context.Context, dir string, args ...string) (string, error)

GitRunner runs a git subcommand in dir and returns its trimmed stdout. The default shells out to the system git; tests inject their own.

type Header struct {
	Cwd       string
	GitBranch string
	SourceID  string
	// contains filtered or unexported fields
}

Header is the minimum the client reads from a session file before deciding where it belongs. The full parse is the server's job.

func PeekHeader

func PeekHeader(f discover.File) (Header, error)

PeekHeader reads only as much of the file as it needs to extract cwd, the git branch, and a stable, unique source session id for the file. The id has to be unique per file: the server keys sessions on (user, agent, source_session_id), so two files that share an id fold into one row and clobber each other. Codex and pi files are already one-id-per-file, but Claude records the same sessionId in a main session file and in every subagent and workflow file under it, so those need an id derived from the file's location, not just its in-file sessionId.

It also performs the positive session test: a file is a session only if at least one peeked line matches its agent's session signature. A parseable *.jsonl that never does (a tool-output log, an event feed under a custom extra_root) returns errNotSession so Resolve can skip it with a clear reason rather than upload it as a junk standalone/orphaned session.

Reading is Lstat-then-Open-then-verify rather than the simpler Stat-then-Open: discover.Discover already rejected a symlink at f.Path when it found the file, but a stat-and-open a moment later reopens a time-of-check-to-time-of-use window, since both Stat and Open follow a symlink. If f.Path was swapped for one in between (deliberately, or by an ordinary rename-based file replace racing the walk), a plain Stat+Open would silently read through it and upload whatever it points to. Lstat here rejects a symlink outright before ever opening it, and comparing the Lstat and the opened file's own Stat with os.SameFile closes the remaining gap: if the path was swapped for a different file of any kind between the two calls, the file identity no longer matches and the read is refused rather than silently served from the wrong file.

type Kind

type Kind string

Kind classifies how a session resolves to a project.

const (
	// KindRemote is a session whose working directory resolves to a canonical git
	// remote. ProjectKey holds that remote.
	KindRemote Kind = "remote"
	// KindStandalone is a session whose working directory exists but yields no
	// usable git remote: not a repository, no origin, multiple origin URLs, or an
	// unrecognized origin URL. It is backed up and keyed by its local location.
	KindStandalone Kind = "standalone"
	// KindOrphaned is a session whose working directory is unknown or no longer
	// exists on disk, so its remote can never be resolved. It is still backed up.
	KindOrphaned Kind = "orphaned"
)

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver resolves files to projects. Its bounded in-memory cache avoids repeat Git processes, invalidates direct repository config changes immediately, and caps the age of results that depend on other Git config sources.

func New

func New() *Resolver

New builds a Resolver with the default system-git runner and ssh alias map.

func NewWith

func NewWith(git GitRunner, aliases map[string]string) *Resolver

NewWith builds a Resolver with an explicit git runner and alias map, for tests.

func (*Resolver) Resolve

func (r *Resolver) Resolve(ctx context.Context, f discover.File) Result

Resolve peeks the file header and classifies the session. A session with a resolvable git remote is KindRemote; one whose folder exists but has no usable remote is KindStandalone; one whose folder is unknown or gone is KindOrphaned. All three are returned ready to upload. Header I/O failures and exhausted transient Git failures are returned in Result.Err; a readable non-session is the only skipped result.

type Result

type Result struct {
	File       discover.File
	Header     Header
	Kind       Kind
	ProjectKey string
	LocalRoot  string
	Skipped    bool
	Reason     string
	Err        error
}

Result is the outcome of resolving one file. Kind classifies the session; ProjectKey is the canonical remote only when Kind is KindRemote. Reason carries the human-readable detail behind a standalone or orphaned classification (and a positive non-session verdict). Skipped is true only when readable content is not a session for its declared agent. Err carries I/O and structural read failures so a backup command cannot silently count an unreadable session as a successful skip.

LocalRoot is set only for a standalone session whose folder is a live git worktree: it holds the main worktree shared by every worktree of the repo, so the server can collapse a local-only repo's worktrees into one project the same way a canonical remote collapses a remote-backed repo's. It is empty for remote sessions, for orphaned sessions (the worktree is gone, so git cannot report it), and for non-git standalone folders.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL