vault

package
v2.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 47 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AppPluginModeOpen      = "open"
	AppPluginModeAllowlist = "allowlist"
	AppPluginModeDisabled  = "disabled"
)
View Source
const (
	QualityEvalServer = "server"
	QualityEvalLocal  = "local"
)

Reevaluate dispatch results: who runs the evaluation.

View Source
const DefaultTeamsLimit = 300

DefaultTeamsLimit is the server-side maximum number of teams a single ListTeams query returns. It is the one source of truth for that cap: the Sleuth lookup paths request it, and the pkg/sxvault facade references it so the public "list all teams" surface and the internal lookups can't silently disagree.

Variables

View Source
var ErrAssetNotFound = errors.New("asset not found")

ErrAssetNotFound is returned when a requested asset does not exist.

View Source
var ErrBenchmarksUnsupported = errors.New(
	"this library's server doesn't support benchmark storage yet")

ErrBenchmarksUnsupported is returned when the vault backend cannot store benchmark records (a server predating the surface).

View Source
var ErrLockFileNotFound = errors.New("lock file not found")

ErrLockFileNotFound is returned when the lock file does not exist in the vault

View Source
var ErrNotImplemented = errors.New("operation not supported for this vault type")

ErrNotImplemented is returned by vaults that do not support a given management operation.

View Source
var ErrQualityReadOnly = errors.New(
	"this library's quality scores are server-evaluated and read-only")

ErrQualityReadOnly is returned when a vault only surfaces its own server-side evaluations and refuses client-written records.

View Source
var ErrQualityUnsupported = errors.New(
	"this library's server doesn't support quality storage yet")

ErrQualityUnsupported is returned when the vault backend cannot store quality records (a server predating the surface).

View Source
var ErrSharedStorageUnsupported = errors.New(
	"this library's server doesn't support shared extension data yet")

ErrSharedStorageUnsupported is returned when the vault backend cannot store shared extension data (a server predating the surface).

View Source
var ErrStorageUpToDate = errors.New("vault storage is already on the current format")

ErrStorageUpToDate is returned by migration entry points when there is nothing to migrate: the vault is already on the current storage format, or is uninitialized (no manifest — the format is stamped when the manifest is first created, not here).

Functions

func ContextWithTrustedScopeWrite

func ContextWithTrustedScopeWrite(ctx context.Context) context.Context

ContextWithTrustedScopeWrite marks ctx as a trusted bulk scope write that skips the file-backed RBAC gate. Used by `sx vault copy`, which replicates a source vault's existing scopes verbatim and must not be blocked just because the operator isn't a team admin in the destination. User-driven scope changes (sx add) never set this, so they stay governed by scopeSetPermissionReason.

Types

type AddAssetResult

type AddAssetResult struct {
	Name           string
	Version        string
	URL            string
	IsFirstVersion bool
}

AddAssetResult contains canonical asset information returned by a vault after upload. Server-backed vaults may normalize the requested name into a persisted slug; callers should use Name for follow-up operations. IsFirstVersion is true when the upload created the first stored version of the asset, which lets callers distinguish new-asset setup from re-publish.

type AppPluginPolicyStore

type AppPluginPolicyStore interface {
	// AppPluginPolicy returns the current policy. A nil policy means
	// "open" — no restrictions.
	AppPluginPolicy(ctx context.Context) (*manifest.AppPluginPolicy, error)

	// SetAppPluginPolicy replaces the policy. Only org-admins may call
	// this on a governed vault; on an ungoverned vault anyone can (the
	// same rule as every other governance surface, see docs/rbac.md).
	// A nil policy clears the table back to open.
	SetAppPluginPolicy(ctx context.Context, policy *manifest.AppPluginPolicy) error
}

AppPluginPolicyStore is implemented by vaults that carry the policy.

type AppPluginSharedStore

type AppPluginSharedStore interface {
	// AppPluginSharedLoad returns the extension's shared JSON document
	// ("" when none exists).
	AppPluginSharedLoad(ctx context.Context, pluginID string) (string, error)

	// AppPluginSharedSave replaces the document. Empty data deletes it.
	AppPluginSharedSave(ctx context.Context, pluginID, data string) error
}

AppPluginSharedStore is implemented by vaults that can hold shared extension state.

type AssetDetails

type AssetDetails struct {
	Name        string
	Type        asset.Type
	Description string
	CreatedAt   time.Time
	UpdatedAt   time.Time
	Versions    []AssetVersion
	Metadata    *metadata.Metadata // Metadata for latest version (or nil if not available)
}

AssetDetails contains detailed information about a specific asset

type AssetEditPermissionError

type AssetEditPermissionError struct {
	Asset    string
	Teams    []string
	AssetGID string
}

AssetEditPermissionError is returned when the actor may not publish a new version of an asset. It carries the asset name so callers (notably `sx add`) can recognize the denial via errors.As and offer a pull-request fallback instead of just failing. See docs/rbac.md.

Teams is set only by the file-backed git/path gate, which reads the gating team scopes from the manifest. The Sleuth vault learns of the denial from the server (a 403 on upload) and doesn't get the teams, but it does get AssetGID — the skill's server GID — which it passes to createAssetPullRequest to open the PR. Either field may be empty depending on which vault produced the error.

func (*AssetEditPermissionError) Error

func (e *AssetEditPermissionError) Error() string

type AssetShimRegistrar

type AssetShimRegistrar struct {
	Repo assetReader
	// contains filtered or unexported fields
}

AssetShimRegistrar registers Pulse-style asset listing/loading MCP tools onto an mcp.Server. PathVault and GitVault both opt in by returning a populated registrar from GetMCPTools(); the cloud serve builder type-asserts on this type and calls Register so claude.ai / chatgpt.com see real tools when they connect via the relay.

Tool descriptions and input schemas mirror sleuth/apps/mcp_gateway/asset_shim so the local-vault MCP and the server-side shim behave identically from a client's perspective. Diverging would mean prompt-tuning has to happen twice.

func (*AssetShimRegistrar) Register

func (r *AssetShimRegistrar) Register(server *mcp.Server)

Register wires the seven shim tools onto the supplied MCP server.

type AssetSummary

type AssetSummary struct {
	Name          string
	Type          asset.Type
	LatestVersion string
	VersionsCount int
	Description   string
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

AssetSummary contains summary information about a vault asset

type AssetVersion

type AssetVersion struct {
	Version    string
	CreatedAt  time.Time
	FilesCount int
}

AssetVersion contains version information for an asset

type BenchmarkStore

type BenchmarkStore interface {
	// ListBenchmarks returns the asset's records as a JSON array string,
	// newest first ("" when none exist).
	ListBenchmarks(ctx context.Context, asset string) (string, error)

	// AddBenchmark prepends one interchange record (a JSON object string).
	AddBenchmark(ctx context.Context, asset, record string) error

	// LatestBenchmarks returns a JSON object mapping asset name to its
	// newest record, for every asset that has one — the dashboard's
	// single bulk read.
	LatestBenchmarks(ctx context.Context) (string, error)
}

BenchmarkStore is implemented by vaults that can hold benchmark records.

type BotApiKeyManager

type BotApiKeyManager interface {
	CreateBotApiKey(ctx context.Context, botName, label string) (rawToken string, key mgmt.BotApiKey, err error)
	ListBotApiKeys(ctx context.Context, botName string) ([]mgmt.BotApiKey, error)
	DeleteBotApiKey(ctx context.Context, botName, keyID string) error
}

BotApiKeyManager is implemented by vaults that issue API tokens for bot identities. File-based vaults (path/git) do not implement this — their trust model is "vault read access ⇒ asset access" so bots are identity-only there. Sleuth vaults issue real OAuth tokens via the existing skills.new createBotApiKey mutation.

type BotRuntimeTokenManager

type BotRuntimeTokenManager interface {
	CreateBotRuntimeToken(ctx context.Context, botName, label string, ttlSeconds int) (rawToken string, expiresAt time.Time, err error)
	RevokeBotRuntimeTokens(ctx context.Context, botName string) (revokedCount int, err error)
}

BotRuntimeTokenManager is implemented by vaults that can issue short-lived, read-only tokens for bot identities. File-based vaults do not implement this because access is granted by the vault checkout itself, not by API tokens.

type CollectionInstaller

type CollectionInstaller interface {
	// SetCollectionInstallation adds one install target to the collection,
	// deduped against existing rows. Unlike asset installs, an org target
	// is stored as an explicit kind=org row (a collection with no rows
	// grants nothing), so org-wide is both addable and removable.
	SetCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

	// RemoveCollectionInstallation removes one matching install target.
	// Member assets' own scopes are never touched. Removing a row that
	// isn't present is a no-op.
	RemoveCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

	// CurrentCollectionInstallTargets reports the collection's own install
	// targets. The bool reports whether the collection exists; an existing
	// collection with no targets returns an empty list (it grants nothing).
	CurrentCollectionInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)
}

CollectionInstaller is implemented by vaults that support collection-level installs. Callers feature-detect via this interface.

type CollectionRenamer

type CollectionRenamer interface {
	RenameCollection(ctx context.Context, oldName, newName string) error
}

CollectionRenamer is implemented by vaults whose collections can be renamed.

type CollectionStore

type CollectionStore interface {
	ListCollections(ctx context.Context) ([]manifest.Collection, error)
	SaveCollection(ctx context.Context, c manifest.Collection) error
	DeleteCollection(ctx context.Context, name string) error
}

CollectionStore is implemented by vaults that support collections.

type Config

type Config interface {
	GetType() string
	GetServerURL() string
	GetAuthToken() string
	GetRepositoryURL() string
}

Config represents the minimal configuration needed to create a vault This avoids circular dependency with the config package

type ErrVersionExists

type ErrVersionExists struct {
	Name    string
	Version string
	// Slug is the server-persisted slug of the conflicting asset. Only the
	// Sleuth vault populates it (from the upload-conflict response); the
	// Git and Path vaults always leave it empty. Callers re-publishing a
	// collision-resolved upload should prefer this over the requested Name
	// when non-empty, so follow-up operations target the uploaded asset and
	// not a same-named one — and must handle the empty case for other vaults.
	Slug    string
	Message string
}

ErrVersionExists is returned when attempting to add an asset version that already exists

func (*ErrVersionExists) Error

func (e *ErrVersionExists) Error() string

type GitSourceHandler

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

GitSourceHandler handles assets with source-git

func NewGitSourceHandler

func NewGitSourceHandler(gitClient *git.Client) *GitSourceHandler

NewGitSourceHandler creates a new Git source handler

func (*GitSourceHandler) Fetch

