dot

package
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Nov 24, 2025 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package dot provides a modern, type-safe symlink manager for dotfiles.

dot is a modern dotfile manager written in Go 1.25.4, following strict constitutional principles: test-driven development, atomic operations, functional programming, and comprehensive error handling.

Architecture

The library uses an interface-based Client pattern to provide a clean public API while keeping internal implementation details hidden:

  • Client interface in pkg/dot (stable public API)
  • Implementation in internal/api (can evolve freely)
  • Domain types in pkg/dot (shared between public and internal)

This pattern avoids import cycles between pkg/dot (which contains domain types like Operation, Plan, Result) and internal packages (which depend on those domain types).

Basic Usage

Create a client and manage packages:

import (
	"context"
	"log"

	"github.com/yaklabco/dot/internal/adapters"
	"github.com/yaklabco/dot/pkg/dot"
)

cfg := dot.Config{
	PackageDir:   "/home/user/dotfiles",
	TargetDir: "/home/user",
	FS:        adapters.NewOSFilesystem(),
	Logger:    adapters.NewNoopLogger(),
}

client, err := dot.NewClient(cfg)
if err != nil {
	log.Fatal(err)
}

ctx := context.Background()
if err := client.Manage(ctx, "vim", "zsh", "git"); err != nil {
	log.Fatal(err)
}

Dry Run Mode

Preview operations without applying changes:

cfg.DryRun = true
client, _ := dot.NewClient(cfg)

// Shows what would be done without executing
if err := client.Manage(ctx, "vim"); err != nil {
	log.Fatal(err)
}

Planning Operations

Get execution plan without applying:

plan, err := client.PlanManage(ctx, "vim")
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Would execute %d operations\n", len(plan.Operations))
for _, op := range plan.Operations {
	fmt.Printf("  %s\n", op.Kind())
}

Query Operations

Check installation status:

status, err := client.Status(ctx, "vim")
if err != nil {
	log.Fatal(err)
}

for _, pkg := range status.Packages {
	fmt.Printf("%s: %d links\n", pkg.Name, pkg.LinkCount)
}

List all installed packages:

packages, err := client.List(ctx)
if err != nil {
	log.Fatal(err)
}

for _, pkg := range packages {
	fmt.Printf("%s (installed %s)\n", pkg.Name, pkg.InstalledAt)
}

Configuration

The Config struct controls all dot behavior:

  • PackageDir: Source directory containing packages (required, absolute path)
  • TargetDir: Destination directory for symlinks (required, absolute path)
  • FS: Filesystem implementation (required)
  • Logger: Logger implementation (required)
  • Tracer: Distributed tracing (optional, defaults to noop)
  • Metrics: Metrics collection (optional, defaults to noop)
  • LinkMode: Relative or absolute symlinks (default: relative)
  • Folding: Enable directory folding (default: true)
  • DryRun: Preview mode (default: false)
  • Verbosity: Logging level (default: 0)
  • BackupDir: Location for backup files (default: <TargetDir>/.dot-backup)
  • Concurrency: Parallel operation limit (default: NumCPU)

Configuration must be validated before use:

cfg := dot.Config{
	PackageDir:   "/home/user/dotfiles",
	TargetDir: "/home/user",
	FS:        adapters.NewOSFilesystem(),
	Logger:    adapters.NewNoopLogger(),
}

if err := cfg.Validate(); err != nil {
	log.Fatal(err)
}

Observability

The library provides first-class observability through injected ports:

  • Structured logging via Logger interface (slog compatible)
  • Distributed tracing via Tracer interface (OpenTelemetry compatible)
  • Metrics collection via Metrics interface (Prometheus compatible)

Example with full observability:

cfg := dot.Config{
	PackageDir: "/home/user/dotfiles",
	TargetDir: "/home/user",
	FS:      adapters.NewOSFilesystem(),
	Logger:  adapters.NewSlogLogger(slog.Default()),
	Tracer:  otelTracer, // Your OpenTelemetry tracer
	Metrics: promMetrics, // Your Prometheus metrics
}

Testing

The library is designed for testability:

  • All operations accept context.Context for cancellation
  • Filesystem abstraction enables testing without disk I/O
  • Pure functional core enables property-based testing
  • Interface-based Client enables mocking

Example test using in-memory filesystem:

func TestMyTool(t *testing.T) {
	fs := adapters.NewMemFS()

	cfg := dot.Config{
		PackageDir:   "/test/packages",
		TargetDir: "/test/target",
		FS:        fs,
		Logger:    adapters.NewNoopLogger(),
	}

	client, _ := dot.NewClient(cfg)
	err := client.Manage(ctx, "vim")
	require.NoError(t, err)
}

Error Handling

All operations return explicit errors. Common error types:

  • ErrInvalidPath: Path validation failed
  • ErrPackageNotFound: Package doesn't exist in PackageDir
  • ErrConflict: Conflict detected during operation
  • ErrCyclicDependency: Circular dependency in operations
  • ErrMultiple: Multiple errors occurred

Errors include user-facing messages via UserFacingErrorMessage().

Safety Guarantees

The library provides strong safety guarantees:

  • Type safety: Phantom types prevent path mixing at compile time
  • Transaction safety: Two-phase commit with automatic rollback on failure
  • Conflict detection: All conflicts reported before modification
  • Atomic operations: All-or-nothing semantics
  • Thread safety: All Client operations safe for concurrent use

Implementation Status

All core operations are fully implemented:

  • Client interface with registration pattern
  • Manage/PlanManage operations with dependency resolution
  • Unmanage operations with restore, purge, and cleanup options
  • Adopt operations with file and directory support
  • Status/List query operations

Future enhancements:

  • Streaming API for large operations
  • ConfigBuilder for fluent configuration
  • Performance optimizations for large package sets

For detailed examples, see examples_test.go. For architecture details, see docs/Architecture.md. For implementation roadmap, see docs/Phase-12-Plan.md.

Index

Constants

View Source
const (
	NodeFile    = domain.NodeFile
	NodeDir     = domain.NodeDir
	NodeSymlink = domain.NodeSymlink
)

NodeType constants

