app

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Overview

Package app is gskill's orchestration layer. It exposes use-case methods that the cli and tui views call, and is the only layer that drives the domain packages (resolver, installer, store, and the rest). Views never import the domain packages directly.

Index

Constants

View Source
const (
	LockSkillInstalled = "installed"
	LockSkillUpToDate  = "up-to-date"
	LockSkillRepaired  = "repaired"
	LockSkillFailed    = "failed"
	LockSkillPlanned   = "planned" // dry-run only
)

Lock-install per-skill statuses (contracts/cli-install-migrate.md).

View Source
const (
	PlannedWouldInstall      = "would-install"
	PlannedWouldRepair       = "would-repair"
	PlannedWouldRemoveTarget = "would-remove-target"
	PlannedWouldUpdateLock   = "would-update-lock"
	PlannedBlocked           = "blocked"
)

Planned actions distinguish what a dry-run entry would do (spec 014 FR-026).

View Source
const (
	VersionLatest  = "latest"
	VersionRelease = "release"
	VersionBranch  = "branch"
	VersionCommit  = "commit"
)

Version candidate kinds offered by the wizard's version step (US3).

View Source
const (
	ConflictCrossSource   = "cross_source_collision"
	ConflictNoopReadd     = "noop_readd"
	ConflictFileOverwrite = "file_overwrite"
)

Plan-time conflict kinds (spec 011 data-model.md). Detection semantics are exactly planAdd's, so guided and non-guided adds fail on the same conflicts.

View Source
const (
	PlanLineMeta     = "meta"     // source / version / agents header
	PlanLineInit     = "init"     // project scaffolding notice (FR-023)
	PlanLineAgent    = "agent"    // per-agent group header ("claude:")
	PlanLineAction   = "action"   // "skill → destination"
	PlanLineFileOp   = "fileop"   // "create|update path"
	PlanLineWarning  = "warning"  // resolution/install warnings
	PlanLineConflict = "conflict" // blocking conflict detail
)

PlanLine kinds, in emission order.

Variables

This section is empty.

Functions

func IntersectStrings added in v0.3.0

func IntersectStrings(a, b []string) []string

IntersectStrings returns the values present in both a and b, in a's order.

func RevisionLabel added in v0.3.0

func RevisionLabel(rev resolver.Revision) string

RevisionLabel names a resolved revision for display and error messages — the single label shared by the wizard preview, dry-run output, and plan errors, so the surfaces cannot disagree on the same revision.

func ShortCommit added in v0.3.0

func ShortCommit(sha string) string

ShortCommit abbreviates a commit SHA to the display width every human surface uses (plan/dry-run labels, version metadata, progress lines), so the same commit never renders at two different lengths in one run.

func Subtract added in v0.3.0

func Subtract(a, b []string) []string

Subtract returns the values in a that are not in b.

Types

type AddRequest

type AddRequest struct {
	Root    string
	Source  string
	Version string
	Ref     string
	Commit  string
	Agents  []string
	Force   bool
	Scope   string
	Mode    string

	// Selection (US2). Selectors are raw --skill values (incl. "*"); All maps
	// --all; Path is the --path disambiguator; ListOnly maps --list.
	Selectors   []string
	All         bool
	Path        string
	ListOnly    bool
	Interactive bool

	// Discovery filters (FR-012).
	MaxDepth int
	Include  []string
	Exclude  []string

	// Chooser, when set and Interactive, picks among multiple discovered skills.
	// It receives every in-scope skill (invalid ones shown but not selectable)
	// and returns the chosen subset. The CLI wires this to the TUI picker; the
	// app stays independent of the view layer (FR-021).
	Chooser func([]discovery.DiscoveredSkill) ([]discovery.DiscoveredSkill, error)

	// Progress, when non-nil, receives install lifecycle events (spec 014,
	// contracts/install-progress-events.md); nil keeps the run unobserved.
	Progress func(InstallProgressEvent)
}

AddRequest describes an `add` invocation.

type AddResult

type AddResult struct {
	Installed []InstalledSkill
	Listed    []discovery.DiscoveredSkill // populated for --list (no install)
	Warnings  []string
}

AddResult reports the outcome of an add (one or more skills).

type AgentChoice added in v0.3.0

type AgentChoice struct {
	ID          string
	DisplayName string
	Detected    bool
	Preselected bool
}

AgentChoice is one row of the wizard's agent step (US2, FR-014).

type AgentHealthEntry added in v0.3.0

type AgentHealthEntry struct {
	ID     string `json:"id"`
	Mode   string `json:"mode"`
	Health string `json:"health"`
}

AgentHealthEntry is one agent's install mode and health for a skill.

type App

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

App holds the injected dependencies shared by every use-case. Business logic is added by sibling files (install.go, inspect.go, lifecycle.go, ...).

func New

func New(opts Options) *App

New builds an App from opts, filling in defaults for any nil dependency.

func (*App) Add

func (a *App) Add(ctx context.Context, req AddRequest) (AddResult, error)

Add resolves, installs, and records a new skill, updating the shared lock. It errors on an already-declared key unless Force is set (FR-047), and writes nothing when no target agent is available (FR-029).

func (*App) AgentChoices added in v0.3.0

func (a *App) AgentChoices(ctx context.Context, root string) ([]AgentChoice, error)

AgentChoices returns the wizard's agent step data: every registered agent, which ones are detected for this project, and — preselected — the exact set a non-guided add would target (explicit-free resolution: lock-declared agents, then detection, then the default agent), per FR-014.

func (*App) Agents

func (a *App) Agents() *agent.Registry