func (g *GitSourceHandler) Fetch(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

Fetch clones/fetches a git repository and retrieves the asset

func (*GitSourceHandler) ResolveRef

func (g *GitSourceHandler) ResolveRef(ctx context.Context, repoURL, ref string) (string, error)

ResolveRef resolves a branch or tag name to a commit SHA This is used during lock file generation to convert friendly names to commit SHAs

type GitVault

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

GitVault implements Vault for Git vaults

func NewGitVault

func NewGitVault(repoURL string) (*GitVault, error)

NewGitVault creates a new Git repository

func NewGitVaultWithOptions

func NewGitVaultWithOptions(repoURL string, opts ...GitVaultOption) (*GitVault, error)

func (*GitVault) AbortPRBranch

func (g *GitVault) AbortPRBranch(ctx context.Context) error

AbortPRBranch tears down PR mode without pushing: it clears the in-memory PR state and restores the cached clone to its base branch, discarding any uncommitted PR changes. It's the cleanup path for a PR add that failed after StartPRBranch but before FinishPRBranch — without it the persistent clone is left checked out on the PR branch (with a local-only commit), which a later cloneOrUpdate would then read from. Safe to call when PR mode isn't active.

func (*GitVault) AddAsset

func (g *GitVault) AddAsset(ctx context.Context, asset *lockfile.Asset, zipData []byte) error

AddAsset uploads an asset to the Git repository

func (*GitVault) AddBenchmark

func (g *GitVault) AddBenchmark(ctx context.Context, asset, record string) error

AddBenchmark records one benchmark result and pushes.

func (*GitVault) AddBotTeam

func (g *GitVault) AddBotTeam(ctx context.Context, bot, team string) error

func (*GitVault) AddOrgAdmins

func (g *GitVault) AddOrgAdmins(ctx context.Context, emails []string) (added int, err error)

func (*GitVault) AddQuality

func (g *GitVault) AddQuality(ctx context.Context, asset, record string) error

AddQuality records one quality evaluation and pushes.

func (*GitVault) AddTeamMember

func (g *GitVault) AddTeamMember(ctx context.Context, team, email string, admin bool) error

func (*GitVault) AddTeamRepository

func (g *GitVault) AddTeamRepository(ctx context.Context, team, repoURL string) error

func (*GitVault) AppPluginPolicy

func (g *GitVault) AppPluginPolicy(ctx context.Context) (*manifest.AppPluginPolicy, error)

AppPluginPolicy returns the vault's extension policy.

func (*GitVault) AppPluginSharedLoad

func (g *GitVault) AppPluginSharedLoad(ctx context.Context, pluginID string) (string, error)

AppPluginSharedLoad reads the extension's shared document from the synced clone.

func (*GitVault) AppPluginSharedSave

func (g *GitVault) AppPluginSharedSave(ctx context.Context, pluginID, data string) error

AppPluginSharedSave replaces the extension's shared document and pushes (the file lives under .sx/, which the vault tx stages).

func (*GitVault) AssetInstallScopes

func (g *GitVault) AssetInstallScopes(_ context.Context, name string) ([]manifest.Scope, bool, error)

AssetInstallScopes exposes the named asset's complete authoring scopes and whether it has a manifest entry. See manifestAssetScopes.

func (*GitVault) Authenticate

func (g *GitVault) Authenticate(ctx context.Context) (string, error)

Authenticate performs authentication with the Git repository For Git repos, this is a no-op as authentication is handled by git itself

func (*GitVault) CheckAssetEditPermission

func (g *GitVault) CheckAssetEditPermission(ctx context.Context, name string) error

CheckAssetEditPermission enforces the file-backed edit gate for a git vault.

func (*GitVault) ClearAssetInstallations

func (g *GitVault) ClearAssetInstallations(ctx context.Context, assetName string) error

func (*GitVault) CommitAndPush

func (g *GitVault) CommitAndPush(ctx context.Context, asset *lockfile.Asset) error

CommitAndPush commits all changes and pushes to remote

func (*GitVault) CreateBot

func (g *GitVault) CreateBot(ctx context.Context, bot mgmt.Bot) (string, error)

CreateBot on a git vault returns ("", err) — file-based vaults are identity-only for bots and never issue API keys.

func (*GitVault) CreateTeam

func (g *GitVault) CreateTeam(ctx context.Context, team mgmt.Team) error

func (*GitVault) CurrentActor

func (g *GitVault) CurrentActor(ctx context.Context) (mgmt.Actor, error)

CurrentActor resolves the caller's identity via git config.

func (*GitVault) CurrentCollectionInstallTargets

func (g *GitVault) CurrentCollectionInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentCollectionInstallTargets reports a collection's install targets.

func (*GitVault) CurrentInstallTargets

func (g *GitVault) CurrentInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentInstallTargets reports the named asset's current installation from the git vault's manifest; see commonCurrentInstallTargets.

func (*GitVault) DeleteBot

func (g *GitVault) DeleteBot(ctx context.Context, name string) error

func (*GitVault) DeleteCollection

func (g *GitVault) DeleteCollection(ctx context.Context, name string) error

DeleteCollection removes a collection by name and pushes.

func (*GitVault) DeleteTeam

func (g *GitVault) DeleteTeam(ctx context.Context, name string) error

func (*GitVault) ExistingAssetScopes

func (g *GitVault) ExistingAssetScopes(name string) []lockfile.Scope

ExistingAssetScopes is the GitVault version; see PathVault's doc.

func (*GitVault) FinishPRBranch

func (g *GitVault) FinishPRBranch(ctx context.Context, title, body string) (PRResult, error)

FinishPRBranch pushes the PR branch, opens a pull request for it, and returns the outcome. It always restores the cached clone to the base branch and clears PR mode, so later sx operations don't run against the PR branch.

The PR is created with the `gh` CLI when it is available on PATH; otherwise the result carries a GitHub compare URL (and a Fallback reason) for the user to open the PR manually.

func (*GitVault) GetAsset

func (g *GitVault) GetAsset(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

GetAsset downloads an asset using its source configuration

func (*GitVault) GetAssetByVersion

func (g *GitVault) GetAssetByVersion(ctx context.Context, name, version string) ([]byte, error)

GetAssetByVersion retrieves an asset by name and version from the git repository This creates a zip from the exploded directory

func (*GitVault) GetAssetDetails

func (g *GitVault) GetAssetDetails(ctx context.Context, name string) (*AssetDetails, error)

GetAssetDetails returns detailed information about a specific asset

func (*GitVault) GetBootstrapOptions

func (g *GitVault) GetBootstrapOptions(ctx context.Context) []bootstrap.Option

GetBootstrapOptions returns no bootstrap options for GitVault

func (*GitVault) GetBot

func (g *GitVault) GetBot(ctx context.Context, name string) (*mgmt.Bot, error)

func (*GitVault) GetLockFile

func (g *GitVault) GetLockFile(ctx context.Context, cachedETag string) (content []byte, etag string, notModified bool, err error)

GetLockFile clones or syncs the Git vault, then returns a lock file resolved from the vault's manifest for the caller's identity. Team and user scopes are flattened to repo-scoped entries based on team membership and the caller's git config email.

func (*GitVault) GetMCPTools

func (g *GitVault) GetMCPTools() any

GetMCPTools returns the asset-shim registrar so callers (notably the cloud serve MCP builder) can publish list_my_assets / load_my_asset / … on top of the git-backed vault. Without this, claude.ai connects to the relay and reports "no tools available" because GitVault has no native MCP surface.

func (*GitVault) GetMetadata

func (g *GitVault) GetMetadata(ctx context.Context, name, version string) (*metadata.Metadata, error)

GetMetadata retrieves metadata for a specific asset version. Git vaults store assets exploded under assets/<name>/<version>/, so the metadata.toml is just a file read away after syncing the repo.

func (*GitVault) GetQuality

func (g *GitVault) GetQuality(ctx context.Context, asset string) (string, error)

GetQuality returns the asset's quality wrapper doc from the clone.

func (*GitVault) GetTeam

func (g *GitVault) GetTeam(ctx context.Context, name string) (*mgmt.Team, error)

func (*GitVault) GetUsageStats

func (g *GitVault) GetUsageStats(ctx context.Context, filter mgmt.UsageFilter) (*mgmt.UsageSummary, error)

func (*GitVault) GetVaultIcon

func (g *GitVault) GetVaultIcon(ctx context.Context) ([]byte, error)

GetVaultIcon reads the shared icon from the working clone. It never pulls: icon freshness rides along with every other vault operation's sync, and a library that has never been used yet simply has no icon to show until it is. The vault flock keeps the read from observing a working tree mid-rewrite (pull/rebase in another process).

func (*GitVault) GetVersionList

func (g *GitVault) GetVersionList(ctx context.Context, name string) ([]string, error)

GetVersionList retrieves available versions for an asset from list.txt

func (*GitVault) ImportAuditEvents

func (g *GitVault) ImportAuditEvents(ctx context.Context, events []mgmt.AuditEvent) error

func (*GitVault) InheritInstallations

func (g *GitVault) InheritInstallations(ctx context.Context, asset *lockfile.Asset) error

InheritInstallations upserts the asset into the manifest, carrying any existing entry's scopes through verbatim, and commits/pushes.

func (*GitVault) LatestBenchmarks

func (g *GitVault) LatestBenchmarks(ctx context.Context) (string, error)

LatestBenchmarks returns the newest record per asset from the clone.

func (*GitVault) LatestQuality

func (g *GitVault) LatestQuality(ctx context.Context) (string, error)

LatestQuality returns the newest record per asset from the clone.

func (*GitVault) ListAssets

func (g *GitVault) ListAssets(ctx context.Context, opts ListAssetsOptions) (*ListAssetsResult, error)

ListAssets returns a list of all assets in the vault by reading the assets/ directory

func (*GitVault) ListBenchmarks

func (g *GitVault) ListBenchmarks(ctx context.Context, asset string) (string, error)

ListBenchmarks returns the asset's benchmark records from the clone.

func (*GitVault) ListBots

func (g *GitVault) ListBots(ctx context.Context) ([]mgmt.Bot, error)

func (*GitVault) ListCollections

func (g *GitVault) ListCollections(ctx context.Context) ([]manifest.Collection, error)

ListCollections returns the vault's collections.

func (*GitVault) ListOrgAdmins

func (g *GitVault) ListOrgAdmins(ctx context.Context) ([]string, error)

func (*GitVault) ListRepoAssets

func (g *GitVault) ListRepoAssets(ctx context.Context) (map[string][]string, error)

ListRepoAssets maps repository URL → asset names scoped to it.

func (*GitVault) ListTeamAssets

func (g *GitVault) ListTeamAssets(ctx context.Context) (map[string][]string, error)

ListTeamAssets maps team name → asset names shared with that team.

func (*GitVault) ListTeams

func (g *GitVault) ListTeams(ctx context.Context, opts ListTeamsOptions) (*ListTeamsResult, error)

func (*GitVault) ListUserAssets

func (g *GitVault) ListUserAssets(ctx context.Context) (map[string][]string, error)

ListUserAssets maps normalized email → asset names installed just for that person.

func (*GitVault) ManifestPath

func (g *GitVault) ManifestPath() string

ManifestPath returns the absolute path to the vault's manifest file.

func (*GitVault) MigrateStorage

func (g *GitVault) MigrateStorage(ctx context.Context) (*MigrationResult, error)

MigrateStorage runs the v1 → v2 storage migration explicitly (`sx vault migrate`). Returns ErrStorageUpToDate when the vault is already current.

func (*GitVault) PlanStorageMigration

func (g *GitVault) PlanStorageMigration(ctx context.Context) (*MigrationPlan, error)

PlanStorageMigration reports what MigrateStorage would do (dry run).

func (*GitVault) PostUsageStats

func (g *GitVault) PostUsageStats(ctx context.Context, jsonlData string) error

PostUsageStats parses the JSONL payload produced by stats.FlushQueue and persists it to .sx/usage/YYYY-MM.jsonl via RecordUsageEvents. This keeps wire compatibility with the existing queue flush pipeline while moving the real storage into the git vault.

func (*GitVault) QueryAuditEvents

func (g *GitVault) QueryAuditEvents(ctx context.Context, filter mgmt.AuditFilter) ([]mgmt.AuditEvent, error)

func (*GitVault) ReadRootFiles

func (g *GitVault) ReadRootFiles(ctx context.Context, names []string) (map[string][]byte, error)

ReadRootFiles reads files from the vault root behind ONE clone sync (e.g. a marketplace's catalog.json + stats.json — per-file reads would pay the fetch twice). Names must be bare filenames — no path separators — so callers can't walk out of the root. Missing files are simply absent from the result, not an error.

func (*GitVault) ReadUsageEvents

func (g *GitVault) ReadUsageEvents(ctx context.Context, filter mgmt.UsageFilter) ([]mgmt.UsageEvent, error)

func (*GitVault) RecordUsageEvents

func (g *GitVault) RecordUsageEvents(ctx context.Context, events []mgmt.UsageEvent) error

RecordUsageEvents appends usage events to the local JSONL log and, at most once per usagePushInterval, commits and pushes the queued .sx/usage files to the remote.

Under active use this can run hundreds of times per hour, and a commit-per-call would spam the git history and turn a background observation channel into a noisy multi-writer workload. Originally the design relied on the next management mutation (team, install, etc.) running runInVaultTx to sweep .sx/ into its commit, but users who only consume assets never trigger such a mutation, so their usage events would accumulate locally and never reach the remote. Throttled push closes that gap without per-call spam.

Queries on the same machine see events immediately because GetUsageStats reads the local working tree regardless of push state.

func (*GitVault) ReevaluateQuality

func (g *GitVault) ReevaluateQuality(ctx context.Context, asset string) (string, error)

ReevaluateQuality on a git vault is the caller's job, same as path.

func (*GitVault) RemoveAsset

func (g *GitVault) RemoveAsset(ctx context.Context, assetName, version string, delete bool) error

RemoveAsset removes an asset from the lock file and pushes to remote. If delete is true, also permanently removes the asset files from the vault.

func (*GitVault) RemoveAssetInstallation

func (g *GitVault) RemoveAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*GitVault) RemoveBotTeam

func (g *GitVault) RemoveBotTeam(ctx context.Context, bot, team string) error

func (*GitVault) RemoveCollectionInstallation

func (g *GitVault) RemoveCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

RemoveCollectionInstallation removes an install target and pushes.

func (*GitVault) RemoveOrgAdmin

func (g *GitVault) RemoveOrgAdmin(ctx context.Context, email string) error

func (*GitVault) RemoveTeamMember

func (g *GitVault) RemoveTeamMember(ctx context.Context, team, email string) error

func (*GitVault) RemoveTeamRepository

func (g *GitVault) RemoveTeamRepository(ctx context.Context, team, repoURL string) error

func (*GitVault) RenameAsset

func (g *GitVault) RenameAsset(ctx context.Context, oldName, newName string) error

RenameAsset renames an asset in the vault. All versions and installations are preserved under the new name.

func (*GitVault) RenameCollection

func (g *GitVault) RenameCollection(ctx context.Context, oldName, newName string) error

RenameCollection renames a collection.

func (*GitVault) RenameTeam

func (g *GitVault) RenameTeam(ctx context.Context, oldName, newName string) error

RenameTeam renames a team and every reference to it.

func (*GitVault) RepairVaultClone

func (g *GitVault) RepairVaultClone(ctx context.Context) (discardedTip string, err error)

RepairVaultClone re-syncs the local vault cache to the remote, discarding any unpushed manifest/asset commits (treated as failed or interrupted mutations) while preserving and pushing queued usage-event appends under .sx/usage. It returns the short SHA of the discarded local tip, or "" if the cache was already in sync with the remote.

It deliberately avoids cloneOrUpdate's `git pull` (a merge): when the cache has diverged on the manifest, that merge can conflict and stall the very repair meant to clear the divergence. Instead it fetches and hard-anchors the branch back to the remote tip. SD-10170.

func (*GitVault) RetireAsset

func (g *GitVault) RetireAsset(ctx context.Context, assetName string) error

RetireAsset removes the asset from the manifest and root view, keeping its version archive, and pushes the change.

func (*GitVault) SaveCollection

func (g *GitVault) SaveCollection(ctx context.Context, c manifest.Collection) error

SaveCollection creates or replaces a collection and pushes.

func (*GitVault) SetAppPluginPolicy

func (g *GitVault) SetAppPluginPolicy(ctx context.Context, policy *manifest.AppPluginPolicy) error

SetAppPluginPolicy replaces the vault's extension policy and pushes.

func (*GitVault) SetAssetInstallation

func (g *GitVault) SetAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*GitVault) SetAssetInstallations

func (g *GitVault) SetAssetInstallations(ctx context.Context, assetName string, targets []InstallTarget, appendMode bool) (skipped []SkippedTarget, err error)

SetAssetInstallations applies a batch of install targets (including identity scopes — team/user/bot) in one commit. Satisfies installSetter so the unified scope flow works against git vaults, not just the Sleuth vault.

func (*GitVault) SetCollectionInstallation

func (g *GitVault) SetCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

SetCollectionInstallation adds an install target to a collection and pushes.

func (*GitVault) SetInstallations

func (g *GitVault) SetInstallations(ctx context.Context, asset *lockfile.Asset, scopeEntity string) error

SetInstallations upserts the asset into the vault's manifest and pushes. The incoming asset's scopes replace the stored set, except for existing scopes the actor isn't allowed to remove (e.g. a team they don't admin), which are carried through — see commonSetInstallations and docs/rbac.md.

