Documentation
¶
Index ¶
- Constants
- Variables
- func AgentDir(registryDir, name string) string
- func AgentsRoot(registryDir string) string
- func AllowOverwrite(lf *LockFile, kind, name, sourceName string, ...) bool
- func BackupSkillFileInDir(skillDir, shortSHA string) (string, error)
- func BehavioralChanges(old, new *Fingerprint) []string
- func BuildAuther(cfg AuthConfig) (gitpkg.Auther, error)
- func CheckUpdatesBackground(registryDir string, logger *slog.Logger)
- func CheckedLocations(client, home string) []string
- func CombineTrackedSourceHash(skills map[string]LockedSkill, agents map[string]LockedAgent) string
- func ContentHashFile(path string) (string, error)
- func DeleteAgent(registryDir, name string) error
- func DeleteOrigin(skillDir string) error
- func DetectAgentDrift(ctx context.Context, registryDir string) ([]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 GuardPackOwnership(lf *LockFile, sourceName string, result *CloneResult, opts ImportOptions) error
- func GuardSourceKey(lf *LockFile, name string, kind, repo string) error
- func HasOrigin(skillDir string) bool
- func InsideGridctlHome(path string) (bool, error)
- func IsPinnedRef(ref string) bool
- func IsSemVerConstraint(ref string) bool
- func KnownAgentRoots(home string) []resolvedLocation
- func KnownSkillRoots(home string) []resolvedLocation
- func KnownSourceName(home, root string) string
- func ListRemoteTags(repoPath string) ([]string, error)
- func LocalSourceHasUpdate(ctx context.Context, src LockedSource) (bool, error)
- func LockFilePath() string
- func MutateLockFile(ctx context.Context, path string, fn func(*LockFile) (bool, error)) error
- func ProjectionHint(client string) string
- func ProjectionHintClients(ctx context.Context, home string, roots []string) ([]string, error)
- func RecordLocalSource(lf *LockFile, sourceName, repo string, fetchedAt time.Time, ...) error
- func ReleaseInstalledNames(lf *LockFile, destination string, destLocal bool, ...)
- func RepoToName(repo string) string
- func ResolveLocalRoot(path string) (string, error)
- func ResolveSemVerConstraint(constraintStr string, tags []string) (string, error)
- func ResolveSourceName(lf *LockFile, in SourceNameInput) (string, error)
- func SafeRepoPath(path string) error
- func ShortSHA(sha string) string
- func ShouldCheckUpdates() bool
- func SkillTreeHash(ctx context.Context, skillDir string) (string, error)
- func SkillsConfigPath() string
- func SupportedImportClients() []string
- func UpdateCachePath() string
- func ValidateAgentName(name string) error
- 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 AgentDefinition
- type AgentExtraField
- type AuthConfig
- type ClientCandidate
- type ClientImportEntry
- type ClientImportOptions
- type ClientImportResult
- type ClientLocation
- type CloneResult
- type CredentialResolver
- type DiffResult
- type DiscoveredAgent
- type DiscoveredSkill
- type EntryProvenance
- type Fingerprint
- type ImportOptions
- type ImportResult
- type ImportedAgent
- type ImportedSkill
- type Importer
- func (imp *Importer) AdvanceTracking(ctx context.Context, skillName, newSHA string) error
- func (imp *Importer) AgentInfo(agentName string) (*SkillInfo, 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(ctx context.Context, 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) RemoveAgent(agentName string) error
- func (imp *Importer) SetCredentialResolver(r CredentialResolver)
- func (imp *Importer) Update(ctx context.Context, skillName string, dryRun, force, trust bool, ...) (*ImportResult, error)
- type InstalledAgent
- type LocalDiscovery
- type LockFile
- func (lf *LockFile) FindAgentSource(agentName string) (string, *LockedSource, bool)
- func (lf *LockFile) FindPackSource(packName string) (string, *LockedSource, bool)
- func (lf *LockFile) FindSkillSource(skillName string) (string, *LockedSource, bool)
- func (lf *LockFile) MemberSources(packName string) []string
- func (lf *LockFile) RemoveAgent(agentName string)
- func (lf *LockFile) RemoveSkill(skillName string)
- func (lf *LockFile) RemoveSource(name string)
- func (lf *LockFile) SetSource(name string, src LockedSource)
- type LockedAgent
- type LockedFragment
- type LockedPack
- type LockedPackLock
- type LockedPackSource
- type LockedRule
- type LockedSkill
- type LockedSource
- type LockedStack
- type LockedVariableDeclaration
- type MalformedAgent
- type MalformedSkill
- type Origin
- type ScanResult
- type SecurityFinding
- type SkillDefaults
- type SkillInfo
- type SkillSource
- type SkillUpdate
- type SkillsConfig
- type SkippedAgent
- type SkippedSkill
- type SnapshotResult
- type SourceAuth
- type SourceConflictError
- type SourceNameInput
- type StoredAuth
- type UpdateStatus
Constants ¶
const ( ResourceKindSkill = "skill" ResourceKindAgent = "agent" )
ResourceKindSkill and ResourceKindAgent restrict an import to one kind.
const ImportLockVersion = lockVersionPackLock
ImportLockVersion is the highest skills.lock.yaml schema version this gridctl reads. Version 1 added the version field itself and per-source agents; version 2 added per-source pack records; version 3 added pack variable declarations; version 4 added ssh-key auth fields (auth_method, ssh_user, ssh_key_path); version 5 added pack stack records and unresolved-detail maps; version 6 added local directory sources (kind: local and per-skill tree_hash); version 7 added pack external sources (LockedPack.Sources and LockedSource.PackMember); version 8 added pack lock state (LockedPack.Lock), member lock pins (LockedSource.LockedBy), and booster fragment records (LockedPack.Fragment). Files are written at the lowest version that can represent them (see WriteLockFile). A reader whose maximum is 4 understands SSH fields only and must refuse a file that carries a stack record or an unresolved-detail map rather than drop those keys on the next write. A reader whose maximum is 5 must refuse a file that carries a local source. A reader whose maximum is 6 must refuse a file that carries pack sources or a pack member marker. A reader whose maximum is 7 must refuse a file that carries a pack lock state, a member locked by a pack lock, or a booster fragment record.
const SourceKindLocal = "local"
SourceKindLocal is the origin and lockfile kind for a directory import.
Variables ¶
var ErrAmbiguousOwner = errors.New("ambiguous duplicate owners")
ErrAmbiguousOwner is returned when more than one lock source owns a name. Local update reports it before any mutation.
var ErrCommitUnreachable = errors.New("locked commit is not reachable")
ErrCommitUnreachable means a locked commit is not present after a full clone. Transport and auth failures are not this error.
var ErrImportLockBusy = errors.New("timeout acquiring import lock")
ErrImportLockBusy signals contention on the cross-process import lock: the operation should be retried, nothing is corrupted.
var ErrInsideGridctlHome = fmt.Errorf("refusing to import from inside the gridctl home")
ErrInsideGridctlHome is returned when a local source resolves inside the gridctl home. The home holds the registry, pack checkouts, the clone cache, and projection backups.
var ErrNewerImportLockVersion = errors.New("import lockfile was written by a newer gridctl version")
ErrNewerImportLockVersion signals a skills.lock.yaml written by a newer gridctl. Callers must never paper over it: acting on state a newer version wrote risks silent data loss (the pkg/project lesson).
var ErrSourceConflict = errors.New("source name conflict")
ErrSourceConflict is a source-name or source-kind collision. REST maps it to 409. The error text names the existing source and, for a directory collision, tells the caller to pass --source-name.
var ErrSourceLocked = errors.New("source is locked by a pack")
ErrSourceLocked marks an update of a member source pinned by a pack lock. The documented prose is on lockedSourceError; callers match this sentinel.
Functions ¶
func AgentDir ¶
AgentDir returns the canonical directory for one imported agent; the definition itself lives at AgentDir(...)/AGENT.md.
func AgentsRoot ¶
AgentsRoot returns the canonical agent store directory under a registry directory.
func AllowOverwrite ¶
func AllowOverwrite(lf *LockFile, kind, name, sourceName string, selected, explicitForce, agent bool) bool
AllowOverwrite reports whether an existing resource may be replaced. Local re-imports of an unowned name, or a name owned only by sourceName, do not need --force. A local owner always requires explicit force from a git or pack caller. Git-only selected overwrite is unchanged.
func BackupSkillFileInDir ¶
BackupSkillFileInDir is BackupSkillFile for callers that already hold the skill directory (skill projection adopt shares the convention, so there is exactly one hand-edit backup vocabulary).
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 CheckedLocations ¶
CheckedLocations lists the path templates a client scan visits.
func CombineTrackedSourceHash ¶
func CombineTrackedSourceHash(skills map[string]LockedSkill, agents map[string]LockedAgent) string
CombineTrackedSourceHash hashes tracked skill tree hashes and agent content hashes. Records are domain-separated and length-delimited so a skill and an agent cannot alias. Order is kind, then name.
func ContentHashFile ¶
ContentHashFile computes a SHA-256 hash of a file.
func DeleteAgent ¶
DeleteAgent removes one agent from the canonical store.
func DeleteOrigin ¶
DeleteOrigin removes the .origin.json file from a skill directory.
func DetectAgentDrift ¶
DetectAgentDrift returns the names of imported agents whose on-disk AGENT.md has been edited since the last import. Same fail-open policy as DetectDrift: a missing origin or InstalledHash is not drift.
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 GuardPackOwnership ¶
func GuardPackOwnership(lf *LockFile, sourceName string, result *CloneResult, opts ImportOptions) error
GuardPackOwnership refuses a pack import that would replace a local-owned resource. Packs have no force option, so this is an error before any write.
func GuardSourceKey ¶
GuardSourceKey refuses to replace an existing local source key with a different root or source kind. Git-to-git reuse of a non-member key is unchanged. A pack member key cannot be pointed at a different repository by any caller; the same repository under the same key stays allowed so pack add can re-pin and skill update can refresh.
func InsideGridctlHome ¶
InsideGridctlHome reports whether path resolves to state.BaseDir or a path beneath it. A missing gridctl home is not an error.
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 KnownAgentRoots ¶
func KnownAgentRoots(home string) []resolvedLocation
KnownAgentRoots returns resolved agent-location directories from the table.
func KnownSkillRoots ¶
func KnownSkillRoots(home string) []resolvedLocation
KnownSkillRoots returns resolved skill-location directories from the table.
func KnownSourceName ¶
KnownSourceName returns the location table's source name when root is a known skill or agent directory. A direct child does not match.
func ListRemoteTags ¶
ListRemoteTags returns all tags from a cached repository.
func LocalSourceHasUpdate ¶
func LocalSourceHasUpdate(ctx context.Context, src LockedSource) (bool, error)
LocalSourceHasUpdate recomputes hashes for tracked entries only. A missing entry counts as changed. Unrelated siblings are ignored. A missing root or a root that now resolves inside the gridctl home is an error.
func LockFilePath ¶
func LockFilePath() string
LockFilePath returns the default path to skills.lock.yaml.
func MutateLockFile ¶
MutateLockFile runs one read-modify-write cycle over skills.lock.yaml while holding the cross-process import lock, so concurrent operations serialize instead of losing each other's updates. fn returns whether its changes should be written; false skips the write and succeeds.
func ProjectionHint ¶
ProjectionHint is the single post-import warning for a colliding client.
func ProjectionHintClients ¶
ProjectionHintClients returns the client slugs whose projection target equals root, is the parent of root, or whose recorded project.Entry.Path equals root. A missing project lock is not an error. A newer project lock is returned as-is.
func RecordLocalSource ¶
func RecordLocalSource(lf *LockFile, sourceName, repo string, fetchedAt time.Time, installedSkills map[string]LockedSkill, installedAgents map[string]LockedAgent, discovered *CloneResult, canDrop bool) error
RecordLocalSource merges installed entries into the previous local maps. Absent entries are dropped only when canDrop is set. The source hash is recomputed from the merged maps.
func ReleaseInstalledNames ¶
func ReleaseInstalledNames(lf *LockFile, destination string, destLocal bool, skills, agents map[string]struct{})
ReleaseInstalledNames removes installed names from other sources when a local source is involved. Unrelated skills, agents, and pack metadata stay. An emptied source is deleted only when no tracked content or pack record remains. Git-only owners are left in place.
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 ResolveLocalRoot ¶
ResolveLocalRoot returns the absolute, symlink-resolved directory.
func ResolveSemVerConstraint ¶
ResolveSemVerConstraint finds the best matching tag for a constraint.
func ResolveSourceName ¶
func ResolveSourceName(lf *LockFile, in SourceNameInput) (string, error)
ResolveSourceName picks a stable lockfile key. An existing local source with the same resolved root is reused. An explicit name that differs from that key is an error. Client import suffixes a colliding basename with the first eight hex characters of sha256(root); skill add fails instead.
A pack member key is "<pack>/<source>". RepoToName returns a basename and cannot produce a slash, so a plain skill add without --source-name never derives that key. GuardSourceKey is what refuses an explicit --source-name that would re-key a member onto another repository.
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. GRIDCTL_NO_SKILL_UPDATE_CHECK accepts the shared boolean vocabulary (env.Bool); a malformed value is ignored and checks proceed.
func SkillTreeHash ¶
SkillTreeHash returns a sha256:-prefixed hash of SKILL.md and installed supporting files, sorted by relative path. Modification times are not hashed. .origin.json, backups, and install temporary files are excluded. Every caller is a local source, so the own-directory layout applies.
func SkillsConfigPath ¶
func SkillsConfigPath() string
SkillsConfigPath returns the default path to skills.yaml.
func SupportedImportClients ¶
func SupportedImportClients() []string
SupportedImportClients lists the v1 client slugs in the error-message order.
func UpdateCachePath ¶
func UpdateCachePath() string
UpdateCachePath returns the path to the cached update status file.
func ValidateAgentName ¶
ValidateAgentName validates an agent name: non-empty, lowercase letters, digits, and hyphens only.
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 AgentDefinition ¶
type AgentDefinition struct {
Name string
Description string
// Extra holds every frontmatter key other than name and description,
// in document order, as raw YAML nodes.
Extra []AgentExtraField
// Body is the markdown after the frontmatter block.
Body string
// Raw is the file exactly as read; imports write it verbatim.
Raw []byte
}
AgentDefinition is a parsed Claude Code subagent definition (AGENT.md / agents/<name>.md). Name and Description are the only typed fields; every other frontmatter key (tools, model, hooks, mcpServers, permissionMode, vendor extensions) rides in Extra as raw YAML nodes in document order.
AgentDefinition deliberately does not reuse AgentSkill/ParseSkillMD: that parser types skill-specific keys and would silently strand tools and model in an untyped map, and its render path normalizes frontmatter. Agents are stored and projected verbatim (identity render), so Raw is the source of truth; the parsed form exists for validation, scanning, and listing.
func ParseAgentMD ¶
func ParseAgentMD(data []byte) (*AgentDefinition, error)
ParseAgentMD parses an agent definition file. Frontmatter with a non-empty description is required: a markdown file without it (a README dropped into an agents/ directory, say) is not an agent definition. The frontmatter mapping is walked by hand so unknown keys are preserved in order rather than silently dropped, and a duplicate key cannot discard the valid ones.
func SaveAgent ¶
func SaveAgent(registryDir, name string, raw []byte) (*AgentDefinition, error)
SaveAgent validates raw as an agent definition named name and writes it into the canonical store byte-for-byte. No normalization happens here on purpose: identity projections copy the canonical bytes verbatim, so any rewrite (key reordering, trailing-newline fixes) would surface as drift on every synced client after an edit. Returns the parsed definition so callers can inspect what was written.
func (*AgentDefinition) DeclaredModel ¶
func (d *AgentDefinition) DeclaredModel() (string, bool)
DeclaredModel reads the definition's top-level `model:` value. ok is false when the declaration exists but is not a scalar (a structured value cannot be honored or safely rewritten); an absent key reports ("", true). Every surface that answers "what model does this agent declare" (sync, CLI, REST) goes through this one helper so they can never disagree on non-scalar handling.
func (*AgentDefinition) ExtraByKey ¶
func (d *AgentDefinition) ExtraByKey(key string) (*yaml.Node, bool)
ExtraByKey returns the raw frontmatter node for one passthrough key. Renderers use it for key-level access without scanning Extra at every call site.
type AgentExtraField ¶
AgentExtraField is one passthrough frontmatter key.
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.
func ResolveStoredAuth ¶
func ResolveStoredAuth(stored StoredAuth, resolver CredentialResolver) (AuthConfig, error)
ResolveStoredAuth rebuilds an AuthConfig from a stored record. A CredentialRef wins and is resolved to a token. Otherwise an ssh-key path is rebuilt and the passphrase is re-read from the environment. Anything else is ambient (the zero value). The passphrase is never taken from the record, because it is never stored.
type ClientCandidate ¶
type ClientCandidate struct {
Kind string
Name string
Location string
Source string
Root string
RelPath string
Resolved string
Client string
ProvPath string
SkipReason string
KnownName string
}
ClientCandidate is one skill or agent visible in a client location.
func EnumerateClient ¶
func EnumerateClient(ctx context.Context, client, home string) ([]ClientCandidate, error)
EnumerateClient lists home-scoped skill and agent candidates for client. Permission errors are returned. A missing location is skipped. A missing project lock is not an error; a newer project lock is.
type ClientImportEntry ¶
type ClientImportEntry struct {
Candidate ClientCandidate
Action string
Reason string
}
ClientImportEntry is one enumerated row after selection is applied.
type ClientImportOptions ¶
ClientImportOptions controls one client-import apply.
type ClientImportResult ¶
type ClientImportResult struct {
Entries []ClientImportEntry
Warnings []string
Roots []string
}
ClientImportResult is the outcome of applying a selection.
func ApplyClientImport ¶
func ApplyClientImport(ctx context.Context, imp *Importer, opts ClientImportOptions, selected []ClientCandidate) (*ClientImportResult, error)
ApplyClientImport imports selected candidates, batched by resolved root and kind. Dry-run does not write. Policy skips stay skips.
type ClientLocation ¶
type ClientLocation struct {
Client string
Owner string
SourceName string
Kind string
Path string
Dialect string
Docs string
SkipReason string
}
ClientLocation is one home-scoped skill or agent directory a client scans. Owner is the provenance slug. SourceName is the lockfile key. They are recorded separately and are equal for every v1 row.
func ClientLocations ¶
func ClientLocations(client string) ([]ClientLocation, bool)
ClientLocations returns the v1 home-scoped locations for client, in display order. The second result is false for an unknown client.
Citations:
- Claude Code skills: https://code.claude.com/docs/en/skills
- Claude Code agents: https://code.claude.com/docs/en/sub-agents
- OpenCode skills: https://opencode.ai/docs/skills/
- OpenCode agents: https://opencode.ai/docs/agents/
- Agents interop dir: https://github.com/vercel-labs/skills
type CloneResult ¶
type CloneResult struct {
RepoPath string
CommitSHA string
Skills []DiscoveredSkill
Malformed []MalformedSkill
// Agents are agent definitions discovered under the agents/*.md
// convention; MalformedAgents records files in agents/ directories
// that are not parseable agent definitions.
Agents []DiscoveredAgent
MalformedAgents []MalformedAgent
// FilteredSkills are relative skill paths DiscoverLocal skipped because
// they carry .origin.json. Git discovery leaves this nil.
FilteredSkills []string
}
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 plus any agents/*.md definitions it ships.
func CloneAtCommit ¶
func CloneAtCommit(repo, commit, subPath string, auth AuthConfig, logger *slog.Logger) (*CloneResult, error)
CloneAtCommit transfers commit and checks it out. It is for lock honoring only: it may disagree with a depth-1 ref clone and must not replace CloneAndDiscover for ordinary ref resolution.
Under the same per-repo cache lock cloneShallow uses: when the cache repo exists, fetch every branch and tag and try to check out the hash. When the object is still absent, or the cache does not exist, remove the cache and clone at full depth, then check out the hash. Head must equal commit. A transport or auth failure is returned redacted and is not ErrCommitUnreachable.
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 DiscoveredAgent ¶
type DiscoveredAgent struct {
Name string
Path string // Relative path from repo root to the .md file
Definition *AgentDefinition
ContentHash string
}
DiscoveredAgent represents an agent definition found in a cloned repo under an agents/ directory.
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 EntryProvenance ¶
EntryProvenance is the client and location written onto one origin.
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)
// SelectedAgents imports exactly these agent names. When empty, the
// legacy behavior holds: all agents when Selected is also empty, no
// agents when a skill selection is present (the web UI picker's
// contract). Pack imports always pass fully resolved lists.
SelectedAgents []string
// Discovered supplies a pre-cloned discovery result so callers that
// already ran CloneAndDiscover (pack add reads the manifest first)
// do not clone twice. Nil means Import clones itself.
Discovered *CloneResult
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
// Kind is SourceKindLocal for a directory import. Empty keeps git import.
Kind string
// SourceName overrides RepoToName. Required when a derived name collides.
SourceName string
// KnownName is the client-location source name for a new local root.
KnownName string
// Provenance maps a discovered relative path to client import metadata.
// skill add leaves it nil.
Provenance map[string]EntryProvenance
// ResourceKind, when set to skill or agent, imports only that kind.
ResourceKind string
// PackImport fails before any registry write when a local source key or
// a local-owned resource would be replaced. Packs have no force option.
PackImport bool
// ExactSelection makes Selected and SelectedAgents authoritative. An
// empty Selected imports no skills and an empty SelectedAgents imports
// no agents, regardless of ResourceKind and of the legacy empty-means-all
// rules. Unset preserves those rules.
ExactSelection bool
// SelectionIsImportAll marks a non-empty Selected list that still means
// import-all. An existing skill is skipped instead of overwritten.
// ExactSelection still decides which names import. Pack add sets this
// for the pack repository when skills: is empty, so declaring sources
// does not change that import-all.
SelectionIsImportAll bool
}
ImportOptions controls the import behavior.
type ImportResult ¶
type ImportResult struct {
Imported []ImportedSkill `json:"imported"`
Skipped []SkippedSkill `json:"skipped"`
Warnings []string `json:"warnings"`
// ImportedAgents and SkippedAgents record agent definitions the same
// import discovered under the agents/*.md convention.
ImportedAgents []ImportedAgent `json:"importedAgents,omitempty"`
SkippedAgents []SkippedAgent `json:"skippedAgents,omitempty"`
}
ImportResult contains the results of an import operation.
type ImportedAgent ¶
type ImportedAgent struct {
Name string `json:"name"`
Path string `json:"path"`
Origin *Origin `json:"origin,omitempty"`
Findings []SecurityFinding `json:"findings,omitempty"`
}
ImportedAgent records a successfully imported agent definition.
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.
// An own-directory skill counts every installed file. A repository-root
// skill counts the allowlisted trees plus 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(ctx context.Context, opts ImportOptions) (*ImportResult, error)
Import clones a repo, discovers skills and agents, validates, scans, and imports. A local directory import sets Kind to SourceKindLocal and skips git. ctx is checked before any registry write and between entries.
func (*Importer) RemoveAgent ¶
RemoveAgent removes an imported agent and cleans up origin and lock entries.
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(ctx context.Context, skillName string, dryRun, force, trust bool, ignoreLock ...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 InstalledAgent ¶
type InstalledAgent struct {
Name string
Definition *AgentDefinition
// Dir is the agent's canonical directory (holds AGENT.md and its
// .origin.json sidecar).
Dir string
}
InstalledAgent is one agent present in the canonical store.
func GetAgent ¶
func GetAgent(registryDir, name string) (*InstalledAgent, error)
GetAgent returns one agent from the canonical store.
func ListAgents ¶
func ListAgents(registryDir string) ([]InstalledAgent, error)
ListAgents returns the agents in the canonical store, sorted by name. A missing store directory is the normal no-agents state. Entries whose AGENT.md is missing or unparseable are skipped: the store lists what it can serve.
type LocalDiscovery ¶
type LocalDiscovery struct {
Result *CloneResult
Warnings []string
}
LocalDiscovery is the result of walking a local directory for skills and agents. Result.RepoPath is the resolved root. CommitSHA is empty.
func DiscoverLocal ¶
func DiscoverLocal(ctx context.Context, root, subpath string, logger *slog.Logger) (*LocalDiscovery, error)
DiscoverLocal walks a resolved directory root for SKILL.md trees and agents/*.md files. subpath, when set, narrows the walk to that relative entry; the recorded paths stay relative to root. The walkers do not follow symlinks. Managed copies (a skill directory carrying .origin.json) are removed with a warning. Skill names are rewritten to the directory name.
type LockFile ¶
type LockFile struct {
Version int `yaml:"version"`
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. Version-less files (written before the schema carried a version) migrate to the current version on read; files from a newer gridctl are rejected with ErrNewerImportLockVersion.
func (*LockFile) FindAgentSource ¶
func (lf *LockFile) FindAgentSource(agentName string) (string, *LockedSource, bool)
FindAgentSource finds the source name for a given agent.
func (*LockFile) FindPackSource ¶
func (lf *LockFile) FindPackSource(packName string) (string, *LockedSource, bool)
FindPackSource finds the source carrying a pack by pack name.
func (*LockFile) FindSkillSource ¶
func (lf *LockFile) FindSkillSource(skillName string) (string, *LockedSource, bool)
FindSkillSource finds the source name for a given skill.
func (*LockFile) MemberSources ¶
MemberSources returns the lock source keys imported as members of packName, sorted by key. A member source has Pack == nil, so FindPackSource does not return it.
func (*LockFile) RemoveAgent ¶
RemoveAgent removes a single agent from the lock file, cleaning up the source when neither skills nor agents remain under it.
func (*LockFile) RemoveSkill ¶
RemoveSkill removes a single skill from the lock file, cleaning up the source when neither skills nor agents remain under it.
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 LockedAgent ¶
LockedAgent records per-agent metadata within a source.
type LockedFragment ¶
type LockedFragment struct {
Base string `yaml:"base,omitempty"`
Path string `yaml:"path,omitempty"`
Name string `yaml:"name,omitempty"`
ContentHash string `yaml:"content_hash,omitempty"`
CheckoutDir string `yaml:"checkout_dir,omitempty"`
}
LockedFragment is a booster fragment pinned under the booster checkout.
type LockedPack ¶
type LockedPack struct {
Name string `yaml:"name"`
Version string `yaml:"version,omitempty"`
// Description and Author persist the manifest metadata a list view
// needs, so no consumer ever has to re-clone the repo to show it.
// Additive fields: files without them keep loading, and version 2
// (which every pack record already stamps) covers them.
Description string `yaml:"description,omitempty"`
Author string `yaml:"author,omitempty"`
Wiring bool `yaml:"wiring,omitempty"`
Clients []string `yaml:"clients,omitempty"`
Skills []string `yaml:"skills,omitempty"`
Agents []string `yaml:"agents,omitempty"`
// Rules lists context rule fragments imported from the pack repo.
// Superseded by RuleFiles, which adds per-rule provenance; retained so
// lockfiles written before that keep loading, and kept in sync on write
// so a downgrade still sees the selection.
Rules []string `yaml:"rules,omitempty"`
// RuleFiles records per-rule provenance keyed by fragment name. An entry
// with an empty ContentHash means provenance is unknown (migrated from a
// Rules-only lockfile), and callers must fall back to byte comparison
// rather than treating the empty hash as a match.
RuleFiles map[string]LockedRule `yaml:"rule_files,omitempty"`
// Unresolved lists manifest-selected names discovery could not find,
// so status can keep reporting them until the upstream repo (or the
// manifest) is fixed.
Unresolved []string `yaml:"unresolved,omitempty"`
Variables map[string]LockedVariableDeclaration `yaml:"variables,omitempty"`
// Stack records a pinned checkout of a pack-carried stack. Nil when
// the manifest has no stack, or the stack did not resolve at import.
Stack *LockedStack `yaml:"stack,omitempty"`
// UnresolvedDetails maps an unresolved token (for example
// "stack:stack.yaml") to the reason it did not resolve, so status can
// show the export or escape error without re-reading the repository.
// A non-empty map stamps lockVersionStack. An older reader has no
// field for the key and would drop it on the next write.
UnresolvedDetails map[string]string `yaml:"unresolved_details,omitempty"`
// Sources records each external git source pinned at import. A
// non-empty map stamps lockVersionPackSources. An older reader has no
// field for the key and would drop it on the next write.
Sources map[string]LockedPackSource `yaml:"sources,omitempty"`
// Lock records whether pack add honored, ignored, or found a stale or
// absent gridctl-pack.lock.yaml. Nil when the manifest declares neither
// sources nor stack.extends. A non-nil value stamps lockVersionPackLock.
Lock *LockedPackLock `yaml:"lock,omitempty"`
// Fragment records a booster's pinned stack fragment. Nil for a base
// pack and for a booster whose fragment did not resolve. A non-nil
// value stamps lockVersionPackLock.
Fragment *LockedFragment `yaml:"fragment,omitempty"`
// Requires is the manifest's requires.gridctl string, copied at import.
// Additive: no new import-lock version. An older reader drops it on the
// next write, which is acceptable because that reader is the version
// the constraint would have excluded.
Requires string `yaml:"requires,omitempty"`
}
LockedPack is the recorded state of an imported pack: the manifest identity plus the selection as resolved against discovery at import time (never the empty-means-all shorthand).
type LockedPackLock ¶
type LockedPackLock struct {
State string `yaml:"state,omitempty"`
Digest string `yaml:"digest,omitempty"`
Path string `yaml:"path,omitempty"`
}
LockedPackLock is the pack-lock state recorded at add time.
type LockedPackSource ¶
type LockedPackSource struct {
// Repo is the authored URL, stored as written, matching the primary
// pack source. Printed lines and source summaries redact userinfo.
Repo string `yaml:"repo"`
Ref string `yaml:"ref,omitempty"`
Path string `yaml:"path,omitempty"`
CommitSHA string `yaml:"commit_sha,omitempty"`
FetchedAt time.Time `yaml:"fetched_at,omitempty"`
// SourceKey is the member lock source key (<pack>/<source>).
SourceKey string `yaml:"source_key,omitempty"`
Skills []string `yaml:"skills,omitempty"`
Agents []string `yaml:"agents,omitempty"`
}
LockedPackSource is one external repository pinned by a pack import. Skills and Agents are the names that actually imported, not the manifest shorthand and not skipped or unresolved selections.
type LockedRule ¶
LockedRule records per-rule-fragment metadata within a pack source. The content hash is what lets a later install tell an upstream change apart from a local edit; without it the only available comparison is raw bytes against disk, which conflates the two.
type LockedSkill ¶
type LockedSkill struct {
Path string `yaml:"path"`
ContentHash string `yaml:"content_hash"`
// TreeHash is the sha256:-prefixed hash of SKILL.md plus installed
// supporting files. Set only for local sources.
TreeHash string `yaml:"tree_hash,omitempty"`
Fingerprint *Fingerprint `yaml:"fingerprint,omitempty"`
}
LockedSkill records per-skill metadata within a source.
type LockedSource ¶
type LockedSource struct {
Repo string `yaml:"repo"`
// Kind is "local" for a directory source and empty for a git source.
Kind string `yaml:"kind,omitempty"`
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"`
// Agents records agent definitions imported from this source.
Agents map[string]LockedAgent `yaml:"agents,omitempty"`
// 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"`
// AuthMethod, SSHUser, and SSHKeyPath persist ssh-key authentication.
// Only the path is stored, never key material or a passphrase.
AuthMethod string `yaml:"auth_method,omitempty"`
SSHUser string `yaml:"ssh_user,omitempty"`
SSHKeyPath string `yaml:"ssh_key_path,omitempty"`
// Pack records the pack manifest this source was imported through,
// with its resolved selection. Nil for plain skill/agent sources.
// A member source keeps Pack nil so FindPackSource never treats it
// as the pack record.
Pack *LockedPack `yaml:"pack,omitempty"`
// PackMember is the pack name when this source was imported as a
// named external source of that pack. Empty for every other source.
// <pack>/<source> cannot collide with RepoToName output, which is a
// basename and never contains a slash. GuardSourceKey is what stops
// an explicit --source-name from re-keying the member to another repo.
PackMember string `yaml:"pack_member,omitempty"`
// LockedBy is the pack whose committed lock pinned this member source.
// Empty when the last add did not honor a lock. A non-empty value
// stamps lockVersionPackLock.
LockedBy string `yaml:"locked_by,omitempty"`
}
LockedSource records the resolved state of a skill source.
func (LockedSource) IsLocal ¶
func (s LockedSource) IsLocal() bool
IsLocal reports whether this source is a local directory import.
func (LockedSource) StoredAuth ¶
func (s LockedSource) StoredAuth() StoredAuth
StoredAuth returns the authentication this source recorded at import.
type LockedStack ¶
type LockedStack struct {
Path string `yaml:"path"`
Name string `yaml:"name"`
ContentHash string `yaml:"content_hash"`
CheckoutDir string `yaml:"checkout_dir"`
}
LockedStack is the pinned checkout of a pack-carried stack file.
type LockedVariableDeclaration ¶
type LockedVariableDeclaration struct {
Required *bool `yaml:"required,omitempty"`
Secret *bool `yaml:"secret,omitempty"`
Type string `yaml:"type,omitempty"`
Description string `yaml:"description,omitempty"`
Docs string `yaml:"docs,omitempty"`
}
LockedVariableDeclaration persists one value-free pack prerequisite.
type MalformedAgent ¶
type MalformedAgent = MalformedSkill
MalformedAgent aliases MalformedSkill so agent call sites read as what they are; the shape and JSON encoding are identical.
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"`
// SupportingFilesInstalled records that the importer evaluated and
// installed the complete supporting-file set, even when it was empty.
// Its absence identifies imports created before supporting-file installs.
SupportingFilesInstalled bool `json:"supportingFilesInstalled,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"`
// AuthMethod, SSHUser, and SSHKeyPath persist ssh-key authentication so a
// later update can rebuild it. Only the path is stored, never key material
// or a passphrase.
AuthMethod string `json:"authMethod,omitempty"`
SSHUser string `json:"sshUser,omitempty"`
SSHKeyPath string `json:"sshKeyPath,omitempty"`
// Kind is "local" for a directory import and empty for a git import.
// Empty is the historical zero value so existing sidecars keep decoding
// as git origins.
Kind string `json:"kind,omitempty"`
// Client and Location are optional client-import provenance. skill add
// does not write them and does not clear a pair that still matches.
Client string `json:"client,omitempty"`
Location string `json:"location,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.
func (*Origin) StoredAuth ¶
func (o *Origin) StoredAuth() StoredAuth
StoredAuth returns the authentication this origin recorded at import.
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 ScanAgent ¶
func ScanAgent(def *AgentDefinition) *ScanResult
ScanAgent checks an agent definition for dangerous patterns in its body and frontmatter values. Like skill bodies (and unlike supporting files), any finding blocks: an agent definition is instructions the client executes with tool access.
func ScanFragment ¶
func ScanFragment(name string, content []byte) *ScanResult
ScanFragment checks a context rule fragment for dangerous patterns. Rule fragments are instructions clients inject into every session, so they get the same blocking scan agents do: the whole file (frontmatter and body) is scanned, and any finding blocks without --trust.
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.
func ScanSkillTree ¶
func ScanSkillTree(sk *registry.AgentSkill, srcDir, kind, discoveredPath string) (findings []SecurityFinding, blocking bool)
ScanSkillTree runs the same security gate an import applies to one discovered skill: the SKILL.md body (any finding blocks) plus the supporting-file tree (danger-severity findings block; lower severities surface without blocking). srcDir is the skill's directory in the clone. kind and discoveredPath select the same layout the importer uses (see layoutFor). Pack preview passes an empty kind, which is git, and the discovered path. Callers that refuse before importing (the pack REST surface) use this so their refusal covers exactly what the importer would skip.
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 SkippedAgent ¶
type SkippedAgent = SkippedSkill
SkippedAgent aliases SkippedSkill so agent call sites read as what they are; the shape and JSON encoding are identical.
type SkippedSkill ¶
SkippedSkill records a skill (or agent) that was skipped during import.
type SnapshotResult ¶
type SnapshotResult struct {
// CheckoutDir is the absolute directory the copy landed in.
CheckoutDir string
// Reused is true when an existing directory for this destination was
// returned without copying.
Reused bool
}
SnapshotResult is a materialized pack checkout.
func SnapshotWorktree ¶
func SnapshotWorktree(ctx context.Context, repoPath, destDir string) (SnapshotResult, error)
SnapshotWorktree copies repoPath, excluding .git, into destDir. The copy skips symlinks, refuses any path that resolves outside the clone root, and fails closed on the repository caps. An existing destDir is reused. The copy holds the cross-process flock on repoPath+".flock" that cloneShallow also acquires, so a cache update cannot rewrite the source mid-copy. A failure leaves no partial destDir.
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 SourceConflictError ¶
SourceConflictError is a source-key collision with an existing record.
func (*SourceConflictError) Error ¶
func (e *SourceConflictError) Error() string
func (*SourceConflictError) Unwrap ¶
func (e *SourceConflictError) Unwrap() error
type SourceNameInput ¶
type SourceNameInput struct {
Kind string
Root string
Explicit string
KnownName string
ClientImport bool
}
SourceNameInput selects the lockfile key for one import.
type StoredAuth ¶
StoredAuth is the non-secret authentication recorded for a source. Token values and passphrases are never part of it.
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.