Agents returns the agent registry.

func (*App) Check

func (a *App) Check(_ context.Context, root string, failOnDrift bool) (CheckReport, error)

Check produces a drift report over the three-hop chain (store → active → agent). With failOnDrift, any drift returns exit 7 (FR-016). A present-but- corrupt store fails closed with exit 6 regardless of the flag (FR-018).

func (*App) Config

func (a *App) Config() *config.Config

Config returns the resolved configuration.

func (*App) Diff

func (a *App) Diff(_ context.Context, root string) ([]DiffEntry, error)

Diff reports lock/disk drift per skill.

func (*App) DiscoverSource added in v0.3.0

func (a *App) DiscoverSource(ctx context.Context, req DiscoverRequest) (DiscoverResult, error)

DiscoverSource resolves the source to a revision and discovers every skill in it. It writes only to the content cache/store (same as `add --list`), never to the manifest, lockfile, or agent directories.

func (*App) Doctor

func (a *App) Doctor(ctx context.Context, root string) (DoctorReport, error)

Doctor checks the environment (git, detected agents) and reports declared requirements, warning on any that are unmet (FR-032). It never installs.

func (*App) ExecutePlan added in v0.3.0

func (a *App) ExecutePlan(ctx context.Context, plan InstallPlan, progress func(InstallProgressEvent)) (AddResult, error)

ExecutePlan performs a previously computed InstallPlan: optional project initialization (FR-023), then the staged, checksum-verified, rollback-on- failure install and the atomic lock commit — the exact pipeline non-guided adds use. It refuses a conflicted plan outright (defense in depth; the wizard's approval step already blocks on conflicts, FR-016/FR-017). progress, when non-nil, receives per-skill events.

func (*App) Find added in v0.1.0

func (a *App) Find(ctx context.Context, query string, scope FindScope) ([]SearchHit, []string, error)

Find searches for skills matching query within a source, across a GitHub owner, or across the configured repositories — always including locally installed skills. Unreachable repositories are reported as warnings rather than aborting the search (FR-036..FR-041). It returns hits and warnings.

func (*App) GskillHome added in v0.4.0

func (a *App) GskillHome() string

GskillHome returns the App-level home override ("" when the environment resolution applies). Tests use it to locate their private store.

func (*App) Info

func (a *App) Info(_ context.Context, root, name string) (SkillInfo, error)

Info returns the full detail for one locked skill.

func (*App) Init

func (a *App) Init(_ context.Context, root string, withLock bool) (InitResult, error)

Init prepares local gskill runtime state: the .gskill state dir, the canonical .agents/skills layer, and .gitignore hints. It never creates a manifest; an empty skills-lock.json is written only when withLock is set. It is idempotent.

func (*App) InstallFromLock added in v0.3.0

func (a *App) InstallFromLock(ctx context.Context, req InstallFromLockRequest) (InstallFromLockResult, error)

InstallFromLock implements the install pipeline: locate and validate skills-lock.json, auto-initialize local state (FR-019/FR-020), then per entry resolve, verify the npx-compatible computedHash before activation, install for the entry's target agents (the entry's declared set, or the exact explicit --agent override when one is given — spec 013), and record the namespaced gskill metadata (FR-016). Failures are isolated per skill: verified successes stay installed and recorded (FR-016a).

func (*App) List

func (a *App) List(_ context.Context, root string) ([]ListedSkill, error)

List returns every locked skill with its drift status, active-layer health, and per-agent health — the union of what `list` and `status` used to report separately (spec 013 FR-001). Health is evaluated with the same non-hash-verifying call `status` used, so this adds no new I/O-heavy work.

func (*App) ListVersions added in v0.3.0

func (a *App) ListVersions(ctx context.Context, root, src string, offline bool) (VersionList, error)

ListVersions lists the selectable versions of a source for the wizard's version step: a synthetic "latest" first, then releases (semver descending), other tags, and branch heads. Listing problems never fail the flow: offline mode, network errors, and rate limits all return a Degraded listing with a reason while "latest" stays selectable and a typed exact ref is still accepted downstream (FR-012).

func (*App) Logger

func (a *App) Logger() *slog.Logger

Logger returns the structured logger.

func (*App) MigrateGlobalStore added in v0.4.0

func (a *App) MigrateGlobalStore(ctx context.Context, root string, dryRun bool) (MigrateReport, error)

MigrateGlobalStore converts a project from the legacy project-local store to the user-level global store (spec 015 US5). Dry-run reports the plan and changes nothing; a real run verifies, dedupes/copies, relinks, updates machine-local state, and removes the legacy store only after complete success — any earlier failure leaves the project fully usable (FR-038).

func (*App) Outdated

func (a *App) Outdated(ctx context.Context, root string) (OutdatedReport, error)

Outdated reports available updates per locked skill (FR-009).

func (*App) PlanInstall added in v0.3.0

func (a *App) PlanInstall(ctx context.Context, req PlanRequest) (InstallPlan, error)

PlanInstall derives the installation plan for the selected skills: per skill × agent destinations, merge-vs-fresh decisions, and conflicts. It is pure computation over the manifest, lockfile, and discovery result — it acquires no lock and writes nothing (SC-002 is structural: only ExecutePlan writes).

func (*App) PreviewLock added in v0.3.0

func (a *App) PreviewLock(root string) (LockPreview, bool, error)

PreviewLock loads and validates the shared lock for display. found=false (with a nil error) means the project has no skills-lock.json.

func (*App) ProjectsInspect added in v0.4.0

func (a *App) ProjectsInspect(_ context.Context, projectID string) (projreg.Entry, error)