func (*GitVault) SetPublishedAssetInstallations

func (g *GitVault) SetPublishedAssetInstallations(ctx context.Context, asset *lockfile.Asset, targets []InstallTarget, appendMode bool) (skipped []SkippedTarget, err error)

SetPublishedAssetInstallations is SetAssetInstallations for a just-published asset version: the manifest row advances to asset's version (existing scopes carried through) in the SAME transaction — and so the same commit/push — the targets apply in. A scoped republish therefore lands as one commit, and the version and scopes change together or not at all. Satisfies publishedInstallSetter.

func (*GitVault) SetTeamAdmin

func (g *GitVault) SetTeamAdmin(ctx context.Context, team, email string, admin bool) error

func (*GitVault) SetVaultIcon

func (g *GitVault) SetVaultIcon(ctx context.Context, data []byte) error

SetVaultIcon stores (or with empty data removes) the shared icon, as its own commit pushed to the vault repository.

func (*GitVault) StartPRBranch

func (g *GitVault) StartPRBranch(ctx context.Context, branch string) error

StartPRBranch puts the git vault into pull-request mode: it syncs the clone, creates a fresh branch off the current (default) branch, and records the base so FinishPRBranch can push the branch, open the PR, and restore the clone.

While in this mode commitAndPush commits locally without pushing, so the whole `sx add` operation accumulates on the branch and lands in a single PR. This is the fallback offered when the caller lacks RBAC permission to publish directly (see docs/rbac.md and AssetEditPermissionError).

func (*GitVault) StorageSourcePath

func (g *GitVault) StorageSourcePath(name, version string) (string, error)

StorageSourcePath returns the vault-relative source path recorded in the manifest for a stored version, per the vault's current storage layout.

func (*GitVault) UninstallAssetTargets

func (g *GitVault) UninstallAssetTargets(ctx context.Context, assetName string, targets []InstallTarget) (removed int, failures []string, err error)

UninstallAssetTargets removes a batch of install targets in one commit. Satisfies targetUninstaller so interactive scope edits can remove individual scopes from a git vault.

func (*GitVault) UpdateBot

func (g *GitVault) UpdateBot(ctx context.Context, bot mgmt.Bot) error

func (*GitVault) UpdateTeam

func (g *GitVault) UpdateTeam(ctx context.Context, team mgmt.Team) error

func (*GitVault) UpdateTemplates

func (g *GitVault) UpdateTemplates(ctx context.Context, commit bool) ([]string, error)

UpdateTemplates updates templates in the repository if needed and returns the list of updated files The commit parameter controls whether to commit and push changes (git-specific behavior)

func (*GitVault) VerifyIntegrity

func (g *GitVault) VerifyIntegrity(data []byte, hashes map[string]string, size int64) error

VerifyIntegrity checks hashes and sizes for downloaded assets

type GitVaultOption

type GitVaultOption func(*gitVaultOptions)

func WithGitClient

func WithGitClient(client *git.Client) GitVaultOption

type HTTPSourceHandler

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

HTTPSourceHandler handles assets with source-http

func NewHTTPSourceHandler

func NewHTTPSourceHandler(authToken string) *HTTPSourceHandler

NewHTTPSourceHandler creates a new HTTP source handler

func (*HTTPSourceHandler) DownloadWithProgress

func (h *HTTPSourceHandler) DownloadWithProgress(ctx context.Context, url string, progressCallback func(current, total int64)) ([]byte, error)

DownloadWithProgress downloads a file with progress reporting This is used for user-facing downloads with progress bars

func (*HTTPSourceHandler) Fetch

