completion

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package completion provides tab completion support for the basecamp CLI. It implements a file-based cache for projects, people, and accounts data that enables fast, offline-capable shell completions without requiring API calls.

Index

Constants

View Source
const (
	// CacheVersion is the current cache schema version.
	CacheVersion = 1

	// DefaultMaxAge is the default cache staleness threshold (1 hour).
	DefaultMaxAge = time.Hour

	// CacheFileName is the default cache file name.
	CacheFileName = "completion.json"
)

Variables

This section is empty.

Functions

func DefaultCacheDirFunc

func DefaultCacheDirFunc(cmd *cobra.Command) string

DefaultCacheDirFunc returns the cache directory by checking (in order): 1. --cache-dir flag on the root command 2. App config from context (set by PersistentPreRunE) 3. BASECAMP_CACHE_DIR environment variable 4. Default cache directory

This is the standard CacheDirFunc that all commands should use.

Limitation: During __complete, PersistentPreRunE doesn't run, so appctx is not set and config files are not loaded. This means cache_dir set in config files is NOT honored during completion—only --cache-dir flag and env vars work. This is intentional: loading config files adds latency that defeats fast completions. Users who set cache_dir in config should also set BASECAMP_CACHE_DIR.

Types

type Cache

type Cache struct {
	Projects          []CachedProject `json:"projects,omitempty"`
	People            []CachedPerson  `json:"people,omitempty"`
	Accounts          []CachedAccount `json:"accounts,omitempty"`
	ProjectsUpdatedAt time.Time       `json:"projects_updated_at"`
	PeopleUpdatedAt   time.Time       `json:"people_updated_at"`
	AccountsUpdatedAt time.Time       `json:"accounts_updated_at"`
	UpdatedAt         time.Time       `json:"updated_at"` // Legacy, kept for backwards compat
	Version           int             `json:"version"`    // Schema version for future migrations
}

Cache stores completion data with metadata for staleness detection.

type CacheDirFunc

type CacheDirFunc func(cmd *cobra.Command) string

CacheDirFunc returns the cache directory to use for completion. Takes the command to allow checking both context and flags at completion time.

type CachedAccount

type CachedAccount struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

CachedAccount holds account data for tab completion.

type CachedPerson

type CachedPerson struct {
	ID           int64  `json:"id"`
	Name         string `json:"name"`
	EmailAddress string `json:"email_address,omitempty"`
}

CachedPerson holds person data for tab completion.

type CachedProfile

type CachedProfile struct {
	Name    string
	BaseURL string
}

CachedProfile holds profile data for tab completion. Unlike other cached items, profiles come from config files, not API calls.

type CachedProject

type CachedProject struct {
	ID         int64     `json:"id"`
	Name       string    `json:"name"`
	Purpose    string    `json:"purpose,omitempty"` // "hq", "team", or empty
	Bookmarked bool      `json:"bookmarked,omitempty"`
	UpdatedAt  time.Time `json:"updated_at"`
}

CachedProject holds project data for tab completion. Fields are chosen to support ranking (HQ, Bookmarked, Recent) and display.

type Completer

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

Completer provides tab completion functions for the basecamp CLI. It reads from a file-based cache and does NOT initialize the full App or SDK.

func NewCompleter

func NewCompleter(getCacheDir CacheDirFunc) *Completer

NewCompleter creates a new Completer. The getCacheDir function is called at completion time to determine the cache directory. If nil, DefaultCacheDirFunc is used.

func (*Completer) AccountCompletion

func (c *Completer) AccountCompletion() cobra.CompletionFunc

AccountCompletion returns a Cobra completion function for account arguments. Accounts are sorted alphabetically by name. The --account flag takes an ID.

func (*Completer) PeopleCompletion

func (c *Completer) PeopleCompletion() cobra.CompletionFunc

PeopleCompletion returns a Cobra completion function for person arguments. People are sorted alphabetically by name, with "me" always first if it matches the filter.

func (*Completer) PeopleNameCompletion

func (c *Completer) PeopleNameCompletion() cobra.CompletionFunc

PeopleNameCompletion returns a Cobra completion function for person name arguments. People are sorted alphabetically by name, with "me" always first if it matches the filter.

func (*Completer) ProfileCompletion

func (c *Completer) ProfileCompletion() cobra.CompletionFunc

ProfileCompletion returns a Cobra completion function for profile arguments. Profiles come from the config file's profiles map. Since completion runs before PersistentPreRunE, we need to load the config directly here.

func (*Completer) ProjectCompletion

func (c *Completer) ProjectCompletion() cobra.CompletionFunc

ProjectCompletion returns a Cobra completion function for project arguments. Projects are ranked: HQ > Bookmarked > Recent > Alphabetical.