ProjectsInspect returns one registry entry.

func (*App) ProjectsList added in v0.4.0

func (a *App) ProjectsList(_ context.Context) ([]ProjectInfo, error)

ProjectsList lists the advisory registry (FR-028).

func (*App) ProjectsPrune added in v0.4.0

func (a *App) ProjectsPrune(ctx context.Context) ([]string, error)

ProjectsPrune removes registry entries whose project no longer exists. It removes registry files only — never repository content (FR-028).

func (*App) ProjectsRefresh added in v0.4.0

func (a *App) ProjectsRefresh(ctx context.Context) (refreshed []string, err error)

ProjectsRefresh re-derives every registered entry from its project's current lockfile, dropping entries per the privacy mode (FR-028/029).

func (*App) QualifiesLocalAgentAdd added in v0.3.0

func (a *App) QualifiesLocalAgentAdd(_ context.Context, root string, req AddRequest) bool

QualifiesLocalAgentAdd reports whether an add request is a pure agent-add — adding agents to already-locked skills from the same source — which App.Add serves entirely from the lockfile and store with no resolver or network call. The guided wizard has no equivalent shortcut, so such requests should take the direct path (review finding: offline interactive agent-adds). The check is read-only.

func (*App) Remove

func (a *App) Remove(ctx context.Context, root string, names []string) (RemoveResult, error)

Remove uninstalls the named skills from the lock and every agent directory, then garbage-collects unreferenced store entries.

func (*App) Repair

func (a *App) Repair(ctx context.Context, root string) (RepairResult, error)

Repair re-materializes broken or modified installs from the store/cache without changing the lockfile, and cleans up orphaned staging left by an interrupted install (FR-024, SC-007).

func (*App) SelectByFlags added in v0.3.0

func (a *App) SelectByFlags(disc DiscoverResult, selectors []string, all bool, path string) ([]discovery.DiscoveredSkill, error)

SelectByFlags resolves explicit --skill/--all selectors against a discovered source, exactly as the non-guided add does, so a flag-preselected wizard session and a scripted add choose identically (FR-004).

func (*App) SkillMarkdown

func (a *App) SkillMarkdown(_ context.Context, root, name string) (string, error)

SkillMarkdown returns the installed SKILL.md content for a skill, read from its first available agent target (for the TUI preview).

func (*App) SourceCheck added in v0.1.0

func (a *App) SourceCheck(ctx context.Context, sourceArg string, opts ScanOptions) (SourceCheckReport, error)

SourceCheck scans a source and reports its invalid and duplicate skills (FR-034). It is read-only; the caller maps HasProblems to a non-zero exit.

func (*App) SourceInspect added in v0.1.0

func (a *App) SourceInspect(ctx context.Context, sourceArg, selector, root string, opts ScanOptions) (SkillInspection, error)

SourceInspect scans a source and returns the detailed view of one selected skill (FR-033). The selector is a name or name@path; invalid skills can be inspected so their diagnostics are visible.

func (*App) SourceList added in v0.1.0

func (a *App) SourceList(ctx context.Context, sourceArg string, opts ScanOptions) (discovery.Result, error)

SourceList scans a source and returns every discovered skill, read-only (FR-032). It never writes to a manifest, lockfile, or agent directory.

func (*App) StoreGC added in v0.4.0

func (a *App) StoreGC(ctx context.Context, apply bool, olderThan time.Duration) (StoreGCReport, error)

StoreGC runs garbage collection: dry-run by default, deleting only with apply (FR-025). olderThan overrides the configured grace period when > 0.

func (*App) StoreInspect added in v0.4.0

func (a *App) StoreInspect(_ context.Context, key string) (StoreInspectReport, error)

StoreInspect verifies (full re-hash) and describes one object.

func (*App) StoreList added in v0.4.0

func (a *App) StoreList(_ context.Context) ([]StoreListItem, error)

StoreList lists every object with its origin-derived display facts and the count of known referencing projects.

func (*App) StorePin added in v0.4.0

func (a *App) StorePin(_ context.Context, key string) error

StorePin exempts an object from GC (FR-026).

func (*App) StorePins added in v0.4.0

func (a *App) StorePins(_ context.Context) ([]string, error)

StorePins lists pinned objects.

func (*App) StoreRepair added in v0.4.0

func (a *App) StoreRepair(ctx context.Context, key string) error

StoreRepair restores one corrupted object from its recorded exact origin (FR-023). It fails without touching the object when the exact source cannot be reproduced.

func (*App) StoreStatus added in v0.4.0

func (a *App) StoreStatus(ctx context.Context) (StoreStatusReport, error)

StoreStatus reports store-wide counts and sizes.

func (*App) StoreUnpin added in v0.4.0

func (a *App) StoreUnpin(_ context.Context, key string) error

StoreUnpin removes a GC exemption.

func (*App) StoreVerify added in v0.4.0

func (a *App) StoreVerify(_ context.Context) (StoreVerifyResult, error)

StoreVerify scans every global store object: full content re-hash, metadata validation, layout, permissions, and stray staging (FR-022).

func (*App) Sync

func (a *App) Sync(ctx context.Context, req SyncRequest) (SyncResult, error)

Sync reconciles the filesystem to the lock's declared state across the three layers (store → active → agent). It restores declared-but-missing installs and skips skills whose store, active entry, and agent targets already match — never re-resolving or re-downloading unchanged content (FR-010..FR-015). With Prune it removes managed agent targets and active entries the lock no longer declares; without Prune it reports such orphans instead of deleting them (FR-013).