func (h *HTTPSourceHandler) Fetch(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

Fetch downloads an asset from an HTTP URL

type InstallKind

type InstallKind string

InstallKind identifies which kind of installation a CLI command is asking the vault to record.

const (
	InstallKindOrg  InstallKind = "org"
	InstallKindRepo InstallKind = "repo"
	InstallKindPath InstallKind = "path"
	InstallKindTeam InstallKind = "team"
	InstallKindUser InstallKind = "user"
	InstallKindBot  InstallKind = "bot"
)

type InstallTarget

type InstallTarget struct {
	Kind  InstallKind
	Repo  string   // Repo and Path
	Paths []string // Path
	Team  string   // Team
	User  string   // User (email)
	Bot   string   // Bot (name)

	// EntityID is the server GID of the installed entity, populated when a
	// target is read back from the server (the current-installation view). It
	// lets a removal target the exact installation via uninstallAssetTargets
	// without re-resolving the entity by name/email. Empty for targets the user
	// is adding (those resolve by name/email at apply time).
	EntityID string
	// MonoRepoConfigID is the server GID of the mono-repo config for a
	// path-scoped repository install, needed to remove that specific install.
	MonoRepoConfigID string
}

InstallTarget describes a single installation target for an asset. Only fields relevant to the chosen Kind need to be set.

func (InstallTarget) AuditData

func (t InstallTarget) AuditData() map[string]any

AuditData returns the payload attached to an install.set audit event for this target. Single source of truth for what each kind records.

func (InstallTarget) Describe

func (t InstallTarget) Describe() string

Describe returns a short human-readable summary of the target, suitable for commit messages and CLI output.

type ListAssetsArgs

type ListAssetsArgs struct {
	Type   string `` /* 207-byte string literal not displayed */
	Search string `json:"search,omitempty" jsonschema:"Case-insensitive substring filter over name + description."`
}

ListAssetsArgs is the input for list_my_assets.

type ListAssetsOptions

type ListAssetsOptions struct {
	Type   string // Filter by asset type (skill, mcp, etc.)
	Search string // Search query for filtering assets
	Limit  int    // Maximum number of assets to return (default 100)
}

ListAssetsOptions contains options for listing vault assets

type ListAssetsResult

type ListAssetsResult struct {
	Assets []AssetSummary
}

ListAssetsResult contains the results of a ListAssets call

type ListByTypeArgs

type ListByTypeArgs struct {
	Search string `json:"search,omitempty" jsonschema:"Case-insensitive substring filter over name + description."`
}

ListByTypeArgs is the input for the per-type list aliases (list_my_skills, …). They pin the type filter server-side so callers can omit it.

type ListTeamsOptions

type ListTeamsOptions struct {
	Filter string // Server-side term search (substring match on team name)
	Limit  int    // Max teams to return (default 20)
}

ListTeamsOptions controls the ListTeams query.

type ListTeamsResult

type ListTeamsResult struct {
	Teams      []mgmt.Team
	TotalCount int  // Total teams matching the filter (-1 if unknown)
	HasMore    bool // True when more teams exist beyond Limit
}

ListTeamsResult holds the paginated team list and total count.

type LoadAssetArgs

type LoadAssetArgs struct {
	Slug string `json:"slug" jsonschema:"Asset slug from list_my_assets."`
}

LoadAssetArgs is the input for load_my_asset.

type LoadAssetFileArgs

type LoadAssetFileArgs struct {
	Slug string `json:"slug" jsonschema:"Asset slug."`
	Path string `json:"path" jsonschema:"File path as returned by load_my_asset's bundled_files."`
}

LoadAssetFileArgs is the input for load_my_asset_file.

type MigrationPlan

type MigrationPlan struct {
	// FromVersion and ToVersion are the storage format versions involved.
	FromVersion int
	ToVersion   int
	// Assets are the asset names whose storage would move.
	Assets []string
}

MigrationPlan is the dry-run description of a pending migration.

type MigrationResult

type MigrationResult struct {
	// Assets is the number of asset directories moved into the archive.
	Assets int
}

MigrationResult describes a completed storage migration.

type PRResult

type PRResult struct {
	// URL is the pull request URL when Created, otherwise a GitHub compare URL
	// the user can open to create the PR by hand.
	URL string
	// Created is true when a pull request was actually opened (via the gh CLI).
	Created bool
	// Fallback explains, when Created is false, why we couldn't open the PR
	// automatically and fell back to the compare URL.
	Fallback string
}

PRResult reports the outcome of FinishPRBranch.

type PathSourceHandler

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

PathSourceHandler handles assets with source-path

func NewPathSourceHandler

func NewPathSourceHandler(lockFileDir string) *PathSourceHandler

NewPathSourceHandler creates a new path source handler

func (*PathSourceHandler) Fetch

func (p *PathSourceHandler) Fetch(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

Fetch reads an asset from a local file path

func (*PathSourceHandler) ResolvePath

func (p *PathSourceHandler) ResolvePath(path string) (string, error)

ResolvePath resolves a path (absolute, relative, or tilde) to an absolute path

type PathVault

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

PathVault implements Vault for local filesystem directories It follows the same pattern as GitRepository and SleuthRepository

func NewPathVault

func NewPathVault(repoURL string) (*PathVault, error)

NewPathVault creates a new path repository from a file:// URL

func (*PathVault) AddAsset

func (p *PathVault) AddAsset(ctx context.Context, asset *lockfile.Asset, zipData []byte) error

AddAsset adds an asset to the local repository Follows the same pattern as GitRepository: exploded storage + list.txt

func (*PathVault) AddBenchmark

func (p *PathVault) AddBenchmark(ctx context.Context, asset, record string) error

AddBenchmark records one benchmark result.

func (*PathVault) AddBotTeam

func (p *PathVault) AddBotTeam(ctx context.Context, bot, team string) error

func (*PathVault) AddOrgAdmins

func (p *PathVault) AddOrgAdmins(ctx context.Context, emails []string) (added int, err error)

func (*PathVault) AddQuality

func (p *PathVault) AddQuality(ctx context.Context, asset, record string) error

AddQuality records one quality evaluation.

func (*PathVault) AddTeamMember

func (p *PathVault) AddTeamMember(ctx context.Context, team, email string, admin bool) error

func (*PathVault) AddTeamRepository

func (p *PathVault) AddTeamRepository(ctx context.Context, team, repoURL string) error

func (*PathVault) AppPluginPolicy

func (p *PathVault) AppPluginPolicy(ctx context.Context) (*manifest.AppPluginPolicy, error)

AppPluginPolicy returns the vault's extension policy.

func (*PathVault) AppPluginSharedLoad

func (p *PathVault) AppPluginSharedLoad(ctx context.Context, pluginID string) (string, error)

AppPluginSharedLoad reads the extension's shared document.

func (*PathVault) AppPluginSharedSave

func (p *PathVault) AppPluginSharedSave(ctx context.Context, pluginID, data string) error

AppPluginSharedSave replaces the extension's shared document.

func (*PathVault) AssetInstallScopes

func (p *PathVault) AssetInstallScopes(_ context.Context, name string) ([]manifest.Scope, bool, error)

AssetInstallScopes exposes the named asset's complete authoring scopes and whether it has a manifest entry. The ctx/error signature matches the server-backed implementation so the copy engine can read scopes uniformly. See manifestAssetScopes.

func (*PathVault) Authenticate

func (p *PathVault) Authenticate(ctx context.Context) (string, error)

Authenticate performs authentication - no-op for path repositories

func (*PathVault) CheckAssetEditPermission

func (p *PathVault) CheckAssetEditPermission(ctx context.Context, name string) error

CheckAssetEditPermission enforces the file-backed edit gate for a path vault.

func (*PathVault) ClearAssetInstallations

func (p *PathVault) ClearAssetInstallations(ctx context.Context, assetName string) error

func (*PathVault) CreateBot

func (p *PathVault) CreateBot(ctx context.Context, bot mgmt.Bot) (string, error)

CreateBot on a path vault returns ("", err) — file-based vaults are identity-only for bots and never issue API keys.

func (*PathVault) CreateTeam

func (p *PathVault) CreateTeam(ctx context.Context, team mgmt.Team) error

func (*PathVault) CurrentActor

func (p *PathVault) CurrentActor(ctx context.Context) (mgmt.Actor, error)

currentActor reads the caller's git identity, falling back to $USER@host. Cached by mgmt.CurrentGitActor for the CLI's lifetime.

func (*PathVault) CurrentCollectionInstallTargets

func (p *PathVault) CurrentCollectionInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentCollectionInstallTargets reports a collection's install targets.

func (*PathVault) CurrentInstallTargets

func (p *PathVault) CurrentInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentInstallTargets reports the named asset's current installation from the path vault's manifest; see commonCurrentInstallTargets.

func (*PathVault) DeleteBot

func (p *PathVault) DeleteBot(ctx context.Context, name string) error

func (*PathVault) DeleteCollection

func (p *PathVault) DeleteCollection(ctx context.Context, name string) error

DeleteCollection removes a collection by name.

func (*PathVault) DeleteTeam

func (p *PathVault) DeleteTeam(ctx context.Context, name string) error

func (*PathVault) ExistingAssetScopes

func (p *PathVault) ExistingAssetScopes(name string) []lockfile.Scope

ExistingAssetScopes returns the manifest's current repo/path scopes for the named asset. Team and user scopes are excluded — the method exists to support UX prompts in `sx add` that show the publisher what repo- shaped scopes an asset already has. Returns nil if the asset is not in the manifest or the vault doesn't support manifest-backed lookup.

func (*PathVault) GetAsset

func (p *PathVault) GetAsset(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

GetAsset downloads an asset using its source configuration Reuses the same dispatch pattern as GitRepository and SleuthRepository

func (*PathVault) GetAssetByVersion

func (p *PathVault) GetAssetByVersion(ctx context.Context, name, version string) ([]byte, error)

GetAssetByVersion retrieves an asset by name and version Creates a zip from the exploded directory

func (*PathVault) GetAssetDetails

func (p *PathVault) GetAssetDetails(ctx context.Context, name string) (*AssetDetails, error)

GetAssetDetails returns detailed information about a specific asset

func (*PathVault) GetBootstrapOptions

func (p *PathVault) GetBootstrapOptions(ctx context.Context) []bootstrap.Option

GetBootstrapOptions returns no bootstrap options for PathVault

func (*PathVault) GetBot

func (p *PathVault) GetBot(ctx context.Context, name string) (*mgmt.Bot, error)

func (*PathVault) GetLockFile

func (p *PathVault) GetLockFile(ctx context.Context, cachedETag string) (content []byte, etag string, notModified bool, err error)

GetLockFile loads the vault's manifest and returns a lock file resolved for the caller's identity. Team/user scopes in the manifest are flattened to repo-scoped entries based on team membership and the caller's email so the install pipeline sees a concrete, identity- specific view. A shared read lock is held for the duration of the read so concurrent mgmt writes can't commit a manifest without its audit trail between the two IO operations.

func (*PathVault) GetMCPTools

func (p *PathVault) GetMCPTools() any

GetMCPTools returns the asset-shim registrar so callers (notably the cloud serve MCP builder) can publish list_my_assets / load_my_asset / … on top of the path-backed vault. Without this, claude.ai connects to the relay and reports "no tools available" because PathVault has no native MCP surface.

func (*PathVault) GetMetadata

func (p *PathVault) GetMetadata(ctx context.Context, name, version string) (*metadata.Metadata, error)

GetMetadata retrieves metadata for a specific asset version

func (*PathVault) GetQuality

func (p *PathVault) GetQuality(ctx context.Context, asset string) (string, error)

GetQuality returns the asset's quality wrapper doc.

func (*PathVault) GetTeam

func (p *PathVault) GetTeam(ctx context.Context, name string) (*mgmt.Team, error)

func (*PathVault) GetUsageStats

func (p *PathVault) GetUsageStats(ctx context.Context, filter mgmt.UsageFilter) (*mgmt.UsageSummary, error)

func (*PathVault) GetVaultIcon

func (p *PathVault) GetVaultIcon(ctx context.Context) ([]byte, error)

GetVaultIcon reads the shared icon, nil when none is set.

func (*PathVault) GetVersionList

func (p *PathVault) GetVersionList(ctx context.Context, name string) ([]string, error)

GetVersionList retrieves available versions for an asset from list.txt Reuses the same pattern as GitRepository

func (*PathVault) ImportAuditEvents

func (p *PathVault) ImportAuditEvents(ctx context.Context, events []mgmt.AuditEvent) error

func (*PathVault) InheritInstallations

func (p *PathVault) InheritInstallations(ctx context.Context, asset *lockfile.Asset) error

InheritInstallations upserts the asset into the manifest, carrying any existing entry's scopes through verbatim. Used when adding a new version of an asset so its install scopes are preserved.

func (*PathVault) LatestBenchmarks

func (p *PathVault) LatestBenchmarks(ctx context.Context) (string, error)

LatestBenchmarks returns the newest record per asset.

func (*PathVault) LatestQuality

func (p *PathVault) LatestQuality(ctx context.Context) (string, error)

LatestQuality returns the newest record per asset.

func (*PathVault) ListAssets

func (p *PathVault) ListAssets(ctx context.Context, opts ListAssetsOptions) (*ListAssetsResult, error)

ListAssets returns a list of all assets in the vault by reading the assets/ directory

func (*PathVault) ListBenchmarks

func (p *PathVault) ListBenchmarks(ctx context.Context, asset string) (string, error)

ListBenchmarks returns the asset's benchmark records.

func (*PathVault) ListBots

func (p *PathVault) ListBots(ctx context.Context) ([]mgmt.Bot, error)

func (*PathVault) ListCollections

func (p *PathVault) ListCollections(ctx context.Context) ([]manifest.Collection, error)

ListCollections returns the vault's collections.

func (*PathVault) ListOrgAdmins

func (p *PathVault) ListOrgAdmins(ctx context.Context) ([]string, error)

func (*PathVault) ListRepoAssets

func (p *PathVault) ListRepoAssets(ctx context.Context) (map[string][]string, error)

ListRepoAssets maps repository URL → asset names scoped to it.

func (*PathVault) ListTeamAssets

func (p *PathVault) ListTeamAssets(ctx context.Context) (map[string][]string, error)

ListTeamAssets maps team name → asset names shared with that team.

func (*PathVault) ListTeams

func (p *PathVault) ListTeams(ctx context.Context, opts ListTeamsOptions) (*ListTeamsResult, error)

func (*PathVault) ListUserAssets

func (p *PathVault) ListUserAssets(ctx context.Context) (map[string][]string, error)

ListUserAssets maps normalized email → asset names installed just for that person.

func (*PathVault) ManifestPath

func (p *PathVault) ManifestPath() string

ManifestPath returns the absolute path to the vault's manifest file.

func (*PathVault) MigrateStorage

func (p *PathVault) MigrateStorage(ctx context.Context) (*MigrationResult, error)

MigrateStorage runs the v1 → v2 storage migration explicitly (`sx vault migrate`). Returns ErrStorageUpToDate when the vault is already current. It takes the write lock directly rather than going through withLock, which would auto-migrate first and make this call always report "already migrated".

func (*PathVault) PlanStorageMigration

func (p *PathVault) PlanStorageMigration(ctx context.Context) (*MigrationPlan, error)

PlanStorageMigration reports what MigrateStorage would do (dry run).

func (*PathVault) PostUsageStats

func (p *PathVault) PostUsageStats(ctx context.Context, jsonlData string) error

PostUsageStats parses the JSONL payload and persists events to .sx/usage/YYYY-MM.jsonl via RecordUsageEvents.

func (*PathVault) QueryAuditEvents

func (p *PathVault) QueryAuditEvents(ctx context.Context, filter mgmt.AuditFilter) ([]mgmt.AuditEvent, error)

func (*PathVault) ReadRootFiles

func (p *PathVault) ReadRootFiles(ctx context.Context, names []string) (map[string][]byte, error)

ReadRootFiles reads files from the vault root (e.g. a marketplace's catalog.json + stats.json; the git vault syncs once for the batch, hence the plural API). Names must be bare filenames — no path separators — so callers can't walk out of the root. Missing files are simply absent from the result, not an error.

func (*PathVault) ReadUsageEvents

func (p *PathVault) ReadUsageEvents(ctx context.Context, filter mgmt.UsageFilter) ([]mgmt.UsageEvent, error)

func (*PathVault) RecordUsageEvents

func (p *PathVault) RecordUsageEvents(ctx context.Context, events []mgmt.UsageEvent) error

func (*PathVault) ReevaluateQuality

func (p *PathVault) ReevaluateQuality(ctx context.Context, asset string) (string, error)

ReevaluateQuality on a path vault is the caller's job: there is no backend that could run the evaluation.

func (*PathVault) RemoveAsset

func (p *PathVault) RemoveAsset(ctx context.Context, assetName, version string, delete bool) error

RemoveAsset removes an asset from the manifest. If delete is true, the asset's files are also removed from the vault's storage directory.

func (*PathVault) RemoveAssetInstallation

func (p *PathVault) RemoveAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*PathVault) RemoveBotTeam

func (p *PathVault) RemoveBotTeam(ctx context.Context, bot, team string) error

func (*PathVault) RemoveCollectionInstallation

func (p *PathVault) RemoveCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

RemoveCollectionInstallation removes an install target from a collection.

func (*PathVault) RemoveOrgAdmin

func (p *PathVault) RemoveOrgAdmin(ctx context.Context, email string) error

func (*PathVault) RemoveTeamMember

func (p *PathVault) RemoveTeamMember(ctx context.Context, team, email string) error

func (*PathVault) RemoveTeamRepository

func (p *PathVault) RemoveTeamRepository(ctx context.Context, team, repoURL string) error

func (*PathVault) RenameAsset

func (p *PathVault) RenameAsset(ctx context.Context, oldName, newName string) error

RenameAsset renames an asset in the vault.

func (*PathVault) RenameCollection

func (p *PathVault) RenameCollection(ctx context.Context, oldName, newName string) error

RenameCollection renames a collection.

func (*PathVault) RenameTeam

func (p *PathVault) RenameTeam(ctx context.Context, oldName, newName string) error

RenameTeam renames a team and every reference to it.

func (*PathVault) RetireAsset

func (p *PathVault) RetireAsset(ctx context.Context, assetName string) error

RetireAsset removes the asset from the manifest and root view, keeping its version archive.

func (*PathVault) SaveCollection

func (p *PathVault) SaveCollection(ctx context.Context, c manifest.Collection) error

SaveCollection creates or replaces a collection.

func (*PathVault) SetAppPluginPolicy

func (p *PathVault) SetAppPluginPolicy(ctx context.Context, policy *manifest.AppPluginPolicy) error

SetAppPluginPolicy replaces the vault's extension policy.

func (*PathVault) SetAssetInstallation

func (p *PathVault) SetAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*PathVault) SetAssetInstallations

func (p *PathVault) SetAssetInstallations(ctx context.Context, assetName string, targets []InstallTarget, appendMode bool) (skipped []SkippedTarget, err error)

SetAssetInstallations applies a batch of install targets (including identity scopes — team/user/bot) in one locked transaction. Satisfies installSetter so the unified scope flow works against path vaults, not just the Sleuth vault.

func (*PathVault) SetCollectionInstallation

func (p *PathVault) SetCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

SetCollectionInstallation adds an install target to a collection.

func (*PathVault) SetInstallations

func (p *PathVault) SetInstallations(ctx context.Context, asset *lockfile.Asset, scopeEntity string) error

SetInstallations upserts an asset into the vault's manifest. The incoming asset's scopes replace the stored set, except for existing scopes the actor isn't allowed to remove (e.g. a team they don't admin), which are carried through — see commonSetInstallations and docs/rbac.md.

func (*PathVault) SetPublishedAssetInstallations

func (p *PathVault) SetPublishedAssetInstallations(ctx context.Context, asset *lockfile.Asset, targets []InstallTarget, appendMode bool) (skipped []SkippedTarget, err error)

SetPublishedAssetInstallations is SetAssetInstallations for a just-published asset version: the manifest row advances to asset's version (existing scopes carried through) in the SAME transaction the targets apply in, so a scoped republish is atomic — the version and scopes change together or not at all. Satisfies publishedInstallSetter.

func (*PathVault) SetTeamAdmin

func (p *PathVault) SetTeamAdmin(ctx context.Context, team, email string, admin bool) error

func (*PathVault) SetVaultIcon

func (p *PathVault) SetVaultIcon(ctx context.Context, data []byte) error

SetVaultIcon stores (or with empty data removes) the shared icon.

func (*PathVault) StorageSourcePath

func (p *PathVault) StorageSourcePath(name, version string) (string, error)

StorageSourcePath returns the vault-relative source path recorded in the manifest for a stored version, per the vault's current storage layout.

func (*PathVault) UninstallAssetTargets

func (p *PathVault) UninstallAssetTargets(ctx context.Context, assetName string, targets []InstallTarget) (removed int, failures []string, err error)

UninstallAssetTargets removes a batch of install targets in one locked transaction. Satisfies targetUninstaller so interactive scope edits can remove individual scopes from a path vault.

func (*PathVault) UpdateBot

func (p *PathVault) UpdateBot(ctx context.Context, bot mgmt.Bot) error

func (*PathVault) UpdateTeam

func (p *PathVault) UpdateTeam(ctx context.Context, team mgmt.Team) error

func (*PathVault) VerifyIntegrity

func (p *PathVault) VerifyIntegrity(data []byte, hashes map[string]string, size int64) error

VerifyIntegrity checks hashes and sizes for downloaded assets Same as GitRepository: no verification needed for local files

type QualityStore

type QualityStore interface {
	// GetQuality returns a wrapper doc for the asset:
	// {"evaluating": bool, "records": [...]} with records newest first.
	// evaluating is only ever true on server-evaluated vaults; records
	// is empty (never null) when the asset has no evaluations.
	GetQuality(ctx context.Context, asset string) (string, error)

	// AddQuality prepends one interchange record (a JSON object string).
	// Server-evaluated vaults refuse this with ErrQualityReadOnly — the
	// server's own evaluation is the source of truth there.
	AddQuality(ctx context.Context, asset, record string) error

	// LatestQuality returns a JSON object mapping asset name to its
	// newest record, for every asset that has one.
	LatestQuality(ctx context.Context) (string, error)

	// ReevaluateQuality requests a fresh evaluation and reports who runs
	// it: "server" when the vault backend evaluates (poll GetQuality
	// until evaluating flips false), "local" when the caller must run
	// the evaluation itself and store the result via AddQuality.
	ReevaluateQuality(ctx context.Context, asset string) (string, error)
}

QualityStore is implemented by vaults that can hold quality records.

type QueryInput

type QueryInput struct {
	Query       string `` /* 235-byte string literal not displayed */
	Integration string `json:"integration" jsonschema:"which integration to query (github, circleci, linear, or datadog)"`
}

QueryInput is the input type for query tool

type RepoAssetLister

type RepoAssetLister interface {
	ListRepoAssets(ctx context.Context) (map[string][]string, error)
}

RepoAssetLister reports which assets are scoped to each repository — the repository-centric inverse of per-asset install targets. Used by the desktop app's repository views (per-library opt-in).

type Role

type Role struct {
	Title       string `json:"title"`
	Slug        string `json:"slug"`
	Description string `json:"description"`
}

Role represents a skill profile (role) from the server

type RoleListResponse

type RoleListResponse struct {
	Roles  []Role  `json:"profiles"`
	Active *string `json:"active"`
}

RoleListResponse represents the response from the roles list endpoint

type ScopeOption

type ScopeOption struct {
	Label       string // Display text (e.g., "Just for me")
	Value       string // Machine value passed to SetInstallations
	Description string // Help text
}

ScopeOption represents a vault-specific scope option (e.g., "personal", "team") displayed in the interactive UI alongside the built-in global/repo options.

type ScopeOptionProvider

type ScopeOptionProvider interface {
	GetScopeOptions() []ScopeOption
}

ScopeOptionProvider is implemented by vaults that provide additional scope options beyond global and per-repository scoping.

type SkippedTarget

type SkippedTarget struct {
	Target InstallTarget
	Reason string
}

SkippedTarget is an install target that SetAssetInstallations could not apply, paired with a human-readable reason — e.g. a team that doesn't exist in the vault, or one the caller is not an admin of (a permissions problem). Callers surface the reason so a skip isn't mistaken for "team not found".

type SleuthVault

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

SleuthVault implements Vault for Sleuth HTTP servers

func NewSleuthVault

func NewSleuthVault(serverURL, authToken string) *SleuthVault

NewSleuthVault creates a new Sleuth repository. If SX_BOT_KEY is set in the environment, it overrides authToken — the bot's API key becomes the bearer for every request, so the same Sleuth vault wired to a CI runner authenticates as the bot rather than the user who ran `sx cloud connect` on a different machine. The user-token path stays untouched when SX_BOT_KEY is empty so interactive use is unchanged.

func (*SleuthVault) AddAsset

func (s *SleuthVault) AddAsset(ctx context.Context, asset *lockfile.Asset, zipData []byte) error

AddAsset uploads an asset to the Sleuth server.

func (*SleuthVault) AddAssetWithResult

func (s *SleuthVault) AddAssetWithResult(ctx context.Context, asset *lockfile.Asset, zipData []byte) (AddAssetResult, error)

AddAssetWithResult uploads an asset to the Sleuth server and returns the persisted asset identifiers from the server response.

func (*SleuthVault) AddBenchmark

func (s *SleuthVault) AddBenchmark(ctx context.Context, asset, record string) error

AddBenchmark records one client-run benchmark result on the server.

func (*SleuthVault) AddBotTeam

func (s *SleuthVault) AddBotTeam(ctx context.Context, botName, teamName string) error

AddBotTeam appends a team to a bot's team set via UpdateBot. Sleuth's updateBot expects the full team list, so we read-modify-write — same limitation as AddTeamMember.

func (*SleuthVault) AddQuality

func (s *SleuthVault) AddQuality(ctx context.Context, asset, record string) error

AddQuality is refused: skills.new evaluates assets itself and its document is the source of truth. Use ReevaluateQuality.

func (*SleuthVault) AddTeamMember

func (s *SleuthVault) AddTeamMember(ctx context.Context, team, email string, admin bool) error

AddTeamMember adds a user to a team via the UpdateTeam mutation. Known limitation: this is a read-modify-write against the server's member list, so two concurrent AddTeamMember calls against the same team can interleave their reads and lose one of the additions. The GraphQL schema does not currently expose an additive "append member" mutation; when that becomes available we should switch to it. Sequential usage (the typical interactive CLI case) is safe.

func (*SleuthVault) AddTeamRepository

func (s *SleuthVault) AddTeamRepository(ctx context.Context, team, repoURL string) error

func (*SleuthVault) AppPluginPolicy

func (s *SleuthVault) AppPluginPolicy(ctx context.Context) (*manifest.AppPluginPolicy, error)

AppPluginPolicy returns the org's extension policy (nil = open).

func (*SleuthVault) AppPluginSharedLoad

func (s *SleuthVault) AppPluginSharedLoad(ctx context.Context, pluginID string) (string, error)

AppPluginSharedLoad reads the extension's shared document ("" when none is stored) — the server twin of .sx/app-plugins/<id>.json.

func (*SleuthVault) AppPluginSharedSave

func (s *SleuthVault) AppPluginSharedSave(ctx context.Context, pluginID, data string) error

AppPluginSharedSave replaces the extension's shared document; empty data deletes it. The server enforces the size cap and id validation.

func (*SleuthVault) AssetInstallScopes

func (s *SleuthVault) AssetInstallScopes(ctx context.Context, name string) ([]manifest.Scope, bool, error)

AssetInstallScopes reads an asset's installation targets from the server and maps them to manifest scopes, so the copy engine can replay scopes when the SOURCE is a skills.new vault (the file-backed vaults read them from sx.toml). An org-wide install is reported as present with no scopes, matching the file-backed convention.

func (*SleuthVault) Authenticate

func (s *SleuthVault) Authenticate(ctx context.Context) (string, error)

Authenticate performs authentication with the Sleuth server

func (*SleuthVault) ClearAssetInstallations

func (s *SleuthVault) ClearAssetInstallations(ctx context.Context, assetName string) error

func (*SleuthVault) CreateAgentAsset

func (s *SleuthVault) CreateAgentAsset(ctx context.Context, name, description, rawContent, botName string) (AddAssetResult, error)

func (*SleuthVault) CreateBot

func (s *SleuthVault) CreateBot(ctx context.Context, bot mgmt.Bot) (string, error)

func (*SleuthVault) CreateBotApiKey

func (s *SleuthVault) CreateBotApiKey(ctx context.Context, botName, label string) (string, mgmt.BotApiKey, error)

func (*SleuthVault) CreateBotRuntimeToken

func (s *SleuthVault) CreateBotRuntimeToken(ctx context.Context, botName, label string, ttlSeconds int) (string, time.Time, error)

func (*SleuthVault) CreateTeam

func (s *SleuthVault) CreateTeam(ctx context.Context, team mgmt.Team) error

func (*SleuthVault) CurrentActor

func (s *SleuthVault) CurrentActor(ctx context.Context) (mgmt.Actor, error)

func (*SleuthVault) CurrentCollectionInstallTargets

func (s *SleuthVault) CurrentCollectionInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentCollectionInstallTargets reads the collection's own installation rows. Unlike assets — where org-wide collapses to an empty target list — an org row is reported as an explicit org target, matching the collection semantics (no rows = grants nothing).

func (*SleuthVault) CurrentInstallTargets

func (s *SleuthVault) CurrentInstallTargets(ctx context.Context, name string) ([]InstallTarget, bool, error)

CurrentInstallTargets reads an asset's current installations from the server as kind-aware targets, each carrying the server entity GID (EntityID, plus MonoRepoConfigID for path installs) so a later removal can target the exact installation via uninstallAssetTargets without re-resolving by name/email. User targets use the email (entityRef) when available. The bool reports whether the asset is installed at all; a present install with no targets is org-wide.

func (*SleuthVault) DeleteBot

func (s *SleuthVault) DeleteBot(ctx context.Context, name string) error

func (*SleuthVault) DeleteBotApiKey

func (s *SleuthVault) DeleteBotApiKey(ctx context.Context, botName, keyID string) error

func (*SleuthVault) DeleteCollection

func (s *SleuthVault) DeleteCollection(ctx context.Context, name string) error

DeleteCollection removes a collection. Member assets are untouched.

func (*SleuthVault) DeleteTeam

func (s *SleuthVault) DeleteTeam(ctx context.Context, name string) error

func (*SleuthVault) GetAsset

func (s *SleuthVault) GetAsset(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

GetAsset downloads an asset using its source configuration

func (*SleuthVault) GetAssetByVersion

func (s *SleuthVault) GetAssetByVersion(ctx context.Context, name, ver string) ([]byte, error)

GetAssetByVersion downloads an asset by name and version

func (*SleuthVault) GetAssetDetails

func (s *SleuthVault) GetAssetDetails(ctx context.Context, name string) (*AssetDetails, error)

GetAssetDetails retrieves detailed information about a specific asset using GraphQL

func (*SleuthVault) GetBootstrapOptions

func (s *SleuthVault) GetBootstrapOptions(ctx context.Context) []bootstrap.Option

GetBootstrapOptions returns bootstrap options for the Sleuth vault. This includes the Sleuth AI Query MCP server.

func (*SleuthVault) GetBot

func (s *SleuthVault) GetBot(ctx context.Context, name string) (*mgmt.Bot, error)

func (*SleuthVault) GetLockFile

func (s *SleuthVault) GetLockFile(ctx context.Context, cachedETag string) (content []byte, etag string, notModified bool, err error)

GetLockFile retrieves the lock file from the Sleuth server

func (*SleuthVault) GetMCPTools

func (s *SleuthVault) GetMCPTools() any

GetMCPTools returns the query tool for Sleuth vault

func (*SleuthVault) GetMetadata

func (s *SleuthVault) GetMetadata(ctx context.Context, name, version string) (*metadata.Metadata, error)

GetMetadata retrieves metadata for a specific asset version

func (*SleuthVault) GetQuality

func (s *SleuthVault) GetQuality(ctx context.Context, asset string) (string, error)

GetQuality returns the asset's quality wrapper doc, normalized from the server's evaluation document. Assets the server hasn't evaluated (and git-sourced assets, which skills.new doesn't evaluate) yield an empty records list.

func (*SleuthVault) GetScopeOptions

func (s *SleuthVault) GetScopeOptions() []ScopeOption

GetScopeOptions returns additional scope options for the Sleuth vault

func (*SleuthVault) GetTeam

func (s *SleuthVault) GetTeam(ctx context.Context, name string) (*mgmt.Team, error)

func (*SleuthVault) GetUsageStats

func (s *SleuthVault) GetUsageStats(ctx context.Context, filter mgmt.UsageFilter) (*mgmt.UsageSummary, error)

func (*SleuthVault) GetVersionList

func (s *SleuthVault) GetVersionList(ctx context.Context, name string) ([]string, error)

GetVersionList retrieves available versions for an asset

func (*SleuthVault) ImportAuditEvents

func (s *SleuthVault) ImportAuditEvents(ctx context.Context, events []mgmt.AuditEvent) error

func (*SleuthVault) InheritInstallations

func (s *SleuthVault) InheritInstallations(ctx context.Context, asset *lockfile.Asset) error

InheritInstallations is a no-op for Sleuth vaults. The server auto-inherits installations when AddAsset uploads a new version.

func (*SleuthVault) LatestBenchmarks

func (s *SleuthVault) LatestBenchmarks(ctx context.Context) (string, error)

LatestBenchmarks returns the newest record per asset in one call.

func (*SleuthVault) LatestQuality

func (s *SleuthVault) LatestQuality(ctx context.Context) (string, error)

LatestQuality returns the newest record per asset, paging the vault's asset list.

func (*SleuthVault) ListAssets

func (s *SleuthVault) ListAssets(ctx context.Context, opts ListAssetsOptions) (*ListAssetsResult, error)

ListAssets retrieves a list of all assets in the vault using GraphQL

func (*SleuthVault) ListBenchmarks

func (s *SleuthVault) ListBenchmarks(ctx context.Context, asset string) (string, error)

ListBenchmarks returns the asset's benchmark records, newest first.

func (*SleuthVault) ListBotApiKeys

func (s *SleuthVault) ListBotApiKeys(ctx context.Context, botName string) ([]mgmt.BotApiKey, error)

func (*SleuthVault) ListBots

func (s *SleuthVault) ListBots(ctx context.Context) ([]mgmt.Bot, error)

func (*SleuthVault) ListCollections

func (s *SleuthVault) ListCollections(ctx context.Context) ([]manifest.Collection, error)

ListCollections returns the vault's collections with memberships.

func (*SleuthVault) ListRepoAssets

func (s *SleuthVault) ListRepoAssets(ctx context.Context) (map[string][]string, error)

ListRepoAssets maps repository → asset names scoped to it, read in one paged query over the vault's assets and their installations.

func (*SleuthVault) ListRoles

func (s *SleuthVault) ListRoles(ctx context.Context) (*RoleListResponse, error)

ListRoles retrieves the list of available roles from the server

func (*SleuthVault) ListTeamAssets

func (s *SleuthVault) ListTeamAssets(ctx context.Context) (map[string][]string, error)

ListTeamAssets maps team name → asset names shared with that team, read in one paged query over the vault's assets and their installations.

func (*SleuthVault) ListTeams

func (s *SleuthVault) ListTeams(ctx context.Context, opts ListTeamsOptions) (*ListTeamsResult, error)

func (*SleuthVault) ListUserAssets

func (s *SleuthVault) ListUserAssets(ctx context.Context) (map[string][]string, error)

ListUserAssets maps normalized email → asset names installed just for that person, read from the same paged installations query ListTeamAssets uses. For USER installations the email is entityRef — entityName is the person's display name (see schema.graphql: "Canonical reference used to install this entity … the email for USER installations"); entityName is only a fallback for servers that predate the ref field.

func (*SleuthVault) OpenAssetPullRequest

func (s *SleuthVault) OpenAssetPullRequest(ctx context.Context, assetGID, title, body string, zipData []byte) (PRResult, error)

OpenAssetPullRequest proposes the uploaded asset as a pull request against an existing skill, used when a direct publish was blocked by the server's edit gate (see docs/rbac.md). It creates the PR for assetGID, then adds one file change per file in the zip. The asset isn't published until a maintainer merges the PR. Returns the PR's source URL.

assetGID comes straight from the upload's 403 response (AssetEditPermissionError. AssetGID), so no asset lookup is needed here.

func (*SleuthVault) OrgInfo

func (s *SleuthVault) OrgInfo(ctx context.Context) (name, iconURL string, err error)

OrgInfo reports the organization behind a sleuth vault: its display name and icon URL ("" when the org has none). Used by the desktop app to show the org's icon for skills.new libraries.

func (*SleuthVault) PostUsageStats

func (s *SleuthVault) PostUsageStats(ctx context.Context, jsonlData string) error

PostUsageStats sends asset usage statistics to the Sleuth server

func (*SleuthVault) QueryAuditEvents

func (s *SleuthVault) QueryAuditEvents(ctx context.Context, filter mgmt.AuditFilter) ([]mgmt.AuditEvent, error)

func (*SleuthVault) QueryIntegrationStream

func (s *SleuthVault) QueryIntegrationStream(
	ctx context.Context,
	query, integration string,
	gitContext any,
	onEvent func(eventType, content string),
) (string, error)

QueryIntegrationStream queries integrated services using SSE streaming. The onEvent callback is called for each event received, which can be used to send MCP log notifications to keep the connection alive.

func (*SleuthVault) ReadUsageEvents

func (s *SleuthVault) ReadUsageEvents(ctx context.Context, filter mgmt.UsageFilter) ([]mgmt.UsageEvent, error)

func (*SleuthVault) RecordUsageEvents

func (s *SleuthVault) RecordUsageEvents(ctx context.Context, events []mgmt.UsageEvent) error

func (*SleuthVault) ReevaluateQuality

func (s *SleuthVault) ReevaluateQuality(ctx context.Context, asset string) (string, error)

ReevaluateQuality asks the server to evaluate the asset and reports "server": the caller polls GetQuality until evaluating flips false.

func (*SleuthVault) RemoveAsset

func (s *SleuthVault) RemoveAsset(ctx context.Context, assetName, version string, delete bool) error

RemoveAsset removes an asset from the Sleuth server's lock file. The delete flag is passed to the server mutation for permanent deletion.

func (*SleuthVault) RemoveAssetInstallation

func (s *SleuthVault) RemoveAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*SleuthVault) RemoveBotTeam

