Documentation
¶
Overview ¶
Package state manages persisted runtime data for a hygge installation.
What lives here ¶
Runtime mutable data that is machine-written (not human-edited): the active profile name, last-used model, recent session identifiers, and per-file trust decisions. This is distinct from config-as-source (TOML files in $XDG_CONFIG_HOME/hygge/), which belongs in package config.
Storage format ¶
JSON, stored at $XDG_STATE_HOME/hygge/state.json (fallback: $HOME/.local/state/hygge/state.json). The directory is created with mode 0o700 on first write; the file itself is written with mode 0o600.
Atomic writes ¶
Save writes to a sibling .tmp file first, syncs, closes, then renames to the real path. Rename is atomic on POSIX filesystems, so readers always see either the previous complete file or the new complete file — never a partial write.
Single-instance limitation ¶
v0.1 provides no daemon or advisory-lock coordination. Each call to Load and Save does a discrete file operation; concurrent processes on the same state file may overwrite each other's changes if they read, modify, and save the state in overlapping windows. This is acceptable for v0.1 where hygge is typically run as a single process. A future version may add advisory locking or a version/sequence field to detect and reject stale writes.
Index ¶
- Constants
- Variables
- func AddAllowRule(rule AllowRule, opts LoadOptions) error
- func AddProjectAllowRule(rule AllowRule, projectDir string) error
- func AddRecentSession(id string, opts LoadOptions) error
- func GitBranch(projectPath string) string
- func InvalidateBranchCache(projectPath string)
- func IsConfigTrusted(absPath string, expectedSha256 string, opts LoadOptions) (bool, error)
- func Path(opts LoadOptions) (string, error)
- func ProjectPermissionsPath(projectDir string) (string, error)
- func RemoveAllowRule(category, pattern string, opts LoadOptions) error
- func Save(s *State, opts LoadOptions) error
- func SetActiveProfile(name string, opts LoadOptions) error
- func SetLastUsedModel(ref ModelRef, opts LoadOptions) error
- func ToggleFavoriteModel(ref string, opts LoadOptions) error
- func TrustConfig(absPath string, sha256hex string, opts LoadOptions) error
- type AllowRule
- type LoadOptions
- type ModelRef
- type State
- type TouchedFiles
Constants ¶
const MaxRecentSessions = 20
MaxRecentSessions is the maximum number of session IDs retained in State.RecentSessions. Older entries are dropped when the cap is reached.
Variables ¶
var ErrCorruptState = errors.New("state file is corrupt or from a newer version")
ErrCorruptState is returned when the state file exists but cannot be decoded as valid JSON conforming to the known schema. This covers empty files, malformed JSON, and files that contain unknown top-level fields (which indicate a state file written by a newer version of hygge).
Functions ¶
func AddAllowRule ¶
func AddAllowRule(rule AllowRule, opts LoadOptions) error
AddAllowRule appends rule to State.AllowedRules and persists. If a rule with the same Category and Pattern already exists, it is left in place and the timestamp is not refreshed (idempotent). The CreatedAt field is set from time.Now if zero.
func AddProjectAllowRule ¶ added in v0.12.0
AddProjectAllowRule appends rule to the project-scoped allow rules at <projectDir>/.hygge/permissions.json, persisting atomically. If a rule with the same Category and Pattern already exists, it is left in place and the call is a no-op. The CreatedAt field is set from time.Now if zero.
func AddRecentSession ¶
func AddRecentSession(id string, opts LoadOptions) error
AddRecentSession prepends id to State.RecentSessions. If id is already present in the list it is removed from its prior position before being prepended (most-recent reference wins). The list is capped at MaxRecentSessions; entries beyond the cap are dropped from the tail.
func GitBranch ¶
GitBranch returns the current branch (or detached-HEAD short SHA) for the repository rooted at or above projectPath. The result is cached per projectPath for the lifetime of the process.
Detection strategy (no git subprocess):
- Walk up from projectPath to the filesystem root looking for a .git directory.
- Read .git/HEAD. - If the content begins with "ref: refs/heads/", strip that prefix and return the branch name. - Otherwise assume a detached HEAD: return "@" + first 7 hex characters of the SHA (e.g. "@a1b2c3d").
- If no .git directory is found, return "".
func InvalidateBranchCache ¶ added in v0.12.0
func InvalidateBranchCache(projectPath string)
InvalidateBranchCache removes the cached branch name for projectPath so the next call to GitBranch re-reads .git/HEAD from disk. Call this when the branch is expected to have changed (e.g. when a new user message is sent or a new session starts) to ensure the sidebar reflects the current branch without paying a filesystem read on every render tick.
func IsConfigTrusted ¶
func IsConfigTrusted(absPath string, expectedSha256 string, opts LoadOptions) (bool, error)
IsConfigTrusted returns true iff a sha256 digest has been recorded for absPath and it matches expectedSha256. Missing entries and digest mismatches both return false.
func Path ¶
func Path(opts LoadOptions) (string, error)
Path returns the resolved path to state.json for the given options. The file need not exist.
func ProjectPermissionsPath ¶ added in v0.12.0
ProjectPermissionsPath returns the path to the project-scoped permissions file for the given project directory. The file need not exist. Returns an error only when projectDir is empty.
func RemoveAllowRule ¶
func RemoveAllowRule(category, pattern string, opts LoadOptions) error
RemoveAllowRule removes any rules in State.AllowedRules whose Category and Pattern match the supplied values. Idempotent: removing a missing rule returns nil.
func Save ¶
func Save(s *State, opts LoadOptions) error
Save writes s to disk atomically. The target directory is created with mode 0o700 if it does not exist. The state file is written with mode 0o600.
func SetActiveProfile ¶
func SetActiveProfile(name string, opts LoadOptions) error
SetActiveProfile sets the active profile name and persists the change.
func SetLastUsedModel ¶
func SetLastUsedModel(ref ModelRef, opts LoadOptions) error
SetLastUsedModel records the most recently used provider/model and persists the change.
func ToggleFavoriteModel ¶ added in v0.15.0
func ToggleFavoriteModel(ref string, opts LoadOptions) error
ToggleFavoriteModel adds ref to State.FavoriteModels if it is not already present, or removes it if it is. The list preserves insertion order; new favorites are appended. ref should be in "provider/model" form.
func TrustConfig ¶
func TrustConfig(absPath string, sha256hex string, opts LoadOptions) error
TrustConfig records that the file at absPath has been trusted at the given sha256hex digest. On subsequent loads, callers should compare the stored digest to the live file's digest; a mismatch means trust has expired.
Types ¶
type AllowRule ¶
type AllowRule struct {
// Category is the permission category: "file.read", "file.write",
// "shell", or "network".
Category string `json:"category"`
// Pattern is the doublestar glob the rule applies to. Typically this is
// the exact Target from the request that prompted the user, but
// mutators accept any valid glob.
Pattern string `json:"pattern"`
// CreatedAt is the unix-millisecond timestamp when the rule was
// recorded.
CreatedAt int64 `json:"created_at"`
}
AllowRule is a persisted "always-allow" decision made by the user through a permission prompt. It is matched against incoming permission requests by the permission engine. Patterns are doublestar globs (the literal Target from the original request is a valid pattern, since it matches itself).
func LoadProjectAllowRules ¶ added in v0.12.0
LoadProjectAllowRules reads the project-scoped allow rules from <projectDir>/.hygge/permissions.json. If the file does not exist, an empty slice is returned with a nil error. Corrupt files return ErrCorruptState.
type LoadOptions ¶
type LoadOptions struct {
// HomeDir overrides $HOME for XDG fallback computation. Empty = real HOME.
HomeDir string
// XDGStateHome overrides $XDG_STATE_HOME. Empty = real env or fallback.
XDGStateHome string
}
LoadOptions controls how Load, Save, and Path resolve the state file path. The zero value uses real environment variables and the real home directory.
type State ¶
type State struct {
ActiveProfile string `json:"active_profile,omitempty"`
LastUsedModel *ModelRef `json:"last_used_model,omitempty"`
RecentSessions []string `json:"recent_sessions,omitempty"`
TrustedConfigs map[string]string `json:"trusted_configs,omitempty"` // absolute path -> sha256 hex
AllowedRules []AllowRule `json:"allowed_rules,omitempty"`
// FavoriteModels is an ordered list of "provider/model" strings the user
// has marked as favorites in the model picker. Stored globally so the
// list is shared across all projects and survives restarts.
FavoriteModels []string `json:"favorite_models,omitempty"`
}
State is the persisted runtime data for a hygge installation.
All fields are optional (omitempty); a zero-value State is valid and represents a clean first-run installation.
func Load ¶
func Load(opts LoadOptions) (*State, error)
Load reads state from disk. If the file does not exist, Load returns a zero-valued State and a nil error — missing state on first run is not an error. If the file exists but cannot be decoded, Load returns ErrCorruptState wrapping the underlying error.
type TouchedFiles ¶
type TouchedFiles struct {
// contains filtered or unexported fields
}
TouchedFiles tracks absolute paths of files modified during the session. Paths are deduplicated; the set is safe for concurrent access.
func NewTouchedFiles ¶
func NewTouchedFiles() *TouchedFiles
NewTouchedFiles returns an empty, ready-to-use TouchedFiles.
func (*TouchedFiles) Add ¶
func (t *TouchedFiles) Add(absPath, projectDir string)
Add registers absPath as touched. If absPath is relative it is resolved against projectDir before storing. Empty strings, bare ".", and paths that resolve to the project directory itself are silently ignored.
func (*TouchedFiles) Len ¶
func (t *TouchedFiles) Len() int
Len returns the number of tracked paths.
func (*TouchedFiles) List ¶
func (t *TouchedFiles) List() []string
List returns all tracked paths, sorted lexicographically. The returned slice is a copy; callers may modify it freely.