func (a *App) Unlink(ctx context.Context, root, skill, agentID string, prune bool) (UnlinkResult, error)

Unlink removes a single agent's access to a skill without affecting other agents (FR-020, SC-008). When the last agent is unlinked, the active entry, store content, and lock entry are retained unless prune is set, in which case the skill is removed entirely and unreferenced store content is GC'd.

func (*App) Update

func (a *App) Update(ctx context.Context, root string, names []string) (InstallResult, error)

Update re-resolves the named skills (or all when names is empty) to the newest version within their constraints and rewrites the lock (FR-009).

func (*App) Verify

func (a *App) Verify(_ context.Context, root string) (VerifyReport, error)

Verify re-hashes every installed skill against the lockfile, failing closed on the first mismatch (exit 6, FR-015).

type CheckReport

type CheckReport struct {
	Skills   []SkillCheck
	HasDrift bool
}

CheckReport aggregates a check run.

type ConflictError added in v0.3.0

type ConflictError struct {
	Skill string
	Kind  string
	// contains filtered or unexported fields
}

ConflictError is a plan-time conflict as an error. It wraps the same errs-coded error the non-guided add path returns, so message text, exit code, and errors.Is behavior are identical in both flows.

func (*ConflictError) Error added in v0.3.0

func (e *ConflictError) Error() string

Error implements the error interface.

func (*ConflictError) Unwrap added in v0.3.0

func (e *ConflictError) Unwrap() error

Unwrap returns the underlying coded error.

type DiffEntry

type DiffEntry struct {
	Name   string
	Status string
}

DiffEntry reports how a locked skill differs from disk.

type DiscoverRequest added in v0.3.0

type DiscoverRequest struct {
	Root    string
	Source  string
	Version string
	Ref     string
	Commit  string
	Scope   string
	Mode    string

	// Discovery filters (FR-012 of spec 006).
	MaxDepth int
	Include  []string
	Exclude  []string
}

DiscoverRequest describes phase 1: resolve a source and discover its skills. It works without a project manifest, so the wizard runs on fresh directories too (FR-023).

type DiscoverResult added in v0.3.0

type DiscoverResult struct {
	Ref      source.Ref
	Revision resolver.Revision
	Scan     discovery.Result
	Skills   []discovery.DiscoveredSkill
	Warnings []string
}

DiscoverResult carries the resolved source and its skill catalog. Scan is the full discovery result (needed by selection); Skills is the catalog scoped to the source's explicit in-repo path, in display order.

type DoctorReport

type DoctorReport struct {
	GitAvailable   bool
	DetectedAgents []string
	Requirements   []RequirementCheck
	Warnings       []string
}

DoctorReport is the result of `gskill doctor`.

type FailureCategory added in v0.3.2

type FailureCategory string

FailureCategory is a normalized install-failure classification. Values are wire values in the --json document (contracts/install-result-json.md). Categories are derived from the typed errs sentinels via errors.Is/As — never by parsing error strings (spec 014 FR-013).

const (
	FailureSourceUnavailable FailureCategory = "source-unavailable"
	FailureAuthentication    FailureCategory = "authentication"
	FailureResolution        FailureCategory = "resolution"
	FailureInvalidMetadata   FailureCategory = "invalid-metadata"
	FailureUnsupportedSource FailureCategory = "unsupported-source"
	FailureUnsupportedAgent  FailureCategory = "unsupported-agent"
	FailureIntegrity         FailureCategory = "integrity"
	FailureStore             FailureCategory = "store"
	FailureFilesystem        FailureCategory = "filesystem"
	FailurePermission        FailureCategory = "permission"
	FailureForeignContent    FailureCategory = "foreign-content"
	FailureLink              FailureCategory = "link"
	FailureLockfile          FailureCategory = "lockfile"
	FailureCancelled         FailureCategory = "cancelled"
	FailureUnknown           FailureCategory = "unknown"
)

Failure categories (data-model.md classification table).

type FindScope added in v0.1.0

type FindScope struct {
	Source string
	Owner  string
	Root   string
}

FindScope selects where a search looks. Exactly one of Source/Owner may be set; when both are empty the configured repositories are searched. Local installed skills are always included.

type InitResult

type InitResult struct {
	LockPath string
	Created  []string
}

InitResult reports what Init created.

type InstallFailure added in v0.3.2

type InstallFailure struct {
	Category FailureCategory
	Phase    InstallPhase
	Message  string
	Hint     string
	Expected string // optional: recorded value (integrity mismatches)
	Actual   string // optional: observed value (integrity mismatches)
	Cause    error  // not serialized; kept for errors.Is/As in tests
}

InstallFailure is the structured explanation of one skill's failure: what category of problem, in which phase, the complete message, and — when the error chain carries one — an actionable remediation hint. Message may contain untrusted remote text; renderers must sanitize it.

type InstallFromLockRequest added in v0.3.0

type InstallFromLockRequest struct {
	Root string
	// Agents distinguishes "no explicit selection" (nil — FR-002a: use each
	// entry's recorded gskill.agents unchanged) from "explicit selection"
	// (non-nil, including a non-nil empty slice — FR-001/FR-002/FR-012: the
	// exact target set for every processed entry, replacing what's recorded).
	// This nil-vs-empty distinction is load-bearing; do not normalize it away
	// with a len()==0 check (research.md Decision 6).
	Agents      []string
	InstallMode string // auto | symlink | copy ("" = per-entry gskill.installMode)
	NoInit      bool   // refuse instead of auto-initializing
	Force       bool   // accept changed upstream content, rewrite computedHash
	DryRun      bool   // report the plan, write nothing
	Offline     bool   // restore from local store/cache only
	Frozen      bool   // never modify the lock file; fail closed on drift
	Prune       bool   // afterwards, remove managed installs the lock no longer declares
	// Progress, when non-nil, receives install lifecycle events synchronously
	// and strictly sequentially (contracts/install-progress-events.md). A nil
	// Progress makes the run behaviorally identical to an unobserved one.
	Progress func(InstallProgressEvent)
}