func (s *SleuthVault) RemoveBotTeam(ctx context.Context, botName, teamName string) error

func (*SleuthVault) RemoveCollectionInstallation

func (s *SleuthVault) RemoveCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

RemoveCollectionInstallation removes the collection's installation row for one target via the uninstallCollection mutation.

func (*SleuthVault) RemoveTeamMember

func (s *SleuthVault) RemoveTeamMember(ctx context.Context, team, email string) error

func (*SleuthVault) RemoveTeamRepository

func (s *SleuthVault) RemoveTeamRepository(ctx context.Context, team, repoURL string) error

func (*SleuthVault) RenameAsset

func (s *SleuthVault) RenameAsset(ctx context.Context, oldName, newName string) error

RenameAsset renames an asset on the Sleuth server using a GraphQL mutation.

func (*SleuthVault) RenameCollection

func (s *SleuthVault) RenameCollection(ctx context.Context, oldName, newName string) error

RenameCollection renames a collection on the server; membership follows the GID.

func (*SleuthVault) RenameTeam

func (s *SleuthVault) RenameTeam(ctx context.Context, oldName, newName string) error

RenameTeam renames a team on the server; installations follow the GID.

func (*SleuthVault) RevokeBotRuntimeTokens

func (s *SleuthVault) RevokeBotRuntimeTokens(ctx context.Context, botName string) (int, error)