func (*Completer) ProjectNameCompletion

func (c *Completer) ProjectNameCompletion() cobra.CompletionFunc

ProjectNameCompletion returns a Cobra completion function for project name arguments. Unlike ProjectCompletion, this returns names instead of IDs for commands that accept names.

type RefreshResult

type RefreshResult struct {
	ProjectsCount int
	PeopleCount   int
	ProjectsErr   error
	PeopleErr     error
}

RefreshResult contains the outcome of a refresh operation.

func (RefreshResult) Error

func (r RefreshResult) Error() error

Error returns a combined error message if any operation failed.

func (RefreshResult) HasError

func (r RefreshResult) HasError() bool

HasError returns true if any refresh operation failed.

type Refresher

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

Refresher handles background cache refresh operations.

func NewRefresher

func NewRefresher(store *Store, sdk *basecamp.AccountClient) *Refresher

NewRefresher creates a new cache refresher.

func (*Refresher) IsRefreshing

func (r *Refresher) IsRefreshing() bool

IsRefreshing returns true if a background refresh is in progress.

func (*Refresher) RefreshAll

func (r *Refresher) RefreshAll(ctx context.Context) RefreshResult

RefreshAll fetches fresh data from the API and updates the cache. This is a synchronous operation - use RefreshIfStale for async. On partial failure, preserves existing cached data for the failed portion. Returns RefreshResult with counts and any errors encountered.

func (*Refresher) RefreshIfStale

func (r *Refresher) RefreshIfStale(maxAge time.Duration)

RefreshIfStale triggers a background refresh if the cache is stale. Returns immediately - the refresh happens asynchronously. If a refresh is already in progress, this is a no-op.

func (*Refresher) RefreshPeople

func (r *Refresher) RefreshPeople(ctx context.Context) error

RefreshPeople fetches fresh people data and updates the cache.

func (*Refresher) RefreshProjects

func (r *Refresher) RefreshProjects(ctx context.Context) error

RefreshProjects fetches fresh project data and updates the cache.

type Store

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

Store handles reading and writing the completion cache.

func NewStore

func NewStore(dir string) *Store

NewStore creates a new cache store. If dir is empty, it uses the default location (~/.cache/basecamp/).

func (*Store) Accounts

func (s *Store) Accounts() []CachedAccount

Accounts returns cached accounts, or nil if cache is empty/missing.

func (*Store) Clear

func (s *Store) Clear() error

Clear removes the cache file.

func (*Store) Dir

func (s *Store) Dir() string

Dir returns the cache directory path.

func (*Store) IsStale

func (s *Store) IsStale(maxAge time.Duration) bool

IsStale returns true if the cache is older than maxAge or incomplete. A cache is considered stale if: - It doesn't exist or can't be loaded - Either per-section timestamp is missing (legacy cache or incomplete) - The oldest section timestamp exceeds maxAge

func (*Store) Load

func (s *Store) Load() (*Cache, error)

Load reads the cache from disk. Returns an empty cache if the file doesn't exist or is invalid.

func (*Store) Path

func (s *Store) Path() string

Path returns the full path to the cache file.

func (*Store) People

func (s *Store) People() []CachedPerson

People returns cached people, or nil if cache is empty/missing.

func (*Store) Profiles

func (s *Store) Profiles() []CachedProfile

Profiles returns configured profiles for tab completion. Since profiles are defined in config files (not API-fetched), this loads the config directly rather than from the completion cache.

func (*Store) Projects

func (s *Store) Projects() []CachedProject

Projects returns cached projects, or nil if cache is empty/missing.

func (*Store) Save

func (s *Store) Save(cache *Cache) error

Save writes the cache to disk atomically. Sets ProjectsUpdatedAt, PeopleUpdatedAt, and UpdatedAt to now. AccountsUpdatedAt is NOT set here; use UpdateAccounts for that. Note: Works on a copy to avoid mutating the caller's cache instance.

func (*Store) UpdateAccounts

func (s *Store) UpdateAccounts(accounts []CachedAccount) error

UpdateAccounts updates just the accounts in the cache. Only updates AccountsUpdatedAt, preserving other timestamps. Note: Accounts are user-level (not account-scoped like projects/people), so they're refreshed separately via `basecamp me`.

func (*Store) UpdatePeople

func (s *Store) UpdatePeople(people []CachedPerson) error

UpdatePeople updates just the people in the cache. Only updates PeopleUpdatedAt, preserving ProjectsUpdatedAt.

func (*Store) UpdateProjects

func (s *Store) UpdateProjects(projects []CachedProject) error

UpdateProjects updates just the projects in the cache. Only updates ProjectsUpdatedAt, preserving PeopleUpdatedAt.

Jump to

Keyboard shortcuts

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