View Source
const (
	OpKindLinkCreate   = domain.OpKindLinkCreate
	OpKindLinkDelete   = domain.OpKindLinkDelete
	OpKindDirCreate    = domain.OpKindDirCreate
	OpKindDirDelete    = domain.OpKindDirDelete
	OpKindDirRemoveAll = domain.OpKindDirRemoveAll
	OpKindFileMove     = domain.OpKindFileMove
	OpKindFileBackup   = domain.OpKindFileBackup
	OpKindFileDelete   = domain.OpKindFileDelete
	OpKindDirCopy      = domain.OpKindDirCopy
)

Operation kind constants

Variables

This section is empty.

Functions

func GetConfigPath added in v0.6.3

func GetConfigPath(appName string) string

GetConfigPath returns XDG-compliant configuration directory path.

func IsManifestNotFoundError

func IsManifestNotFoundError(err error) bool

IsManifestNotFoundError checks if an error indicates a missing manifest.

func UntranslateDotfile added in v0.6.3

func UntranslateDotfile(name string) string

UntranslateDotfile converts a dotfile name to its untranslated package form. Example: ".ssh" -> "dot-ssh"

func UpgradeConfig added in v0.6.3

func UpgradeConfig(configPath string, force bool) (string, error)

UpgradeConfig upgrades the configuration file to the latest format.

func UserFacingError

func UserFacingError(err error) string

UserFacingError converts an error into a user-friendly message.

Types

type AdoptService

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

AdoptService handles file adoption operations.

func (*AdoptService) Adopt

func (s *AdoptService) Adopt(ctx context.Context, files []string, pkg string) error

Adopt moves existing files from target into package then creates symlinks.

func (*AdoptService) GetManagedPaths

func (s *AdoptService) GetManagedPaths(ctx context.Context) (map[string]struct{}, error)

GetManagedPaths returns a map of all paths currently managed by dot. The map keys are absolute paths that are already symlinked. This is useful for filtering out already-managed files during discovery.

func (*AdoptService) PlanAdopt

func (s *AdoptService) PlanAdopt(ctx context.Context, files []string, pkg string) (Plan, error)

PlanAdopt computes the execution plan for adopting files.

type Attribute

type Attribute = domain.Attribute

Attribute represents a span attribute.

type BootstrapResult

type BootstrapResult struct {
	// Config is the generated bootstrap configuration
	Config bootstrap.Config

	// YAML is the marshaled configuration
	YAML []byte

	// PackageCount is the number of packages included
	PackageCount int

	// InstalledCount is the number of packages currently installed
	InstalledCount int
}

BootstrapResult contains the generated bootstrap configuration.

type BootstrapService

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

BootstrapService handles bootstrap configuration generation.

func (*BootstrapService) GenerateBootstrap

GenerateBootstrap creates a bootstrap configuration from the current installation.

The method:

  1. Scans package directory for available packages
  2. Reads manifest to identify installed packages
  3. Generates bootstrap configuration with appropriate defaults
  4. Marshals configuration to YAML

Returns an error if:

  • Package directory cannot be scanned
  • No packages are found
  • Configuration generation fails
  • YAML marshaling fails

func (*BootstrapService) WriteBootstrap

func (s *BootstrapService) WriteBootstrap(ctx context.Context, data []byte, outputPath string) error

WriteBootstrap writes the bootstrap configuration to a file.

Returns an error if:

  • File already exists (unless Force option was set during generation)
  • File cannot be written

type Client

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

Client provides the high-level API for dot operations.

Client acts as a facade that delegates operations to specialized services. This design provides clean separation of concerns while maintaining a simple public API.

All operations are safe for concurrent use from multiple goroutines.

func NewClient

func NewClient(cfg Config) (*Client, error)

NewClient creates a new Client with the given configuration.

Returns an error if:

  • Configuration is invalid (see Config.Validate)
  • Required dependencies are missing (FS, Logger)

The returned Client is safe for concurrent use from multiple goroutines.

func (*Client) Adopt

func (c *Client) Adopt(ctx context.Context, files []string, pkg string) error

Adopt moves existing files from target into package then creates symlinks.

func (*Client) Clone

func (c *Client) Clone(ctx context.Context, repoURL string, opts CloneOptions) error

Clone clones a dotfiles repository and installs packages.

Workflow:

  1. Validates package directory is empty (unless Force=true)
  2. Clones repository to package directory
  3. Loads optional bootstrap configuration
  4. Selects packages (via profile, interactive, or all)
  5. Filters packages by current platform
  6. Installs selected packages
  7. Updates manifest with repository tracking

Returns an error if:

  • Package directory is not empty (and Force=false)
  • Authentication fails
  • Clone operation fails
  • Bootstrap config is invalid
  • Package installation fails

func (*Client) Config

func (c *Client) Config() Config

Config returns the client's configuration.

func (*Client) Doctor

func (c *Client) Doctor(ctx context.Context) (DiagnosticReport, error)

Doctor performs health checks with default scan configuration.

func (*Client) DoctorWithMode

func (c *Client) DoctorWithMode(ctx context.Context, mode DiagnosticMode, scanCfg ScanConfig) (DiagnosticReport, error)

DoctorWithMode performs health checks with explicit mode and scan configuration.

func (*Client) DoctorWithScan

func (c *Client) DoctorWithScan(ctx context.Context, scanCfg ScanConfig) (DiagnosticReport, error)

DoctorWithScan performs health checks with explicit scan configuration.

func (*Client) GenerateBootstrap

func (c *Client) GenerateBootstrap(ctx context.Context, opts GenerateBootstrapOptions) (BootstrapResult, error)

GenerateBootstrap creates a bootstrap configuration from current installation.

Workflow:

  1. Discovers packages in package directory
  2. Reads manifest to identify installed packages (optional)
  3. Generates bootstrap configuration with defaults
  4. Marshals configuration to YAML

Returns bootstrap result containing configuration and YAML, or an error if:

  • No packages found
  • Configuration generation fails
  • YAML marshaling fails

func (*Client) List

func (c *Client) List(ctx context.Context) ([]PackageInfo, error)

List returns all installed packages from the manifest.

func (*Client) Manage

func (c *Client) Manage(ctx context.Context, packages ...string) error

Manage installs the specified packages by creating symlinks.

func (*Client) PlanAdopt

func (c *Client) PlanAdopt(ctx context.Context, files []string, pkg string) (Plan, error)

PlanAdopt computes the execution plan for adopting files.

