migrate

package
v0.1.0-dev.20260217073406 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Execute

func Execute(graph *execution.Graph, analysis *MigrationAnalysis) error

Execute performs the directory renames specified in the execution graph. It writes progress to stderr using standard cli output functions.

func FormatMigrationExplain

func FormatMigrationExplain(ctx context.Context, w io.Writer, analysis *MigrationAnalysis, provider model.Provider) error

FormatMigrationExplain uses AI to generate a natural language explanation of the migration analysis. This provides a conversational summary that highlights key findings and actionable recommendations.

func FormatMigrationPlan

func FormatMigrationPlan(w io.Writer, graph *execution.Graph, analysis *MigrationAnalysis, format string) error

FormatMigrationPlan renders the execution Graph and MigrationAnalysis as human-readable output.

Supported formats: "text" (default), "yaml", "json" For "explain" format, use FormatMigrationExplain which requires an AI provider.

func WriteMigratedMarker

func WriteMigratedMarker(sourceRoot string, graph *execution.Graph, analysis *MigrationAnalysis) error

WriteMigratedMarker writes the .writ-migrated marker file.

Types

type DetectedInstall

type DetectedInstall struct {
	Line        int    `json:"line" yaml:"line"`
	Manager     string `json:"manager" yaml:"manager"`
	Name        string `json:"name" yaml:"name"`
	Command     string `json:"command" yaml:"command"`
	LorePackage string `json:"lore_package,omitempty" yaml:"lore_package,omitempty"`
}

DetectedInstall represents a package installation detected in a script. The LLM may populate this when analyzing scripts that contain package manager commands.

func (DetectedInstall) IsResolved

func (d DetectedInstall) IsResolved() bool

IsResolved returns true if this install maps to a known lore package.

type EncryptionSystem

type EncryptionSystem string

EncryptionSystem identifies the secret encryption tool in use.

const (
	EncryptGitCrypt     EncryptionSystem = "git-crypt"
	EncryptBlackbox     EncryptionSystem = "blackbox"
	EncryptTranscrypt   EncryptionSystem = "transcrypt"
	EncryptGPG          EncryptionSystem = "gpg"
	EncryptAge          EncryptionSystem = "age"
	EncryptAnsibleVault EncryptionSystem = "ansible-vault"
	EncryptSOPS         EncryptionSystem = "sops"
	EncryptNone         EncryptionSystem = "none"
)

type ExecutableFile

type ExecutableFile struct {
	Path     string `json:"path"`     // Relative path from root
	Contents string `json:"contents"` // File contents
}

ExecutableFile holds a script's path and contents.

type GatherInput

type GatherInput struct {
	Root        string           `json:"root"`        // Absolute path to source root
	Tree        *TreeNode        `json:"tree"`        // Directory structure
	Executables []ExecutableFile `json:"executables"` // Scripts with contents
}

GatherInput collects tree structure and script contents for LLM analysis.

func GatherInputs

func GatherInputs(root string, maxDepth int, maxScriptBytes int) (*GatherInput, error)

GatherInputs walks the directory tree and collects structure and executable contents. maxDepth limits how deep to recurse (0 = root only, -1 = unlimited). maxScriptBytes limits total script content (0 = unlimited).

func (*GatherInput) FormatForPrompt

func (g *GatherInput) FormatForPrompt() string

FormatForPrompt formats the gathered input for the LLM prompt.

func (*GatherInput) ToJSON

func (g *GatherInput) ToJSON() ([]byte, error)

ToJSON serializes the GatherInput for the LLM prompt.

type InputLimits

type InputLimits struct {
	TreeDepth    int `yaml:"tree_depth" json:"tree_depth"`
	ScriptBudget int `yaml:"script_budget" json:"script_budget"`
}

InputLimits holds computed limits for input gathering.

func LoadInputLimits

func LoadInputLimits(reg *lorepackage.Registry, provider model.Provider) (InputLimits, error)

LoadInputLimits reads provider and model limits from the registry.

