Documentation
¶
Index ¶
- func BehavioralChanges(old, new *Fingerprint) []string
- func BuildAuther(cfg AuthConfig) (gitpkg.Auther, error)
- func CheckUpdatesBackground(registryDir string, logger *slog.Logger)
- func ContentHashFile(path string) (string, error)
- func DeleteOrigin(skillDir string) error
- func DetectDrift(ctx context.Context, store *registry.Store, lockPath, sourceName string) ([]string, error)
- func FetchAndCompare(repo, ref, currentSHA string, auth AuthConfig, logger *slog.Logger) (string, bool, error)
- func FormatFindings(findings []SecurityFinding) string
- func FormatUpdateNotice() string
- func HasOrigin(skillDir string) bool
- func IsPinnedRef(ref string) bool
- func IsSemVerConstraint(ref string) bool
- func ListRemoteTags(repoPath string) ([]string, error)
- func LockFilePath() string
- func RepoToName(repo string) string
- func ResolveSemVerConstraint(constraintStr string, tags []string) (string, error)
- func SafeRepoPath(path string) error
- func ShortSHA(sha string) string
- func ShouldCheckUpdates() bool
- func SkillsConfigPath() string
- func UpdateCachePath() string
- func WriteLockFile(path string, lf *LockFile) error
- func WriteOrigin(skillDir string, origin *Origin) error
- func WriteUpdateCache(status *UpdateStatus) error
- func WriteUpdateCacheAt(path string, status *UpdateStatus) error
- type AuthConfig
- type CloneResult
- type CredentialResolver
- type DiffResult
- type DiscoveredSkill
- type Fingerprint
- type ImportOptions
- type ImportResult
- type ImportedSkill
- type Importer
- func (imp *Importer) AdvanceTracking(ctx context.Context, skillName, newSHA string) error
- func (imp *Importer) BackupSkillFile(ctx context.Context, skillName, shortSHA string) (string, error)
- func (imp *Importer) Detach(ctx context.Context, skillName string) error
- func (imp *Importer) Diff(ctx context.Context, skillName string) (*DiffResult, error)
- func (imp *Importer) Import(opts ImportOptions) (*ImportResult, error)
- func (imp *Importer) Info(skillName string) (*SkillInfo, error)
- func (imp *Importer) Pin(skillName, ref string) error
- func (imp *Importer) Remove(skillName string) error
- func (imp *Importer) SetCredentialResolver(r CredentialResolver)
- func (imp *Importer) Update(skillName string, dryRun, force, trust bool) (*ImportResult, error)
- type LockFile
- type LockedSkill
- type LockedSource
- type MalformedSkill
- type Origin
- type ScanResult
- type SecurityFinding
- type SkillDefaults
- type SkillInfo
- type SkillSource
- type SkillUpdate
- type SkillsConfig
- type SkippedSkill
- type SourceAuth
- type UpdateStatus
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BehavioralChanges ¶
func BehavioralChanges(old, new *Fingerprint) []string
BehavioralChanges compares two fingerprints and returns human-readable changes.
func BuildAuther ¶
func BuildAuther(cfg AuthConfig) (gitpkg.Auther, error)
BuildAuther constructs a git.Auther matching the AuthConfig's Method. Returns an error for unknown methods. Individual Auther implementations also validate their own inputs (e.g. HTTPSTokenAuth rejects empty tokens).
func CheckUpdatesBackground ¶
CheckUpdatesBackground runs update checks in a background goroutine. Results are written to the cache file for display on next CLI command.
func ContentHashFile ¶
ContentHashFile computes a SHA-256 hash of a file.
func DeleteOrigin ¶
DeleteOrigin removes the .origin.json file from a skill directory.
func DetectDrift ¶
func DetectDrift(ctx context.Context, store *registry.Store, lockPath, sourceName string) ([]string, error)
DetectDrift returns the names of imported skills in sourceName whose on-disk SKILL.md has been edited since the last import or sync. Drift is detected by comparing the current file hash against the InstalledHash snapshot written when the skill was last installed.
Skills imported before InstalledHash was tracked (empty value) are treated as not drifted — DetectDrift fails open rather than reporting noise. Skills with no Origin (purely local) are not considered.
Pass an empty sourceName to scan every imported skill in the registry.
func FetchAndCompare ¶
func FetchAndCompare(repo, ref, currentSHA string, auth AuthConfig, logger *slog.Logger) (string, bool, error)
FetchAndCompare fetches the latest from a remote and compares with current.
func FormatFindings ¶
func FormatFindings(findings []SecurityFinding) string
FormatFindings returns a human-readable summary of security findings.
func FormatUpdateNotice ¶
func FormatUpdateNotice() string
FormatUpdateNotice returns a user-friendly message about available updates.
func IsPinnedRef ¶
IsPinnedRef returns true when ref looks like an immutable pin (a specific version tag containing a ".", or a full 40-character commit SHA). Bare branch names and empty refs return false so they are treated as floating.
This is a heuristic, not a guarantee: a tag like "release-2026" with no dot will read as unpinned, and a branch named "feature.x" will read as pinned. Used by aggregate sync to skip pins by default so a bulk operation does not silently bump a user's intentionally-fixed version.
func IsSemVerConstraint ¶
IsSemVerConstraint returns true if the ref looks like a semver constraint.
func ListRemoteTags ¶
ListRemoteTags returns all tags from a cached repository.
func LockFilePath ¶
func LockFilePath() string
LockFilePath returns the default path to skills.lock.yaml.
func RepoToName ¶
RepoToName extracts a short name from a repo URL (the last path segment with any ".git" suffix stripped). Exported so callers like the CLI can match the source names this package uses without duplicating the logic.
func ResolveSemVerConstraint ¶
ResolveSemVerConstraint finds the best matching tag for a constraint.
func SafeRepoPath ¶
SafeRepoPath validates a path component to prevent directory traversal.
func ShortSHA ¶
ShortSHA returns the first 8 characters of a commit SHA, or the whole string when it is shorter (including the empty string from an uncached fetch). It keeps SHA formatting panic-free for logs, backup names, and messages.
func ShouldCheckUpdates ¶
func ShouldCheckUpdates() bool
ShouldCheckUpdates returns false if update checks are disabled.
func SkillsConfigPath ¶
func SkillsConfigPath() string
SkillsConfigPath returns the default path to skills.yaml.
func UpdateCachePath ¶
func UpdateCachePath() string
UpdateCachePath returns the path to the cached update status file.
func WriteLockFile ¶
WriteLockFile writes skills.lock.yaml atomically. Keys are sorted for minimal merge conflicts.
func WriteOrigin ¶
WriteOrigin writes the .origin.json file to a skill directory.
func WriteUpdateCache ¶
func WriteUpdateCache(status *UpdateStatus) error
WriteUpdateCache writes the update status to the default cache path.
func WriteUpdateCacheAt ¶
func WriteUpdateCacheAt(path string, status *UpdateStatus) error
WriteUpdateCacheAt writes the update status to an explicit path.
Types ¶
type AuthConfig ¶
type AuthConfig struct {
Method string // "", "none", "token", "ssh-agent", "ssh-key"
Token string // resolved plaintext — transient, never persisted
CredentialRef string // e.g. "${vault:GIT_TOKEN}" — persisted
SSHUser string // defaults to "git" when empty
SSHKeyPath string // required for method "ssh-key"
SSHPassphrase string // transient
KnownHostsPath string // reserved for future host-key policy work
}
AuthConfig carries authentication configuration for a git operation. The Token and SSHPassphrase fields are transient — they must never be persisted to disk. CredentialRef is the opaque reference string (e.g. "${vault:GIT_TOKEN}") that gets stored in Origin/LockFile so that Update can re-resolve it later.
type CloneResult ¶
type CloneResult struct {
RepoPath string
CommitSHA string
Skills []DiscoveredSkill
Malformed []MalformedSkill
}
CloneResult contains the result of a clone + discovery operation.
func CloneAndDiscover ¶
func CloneAndDiscover(repo, ref, subPath string, auth AuthConfig, logger *slog.Logger) (*CloneResult, error)
CloneAndDiscover clones a repo and discovers all SKILL.md files.
type CredentialResolver ¶
CredentialResolver resolves an opaque reference like "${vault:GIT_TOKEN}" to its raw value. Callers (CLI, HTTP API) register one via Importer.SetCredentialResolver so that Update can re-resolve credentials recorded in Origin/LockFile without the importer needing to know where the values live.
type DiffResult ¶
type DiffResult struct {
Skill string `json:"skill"`
Local string `json:"local"` // current on-disk full SKILL.md text
Upstream string `json:"upstream"` // content an update would install
Drifted bool `json:"drifted"` // on-disk file diverges from InstalledHash
}
DiffResult holds a skill's current on-disk SKILL.md alongside the content an update would install, for on-demand comparison. Producing it changes no registry state, SHAs, or InstalledHashes.
type DiscoveredSkill ¶
type DiscoveredSkill struct {
Name string
Path string // Relative path from repo root to SKILL.md directory
Skill *registry.AgentSkill
ContentHash string
}
DiscoveredSkill represents a SKILL.md found in a cloned repo.
type Fingerprint ¶
type Fingerprint struct {
ContentHash string `json:"contentHash" yaml:"content_hash"`
ToolsHash string `json:"toolsHash" yaml:"tools_hash"`
Tools []string `json:"tools,omitempty" yaml:"tools,omitempty"`
}
Fingerprint captures the behavioral identity of a skill.
func ComputeFingerprint ¶
func ComputeFingerprint(skill *registry.AgentSkill) *Fingerprint
ComputeFingerprint generates a behavioral fingerprint for a skill.
type ImportOptions ¶
type ImportOptions struct {
Repo string
Ref string
Path string
Trust bool // Skip security scan confirmation
NoActivate bool // Import as draft instead of active
Force bool // Overwrite existing skills
Rename string // Rename the skill on import
Selected []string // Only import skills with these names (empty = import all)
Auth AuthConfig
// PreserveState carries over the existing skill's State (draft/active/
// disabled) instead of resetting it. Used by Update so that re-syncing
// a source does not silently re-activate skills the user disabled.
PreserveState bool
}
ImportOptions controls the import behavior.
type ImportResult ¶
type ImportResult struct {
Imported []ImportedSkill `json:"imported"`
Skipped []SkippedSkill `json:"skipped"`
Warnings []string `json:"warnings"`
}
ImportResult contains the results of an import operation.
type ImportedSkill ¶
type ImportedSkill struct {
Name string `json:"name"`
Path string `json:"path"`
Origin *Origin `json:"origin,omitempty"`
// FilesCopied counts supporting files installed alongside SKILL.md
// (scripts/, references/, assets/, and package metadata).
FilesCopied int `json:"filesCopied"`
Findings []SecurityFinding `json:"findings,omitempty"`
}
ImportedSkill records a successfully imported skill.
type Importer ¶
type Importer struct {
// contains filtered or unexported fields
}
Importer orchestrates the skill import process.
func NewImporter ¶
func NewImporter(store *registry.Store, registryDir, lockPath string, logger *slog.Logger) *Importer
NewImporter creates a new skill importer.
func (*Importer) AdvanceTracking ¶
AdvanceTracking records that a skill has been reconciled against upstream commit newSHA without changing its on-disk content. It advances only the version-tracking metadata — the skill's origin CommitSHA and the lock-file source's CommitSHA/ContentHash/FetchedAt — leaving the SKILL.md file and its InstalledHash untouched.
Used when a sync skips a locally-edited (drifted) skill: the reviewed upstream version is recorded so it no longer surfaces as an available update, while the user's local edits (and the drift signal that DetectDrift derives from InstalledHash) are preserved.
func (*Importer) BackupSkillFile ¶
func (imp *Importer) BackupSkillFile(ctx context.Context, skillName, shortSHA string) (string, error)
BackupSkillFile copies a skill's current SKILL.md to SKILL.md.pre-<shortSHA> next to it before an overwrite, so a forced update of a locally-edited skill stays recoverable. It returns the backup file name (relative to the skill directory). A missing SKILL.md is a no-op that returns an empty name.
func (*Importer) Detach ¶
Detach makes an imported skill local-only by removing its origin sidecar and its lock-file entry. The SKILL.md and the skill itself remain; it simply no longer tracks an upstream source and will not be touched by sync.
func (*Importer) Diff ¶
Diff fetches the latest upstream SKILL.md for an imported skill and returns both the current on-disk content and the content an update would install, without writing anything to the registry or changing any SHAs/InstalledHash. It is on-demand only — the caller pays for one git fetch.
func (*Importer) Import ¶
func (imp *Importer) Import(opts ImportOptions) (*ImportResult, error)
Import clones a repo, discovers skills, validates, scans, and imports.
func (*Importer) SetCredentialResolver ¶
func (imp *Importer) SetCredentialResolver(r CredentialResolver)
SetCredentialResolver registers a resolver used to expand CredentialRef values stored in Origin/LockFile when Update fetches the latest state. Without a resolver, Update can still run for sources that have no stored reference (ambient GITHUB_TOKEN / public repos), but will fail fast for sources that do.
func (*Importer) Update ¶
func (imp *Importer) Update(skillName string, dryRun, force, trust bool) (*ImportResult, error)
Update fetches latest for a skill and applies changes.
trust forwards to ImportOptions.Trust. It defaults to false at every caller: a sync that surfaces new security findings is skipped with the finding text rather than applied silently. Previously this was hardcoded true, which meant every sync refreshed upstream content with the scan gate disabled, harmless while only the SKILL.md body was scanned, but not once supporting files are installed too.
type LockFile ¶
type LockFile struct {
Sources map[string]LockedSource `yaml:"sources"`
}
LockFile represents skills.lock.yaml — pins exact versions of imported skills.
func ReadLockFile ¶
ReadLockFile reads and parses skills.lock.yaml.
func (*LockFile) FindSkillSource ¶
func (lf *LockFile) FindSkillSource(skillName string) (string, *LockedSource, bool)
FindSkillSource finds the source name for a given skill.
func (*LockFile) RemoveSkill ¶
RemoveSkill removes a single skill from the lock file, cleaning up the source if empty.
func (*LockFile) RemoveSource ¶
RemoveSource removes a source from the lock file.
func (*LockFile) SetSource ¶
func (lf *LockFile) SetSource(name string, src LockedSource)
SetSource updates or adds a source in the lock file.
type LockedSkill ¶
type LockedSkill struct {
Path string `yaml:"path"`
ContentHash string `yaml:"content_hash"`
Fingerprint *Fingerprint `yaml:"fingerprint,omitempty"`
}
LockedSkill records per-skill metadata within a source.
type LockedSource ¶
type LockedSource struct {
Repo string `yaml:"repo"`
Ref string `yaml:"ref"`
ResolvedRef string `yaml:"resolved_ref,omitempty"`
CommitSHA string `yaml:"commit_sha"`
FetchedAt time.Time `yaml:"fetched_at"`
ContentHash string `yaml:"content_hash"`
Skills map[string]LockedSkill `yaml:"skills"`
// CredentialRef is an opaque reference like "${vault:GIT_TOKEN}" used to
// re-resolve credentials on source update. Raw tokens are never stored.
CredentialRef string `yaml:"credential_ref,omitempty"`
}
LockedSource records the resolved state of a skill source.
type MalformedSkill ¶
type MalformedSkill struct {
Path string `json:"path"` // Relative path from repo root
Err string `json:"error"`
}
MalformedSkill records a SKILL.md that could not be read or parsed (or a directory that could not be walked), so callers can surface the failure instead of silently dropping it.
type Origin ¶
type Origin struct {
Repo string `json:"repo"`
Ref string `json:"ref"`
Path string `json:"path,omitempty"`
CommitSHA string `json:"commitSha"`
ImportedAt time.Time `json:"importedAt"`
ContentHash string `json:"contentHash"`
// InstalledHash is the SHA-256 of the SKILL.md as written to disk
// immediately after the last import. DetectDrift compares the current
// on-disk hash against this to surface local user edits. Distinct from
// ContentHash, which records the upstream file as fetched (and which
// diverges from the installed file because of frontmatter render
// normalization and state injection).
InstalledHash string `json:"installedHash,omitempty"`
Fingerprint *Fingerprint `json:"fingerprint,omitempty"`
// CredentialRef is an opaque reference like "${vault:GIT_TOKEN}" used to
// re-resolve credentials on skill update. Raw token values are never
// persisted — only the reference string.
CredentialRef string `json:"credentialRef,omitempty"`
}
Origin tracks the remote source of an imported skill. Stored as .origin.json alongside the SKILL.md file.
func ReadOrigin ¶
ReadOrigin reads the .origin.json file from a skill directory.
type ScanResult ¶
type ScanResult struct {
SkillName string `json:"skillName"`
Findings []SecurityFinding `json:"findings"`
Safe bool `json:"safe"`
}
ScanResult contains the security scan results for a skill.
func ScanSkill ¶
func ScanSkill(sk *registry.AgentSkill) *ScanResult
ScanSkill checks a skill for dangerous patterns in its body.
type SecurityFinding ¶
type SecurityFinding struct {
StepID string `json:"stepId"`
Pattern string `json:"pattern"`
Description string `json:"description"`
Severity string `json:"severity"` // "warning" or "danger"
}
SecurityFinding represents a potentially dangerous pattern found in a skill.
type SkillDefaults ¶
type SkillDefaults struct {
AutoUpdate bool `yaml:"auto_update" json:"autoUpdate"`
UpdateInterval string `yaml:"update_interval" json:"updateInterval"`
}
SkillDefaults defines global defaults for skill sources.
type SkillInfo ¶
type SkillInfo struct {
Name string `json:"name"`
Origin *Origin `json:"origin,omitempty"`
IsRemote bool `json:"isRemote"`
UpdateAvail bool `json:"updateAvailable"`
LatestSHA string `json:"latestSha,omitempty"`
LastChecked time.Time `json:"lastChecked,omitempty"`
}
SkillInfo returns details about an imported skill.
type SkillSource ¶
type SkillSource struct {
Name string `yaml:"name" json:"name"`
Repo string `yaml:"repo" json:"repo"`
Ref string `yaml:"ref,omitempty" json:"ref,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
AutoUpdate *bool `yaml:"auto_update,omitempty" json:"autoUpdate,omitempty"`
UpdateInterval string `yaml:"update_interval,omitempty" json:"updateInterval,omitempty"`
Auth *SourceAuth `yaml:"auth,omitempty" json:"auth,omitempty"`
}
SkillSource defines a remote skill source in skills.yaml.
type SkillUpdate ¶
type SkillUpdate struct {
CurrentSHA string `yaml:"current_sha"`
LatestSHA string `yaml:"latest_sha"`
Repo string `yaml:"repo"`
Ref string `yaml:"ref"`
}
SkillUpdate describes an available update for a skill.
type SkillsConfig ¶
type SkillsConfig struct {
Defaults SkillDefaults `yaml:"defaults,omitempty" json:"defaults,omitempty"`
Sources []SkillSource `yaml:"sources" json:"sources"`
}
SkillsConfig represents the skills.yaml file.
func DefaultSkillsConfig ¶
func DefaultSkillsConfig() *SkillsConfig
DefaultSkillsConfig returns a config with sensible defaults.
func LoadSkillsConfig ¶
func LoadSkillsConfig(path string) (*SkillsConfig, error)
LoadSkillsConfig reads and parses a skills.yaml file.
func (*SkillsConfig) EffectiveAutoUpdate ¶
func (c *SkillsConfig) EffectiveAutoUpdate(src *SkillSource) bool
EffectiveAutoUpdate returns the auto_update setting for a source, falling back to the global default.
func (*SkillsConfig) EffectiveUpdateInterval ¶
func (c *SkillsConfig) EffectiveUpdateInterval(src *SkillSource) time.Duration
EffectiveUpdateInterval returns the update_interval for a source, falling back to the global default.
type SkippedSkill ¶
SkippedSkill records a skill that was skipped during import.
type SourceAuth ¶
type SourceAuth struct {
Method string `yaml:"method,omitempty" json:"method,omitempty"`
CredentialRef string `yaml:"credential_ref,omitempty" json:"credentialRef,omitempty"`
SSHUser string `yaml:"ssh_user,omitempty" json:"sshUser,omitempty"`
SSHKeyPath string `yaml:"ssh_key_path,omitempty" json:"sshKeyPath,omitempty"`
}
SourceAuth is the declarative auth block on a skills.yaml source. Raw tokens must NOT appear here — use CredentialRef (e.g. "${vault:GIT_TOKEN}") which is resolved against the live vault at clone/fetch time.
func (*SourceAuth) ToAuthConfig ¶
func (a *SourceAuth) ToAuthConfig() AuthConfig
ToAuthConfig converts the declarative block into a runtime AuthConfig. CredentialRef is copied through unchanged; callers are responsible for resolving it to a raw Token before invoking the importer.
type UpdateStatus ¶
type UpdateStatus struct {
CheckedAt time.Time `yaml:"checked_at"`
Updates map[string]SkillUpdate `yaml:"updates,omitempty"`
Errors []string `yaml:"errors,omitempty"`
}
UpdateStatus records the result of a background update check.
func ReadUpdateCache ¶
func ReadUpdateCache() (*UpdateStatus, error)
ReadUpdateCache reads the cached update status from the default path.
func ReadUpdateCacheAt ¶
func ReadUpdateCacheAt(path string) (*UpdateStatus, error)
ReadUpdateCacheAt reads the cached update status from an explicit path. Returns (nil, nil) when the file does not exist so callers can fail open.