func (*Client) PlanManage

func (c *Client) PlanManage(ctx context.Context, packages ...string) (Plan, error)

PlanManage computes the execution plan for managing packages without applying changes.

func (*Client) PlanRemanage

func (c *Client) PlanRemanage(ctx context.Context, packages ...string) (Plan, error)

PlanRemanage computes incremental execution plan using hash-based change detection.

func (*Client) PlanUnmanage

func (c *Client) PlanUnmanage(ctx context.Context, packages ...string) (Plan, error)

PlanUnmanage computes the execution plan for unmanaging packages.

func (*Client) Remanage

func (c *Client) Remanage(ctx context.Context, packages ...string) error

Remanage reinstalls packages using incremental hash-based change detection.

func (*Client) Status

func (c *Client) Status(ctx context.Context, packages ...string) (Status, error)

Status reports the current installation state for packages.

func (*Client) Triage

func (c *Client) Triage(ctx context.Context, scanCfg ScanConfig, opts TriageOptions) (TriageResult, error)

Triage performs interactive triage of orphaned symlinks.

func (*Client) Unmanage

func (c *Client) Unmanage(ctx context.Context, packages ...string) error

Unmanage removes the specified packages by deleting symlinks. Adopted packages are automatically restored unless disabled.

func (*Client) UnmanageAll

func (c *Client) UnmanageAll(ctx context.Context, opts UnmanageOptions) (int, error)

UnmanageAll removes all installed packages with specified options. Returns the count of packages unmanaged.

func (*Client) UnmanageWithOptions

func (c *Client) UnmanageWithOptions(ctx context.Context, opts UnmanageOptions, packages ...string) error

UnmanageWithOptions removes packages with specified options.

func (*Client) WriteBootstrap

func (c *Client) WriteBootstrap(ctx context.Context, data []byte, outputPath string) error

WriteBootstrap writes bootstrap configuration to a file.

Returns an error if:

  • File already exists
  • Parent directory cannot be created
  • File cannot be written

type CloneOptions

type CloneOptions struct {
	// Profile specifies which bootstrap profile to use.
	// If empty, uses default profile or interactive selection.
	Profile string

	// Interactive forces interactive package selection.
	// If false, uses profile or installs all packages.
	Interactive bool

	// Force allows cloning into non-empty packageDir.
	Force bool

	// Branch specifies which branch to clone.
	// If empty, clones default branch.
	Branch string
}

CloneOptions configures repository cloning behavior.

type CloneService

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

CloneService handles repository cloning and package installation.

func (*CloneService) Clone

func (s *CloneService) Clone(ctx context.Context, repoURL string, opts CloneOptions) error

Clone clones a repository and installs packages.

Workflow:

  1. Validate packageDir is empty (unless Force=true)
  2. Resolve authentication from environment
  3. Clone repository to packageDir
  4. Load bootstrap config if present
  5. Select packages (profile, interactive, or all)
  6. Filter packages by current platform
  7. Install selected packages via ManageService
  8. Update manifest with repository information

type Config

type Config struct {
	// PackageDir is the source directory containing packages.
	// Must be an absolute path.
	PackageDir string

	// TargetDir is the destination directory for symlinks.
	// Must be an absolute path.
	TargetDir string

	// LinkMode specifies whether to create relative or absolute symlinks.
	LinkMode LinkMode

	// Folding enables directory-level linking when all contents
	// belong to a single package.
	Folding bool

	// DryRun enables preview mode without applying changes.
	DryRun bool

	// Verbosity controls logging detail (0=quiet, 1=info, 2=debug, 3=trace).
	Verbosity int

	// BackupDir specifies where to store backup files.
	// If empty, backups go to <TargetDir>/.dot-backup/
	BackupDir string

	// Backup enables automatic backup of conflicting files.
	// When true, conflicting files are backed up before being replaced.
	Backup bool

	// Overwrite enables automatic overwriting of conflicting files.
	// When true, conflicting files are deleted before creating symlinks.
	// Takes precedence over Backup if both are true.
	Overwrite bool

	// ManifestDir specifies where to store the manifest file.
	// If empty, manifest is stored in TargetDir for backward compatibility.
	ManifestDir string

	// Concurrency limits parallel operation execution.
	// If zero, defaults to runtime.NumCPU().
	Concurrency int

	// PackageNameMapping enables package name to target directory mapping.
	// When enabled, package "dot-gnupg" targets ~/.gnupg/ instead of ~/.
	// Default: true (project is pre-1.0, breaking change acceptable)
	PackageNameMapping bool

	// IgnorePatterns contains additional ignore patterns beyond defaults.
	// Supports glob patterns and negation with ! prefix.
	IgnorePatterns []string

	// UseDefaultIgnorePatterns controls whether default patterns are applied.
	// Default: true (.git, .DS_Store, etc.)
	UseDefaultIgnorePatterns bool

	// PerPackageIgnore enables reading .dotignore files from packages.
	// Default: true
	PerPackageIgnore bool

	// MaxFileSize is the maximum file size to include in bytes (0 = no limit).
	MaxFileSize int64

	// InteractiveLargeFiles enables prompting for large files in TTY mode.
	// Default: true
	InteractiveLargeFiles bool

	// Infrastructure dependencies (required)
	FS      FS
	Logger  Logger
	Tracer  Tracer
	Metrics Metrics
}

Config holds configuration for the dot Client.

func (Config) Validate

func (c Config) Validate() error

Validate checks that the configuration is valid.

func (Config) WithDefaults

func (c Config) WithDefaults() Config

WithDefaults returns a copy of the config with defaults applied.

type ConfigLoader added in v0.6.3

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

ConfigLoader handles configuration loading with precedence.

func NewConfigLoader added in v0.6.3

func NewConfigLoader(appName, configPath string) *ConfigLoader

NewConfigLoader creates a new configuration loader.

func (*ConfigLoader) LoadWithEnv added in v0.6.3

func (l *ConfigLoader) LoadWithEnv() (*ExtendedConfig, error)

LoadWithEnv loads configuration with environment variable overrides.

type ConfigWriter added in v0.6.3

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

ConfigWriter wraps the internal config writer.

func NewConfigWriter added in v0.6.3

func NewConfigWriter(path string) *ConfigWriter