Resolution order: 1. Look up model in litellm-cache.json, compute limits from max_input_tokens 2. Apply provider overrides (e.g., GitHub's rate limits) 3. Fall back to provider's default input_limits if model not found

type LLMResult

type LLMResult struct {
	Analysis *MigrationAnalysis
	Graph    *execution.Graph
}

LLMResult holds the parsed response from LLM analysis.

func AnalyzeWithLLMFromRegistry

func AnalyzeWithLLMFromRegistry(ctx context.Context, provider model.Provider, reg *lorepackage.Registry, input *GatherInput) (*LLMResult, error)

AnalyzeWithLLMFromRegistry sends gathered inputs to the LLM using registry-loaded prompt.

type MigratedMarker

type MigratedMarker struct {
	Timestamp string   `yaml:"timestamp"`
	System    string   `yaml:"system"`
	Renames   []Rename `yaml:"renames"`
}

MigratedMarker records what was done during execution.

type MigrationAnalysis

type MigrationAnalysis struct {
	// SourceRoot is the absolute path to the source repository.
	SourceRoot string `json:"source_root" yaml:"source_root"`

	// System is the detected source system (tuckr, stow, chezmoi, etc.).
	System SourceSystem `json:"system" yaml:"system"`

	// SystemConfidence is the detection confidence (0.0-1.0).
	SystemConfidence float64 `json:"system_confidence,omitempty" yaml:"system_confidence,omitempty"`

	// InputSummary describes what the LLM saw in the inputs.
	InputSummary string `json:"input_summary,omitempty" yaml:"input_summary,omitempty"`

	// Structure describes the detected repository structure.
	Structure *StructureInfo `json:"structure,omitempty" yaml:"structure,omitempty"`

	// RepoLayer indicates the precedence layer (base, team, personal).
	RepoLayer RepoLayer `json:"repo_layer" yaml:"repo_layer"`

	// EncryptionSystems lists detected encryption tools (git-crypt, sops, etc.).
	EncryptionSystems []EncryptionSystem `json:"encryption_systems,omitempty" yaml:"encryption_systems,omitempty"`

	// Projects lists unique project names found in the repository.
	Projects []string `json:"projects,omitempty" yaml:"projects,omitempty"`

	// Platforms lists unique platform names found in the repository.
	Platforms []string `json:"platforms,omitempty" yaml:"platforms,omitempty"`

	// Scripts contains analysis of lifecycle scripts.
	Scripts []ScriptAnalysis `json:"scripts,omitempty" yaml:"scripts,omitempty"`

	// SecretFindings contains detected secrets with explanations.
	SecretFindings []SecretFinding `json:"secret_findings,omitempty" yaml:"secret_findings,omitempty"`

	// Observations are insights about the repository structure.
	Observations []string `json:"observations,omitempty" yaml:"observations,omitempty"`

	// Warnings are concerns that may need attention before/after migration.
	Warnings []string `json:"warnings,omitempty" yaml:"warnings,omitempty"`

	// Recommendations are suggested actions after migration.
	Recommendations []string `json:"recommendations,omitempty" yaml:"recommendations,omitempty"`

	// Stats provides summary counts derived from the inventory.
	Stats MigrationStats `json:"stats,omitempty" yaml:"stats,omitempty"`
}

MigrationAnalysis holds non-executable understanding of a source repository. This is the "why" and "what to watch out for" — separate from the execution Graph which specifies "what to do".

The execution Graph and MigrationAnalysis are produced together by BuildMigration(). FormatMigrationPlan() renders both as human-readable output.

func BuildMigration

func BuildMigration(ctx context.Context, opts Options) (*execution.Graph, *MigrationAnalysis, error)

BuildMigration performs LLM-based analysis, returning an execution Graph and MigrationAnalysis. This is the primary API that separates executable operations from non-executable understanding.

The LLM receives:

  • Directory tree structure (built with Go, cross-platform)
  • Contents of all executable scripts

The LLM returns:

  • Analysis: system detection, structure, observations, warnings, recommendations
  • Execution Graph: rename operations for directory structure changes

type MigrationStats

type MigrationStats struct {
	TotalFiles       int `json:"total_files" yaml:"total_files"`
	StaticConfigs    int `json:"static_configs" yaml:"static_configs"`
	Scripts          int `json:"scripts" yaml:"scripts"`
	LifecycleScripts int `json:"lifecycle_scripts" yaml:"lifecycle_scripts"`
	Secrets          int `json:"secrets" yaml:"secrets"`
	Fonts            int `json:"fonts" yaml:"fonts"`
	Templates        int `json:"templates" yaml:"templates"`
	Completions      int `json:"completions" yaml:"completions"`
	ManPages         int `json:"man_pages" yaml:"man_pages"`
	Binaries         int `json:"binaries" yaml:"binaries"`
	Projects         int `json:"projects" yaml:"projects"`
	Platforms        int `json:"platforms" yaml:"platforms"`
	Renames          int `json:"renames" yaml:"renames"`
}

MigrationStats summarizes the migration numerically.

type ModelCache

type ModelCache struct {
	Meta   ModelCacheMeta         `json:"_meta"`
	Models map[string]ModelLimits `json:"models"`
}

ModelCache represents the litellm-cache.json structure.

type ModelCacheMeta

type ModelCacheMeta struct {
	Source     string `json:"source"`
	SourceFile string `json:"source_file"`
	FetchedAt  string `json:"fetched_at"`
}

ModelCacheMeta contains metadata about the cache.

type ModelLimits

type ModelLimits struct {
	MaxInputTokens  int    `json:"max_input_tokens"`
	MaxOutputTokens int    `json:"max_output_tokens"`
	LiteLLMProvider string `json:"litellm_provider"`
}

ModelLimits holds limits for a specific model from LiteLLM.

type Options

type Options struct {
	SourceRoot   string
	TargetRoot   string // empty = rename in place
	Execute      bool
	Verbose      bool
	Format       string // "json" (default), "yaml", "text"
	Provider     model.Provider
	RegClient    *lorepackage.Registry
	TreeDepth    int // max directory depth to scan (0 = auto based on provider)
	ScriptBudget int // max bytes of script content to include (0 = auto based on provider)
}

Options controls migration behavior.

type ProviderConfig

type ProviderConfig struct {
	ModelCache string                  `yaml:"model_cache"` // Path to litellm-cache.json
	Providers  map[string]ProviderInfo `yaml:"providers"`
}

ProviderConfig represents the providers.yaml structure from devlore-registry.

type ProviderInfo

type ProviderInfo struct {
	Description       string      `yaml:"description"`
	LiteLLMProvider   string      `yaml:"litellm_provider"`   // Maps to litellm_provider in cache
	MaxInputOverride  int         `yaml:"max_input_override"` // Provider-enforced limit (e.g., GitHub)
	MaxOutputOverride int         `yaml:"max_output_override"`
	InputLimits       InputLimits `yaml:"input_limits"` // Default limits if model not in cache
}

ProviderInfo holds configuration for a specific provider.

type Rename

type Rename struct {
	From string `yaml:"from"`
	To   string `yaml:"to"`
}

Rename records a single directory rename.

type RepoLayer

type RepoLayer string

RepoLayer indicates the precedence layer of a repository. Precedence: base (lowest) → team → personal (highest).

const (
	LayerBase     RepoLayer = "base"
	LayerTeam     RepoLayer = "team"
	LayerPersonal RepoLayer = "personal"
)

type ScriptAnalysis

type ScriptAnalysis struct {
	RelPath       string            `json:"rel_path" yaml:"rel_path"`
	Name          string            `json:"name" yaml:"name"`
	Phase         string            `json:"phase" yaml:"phase"`
	PlatformGuard string            `json:"platform_guard,omitempty" yaml:"platform_guard,omitempty"`
	LineCount     int               `json:"line_count" yaml:"line_count"`
	Resolved      []DetectedInstall `json:"resolved,omitempty" yaml:"resolved,omitempty"`
	Unresolved    []DetectedInstall `json:"unresolved,omitempty" yaml:"unresolved,omitempty"`
	Observations  []string          `json:"observations,omitempty" yaml:"observations,omitempty"`
}

ScriptAnalysis captures information extracted from a lifecycle script. In the LLM-first approach, this is populated by the LLM based on reading script contents directly.

type SecretFinding

type SecretFinding struct {
	RelPath          string           `json:"rel_path" yaml:"rel_path"`
	Encryption       EncryptionSystem `json:"encryption" yaml:"encryption"`
	Reason           string           `json:"reason" yaml:"reason"`
	SuggestedPattern string           `json:"suggested_pattern,omitempty" yaml:"suggested_pattern,omitempty"`
}

SecretFinding represents a detected secret file.

type Session

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

Session implements console.Session for interactive migration.

func NewSession

func NewSession(opts Options) *Session

NewSession creates a new migration session.

func NewSessionWithProvider

func NewSessionWithProvider(opts Options, provider model.Provider, regClient *lorepackage.Registry) *Session

NewSessionWithProvider creates a session with an AI provider.

func (*Session) Complete

func (s *Session) Complete() bool

Complete returns true if the session has finished.

func (*Session) Current

func (s *Session) Current() *console.Step

Current returns the current step.

func (*Session) Error

func (s *Session) Error() error

Error returns any error that terminated the session.

func (*Session) Next

func (s *Session) Next() *console.Step

Next advances the session and returns the next step.

func (*Session) Respond

func (s *Session) Respond(response string) error

Respond processes the user's input.

func (*Session) Result

func (s *Session) Result() any

Result returns the session result.

type SessionResult

type SessionResult struct {
	Graph       *execution.Graph
	Analysis    *MigrationAnalysis
	Executed    bool
	ReceiptPath string
}

SessionResult is the final output of a migration session.

type SessionState

type SessionState int

SessionState represents a state in the migration session.

const (
	StateAnalyzing SessionState = iota
	StateConversing
	StatePlanProposed
	StateExecuting
	StateComplete
	StateError
)

type SourceSystem

type SourceSystem string

SourceSystem identifies the dotfile management approach used in the source repository.

const (
	SystemNative      SourceSystem = "native"       // Already writ-compatible (Home/ or System/)
	SystemTuckr       SourceSystem = "tuckr"        // Tuckr dotfile manager
	SystemStow        SourceSystem = "stow"         // GNU Stow
	SystemChezmoi     SourceSystem = "chezmoi"      // chezmoi
	SystemYadm        SourceSystem = "yadm"         // yadm
	SystemBareGit     SourceSystem = "bare-git"     // Bare git repo as home
	SystemScriptBased SourceSystem = "script-based" // Custom install scripts
	SystemUnknown     SourceSystem = "unknown"
)

type StructureInfo

type StructureInfo struct {
	// GroupsPath is where groups live (e.g., "Home/Configs").
	GroupsPath string `json:"groups_path" yaml:"groups_path"`

	// NamingConvention is the current naming pattern (e.g., "<group>-<Platform>").
	NamingConvention string `json:"naming_convention" yaml:"naming_convention"`

	// Groups is the list of group names found.
	Groups []string `json:"groups" yaml:"groups"`

	// Platforms is the list of platform names found.
	Platforms []string `json:"platforms" yaml:"platforms"`
}

StructureInfo describes the detected repository structure.

type TreeNode

type TreeNode struct {
	Type     string      `json:"type"`               // "directory" or "file"
	Name     string      `json:"name"`               // File/directory name
	Contents []*TreeNode `json:"contents,omitempty"` // Children (directories only)
}

TreeNode represents a directory or file in the tree structure. This mirrors the format produced by `tree -J` for LLM consumption.

Jump to

Keyboard shortcuts

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