func (*SleuthVault) SaveCollection

func (s *SleuthVault) SaveCollection(ctx context.Context, c manifest.Collection) error

SaveCollection creates or replaces a collection: the server copy ends up with exactly the given description and membership.

func (*SleuthVault) SetActiveRole

func (s *SleuthVault) SetActiveRole(ctx context.Context, slug *string) (*Role, error)

SetActiveRole sets or clears the active role on the server. Pass nil to clear the active role.

func (*SleuthVault) SetAppPluginPolicy

func (s *SleuthVault) SetAppPluginPolicy(ctx context.Context, policy *manifest.AppPluginPolicy) error

SetAppPluginPolicy replaces the org's extension policy. A nil policy clears back to open. The server enforces org-admin RBAC and audits.

func (*SleuthVault) SetAssetInstallation

func (s *SleuthVault) SetAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

func (*SleuthVault) SetAssetInstallations

func (s *SleuthVault) SetAssetInstallations(ctx context.Context, assetName string, targets []InstallTarget, appendMode bool) (skipped []SkippedTarget, err error)

SetAssetInstallations replaces an asset's entire installation set in a single server call. The skills.new mutation replaces (rather than appends), so setting targets one at a time would let each call clobber the previous one for a multi-scope asset; sending every target at once makes them all stick.