NewConfigWriter creates a new config writer for the given path.

func (*ConfigWriter) Update added in v0.6.3

func (w *ConfigWriter) Update(key, value string) error

Update updates a configuration value by key.

func (*ConfigWriter) WriteDefault added in v0.6.3

func (w *ConfigWriter) WriteDefault(opts config.WriteOptions) error

WriteDefault writes default configuration with options.

type ConflictInfo

type ConflictInfo = domain.ConflictInfo

ConflictInfo represents conflict information in plan metadata.

type Counter

type Counter = domain.Counter

Counter represents a monotonically increasing counter.

type DiagnosticMode

type DiagnosticMode string

DiagnosticMode defines the depth of diagnostic checks to perform.

const (
	// DiagnosticFast performs only essential checks (managed packages, manifest integrity).
	DiagnosticFast DiagnosticMode = "fast"
	// DiagnosticDeep performs comprehensive checks including orphan detection.
	DiagnosticDeep DiagnosticMode = "deep"
)

type DiagnosticReport

type DiagnosticReport struct {
	OverallHealth HealthStatus    `json:"overall_health" yaml:"overall_health"`
	Issues        []Issue         `json:"issues" yaml:"issues"`
	Statistics    DiagnosticStats `json:"statistics" yaml:"statistics"`
}

DiagnosticReport contains health check results.

type DiagnosticStats

type DiagnosticStats struct {
	TotalLinks    int `json:"total_links" yaml:"total_links"`
	BrokenLinks   int `json:"broken_links" yaml:"broken_links"`
	OrphanedLinks int `json:"orphaned_links" yaml:"orphaned_links"`
	ManagedLinks  int `json:"managed_links" yaml:"managed_links"`
}

DiagnosticStats contains summary statistics.

type DirCopy

type DirCopy = domain.DirCopy

DirCopy recursively copies a directory.

func NewDirCopy

func NewDirCopy(id OperationID, source, dest FilePath) DirCopy

NewDirCopy creates a new DirCopy operation.

type DirCreate

type DirCreate = domain.DirCreate

DirCreate creates a directory.

func NewDirCreate

func NewDirCreate(id OperationID, path FilePath) DirCreate

NewDirCreate creates a new DirCreate operation.

type DirDelete

type DirDelete = domain.DirDelete

DirDelete removes a directory.

func NewDirDelete

func NewDirDelete(id OperationID, path FilePath) DirDelete

NewDirDelete creates a new DirDelete operation.

type DirEntry

type DirEntry = domain.DirEntry

DirEntry provides information about a directory entry.

type DirRemoveAll

type DirRemoveAll = domain.DirRemoveAll

DirRemoveAll recursively removes a directory and all its contents.

func NewDirRemoveAll

func NewDirRemoveAll(id OperationID, path FilePath) DirRemoveAll

NewDirRemoveAll creates a new DirRemoveAll operation.

type DoctorService

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

DoctorService handles health check and diagnostic operations.

func (*DoctorService) Doctor

Doctor performs health checks with default scan configuration.

func (*DoctorService) DoctorWithMode

func (s *DoctorService) DoctorWithMode(ctx context.Context, mode DiagnosticMode, scanCfg ScanConfig) (DiagnosticReport, error)

DoctorWithMode performs health checks with explicit mode and configuration.

func (*DoctorService) DoctorWithScan

func (s *DoctorService) DoctorWithScan(ctx context.Context, scanCfg ScanConfig) (DiagnosticReport, error)

DoctorWithScan performs health checks with explicit scan configuration.

func (*DoctorService) Fix

func (s *DoctorService) Fix(ctx context.Context, scanCfg ScanConfig, opts FixOptions) (FixResult, error)

Fix repairs broken symlinks found during doctor scan.

func (s *DoctorService) IgnoreLink(ctx context.Context, linkPath, reason string) error

IgnoreLink adds a symlink to the ignore list.

func (*DoctorService) IgnorePattern

func (s *DoctorService) IgnorePattern(ctx context.Context, pattern string) error

IgnorePattern adds a glob pattern to ignore list.

func (*DoctorService) ListIgnored

func (s *DoctorService) ListIgnored(ctx context.Context) (map[string]manifest.IgnoredLink, []string, error)

ListIgnored returns all ignored links and patterns.

func (*DoctorService) PreFlightCheck

func (s *DoctorService) PreFlightCheck(ctx context.Context, packages []string) (DiagnosticReport, error)

PreFlightCheck performs quick checks before an operation.

func (*DoctorService) Triage

func (s *DoctorService) Triage(ctx context.Context, scanCfg ScanConfig, opts TriageOptions) (TriageResult, error)

Triage performs interactive triage of orphaned symlinks.

func (s *DoctorService) UnignoreLink(ctx context.Context, linkPath string) error

UnignoreLink removes a symlink from ignore list.

type ErrAuthFailed

type ErrAuthFailed struct {
	Cause error
}

ErrAuthFailed indicates authentication failure during git clone.

func (ErrAuthFailed) Error

func (e ErrAuthFailed) Error() string

func (ErrAuthFailed) Unwrap

func (e ErrAuthFailed) Unwrap() error

type ErrBootstrapExists

type ErrBootstrapExists struct {
	Path string
}

ErrBootstrapExists indicates the bootstrap file already exists.

func (ErrBootstrapExists) Error

func (e ErrBootstrapExists) Error() string

type ErrBootstrapNotFound

type ErrBootstrapNotFound struct {
	Path string
}

ErrBootstrapNotFound indicates the bootstrap configuration file was not found.

func (ErrBootstrapNotFound) Error

func (e ErrBootstrapNotFound) Error() string

type ErrCheckpointNotFound

type ErrCheckpointNotFound = domain.ErrCheckpointNotFound

ErrCheckpointNotFound represents a missing checkpoint error.

type ErrCloneFailed

type ErrCloneFailed struct {
	URL   string
	Cause error
}

ErrCloneFailed indicates repository cloning failed.

func (ErrCloneFailed) Error

func (e ErrCloneFailed) Error() string

func (ErrCloneFailed) Unwrap

func (e ErrCloneFailed) Unwrap() error

type ErrConflict

type ErrConflict = domain.ErrConflict

ErrConflict represents a conflict during installation.

type ErrCyclicDependency

