Documentation
¶
Overview ¶
Package profile manages the ccx profile registry (~/.ccx/profiles.toml). It implements profile CRUD, validation, atomic file writes, and active- profile detection. All ProfileManager methods take context.Context. The registry file is rewritten atomically on every mutation (write to profiles.toml.tmp, then os.Rename).
Index ¶
- Constants
- func ValidateProfile(p contracts.Profile) error
- type Manager
- func (m *Manager) Active(ctx context.Context) (contracts.Profile, bool, error)
- func (m *Manager) Add(ctx context.Context, p contracts.Profile) error
- func (m *Manager) Get(ctx context.Context, name string) (contracts.Profile, error)
- func (m *Manager) List(ctx context.Context) ([]contracts.Profile, error)
- func (m *Manager) MarkUsed(ctx context.Context, name string) error
- func (m *Manager) Path() string
- func (m *Manager) Remove(ctx context.Context, name string) error
- func (m *Manager) Root() string
- func (m *Manager) Update(ctx context.Context, name string, fn func(*contracts.Profile) error) error
Constants ¶
const ( EnvActiveProfile = "CCX_ACTIVE_PROFILE" EnvConfigDir = "CLAUDE_CONFIG_DIR" )
Environment variable names that control active-profile detection. Defined here so tests and callers reference a single source of truth.
Variables ¶
This section is empty.
Functions ¶
func ValidateProfile ¶
ValidateProfile checks that p is well-formed enough to be stored in the registry. It does NOT touch the filesystem; existence checks are done by the Manager so that pure validation is cheap and testable.
Rules:
- Name is non-empty
- Name matches ^[a-z0-9-]+$
- ConfigDir is non-empty and absolute (filepath.IsAbs)
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the profile registry at <root>/profiles.toml. All mutating methods rewrite the whole file atomically. The zero Manager is not usable; always construct via NewManager.
func NewManager ¶
NewManager returns a Manager rooted at the given directory (typically ~/.ccx). The directory does not need to exist yet; it is created lazily by the first mutating call.
func (*Manager) Active ¶
Active returns the active profile, if any, plus a boolean indicating whether one was found.
Resolution order, per spec section 6:
- If CCX_ACTIVE_PROFILE is set, look it up in the registry. Found -> return (p, true, nil). Not found -> (zero, false, ErrProfileNotFound wrapped).
- Else, if CLAUDE_CONFIG_DIR is set, search the registry by ConfigDir. Found -> return (p, true, nil). Not found -> (zero, false, ErrNoActiveProfile wrapped) to indicate an "unmanaged" config dir.
- Else, return (zero, false, nil) - no active profile and no error.
func (*Manager) Add ¶
Add registers a new profile. Behavior:
- Validates the profile shape (name, absolute ConfigDir).
- Rejects with contracts.ErrProfileAlreadyExists if another profile has the same name.
- Ensures ConfigDir exists (creating it with mode 0700 if missing).
- Sets CreatedAt/LastUsedAt to time.Now().UTC() when the caller leaves them zero, so callers can pass a bare Profile{Name, ConfigDir}.
- Writes the full registry atomically.
func (*Manager) Get ¶
Get returns the profile with the given name. If no such profile exists, the returned error wraps contracts.ErrProfileNotFound.
func (*Manager) List ¶
List returns all profiles, sorted by Name. The returned slice is a fresh copy; mutating it does not affect the on-disk registry.
func (*Manager) MarkUsed ¶
MarkUsed updates the LastUsedAt field of the named profile to time.Now() in UTC. It is intended to be called by the cli layer after `ccx use` successfully emits an activation script. If no such profile exists, the returned error wraps contracts.ErrProfileNotFound.