It is best-effort on a per-target basis: team/user/bot targets whose entity can't be resolved in the destination org are skipped and returned in unresolved (rather than failing the whole call), so the resolvable targets still land in one atomic call — no clobbering. A returned error means the single GraphQL call itself failed (e.g. a repository URL the server rejects), in which case nothing was applied. Org-wide is exclusive — if any target is org, the asset goes global.

func (*SleuthVault) SetCollectionInstallation

func (s *SleuthVault) SetCollectionInstallation(ctx context.Context, name string, target InstallTarget) error

SetCollectionInstallation installs the collection to one target via the installCollection mutation.

func (*SleuthVault) SetInstallations

func (s *SleuthVault) SetInstallations(ctx context.Context, asset *lockfile.Asset, scopeEntity string) error

SetInstallations sets the installation scopes for an asset using GraphQL mutation

func (*SleuthVault) SetTeamAdmin

func (s *SleuthVault) SetTeamAdmin(ctx context.Context, team, email string, admin bool) error

func (*SleuthVault) SupportsAppPlugins

func (s *SleuthVault) SupportsAppPlugins(ctx context.Context) (supported, definitive bool)

SupportsAppPlugins probes whether the connected server knows the app-plugin surface at all — deployed servers predating it reject both the asset type and the policy query. The policy read doubles as the capability check. definitive is false for transient failures, so callers don't durably cache an answer the server never gave.

func (*SleuthVault) UninstallAssetTargets

func (s *SleuthVault) UninstallAssetTargets(ctx context.Context, assetName string, targets []InstallTarget) (removed int, failures []string, err error)

UninstallAssetTargets removes specific installations from an asset via the bulk uninstallAssetTargets mutation. The asset is identified by slug (assetName) — the server resolves it, so there's no client-side GID lookup — and each target carries the server EntityID (GID) captured from CurrentInstallTargets, so removal is by GID with no name/email re-resolution. It is best-effort: the returned failures describe targets the server could not remove (no permission, not installed), while removed reports how many installations were actually removed. A returned error means the GraphQL call itself failed and nothing was applied.

func (*SleuthVault) UpdateBot

func (s *SleuthVault) UpdateBot(ctx context.Context, bot mgmt.Bot) error