type ErrCyclicDependency = domain.ErrCyclicDependency

ErrCyclicDependency represents a dependency cycle error.

type ErrEmptyPlan

type ErrEmptyPlan = domain.ErrEmptyPlan

ErrEmptyPlan represents an empty plan error.

type ErrExecutionFailed

type ErrExecutionFailed = domain.ErrExecutionFailed

ErrExecutionFailed represents an execution failure error.

type ErrFilesystemOperation

type ErrFilesystemOperation = domain.ErrFilesystemOperation

ErrFilesystemOperation represents a filesystem operation error.

type ErrInvalidBootstrap

type ErrInvalidBootstrap struct {
	Reason string
	Cause  error
}

ErrInvalidBootstrap indicates the bootstrap configuration is invalid.

func (ErrInvalidBootstrap) Error

func (e ErrInvalidBootstrap) Error() string

func (ErrInvalidBootstrap) Unwrap

func (e ErrInvalidBootstrap) Unwrap() error

type ErrInvalidPath

type ErrInvalidPath = domain.ErrInvalidPath

ErrInvalidPath represents a path validation error.

type ErrMultiple

type ErrMultiple = domain.ErrMultiple

ErrMultiple represents multiple aggregated errors.

type ErrNotImplemented

type ErrNotImplemented = domain.ErrNotImplemented

ErrNotImplemented represents a not implemented error.

type ErrPackageDirNotEmpty

type ErrPackageDirNotEmpty struct {
	Path  string
	Cause error
}

ErrPackageDirNotEmpty indicates the package directory is not empty.

func (ErrPackageDirNotEmpty) Error

func (e ErrPackageDirNotEmpty) Error() string

func (ErrPackageDirNotEmpty) Unwrap

func (e ErrPackageDirNotEmpty) Unwrap() error

type ErrPackageNotFound

type ErrPackageNotFound = domain.ErrPackageNotFound

ErrPackageNotFound represents a missing package error.

type ErrParentNotFound

type ErrParentNotFound = domain.ErrParentNotFound

ErrParentNotFound represents a missing parent directory error.

type ErrPermissionDenied

type ErrPermissionDenied = domain.ErrPermissionDenied

ErrPermissionDenied represents a permission denied error.

type ErrProfileNotFound

type ErrProfileNotFound struct {
	Profile string
}

ErrProfileNotFound indicates the requested profile does not exist.

func (ErrProfileNotFound) Error

func (e ErrProfileNotFound) Error() string

type ErrSourceNotFound

type ErrSourceNotFound = domain.ErrSourceNotFound

ErrSourceNotFound represents a missing source file error.

type ExecutionResult

type ExecutionResult = domain.ExecutionResult

ExecutionResult contains the outcome of plan execution.

type ExtendedConfig added in v0.6.3

type ExtendedConfig = config.ExtendedConfig

ExtendedConfig contains all application configuration. It is an alias to the internal ExtendedConfig to provide a stable API.

func DefaultExtendedConfig added in v0.6.3

func DefaultExtendedConfig() *ExtendedConfig

DefaultExtendedConfig returns extended configuration with sensible defaults.

func LoadExtendedFromFile added in v0.6.3

func LoadExtendedFromFile(path string) (*ExtendedConfig, error)

LoadExtendedFromFile loads extended configuration from specified file.

type FS

type FS = domain.FS

FS defines the filesystem abstraction interface.

func NewOSFilesystem added in v0.6.3

func NewOSFilesystem() FS

NewOSFilesystem returns a filesystem implementation that uses the OS filesystem.

type FileBackup

type FileBackup = domain.FileBackup

FileBackup backs up a file before modification.

func NewFileBackup

func NewFileBackup(id OperationID, source, backup FilePath) FileBackup

NewFileBackup creates a new FileBackup operation.

type FileDelete

type FileDelete = domain.FileDelete

FileDelete deletes a file.

func NewFileDelete

func NewFileDelete(id OperationID, path FilePath) FileDelete

NewFileDelete creates a new FileDelete operation.

type FileInfo

type FileInfo = domain.FileInfo

FileInfo provides information about a file.

type FileMove

type FileMove = domain.FileMove

FileMove moves a file from one location to another.

func NewFileMove

func NewFileMove(id OperationID, source TargetPath, dest FilePath) FileMove

NewFileMove creates a new FileMove operation.

type FilePath

type FilePath = domain.FilePath

FilePath is a path to a file or directory within a package. Includes methods: String(), Join(), Parent(), Equals()

func MustParsePath

func MustParsePath(s string) FilePath

MustParsePath creates a FilePath from a string, panicking on error. This function is intended for use in tests only where paths are known to be valid. Production code should use NewFilePath which returns a Result for proper error handling.

type FixOptions

type FixOptions struct {
	DryRun      bool
	AutoConfirm bool // --yes flag
	Interactive bool // Prompt user for decisions
}

FixOptions configures fix behavior.

type FixResult

type FixResult struct {
	Fixed   []string
	Skipped []string
	Errors  map[string]error
}

FixResult contains the results of a fix operation.

type Gauge

type Gauge = domain.Gauge

Gauge represents an instantaneous value.

type GenerateBootstrapOptions

type GenerateBootstrapOptions struct {
	// FromManifest only includes packages from manifest
	FromManifest bool

	// ConflictPolicy sets default conflict resolution policy
	ConflictPolicy string

	// IncludeComments adds helpful comments to output
	IncludeComments bool

	// Force allows overwriting existing bootstrap files
	Force bool
}

GenerateBootstrapOptions configures bootstrap generation.

type GitHubRelease added in v0.6.3

type GitHubRelease = updater.GitHubRelease

GitHubRelease represents a GitHub release.

type HealthChecker

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

HealthChecker provides unified health checking logic for symlinks.

func (h *HealthChecker) CheckLink(ctx context.Context, pkgName, linkPath, packageDir string) LinkHealthResult

CheckLink validates a single symlink and returns detailed health information. This is the single source of truth for link health checking.

func (*HealthChecker) CheckPackage

func (h *HealthChecker) CheckPackage(ctx context.Context, pkgName string, links []string, packageDir string) (bool, string)

CheckPackage validates all symlinks for a package and returns aggregated health status. Returns healthy status and issue type if problems are found.

type HealthStatus

type HealthStatus int