InstallFromLockRequest describes an install (spec 012 US1/US2, spec 013): restore every skill declared in skills-lock.json for its declared agents. An explicit --agent selection (spec 013) is the exact, authoritative target set for the run, replacing each entry's declared set outright.

type InstallFromLockResult added in v0.3.0

type InstallFromLockResult struct {
	Initialized bool
	Agents      []string
	Skills      []LockSkillResult
	Pruned      []string
	Changed     bool
}

InstallFromLockResult is the run summary.

type InstallOutcome added in v0.3.2

type InstallOutcome string

InstallOutcome is a run's overall result classification, serialized as the --json document's top-level status (contracts/install-result-json.md).

const (
	InstallOutcomeSuccess   InstallOutcome = "success"
	InstallOutcomePartial   InstallOutcome = "partial"
	InstallOutcomeFailure   InstallOutcome = "failure"
	InstallOutcomeCancelled InstallOutcome = "cancelled"
	InstallOutcomePlanned   InstallOutcome = "planned"
)

Run outcomes. Cancellation dominates: a user-interrupted run reports cancelled (exit 130) even when some entries had already failed.

type InstallPhase added in v0.3.2

type InstallPhase string

InstallPhase identifies the pipeline step a skill is in. Not every install emits every phase (the up-to-date fast path skips the fetch phases), but within one skill phases only ever advance (see Rank).

const (
	// InstallPhasePrefetching is a run-scoped phase (SkillName empty): the
	// pre-flight warming of source resolutions and the commit cache before
	// per-skill processing starts.
	InstallPhasePrefetching     InstallPhase = "prefetching"
	InstallPhaseResolving       InstallPhase = "resolving"
	InstallPhaseFetching        InstallPhase = "fetching"
	InstallPhaseReadingMetadata InstallPhase = "reading-metadata"
	InstallPhaseHashing         InstallPhase = "hashing"
	InstallPhaseVerifying       InstallPhase = "verifying"
	InstallPhaseStoring         InstallPhase = "storing"
	InstallPhaseLinking         InstallPhase = "linking"
	InstallPhaseLocking         InstallPhase = "locking"
	InstallPhaseCleaning        InstallPhase = "cleaning"
	InstallPhaseComplete        InstallPhase = "complete"
)

Install pipeline phases, in execution order.

func (InstallPhase) Rank added in v0.3.2

func (p InstallPhase) Rank() int

Rank returns the phase's pipeline position for monotonicity checks, or -1 for an unknown (including zero-value) phase.

type InstallPlan added in v0.3.0

type InstallPlan struct {
	Root   string `json:"-"`
	Source string `json:"source"`

	// Requested pins (manifest intent).
	Version         string `json:"version,omitempty"`
	RequestedRef    string `json:"ref,omitempty"`
	RequestedCommit string `json:"commit,omitempty"`

	SourceRef source.Ref        `json:"-"`
	Revision  resolver.Revision `json:"resolved"`

	Scope string `json:"scope,omitempty"`
	Mode  string `json:"mode,omitempty"`
	Force bool   `json:"force,omitempty"`

	// InitProject marks that no manifest exists yet: ExecutePlan scaffolds the
	// project first, and the preview lists the manifest as created (FR-023).
	InitProject bool `json:"init_project,omitempty"`

	Selected []discovery.DiscoveredSkill `json:"-"`
	// ExplicitAgents is the raw agent selection (manifest intent); AgentIDs is
	// the resolved target set.
	ExplicitAgents []string `json:"-"`
	AgentIDs       []string `json:"agents"`

	Actions   []PlannedAction `json:"actions"`
	Conflicts []PlanConflict  `json:"conflicts,omitempty"`
	Warnings  []string        `json:"warnings,omitempty"`
}

InstallPlan is the read-only output of PlanInstall: exactly what ExecutePlan will do, rendered by the wizard's preview and by `add --dry-run` (FR-015, FR-024). Computing it writes nothing.

func (InstallPlan) Lines added in v0.3.0

func (p InstallPlan) Lines(versionLabel string) []PlanLine