func (*SleuthVault) UpdateTeam

func (s *SleuthVault) UpdateTeam(ctx context.Context, team mgmt.Team) error

func (*SleuthVault) VerifyIntegrity

func (s *SleuthVault) VerifyIntegrity(data []byte, hashes map[string]string, size int64) error

VerifyIntegrity checks hashes and sizes for downloaded assets

type SourceHandler

type SourceHandler interface {
	// Fetch retrieves asset data from the source
	Fetch(ctx context.Context, asset *lockfile.Asset) ([]byte, error)
}

SourceHandler handles fetching assets from specific source types This is used internally by Vault implementations to handle different source types

type TeamAssetLister

type TeamAssetLister interface {
	ListTeamAssets(ctx context.Context) (map[string][]string, error)
}

TeamAssetLister reports which assets are shared with each team — the team-centric inverse of per-asset install targets. Used by the desktop app's team views.

type TeamRenamer

type TeamRenamer interface {
	RenameTeam(ctx context.Context, oldName, newName string) error
}

TeamRenamer is implemented by vaults whose teams can be renamed.

type ToolDef

type ToolDef struct {
	Tool    *mcp.Tool
	Handler func(context.Context, *mcp.CallToolRequest, QueryInput) (*mcp.CallToolResult, any, error)
}

ToolDef represents an MCP tool with its handler

type UserAssetLister

type UserAssetLister interface {
	ListUserAssets(ctx context.Context) (map[string][]string, error)
}

UserAssetLister reports which assets carry personal (user) scopes — the person-centric inverse of per-asset install targets, keyed by normalized email. Used by the desktop app's "My skills" view.

type Vault

type Vault interface {
	// Authenticate performs authentication with the repository
	// Returns an auth token or empty string if no auth needed
	Authenticate(ctx context.Context) (string, error)

	// GetLockFile retrieves the lock file from the repository
	// Returns lock file content and ETag for caching
	// If cachedETag matches, returns notModified=true with empty content
	GetLockFile(ctx context.Context, cachedETag string) (content []byte, etag string, notModified bool, err error)

	// GetAsset downloads an asset using its source configuration from the lock file
	// The asset parameter contains the source configuration (source-http, source-git, source-path)
	GetAsset(ctx context.Context, asset *lockfile.Asset) ([]byte, error)

	// AddAsset uploads an asset to the repository
	AddAsset(ctx context.Context, asset *lockfile.Asset, zipData []byte) error

	// SetInstallations configures where an asset should be installed
	// Updates the lock file with the installation scopes
	// scopeEntity is a vault-specific value from ScopeOptionProvider (e.g., "personal").
	// Empty string means standard global/repo scoping via asset.Scopes.
	SetInstallations(ctx context.Context, asset *lockfile.Asset, scopeEntity string) error

	// InheritInstallations preserves existing installation scopes for an asset.
	// Called when no scope flags are provided (e.g., `sx add ./skill --yes`).
	// For server-managed vaults (Sleuth), this is a no-op since the server
	// auto-inherits installations when a new version is uploaded.
	// For file-based vaults (Path, Git), this copies scopes from any existing
	// version of the asset in the lock file.
	InheritInstallations(ctx context.Context, asset *lockfile.Asset) error

	// GetVersionList retrieves available versions for an asset (for resolution)
	// Only applicable to repositories with version management (Sleuth, not Git)
	GetVersionList(ctx context.Context, name string) ([]string, error)

	// GetMetadata retrieves metadata for a specific asset version
	GetMetadata(ctx context.Context, name, version string) (*metadata.Metadata, error)

	// GetAssetByVersion downloads an asset by name and version
	// Used for comparing content when adding assets
	GetAssetByVersion(ctx context.Context, name, version string) ([]byte, error)

	// VerifyIntegrity checks hashes and sizes for downloaded assets
	VerifyIntegrity(data []byte, hashes map[string]string, size int64) error

	// PostUsageStats sends asset usage statistics to the repository
	// jsonlData is newline-separated JSON (JSONL format)
	PostUsageStats(ctx context.Context, jsonlData string) error

	// RemoveAsset removes an asset from the lock file.
	// If delete is true, also permanently removes the asset files from the vault.
	// If version is empty, removes all versions of the asset.
	RemoveAsset(ctx context.Context, assetName, version string, delete bool) error

	// RenameAsset renames an asset in the vault.
	// All versions and installations are preserved under the new name.
	RenameAsset(ctx context.Context, oldName, newName string) error

	// ListAssets returns a list of all assets in the vault
	// This enables asset discovery via `sx vault list`
	ListAssets(ctx context.Context, opts ListAssetsOptions) (*ListAssetsResult, error)

	// GetAssetDetails returns detailed information about a specific asset
	// This enables asset inspection via `sx vault show <name>`
	GetAssetDetails(ctx context.Context, name string) (*AssetDetails, error)

	// GetMCPTools returns additional MCP tools provided by this vault
	// Returns nil if the vault doesn't provide any MCP tools
	GetMCPTools() any

	// GetBootstrapOptions returns bootstrap options provided by this vault
	// These are options for MCP servers or other infrastructure the vault provides
	GetBootstrapOptions(ctx context.Context) []bootstrap.Option

	// CurrentActor returns the identity of the caller as resolved by this
	// vault. For git/path vaults this comes from `git config user.email`;
	// for sleuth vaults it comes from the authenticated user token.
	CurrentActor(ctx context.Context) (mgmt.Actor, error)

	// Team management
	ListTeams(ctx context.Context, opts ListTeamsOptions) (*ListTeamsResult, error)
	GetTeam(ctx context.Context, name string) (*mgmt.Team, error)
	CreateTeam(ctx context.Context, team mgmt.Team) error
	UpdateTeam(ctx context.Context, team mgmt.Team) error
	DeleteTeam(ctx context.Context, name string) error
	AddTeamMember(ctx context.Context, team, email string, admin bool) error
	RemoveTeamMember(ctx context.Context, team, email string) error
	SetTeamAdmin(ctx context.Context, team, email string, admin bool) error
	AddTeamRepository(ctx context.Context, team, repoURL string) error
	RemoveTeamRepository(ctx context.Context, team, repoURL string) error

	// Bot management. Bots are non-human service identities. They gain
	// repo context through teams (the same way human team members do)
	// and can also be a direct install target via InstallKindBot.
	ListBots(ctx context.Context) ([]mgmt.Bot, error)
	GetBot(ctx context.Context, name string) (*mgmt.Bot, error)
	// CreateBot creates a new bot. The returned rawToken is non-empty
	// only on Sleuth vaults, which auto-issue a default API key as part
	// of bot creation; file-based vaults treat bots as identity-only and
	// always return "". Callers print the token (shown once) when
	// non-empty so the auto-issued key is not silently wasted.
	CreateBot(ctx context.Context, bot mgmt.Bot) (rawToken string, err error)
	UpdateBot(ctx context.Context, bot mgmt.Bot) error
	DeleteBot(ctx context.Context, name string) error
	AddBotTeam(ctx context.Context, bot, team string) error
	RemoveBotTeam(ctx context.Context, bot, team string) error

	// SetAssetInstallation records a new installation target for an
	// asset. File-backed vaults append the target to the asset's scope
	// list in sx.toml; Sleuth vaults delegate to the server.
	SetAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

	// RemoveAssetInstallation removes one installation target from an
	// asset. The bot (or team) named by target must exist on every
	// backend; if it does not, the call returns an error. Beyond that,
	// file-backed vaults (Git, Path) soft no-op when no install row
	// references the target. The Sleuth backend additionally errors when
	// the asset name doesn't resolve, rather than no-opping, and today
	// only supports InstallKindBot targets — every other kind returns
	// ErrNotImplemented (file-backed vaults support all kinds). Removing an
	// InstallKindOrg target is not supported on any backend (an org-wide
	// install has no scope row to remove) and returns ErrNotImplemented —
	// remove the asset from the vault to stop distributing a global
	// install (ClearAssetInstallations no-ops on an empty scope list). For bot and
	// team targets the bot-exists / team-admin precondition is checked
	// unconditionally, before the scope walk — so even a no-op removal of
	// an already-absent row requires the caller to still hold those rights.
	RemoveAssetInstallation(ctx context.Context, assetName string, target InstallTarget) error

	// ClearAssetInstallations removes every installation target from an
	// asset. Soft no-op if the asset is absent from the vault. Unlike
	// RemoveAssetInstallation — which drops the manifest entry when it
	// removes the asset's last scope — Clear keeps the (now scope-less)
	// entry in place, so a later install adds a scope to the existing
	// entry rather than recreating it.
	ClearAssetInstallations(ctx context.Context, assetName string) error

	// RecordUsageEvents appends usage events to the vault's persistent
	// usage log. Replaces the string-based PostUsageStats for new code.
	RecordUsageEvents(ctx context.Context, events []mgmt.UsageEvent) error

	// GetUsageStats returns an aggregated usage summary across the vault.
	GetUsageStats(ctx context.Context, filter mgmt.UsageFilter) (*mgmt.UsageSummary, error)

	// ReadUsageEvents returns the raw usage events matching the filter (not
	// aggregated). Used to copy usage history between vaults losslessly.
	ReadUsageEvents(ctx context.Context, filter mgmt.UsageFilter) ([]mgmt.UsageEvent, error)

	// QueryAuditEvents returns audit events matching the filter.
	QueryAuditEvents(ctx context.Context, filter mgmt.AuditFilter) ([]mgmt.AuditEvent, error)

	// ImportAuditEvents appends pre-existing audit events to the vault's audit
	// trail verbatim, preserving each event's timestamp, actor, event name, and
	// target. Used to copy audit history between vaults losslessly. File-backed
	// vaults write the JSONL directly; the Sleuth vault delegates to the
	// importAuditEvents mutation (which resolves actors by email and falls back
	// to the caller for unknown ones).
	ImportAuditEvents(ctx context.Context, events []mgmt.AuditEvent) error
}

Vault represents a source of assets with read and write capabilities This interface unifies the concepts of "vault" and "source fetcher"

func NewFromConfig

func NewFromConfig(cfg Config) (Vault, error)

NewFromConfig creates a vault instance from configuration This factory function eliminates repetitive switch statements across commands

type VaultIconStore

type VaultIconStore interface {
	GetVaultIcon(ctx context.Context) ([]byte, error)
	// SetVaultIcon stores the icon; empty data removes it.
	SetVaultIcon(ctx context.Context, data []byte) error
}

VaultIconStore is implemented by file-backed vaults (git, path) whose icon is stored in the vault itself.

Directories

Path Synopsis
Package layout is the single source of truth for where asset files live inside a file-based vault (git or path), across storage format versions.
Package layout is the single source of truth for where asset files live inside a file-based vault (git or path), across storage format versions.

Jump to

Keyboard shortcuts

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