HealthStatus represents the overall health of the installation.

const (
	// HealthOK indicates no issues found.
	HealthOK HealthStatus = iota
	// HealthWarnings indicates non-critical issues found.
	HealthWarnings
	// HealthErrors indicates critical issues found.
	HealthErrors
)

func (HealthStatus) MarshalJSON

func (h HealthStatus) MarshalJSON() ([]byte, error)

MarshalJSON marshals HealthStatus as a string.

func (HealthStatus) MarshalYAML

func (h HealthStatus) MarshalYAML() (interface{}, error)

MarshalYAML marshals HealthStatus as a string.

func (HealthStatus) String

func (h HealthStatus) String() string

String returns the string representation of health status.

type Histogram

type Histogram = domain.Histogram

Histogram represents a distribution of values.

type Issue

type Issue struct {
	Severity   IssueSeverity `json:"severity" yaml:"severity"`
	Type       IssueType     `json:"type" yaml:"type"`
	Path       string        `json:"path,omitempty" yaml:"path,omitempty"`
	Message    string        `json:"message" yaml:"message"`
	Suggestion string        `json:"suggestion,omitempty" yaml:"suggestion,omitempty"`
}

Issue represents a single diagnostic issue.

type IssueSeverity

type IssueSeverity int

IssueSeverity indicates the severity of an issue.

const (
	// SeverityInfo represents informational messages.
	SeverityInfo IssueSeverity = iota
	// SeverityWarning represents non-critical issues.
	SeverityWarning
	// SeverityError represents critical issues requiring attention.
	SeverityError
)

func (IssueSeverity) MarshalJSON

func (s IssueSeverity) MarshalJSON() ([]byte, error)

MarshalJSON marshals IssueSeverity as a string.

func (IssueSeverity) MarshalYAML

func (s IssueSeverity) MarshalYAML() (interface{}, error)

MarshalYAML marshals IssueSeverity as a string.

func (IssueSeverity) String

func (s IssueSeverity) String() string

String returns the string representation of severity.

type IssueType

type IssueType int

IssueType categorizes the type of issue.

const (
	// IssueBrokenLink indicates a symlink pointing to a non-existent target.
	IssueBrokenLink IssueType = iota
	// IssueOrphanedLink indicates a symlink not managed by any package.
	IssueOrphanedLink
	// IssueWrongTarget indicates a symlink pointing to an unexpected target.
	IssueWrongTarget
	// IssuePermission indicates insufficient permissions for an operation.
	IssuePermission
	// IssueCircular indicates a circular symlink reference.
	IssueCircular
	// IssueManifestInconsistency indicates mismatch between manifest and filesystem.
	IssueManifestInconsistency
)

func (IssueType) MarshalJSON

func (t IssueType) MarshalJSON() ([]byte, error)

MarshalJSON marshals IssueType as a string.

func (IssueType) MarshalYAML

func (t IssueType) MarshalYAML() (interface{}, error)

MarshalYAML marshals IssueType as a string.

func (IssueType) String

func (t IssueType) String() string

String returns the string representation of issue type.

type LinkCreate

type LinkCreate = domain.LinkCreate

LinkCreate creates a symbolic link.

func NewLinkCreate

func NewLinkCreate(id OperationID, source FilePath, target TargetPath) LinkCreate

NewLinkCreate creates a new LinkCreate operation.

type LinkDelete

type LinkDelete = domain.LinkDelete

LinkDelete removes a symbolic link.

func NewLinkDelete

func NewLinkDelete(id OperationID, target TargetPath) LinkDelete

NewLinkDelete creates a new LinkDelete operation.

type LinkHealthResult

type LinkHealthResult struct {
	IsHealthy  bool
	IssueType  IssueType
	Severity   IssueSeverity
	Message    string
	Suggestion string
}

LinkHealthResult contains detailed health information for a single link.

type LinkMode

type LinkMode int

LinkMode specifies symlink creation strategy.

const (
	// LinkRelative creates relative symlinks (default).
	LinkRelative LinkMode = iota
	// LinkAbsolute creates absolute symlinks.
	LinkAbsolute
)

type Logger

type Logger = domain.Logger

Logger provides structured logging.

func NewJSONLogger added in v0.6.3

func NewJSONLogger(w io.Writer, level slog.Level) Logger

NewJSONLogger returns a configured JSON logger.

func NewNoopLogger added in v0.6.3

func NewNoopLogger() Logger

NewNoopLogger returns a logger that discards all output.

func NewSlogLogger added in v0.6.3

func NewSlogLogger(l *slog.Logger) Logger

NewSlogLogger returns a logger backed by slog.

func NewTextLogger added in v0.6.3

func NewTextLogger(w io.Writer, level slog.Level) Logger

NewTextLogger returns a configured text logger.

type ManageService

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

ManageService handles package installation (manage and remanage operations).

func (*ManageService) Manage

func (s *ManageService) Manage(ctx context.Context, packages ...string) error

Manage installs the specified packages by creating symlinks.

func (*ManageService) PlanManage

func (s *ManageService) PlanManage(ctx context.Context, packages ...string) (Plan, error)

PlanManage computes the execution plan for managing packages without applying changes.

func (*ManageService) PlanRemanage

func (s *ManageService) PlanRemanage(ctx context.Context, packages ...string) (Plan, error)

PlanRemanage computes incremental execution plan using hash-based change detection.

func (*ManageService) Remanage

func (s *ManageService) Remanage(ctx context.Context, packages ...string) error

Remanage reinstalls packages using incremental hash-based change detection.

type ManifestService

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

ManifestService manages manifest operations.

func (*ManifestService) Load

Load loads the manifest from the target directory.

func (*ManifestService) RemovePackage

func (s *ManifestService) RemovePackage(ctx context.Context, targetPath TargetPath, pkg string) error

RemovePackage removes a package from the manifest.

func (*ManifestService) Save

func (s *ManifestService) Save(ctx context.Context, targetPath TargetPath, m manifest.Manifest) error

Save saves the manifest to the target directory.

func (*ManifestService) Update

func (s *ManifestService) Update(ctx context.Context, targetPath TargetPath, packageDir string, packages []string, plan Plan) error

Update updates the manifest with package information from a plan.

func (*ManifestService) UpdateWithSource