Lines flattens the plan into renderable lines. versionLabel overrides the version text (the wizard prefers the user's chosen label); "" derives it from the resolved revision.

type InstallProgressEvent added in v0.3.2

type InstallProgressEvent struct {
	SkillIndex int // 1-based position in the run
	SkillTotal int // total skills in the run
	SkillName  string
	Source     string
	SourceType string
	Version    string // resolved version when known
	Ref        string // requested ref when known
	Commit     string // resolved commit when known

	Phase   InstallPhase
	Status  InstallStatus
	Message string
	Err     error // set only on failed/cancelled terminal events
}

InstallProgressEvent is one observation of an install run. Events are emitted synchronously and strictly sequentially: at most one skill is in a non-terminal state at any time, and each skill emits exactly one terminal event (contracts/install-progress-events.md). SkillName, Source, Version, Ref, and Message may originate from remote content and are untrusted: renderers must sanitize them.

type InstallRequest

type InstallRequest struct {
	Root           string
	Scope          string
	Mode           string
	Frozen         bool
	Offline        bool
	NoCache        bool
	UpdateLockfile bool
}

InstallRequest describes an `install` invocation over the existing manifest.

type InstallResult

type InstallResult struct {
	Skills  []SkillChange
	Changed bool
}

InstallResult reports an install run.

type InstallStatus added in v0.3.2

type InstallStatus string

InstallStatus is a skill's state within an install run. The terminal values reuse the existing lock-install status strings (LockSkillInstalled etc.) so legacy result consumers keep working unchanged.

const (
	InstallStatusPending      InstallStatus = "pending"
	InstallStatusRunning      InstallStatus = "running"
	InstallStatusInstalled    InstallStatus = InstallStatus(LockSkillInstalled)
	InstallStatusUpToDate     InstallStatus = InstallStatus(LockSkillUpToDate)
	InstallStatusRepaired     InstallStatus = InstallStatus(LockSkillRepaired)
	InstallStatusSkipped      InstallStatus = "skipped"
	InstallStatusFailed       InstallStatus = InstallStatus(LockSkillFailed)
	InstallStatusCancelled    InstallStatus = "cancelled"
	InstallStatusNotAttempted InstallStatus = "not-attempted"
	InstallStatusPlanned      InstallStatus = InstallStatus(LockSkillPlanned)
)

Install statuses. pending and running are event-only; the rest are terminal.

func (InstallStatus) IsTerminal added in v0.3.2

func (s InstallStatus) IsTerminal() bool

IsTerminal reports whether the status is a final per-skill outcome.

type InstallSummary added in v0.3.2

type InstallSummary struct {
	Total        int
	Installed    int
	Repaired     int
	UpToDate     int
	Skipped      int
	Failed       int
	Cancelled    int
	NotAttempted int
	Planned      int
	Outcome      InstallOutcome
}

InstallSummary aggregates a run's per-skill results into the counters every renderer shares. The invariant Total == sum of all per-status counters (FR-015) holds by construction: Aggregate counts each entry exactly once.

func Aggregate added in v0.3.2

func Aggregate(skills []LockSkillResult) InstallSummary

Aggregate computes the summary for a run's results. Unknown status strings count toward Total (never silently dropped) and force the failed counter so a miscounted entry can never inflate the success story.

type InstalledSkill added in v0.1.0

type InstalledSkill struct {
	Name        string            `json:"name"`
	Path        string            `json:"path"`
	ContentHash string            `json:"content_hash"`
	Targets     map[string]string `json:"targets"`
}

InstalledSkill reports one installed skill in a (possibly multi-skill) add.

type ListedSkill

type ListedSkill struct {
	Name        string
	Source      string
	Version     string
	Status      string
	Agents      []string
	Commit      string
	ContentHash string
	Active      string
	AgentHealth []AgentHealthEntry
}

ListedSkill is one row of `gskill list`. It carries every field `gskill status` used to carry (Commit, ContentHash, Active, AgentHealth) alongside list's own drift Status, so the two commands' data are now one shape (spec 013).

type LockPreview added in v0.3.0

type LockPreview struct {
	Path   string
	Skills []LockPreviewSkill
}

LockPreview describes the shared lock for the interactive install flow.

type LockPreviewSkill added in v0.3.0

type LockPreviewSkill struct {
	Name   string
	Source string
	// Agents is the entry's currently recorded gskill.agents (nil for a raw,
	// unmanaged entry) — used by the TUI to compute the kept/added/removed
	// plan before the user confirms an agent selection (spec 013 FR-006).
	Agents []string
}

LockPreviewSkill is one entry's display line.

type LockSkillResult added in v0.3.0

type LockSkillResult struct {
	Name         string
	Source       string
	Status       string
	ComputedHash string
	// AgentsKept, AgentsAdded, AgentsRemoved are populated only when the run
	// had an explicit agent selection (req.Agents != nil) — never based on
	// whether the resulting slice happens to be non-empty (spec 013 FR-014).
	AgentsKept    []string
	AgentsAdded   []string
	AgentsRemoved []string
	Err           error

	// Provenance and failure detail (spec 014): populated for successes and
	// failures alike whenever known; empty strings render as "—", never as
	// fabricated data (FR-014). Failure is non-nil exactly when the entry
	// failed (or was cancelled with a cause).
	SourceType      string
	SkillPath       string
	RequestedRef    string
	ResolvedVersion string
	ResolvedRef     string
	Commit          string
	Agents          []string
	InstallMode     string
	Phase           InstallPhase
	PlannedAction   string // dry-run only: would-install|would-repair|would-remove-target|would-update-lock|blocked
	Failure         *InstallFailure

	// StoreReuse reports whether the content store satisfied this skill
	// ("reused") or its source was fetched ("downloaded") — spec 015 FR-007.
	// Empty when the entry never reached the store (failures, plans).
	StoreReuse string
	// StoreScope names the physical store that served the skill: "global" or
	// "project".
	StoreScope string
}

LockSkillResult is one skill's outcome in an InstallFromLock run.

type MigrateReport added in v0.4.0

type MigrateReport struct {
	DryRun bool
	// NothingToDo reports an already-migrated project (no legacy store).
	NothingToDo bool
	Plan        migrate.Plan
	Result      migrate.Result
}

MigrateReport is the outcome of `gskill migrate global-store` (FR-037).

type Options

type Options struct {
	Config *config.Config
	Logger *slog.Logger
	Agents *agent.Registry
	Git    git.Runner
	Repos  RepoLister
	// GskillHome overrides the resolved gskill home directory (default:
	// GSKILL_HOME env, else ~/.gskill). Tests use it for isolated stores.
	GskillHome string
}

Options configures New. Nil dependencies are replaced with safe defaults.

type OutdatedReport

type OutdatedReport struct {
	Skills       []OutdatedSkill
	AnyAvailable bool
}

OutdatedReport aggregates an outdated run.

type OutdatedSkill

type OutdatedSkill struct {
	Name      string
	Current   string
	Latest    string
	Available bool
}

OutdatedSkill reports one skill's update availability.

type PlanConflict added in v0.3.0

type PlanConflict struct {
	Skill  string `json:"skill"`
	Kind   string `json:"kind"`
	Detail string `json:"detail"`
	Err    error  `json:"-"`
}

PlanConflict is one conflict the preview shows. A non-empty conflict list blocks approval (FR-016) and makes ExecutePlan refuse the plan.

type PlanLine added in v0.3.0

type PlanLine struct {
	Kind string
	Text string
}

PlanLine is one renderable line of an InstallPlan. The wizard preview and `add --dry-run` both render from this single sequence, so the two surfaces describe the same plan by construction (FR-015/FR-024); renderers add their own styling and prefixes per kind.

type PlanRequest added in v0.3.0

type PlanRequest struct {
	Root     string
	Source   string
	Version  string
	Ref      string
	Commit   string
	Discover DiscoverResult
	Selected []discovery.DiscoveredSkill
	// AgentIDs is the explicit agent selection ([] = resolve via manifest
	// defaults, then detection, then the default agent — same as --agent).
	AgentIDs []string
	Scope    string
	Mode     string
	Force    bool

	// Discovery filters, mirrored from the original DiscoverRequest so a
	// version re-pin re-discovers under the SAME constraints the user set
	// (review finding: dropping them could remap onto an excluded skill).
	MaxDepth int
	Include  []string
	Exclude  []string
}

PlanRequest describes phase 3: derive an installation plan from the wizard session (or flag-derived answers). Version/Ref/Commit are the *requested* pins recorded as manifest intent; the resolved revision rides in Discover.

type PlannedAction added in v0.3.0

type PlannedAction struct {
	Skill       string          `json:"skill"`
	AgentID     string          `json:"agent"`
	Destination string          `json:"destination"`
	MergeInto   bool            `json:"merge_into,omitempty"` // agent-add into an existing install
	FileOps     []PlannedFileOp `json:"file_ops,omitempty"`
}

PlannedAction is one skill × agent placement the plan will perform.

type PlannedFileOp added in v0.3.0

type PlannedFileOp struct {
	Path string `json:"path"`
	Op   string `json:"op"` // "create" or "update"
}

PlannedFileOp is one file the install will create or update (US4).

type ProjectInfo added in v0.4.0

type ProjectInfo struct {
	ProjectID string
	Root      string
	Skills    int
	LastSeen  time.Time
	// Missing reports a recorded root that no longer exists on disk.
	Missing bool
}

ProjectInfo is one registered project's listing row (contracts §3).

type RemoveResult

type RemoveResult struct {
	Removed    []string
	StoreGCed  int
	NotPresent []string
}

RemoveResult reports a remove run.

type RepairResult

type RepairResult struct {
	Repaired       []string
	StagingCleaned int
}

RepairResult reports a repair run.

type RepoLister added in v0.1.0

type RepoLister interface {
	ListOwnerRepos(ctx context.Context, owner string) ([]registry.RepoRef, error)
}

RepoLister lists a GitHub owner's repositories, so `find --owner` can fan out across them. The default implementation calls the GitHub REST API; tests inject a fake.

type RequirementCheck

type RequirementCheck struct {
	Skill     string
	Kind      string // command | environment | skill | mcp
	Name      string
	Satisfied bool
	Checked   bool // false for kinds gskill cannot verify (e.g. mcp)
}

RequirementCheck is one declared requirement and whether the environment satisfies it. Requirements are recorded and surfaced only — gskill never resolves them transitively or auto-installs anything (FR-032).

type ScanOptions added in v0.1.0

type ScanOptions struct {
	Ref      string
	MaxDepth int
	Include  []string
	Exclude  []string
}

ScanOptions configures a read-only source scan.

type SearchHit added in v0.1.0

type SearchHit struct {
	ID          string `json:"id"`
	DisplayName string `json:"display_name"`
	Description string `json:"description"`
	Source      string `json:"source"`
	RepoPath    string `json:"repo_path"`
	Installed   bool   `json:"installed"`
	Score       int    `json:"score"`
}

SearchHit is one search result, attributed to its source and in-repo path.

type SkillChange

type SkillChange struct {
	Name        string
	ContentHash string
	Changed     bool
}

SkillChange records the per-skill outcome of an install.

type SkillCheck

type SkillCheck struct {
	Name   string
	Status string
}

SkillCheck is one skill's fast drift status.

type SkillHealth added in v0.1.0

type SkillHealth struct {
	Name         string
	Scope        string
	StorePresent bool
	Hashed       bool // whether store/copy content was hash-verified this evaluation
	StoreHashOK  bool // only meaningful when Hashed
	StorePath    string
	ActiveState  active.Health
	ActivePath   string // project-relative active entry
	Agents       map[string]TargetState
	Modes        map[string]string
}

SkillHealth is the evaluated three-hop state for one locked skill.

func (SkillHealth) Faults added in v0.1.0

func (h SkillHealth) Faults() []string

Faults returns human-readable descriptions of every non-OK rung.

func (SkillHealth) Healthy added in v0.1.0

func (h SkillHealth) Healthy() bool

Healthy reports whether every rung of the chain is in a good state. When the store was hash-verified, a content mismatch is unhealthy (fail closed).

func (SkillHealth) IntegrityFault added in v0.1.0

func (h SkillHealth) IntegrityFault() bool

IntegrityFault reports whether any fault is a content-integrity failure — a hash-verified store mismatch or a corrupt copy target — which maps to a fail-closed exit code.

type SkillInfo

type SkillInfo struct {
	Name        string
	Source      string
	Version     string
	Commit      string
	ContentHash string
	Description string
	License     string
	Requires    skillslock.Requires
	Agents      []string
	Targets     map[string]string
}

SkillInfo is the detail shown by `gskill info`.

type SkillInspection added in v0.1.0

type SkillInspection struct {
	Skill  discovery.DiscoveredSkill
	Source string   // source identity (host/owner/repo or local path)
	Agents []string // agents the skill would install into at the given root
}

SkillInspection is the detailed view of one discovered skill (FR-033).

type SkillVerify

type SkillVerify struct {
	Name     string
	OK       bool
	Expected string
	Actual   string
	Issue    string // ok | missing | mismatch
}

SkillVerify is one skill's integrity-verification outcome.

type SourceCheckReport added in v0.1.0

type SourceCheckReport struct {
	Invalid    []discovery.DiscoveredSkill
	Duplicates []discovery.DuplicateConflict
}

SourceCheckReport summarizes a source's defects (FR-034).

func (SourceCheckReport) HasProblems added in v0.1.0

func (r SourceCheckReport) HasProblems() bool

HasProblems reports whether the source has any invalid or duplicate skills.

type StoreGCReport added in v0.4.0

type StoreGCReport struct {
	Applied bool
	globalstore.GCReport
}

StoreGCReport is the outcome of a GC run (contracts §2).

type StoreInspectReport added in v0.4.0

type StoreInspectReport struct {
	Key       string
	Integrity string // "verified" | the failure detail
	SizeBytes int64
	Origins   []globalstore.Origin
	UsedBy    []string
	Pinned    bool
}

StoreInspectReport is one object's detail view (contracts §2).

type StoreListItem added in v0.4.0

type StoreListItem struct {
	Key       string
	Skill     string
	Version   string
	SizeBytes int64
	Projects  int
}

StoreListItem is one object's listing row (contracts §2).

type StoreStatusReport added in v0.4.0

type StoreStatusReport struct {
	Path      string
	Objects   int
	SizeBytes int64
	Projects  int
	Unused    int
	Corrupted int
}

StoreStatusReport summarizes the global store (contracts §2).

type StoreVerifyResult added in v0.4.0

type StoreVerifyResult struct {
	Path     string
	Checked  int
	Healthy  int
	Findings []globalstore.ScanFinding
}

StoreVerifyResult is the outcome of a store-wide verification (FR-022).

func (StoreVerifyResult) Failed added in v0.4.0

func (r StoreVerifyResult) Failed() bool

Failed reports whether the scan found any problem.

type SyncChange added in v0.1.0

type SyncChange struct {
	Name        string   `json:"name"`
	ContentHash string   `json:"content_hash"`
	Changed     bool     `json:"changed"`
	AgentsAdded []string `json:"agents_added,omitempty"`
}

SyncChange reports one skill's reconcile outcome.

type SyncRequest

type SyncRequest struct {
	Root    string
	Prune   bool
	Offline bool
}

SyncRequest describes a `sync` invocation.

type SyncResult

type SyncResult struct {
	Reconciled []SyncChange
	Pruned     []string
	Orphans    []string
	UpToDate   bool
}

SyncResult reports a sync run.

type TargetState added in v0.1.0

type TargetState string

TargetState classifies one agent target's health relative to the locked state.

const (
	TargetOKSymlink    TargetState = "ok-symlink"    // symlink into the active entry
	TargetOKCopy       TargetState = "ok-copy"       // a copy whose content is present
	TargetMissing      TargetState = "missing"       // no target on disk
	TargetBroken       TargetState = "broken-link"   // symlink whose target is gone
	TargetForeign      TargetState = "foreign"       // present but not gskill-managed
	TargetModeMismatch TargetState = "mode-mismatch" // recorded mode differs from on disk
	TargetLegacyStore  TargetState = "legacy-store"  // symlink directly into the store (pre-active-layer)
	TargetCorrupt      TargetState = "corrupt"       // a copy whose content no longer matches the lock
)

Agent-target health states.

type UnlinkResult added in v0.1.0

type UnlinkResult struct {
	Skill           string
	UnlinkedAgent   string
	RemainingAgents []string
	Pruned          bool
	Unreferenced    bool
}

UnlinkResult reports the outcome of an unlink.

type VerifyReport

type VerifyReport struct {
	Skills []SkillVerify
	OK     bool
}

VerifyReport aggregates a verify run.

type VersionCandidate added in v0.3.0

type VersionCandidate struct {
	Kind     string // VersionLatest | VersionRelease | VersionBranch | VersionCommit
	Label    string // display text, e.g. "v1.4.0", "main", "latest → v1.4.0"
	Version  string // bare semver for releases, when parseable
	Ref      string // tag or branch name to request
	Commit   string // exact SHA for commit candidates
	Metadata string // optional annotation shown next to the label
}

VersionCandidate is one selectable version of a source.

type VersionList added in v0.3.0

type VersionList struct {
	Candidates     []VersionCandidate
	Degraded       bool
	DegradedReason string
}

VersionList is the version step's data. Listing problems are never fatal: Degraded marks that browsing is unavailable and why (FR-012).

Jump to

Keyboard shortcuts

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