func (s *ManifestService) UpdateWithSource(ctx context.Context, targetPath TargetPath, packageDir string, packages []string, plan Plan, source manifest.PackageSource) error

UpdateWithSource updates the manifest with package information and source type.

type Metrics

type Metrics = domain.Metrics

Metrics provides metrics collection.

func NewNoopMetrics

func NewNoopMetrics() Metrics

NewNoopMetrics returns a metrics collector that does nothing.

type Node

type Node = domain.Node

Node represents a node in a filesystem tree.

type NodeType

type NodeType = domain.NodeType

NodeType identifies the type of filesystem node.

type Operation

type Operation = domain.Operation

Operation represents a filesystem operation to be executed.

type OperationID

type OperationID = domain.OperationID

OperationID uniquely identifies an operation.

type OperationKind

type OperationKind = domain.OperationKind

OperationKind identifies the type of operation.

type OrphanGroup

type OrphanGroup struct {
	Category        *doctor.PatternCategory
	Links           []Issue
	Confidence      string
	Pattern         string // Suggested ignore pattern
	IsUncategorized bool
}

OrphanGroup groups orphaned symlinks by category.

type Package

type Package = domain.Package

Package represents a collection of configuration files to be managed.

type PackageInfo

type PackageInfo struct {
	Name        string    `json:"name" yaml:"name"`
	Source      string    `json:"source" yaml:"source"`
	InstalledAt time.Time `json:"installed_at" yaml:"installed_at"`
	LinkCount   int       `json:"link_count" yaml:"link_count"`
	Links       []string  `json:"links" yaml:"links"`
	TargetDir   string    `json:"target_dir,omitempty" yaml:"target_dir,omitempty"`
	PackageDir  string    `json:"package_dir,omitempty" yaml:"package_dir,omitempty"`
	IsHealthy   bool      `json:"is_healthy" yaml:"is_healthy"`
	IssueType   string    `json:"issue_type,omitempty" yaml:"issue_type,omitempty"`
}

PackageInfo contains metadata about an installed package.

type PackageManager added in v0.6.3

type PackageManager = updater.PackageManager

PackageManager represents a package manager for upgrades.

func ResolvePackageManager added in v0.6.3

func ResolvePackageManager(configured string) (PackageManager, error)

ResolvePackageManager resolves the package manager based on configuration.

type PackagePath

type PackagePath = domain.PackagePath

PackagePath is a path to a package directory. Includes methods: String(), Join(), Parent(), Equals()

type Plan

type Plan = domain.Plan

Plan represents a set of operations to execute.

type PlanMetadata

type PlanMetadata = domain.PlanMetadata

PlanMetadata contains statistics and diagnostic information about a plan.

type Result

type Result[T any] domain.Result[T]

Result represents a value or an error, implementing a Result monad for error handling. This provides a functional approach to error handling with composition support.

This is a re-export of domain.Result. See internal/domain for implementation.

func Collect

func Collect[T any](results []Result[T]) Result[[]T]

Collect aggregates a slice of Results into a Result containing a slice. Returns Err if any Result is Err, otherwise returns Ok with all values.

func Err

func Err[T any](err error) Result[T]

Err creates a failed Result containing an error.

func FlatMap

func FlatMap[T, U any](r Result[T], fn func(T) Result[U]) Result[U]

FlatMap applies a function that returns a Result to the contained value if Ok. This is the monadic bind operation, enabling composition of Result-returning functions.

func Map

func Map[T, U any](r Result[T], fn func(T) U) Result[U]

Map applies a function to the contained value if Ok, otherwise propagates the error. This is the functorial map operation.

func NewFilePath

func NewFilePath(s string) Result[FilePath]

NewFilePath creates a new file path with validation.

func NewPackagePath

func NewPackagePath(s string) Result[PackagePath]

NewPackagePath creates a new package path with validation.

func NewTargetPath

func NewTargetPath(s string) Result[TargetPath]

NewTargetPath creates a new target path with validation.

func Ok

func Ok[T any](value T) Result[T]

Ok creates a successful Result containing a value.

func (Result[T]) IsErr

func (r Result[T]) IsErr() bool

IsErr returns true if the Result contains an error.

func (Result[T]) IsOk

func (r Result[T]) IsOk() bool

IsOk returns true if the Result contains a value.

func (Result[T]) Unwrap

func (r Result[T]) Unwrap() T

Unwrap returns the contained value.

func (Result[T]) UnwrapErr

func (r Result[T]) UnwrapErr() error

UnwrapErr returns the contained error.

func (Result[T]) UnwrapOr

func (r Result[T]) UnwrapOr(defaultValue T) T

UnwrapOr returns the contained value or a default if Result is Err.

type ScanConfig

type ScanConfig struct {
	// Mode determines the scanning strategy.
	Mode ScanMode

	// MaxDepth limits directory recursion depth.
	// Values <= 0 are normalized to 3 (scoped) or 10 (deep) by constructor helpers.
	// Default: 3 (scoped), 10 (deep)
	MaxDepth int

	// ScopeToDirs limits scanning to specific directories.
	// Empty means auto-detect from manifest (for ScanScoped) or target dir (for ScanDeep).
	ScopeToDirs []string

	// SkipPatterns are directory names/patterns to skip during scanning.
	// Default constructors include common large directories unlikely to contain dotfile symlinks.
	SkipPatterns []string

	// MaxWorkers limits parallel directory scanning goroutines.
	// Values <= 0 default to runtime.NumCPU().
	// Set to 1 to disable parallel scanning.
	// Default: 0 (use NumCPU)
	MaxWorkers int

	// MaxIssues limits the number of issues to collect before stopping scan.
	// Values <= 0 mean unlimited (scan everything).
	// Useful for fast health checks without full enumeration.
	// Default: 0 (unlimited)
	MaxIssues int
}

ScanConfig controls orphaned link detection behavior.

func DeepScanConfig

func DeepScanConfig(maxDepth int) ScanConfig

DeepScanConfig returns a scan configuration for deep scanning.

func DefaultScanConfig

func DefaultScanConfig() ScanConfig

DefaultScanConfig returns the default scan configuration (scoped). Scoped scanning checks directories containing managed links for orphaned symlinks.

func ScopedScanConfig

func ScopedScanConfig() ScanConfig

ScopedScanConfig returns a scan configuration for scoped scanning.

type ScanMode

type ScanMode int

ScanMode controls orphaned link detection behavior.

const (
	// ScanOff disables orphaned link detection (fastest, use --scan-mode=off to enable).
	ScanOff ScanMode = iota
	// ScanScoped only scans directories containing managed links (default, recommended).
	ScanScoped
	// ScanDeep performs full recursive scan with depth limits (slowest, thorough).
	ScanDeep
)

func (ScanMode) String

func (s ScanMode) String() string

String returns the string representation of scan mode.

type SecretDetection added in v0.6.3

type SecretDetection = doctor.SecretDetection

SecretDetection represents a detected potential secret.

func DetectSecrets added in v0.6.3

func DetectSecrets(files []string, patterns []SensitivePattern) []SecretDetection

DetectSecrets scans files for potential secrets using the provided patterns.

type SensitivePattern added in v0.6.3

type SensitivePattern = doctor.SensitivePattern

SensitivePattern represents a pattern for detecting sensitive information.

func DefaultSensitivePatterns added in v0.6.3

func DefaultSensitivePatterns() []SensitivePattern

DefaultSensitivePatterns returns the default patterns for secret detection.

type Span

type Span = domain.Span

Span represents a trace span.

type SpanOption

type SpanOption = domain.SpanOption

SpanOption configures span creation.

type StartupChecker added in v0.6.3

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

StartupChecker checks for updates at startup. It wraps the internal StartupChecker.

func NewStartupChecker added in v0.6.3

func NewStartupChecker(currentVersion string, cfg *ExtendedConfig, configDir string, output io.Writer) *StartupChecker

NewStartupChecker creates a new startup update checker.

func (*StartupChecker) Check added in v0.6.3

func (c *StartupChecker) Check() (*UpdateCheckResult, error)

Check performs the update check.

func (*StartupChecker) ShowNotification added in v0.6.3

func (c *StartupChecker) ShowNotification(result *UpdateCheckResult)

ShowNotification displays an update notification if available.

type Status

type Status struct {
	Packages []PackageInfo `json:"packages" yaml:"packages"`
}

Status represents the installation state of packages.

type StatusService

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

StatusService handles status and listing operations.

func (*StatusService) List

func (s *StatusService) List(ctx context.Context) ([]PackageInfo, error)

List returns all installed packages from the manifest.

func (*StatusService) Status

func (s *StatusService) Status(ctx context.Context, packages ...string) (Status, error)

Status reports the current installation state for packages.

type TargetPath

type TargetPath = domain.TargetPath

TargetPath is a path to a target directory. Includes methods: String(), Join(), Parent(), Equals()

func MustParseTargetPath

func MustParseTargetPath(s string) TargetPath

MustParseTargetPath creates a TargetPath from a string, panicking on error. This function is intended for use in tests only where paths are known to be valid. Production code should use NewTargetPath which returns a Result for proper error handling.

Panic is appropriate here because: - Function is only used in test code with hardcoded, known-valid paths - Panicking on test setup errors fails fast and clearly indicates test bugs - Test failures from panic are easier to debug than silent errors

type Tracer

type Tracer = domain.Tracer

Tracer provides distributed tracing support.

func NewNoopTracer

func NewNoopTracer() Tracer

NewNoopTracer returns a tracer that does nothing.

type TriageOptions

type TriageOptions struct {
	AutoIgnoreHighConfidence bool // Automatically ignore high confidence categories
	DryRun                   bool // Show what would change without modifying
	AutoConfirm              bool // Skip confirmation prompts (--yes flag)
}

TriageOptions configures triage behavior.

type TriageResult

type TriageResult struct {
	Ignored  []string          // Links ignored
	Patterns []string          // Patterns added
	Adopted  map[string]string // Link -> package name
	Skipped  []string          // Links skipped
	Errors   map[string]error  // Link -> error
}

TriageResult contains the results of a triage operation.

type UnmanageOptions

type UnmanageOptions struct {
	// Purge deletes the package directory instead of restoring files
	Purge bool
	// Restore moves adopted files back to target directory (default for adopted packages)
	Restore bool
	// Cleanup removes orphaned manifest entries (packages with no links or missing directories)
	Cleanup bool
}

UnmanageOptions configures unmanage behavior.

func DefaultUnmanageOptions

func DefaultUnmanageOptions() UnmanageOptions

DefaultUnmanageOptions returns default unmanage options.

type UnmanageService

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

UnmanageService handles package removal (unmanage operations).

func (*UnmanageService) PlanUnmanage

func (s *UnmanageService) PlanUnmanage(ctx context.Context, packages ...string) (Plan, error)

PlanUnmanage computes the execution plan for unmanaging packages.

func (*UnmanageService) Unmanage

func (s *UnmanageService) Unmanage(ctx context.Context, packages ...string) error

Unmanage removes the specified packages by deleting symlinks. Uses default options (restore adopted packages, don't purge).

func (*UnmanageService) UnmanageAll

func (s *UnmanageService) UnmanageAll(ctx context.Context, opts UnmanageOptions) (int, error)

UnmanageAll removes all installed packages with specified options. Returns the count of packages unmanaged.

func (*UnmanageService) UnmanageWithOptions

func (s *UnmanageService) UnmanageWithOptions(ctx context.Context, opts UnmanageOptions, packages ...string) error

UnmanageWithOptions removes packages with specified options.

type UpdateCheckResult added in v0.6.3

type UpdateCheckResult = updater.CheckResult

UpdateCheckResult contains the result of an update check.

type VersionChecker added in v0.6.3

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

VersionChecker checks for new versions on GitHub.

func NewVersionChecker added in v0.6.3

func NewVersionChecker(repository string) *VersionChecker

NewVersionChecker creates a new version checker.

func (*VersionChecker) CheckForUpdate added in v0.6.3

func (v *VersionChecker) CheckForUpdate(currentVersion string, includePrerelease bool) (*GitHubRelease, bool, error)

CheckForUpdate checks if a new version is available.

type WarningInfo

type WarningInfo = domain.WarningInfo

WarningInfo represents warning information in plan metadata.

type WriteOptions added in v0.6.3

type WriteOptions = config.WriteOptions

WriteOptions contains options for writing configuration.

Jump to

Keyboard shortcuts

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