Documentation
¶
Overview ¶
Package setup provides initialisation helpers for GTB-based tools, including configuration directory bootstrapping, default config file creation, and self-update orchestration.
The Initialiser interface supports a modular hook-based pattern for extending the init process — SSH key setup, authentication configuration, and custom post-init steps can be composed and ordered. Update checks use semantic version comparison against the configured release source (GitHub or GitLab).
Package setup provides self-update and bootstrap functionality for GTB-based tools. This file registers the release providers via blank imports so they are available whenever pkg/setup is imported.
Each provider now ships as its own module, so a tool that needs only one forge can drop the others: replace this file's effect by importing just the providers you want before calling into setup. The full set is imported here because the framework cannot know which forge a downstream tool targets.
`direct` is not a forge — it is a plain download source — and ships inside the forge module itself rather than separately.
Index ¶
- Constants
- Variables
- func AssetDocument(p *props.Props, path string) []byte
- func AssetSource(p *props.Props, path string) *config.NamedSource
- func Chain(feature props.FeatureCmd, runE func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error
- func EnsureDefaultConfigDir(fs afero.Fs, name string) (string, error)
- func ExclusiveChanges(winning map[string]any, all []string) []config.Change
- func FeatureOf(cmd *cobra.Command) props.FeatureCmd
- func GetAssets() map[props.FeatureCmd][]AssetBundle
- func GetCheckedVersion(fs afero.Fs, name string) string
- func GetChecks() map[props.FeatureCmd][]CheckProvider
- func GetDefaultConfigDir(_ afero.Fs, name string) string
- func GetFeatureFlags() map[props.FeatureCmd][]FeatureFlag
- func GetInitialisers() map[props.FeatureCmd][]InitialiserProvider
- func GetSubcommands() map[props.FeatureCmd][]SubcommandProvider
- func GetTimeSinceLast(fs afero.Fs, name string, status timeSinceKey) time.Duration
- func Initialise(ctx context.Context, p *props.Props, opts InitOptions) (string, error)
- func IsExposedToMCP(cmd *cobra.Command) bool
- func IsSealed() bool
- func MarkSkipUpdateCheck(cmd *cobra.Command) *cobra.Command
- func Register(feature props.FeatureCmd, ips []InitialiserProvider, sps []SubcommandProvider, ...)
- func RegisterAssets(feature props.FeatureCmd, name string, bundle fs.FS)
- func RegisterChecks(feature props.FeatureCmd, cps []CheckProvider)
- func RegisterGlobalMiddleware(mw ...Middleware)
- func RegisterMiddleware(feature props.FeatureCmd, mw ...Middleware)
- func ResetRegistryForTesting()
- func ResolveCheckInterval(toolDefault time.Duration, configValue string) time.Duration
- func Seal()
- func SealRegistry()
- func SetCheckedVersion(fs afero.Fs, name, version string) error
- func SetTimeSinceLast(fs afero.Fs, name string, status timeSinceKey) error
- func SkipConfigCheck(cmd *cobra.Command) *cobra.Command
- func SkipUpdateCheck(fs afero.Fs, name string, cmd *cobra.Command, checkInterval time.Duration) bool
- func SkipsConfigCheck(cmd *cobra.Command) bool
- func SkipsUpdateCheck(cmd *cobra.Command) bool
- func VerifyChecksum(fs afero.Fs, sidecarPath string, data []byte) error
- func VerifyChecksumFromManifest(manifest []byte, filename string, data []byte) error
- func VerifyChecksumFromManifestReader(manifest []byte, filename string, dataReader io.Reader, dst io.Writer, ...) (int64, error)
- func WriteExclusive(e Editor, winning map[string]any, all []string) error
- type AssetBundle
- type CheckFunc
- type CheckProvider
- type CheckResult
- type Command
- type Editor
- type FeatureFlag
- type FeatureRegistry
- type InitOptions
- type Initialiser
- type InitialiserProvider
- type MCPExposure
- type Middleware
- type SelfUpdater
- func (s *SelfUpdater) DownloadAsset(ctx context.Context, asset forge.ReleaseAsset) (bytes.Buffer, error)
- func (s *SelfUpdater) GetCurrentVersion() string
- func (s *SelfUpdater) GetLatestRelease(ctx context.Context) (forge.Release, error)
- func (s *SelfUpdater) GetLatestVersionString(ctx context.Context) (string, error)
- func (s *SelfUpdater) GetReleaseNotes(ctx context.Context, from string, to string) (string, error)
- func (s *SelfUpdater) GetStructuredReleaseNotes(ctx context.Context, from, to string, archive ...bytes.Buffer) (*changelog.Changelog, error)
- func (s *SelfUpdater) IsLatestVersion(ctx context.Context) (bool, string, error)
- func (s *SelfUpdater) SignatureAssetName() string
- func (s *SelfUpdater) Update(ctx context.Context) (string, error)
- func (s *SelfUpdater) UpdateFromFile(filePath string) (string, error)
- type SubcommandProvider
- type UpdaterOption
- func WithEmbeddedKeys(armoredKeys ...[]byte) UpdaterOption
- func WithExecLookPath(fn func(string) (string, error)) UpdaterOption
- func WithKeyResolver(r verify.KeyResolver) UpdaterOption
- func WithMaxBinaryDownloadSize(maxBytes int64) UpdaterOption
- func WithMaxChecksumsSize(maxBytes int64) UpdaterOption
- func WithOsExecutable(fn func() (string, error)) UpdaterOption
- func WithReleaseProvider(p forge.Provider) UpdaterOption
- func WithRequireChecksum(require bool) UpdaterOption
Constants ¶
const ( // DefaultMaxChecksumsSize caps a downloaded checksums manifest. A // GoReleaser manifest for a typical multi-OS release is ~1 KiB, so 1 MiB // is roughly 1000x headroom. DefaultMaxChecksumsSize int64 = 1 << 20 // DefaultMaxBinaryDownloadSize caps a downloaded binary asset. 512 MiB is // far above any realistic CLI binary. DefaultMaxBinaryDownloadSize int64 = 512 << 20 )
Default size bounds on untrusted inputs. Generous, but they stop a hostile server streaming an unbounded response into memory.
These are constants, and a tool with an exceptional release layout raises them per-updater with WithMaxChecksumsSize or WithMaxBinaryDownloadSize rather than by reassigning a package variable. That is a deliberate change: the previous mutable globals raced under t.Parallel — which is why the oversized-response test could not run in parallel — and scoped a bound to the whole process rather than to the updater that needed it.
const ( DefaultConfigFilename = "config.yaml" // DefaultsAssetPath is the bare asset path the embedded-defaults layer is // read from. props.Assets merges it across every registered bundle, so each // package ships its own defaults (segregated-default-config spec, D1). DefaultsAssetPath = "assets/config.yaml" // InitTemplateAssetPath is the bare asset path init templates are read // from — the human-facing document Initialise writes to the user's config // file, merged across every registered bundle (D9). InitTemplateAssetPath = "assets/init/config.yaml" )
const ( UpdatedKey = timeSinceKey("updated") CheckedKey = timeSinceKey("checked") )
const DefaultCheckInterval = defaultCheckInterval
DefaultCheckInterval is the update-check throttle used when `update.check_interval` is unset or invalid.
const FeatureAnnotation = "gtb.feature"
FeatureAnnotation is the cobra.Command.Annotations key under which Wrap records the feature a command belongs to. Code that only has the raw *cobra.Command (e.g. a PersistentPreRunE hook) can identify the command by feature via FeatureOf instead of matching the fragile Use string.
const MCPExposureAnnotation = "gtb.mcp.exposure"
MCPExposureAnnotation is the cobra.Command.Annotations key under which a command's explicit MCP-exposure decision is recorded. It mirrors FeatureAnnotation. The value is [mcpExposureValueExposed] or [mcpExposureValueExcluded]; the key is absent when the command inherits.
const SkipConfigCheckAnnotation = "gtb.skip_config_check"
SkipConfigCheckAnnotation is the cobra.Command.Annotations key under which SkipConfigCheck records that a command's missing-config gate should be relaxed to a tolerant load by the root pre-run. It is the rename-safe counterpart to the string list in props.BootstrapPolicy.SkipConfigCheck.
const SkipUpdateCheckAnnotation = "gtb.skip_update_check"
SkipUpdateCheckAnnotation is the cobra.Command.Annotations key under which MarkSkipUpdateCheck records that the pre-run update check must never run for a command (or its subtree). It is the rename-safe counterpart to the old Use-string skip list inside SkipUpdateCheck, mirroring SkipConfigCheckAnnotation.
const ( // VersionCheckTimeout bounds passive, best-effort latest-version // lookups — the courtesy annotation on the `version` command — where // the check decorates an otherwise-local command and must not stall // it for minutes on a black-holing network. The root pre-run update // check currently still runs under the download-sized updateTimeout // and is expected to adopt this constant in a follow-up (see // docs/development/specs/2026-07-23-version-command-offline-degradation.md // §2, "Related but out of scope"). VersionCheckTimeout = 10 * time.Second )
Variables ¶
var ErrBinaryNotInArchive = errors.New("expected binary not found in archive")
ErrBinaryNotInArchive is returned when the release archive does not contain a binary matching the tool name. Without this, extraction silently reported success while leaving the old binary in place.
var ErrBinaryTooLarge = errors.New("binary download exceeds maximum size")
ErrBinaryTooLarge is returned when a downloaded release binary exceeds MaxBinaryDownloadSize. Indicates a hostile or misbehaving server.
var ErrChecksumAssetNotFound = errors.New("asset not found in checksums manifest")
ErrChecksumAssetNotFound is returned when the target filename is not listed in the checksums manifest. The release may have been created without GoReleaser or with a non-default checksums layout.
var ErrChecksumManifestDuplicate = errors.New("checksums manifest contains a duplicate filename")
ErrChecksumManifestDuplicate is returned when a filename appears more than once in the checksums manifest. A duplicate entry is ambiguous — silently letting the last one win would let a tampered manifest shadow the genuine hash with an attacker-chosen one — so the whole manifest is rejected.
var ErrChecksumManifestMalformed = errors.New("checksums manifest is malformed")
ErrChecksumManifestMalformed is returned when the checksums manifest does not conform to the expected GoReleaser format (`<sha256-hex> <filename>` per line). Rather than silently skip malformed lines, the parser rejects the entire manifest so a truncated or corrupted download never produces a false pass.
var ErrChecksumTooLarge = errors.New("download exceeds maximum size")
ErrChecksumTooLarge is returned when either the checksums manifest or the binary download exceeds its configured size bound. Indicates a hostile or misbehaving server; the update aborts before hashing.
var ErrDowngradeRefused = errors.New("refusing to downgrade")
ErrDowngradeRefused is returned when the implicit (no --version) update path would install a release older than the running binary. Signature and checksum verification authenticate an artefact, not its recency, so a stale or rolled-back release listing must not silently downgrade the tool (see the 2026-07-23 self-update downgrade guard spec).
Functions ¶
func AssetDocument ¶ added in v0.32.0
AssetDocument returns the named document merged across every registered asset bundle, or nil when no bundle ships one.
fs.ReadFile rather than a ReadFile method on Assets, and the distinction is load-bearing: fs.ReadFile falls back to Open, and Open is where Assets merges a structured file across every registered bundle. A hand-rolled ReadFile that indexed one bundle would compile, read plausibly, and silently return only the last bundle's copy.
func AssetSource ¶ added in v0.32.0
func AssetSource(p *props.Props, path string) *config.NamedSource
AssetSource wraps a merged asset document as a named config source, or nil when no bundle ships the path. The "embedded:" prefix is the provenance name convention for embedded layers.
func Chain ¶
func Chain(feature props.FeatureCmd, runE func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error
Chain applies all registered middleware (global + feature-specific) to the given RunE function and returns the wrapped function.
func EnsureDefaultConfigDir ¶ added in v0.32.0
EnsureDefaultConfigDir creates the tool's default config directory with user-only permissions (it may hold credential-bearing files) and returns its path, or "" when the home directory cannot be resolved. One shared home for the pre-create every Apply-to-the-default-path caller needs; each caller keeps its own error posture.
func ExclusiveChanges ¶ added in v0.32.0
ExclusiveChanges builds the ordered change list WriteExclusive applies: the winning keys set, every other key in all removed. Callers that need to commit the credential together with other keys (e.g. the AI wizard writing the provider selection in the same transaction) compose this list rather than issuing a separate Apply. Removing an already-absent key is a no-op, so stale keys end up absent rather than blanked.
Change ordering matters twice over. A stale key on the same dotted path as a winning key (bitbucket.username versus bitbucket.username.env) must be removed BEFORE that key is set, or the set has to write through a scalar — and a later subtree removal would take the winner with it. Every other stale key is removed AFTER all sets, so a parent mapping shared by winning and stale keys never passes through an empty state mid-batch.
func FeatureOf ¶ added in v0.17.0
func FeatureOf(cmd *cobra.Command) props.FeatureCmd
FeatureOf returns the feature a command was wrapped with via Wrap, or the empty FeatureCmd when the command carries no feature annotation. It works on the raw *cobra.Command, so it is usable from hooks that never see the composing *Command.
func GetAssets ¶ added in v0.32.0
func GetAssets() map[props.FeatureCmd][]AssetBundle
GetAssets returns a snapshot of all registered asset bundles.
func GetCheckedVersion ¶ added in v0.18.0
GetCheckedVersion returns the latest release version recorded by the most recent update check (the body of the last_checked marker), or "" when none has been recorded or the tool was up to date at the last check.
func GetChecks ¶
func GetChecks() map[props.FeatureCmd][]CheckProvider
GetChecks returns a snapshot of all registered check providers.
func GetDefaultConfigDir ¶
GetDefaultConfigDir returns the default config directory for the named tool (~/.toolname/). It returns an empty string when the user home directory cannot be resolved (e.g. HOME is unset or empty) — callers must treat an empty result as "no config dir" and skip any read/write rather than joining it with a filename, which would otherwise resolve to a relative path under the current working directory.
It is pure: it computes and returns the path only and never creates the directory. Building the command tree (--help, completions, default flag values) resolves this path, so a hidden MkdirAll here would create ~/.toolname as a side effect of merely running --help. Directory creation is deferred to the writers that actually persist a file under it (Initialise, setTimeSinceLastIn, the config writers in pkg/cmd), each of which MkdirAlls its parent at write time. The fs parameter is retained for API compatibility and is unused.
func GetFeatureFlags ¶
func GetFeatureFlags() map[props.FeatureCmd][]FeatureFlag
GetFeatureFlags returns a snapshot of all registered feature flag providers.
func GetInitialisers ¶
func GetInitialisers() map[props.FeatureCmd][]InitialiserProvider
GetInitialisers returns a snapshot of all registered initialiser providers.
func GetSubcommands ¶
func GetSubcommands() map[props.FeatureCmd][]SubcommandProvider
GetSubcommands returns a snapshot of all registered subcommand providers.
func GetTimeSinceLast ¶
GetTimeSinceLast returns the duration since the last update check or update, or DefaultCheckInterval when no timestamp has been recorded yet.
func Initialise ¶
Initialise creates the tool's configuration file in the specified directory and runs the supplied initialisers over it.
func IsExposedToMCP ¶ added in v0.21.0
IsExposedToMCP reports whether cmd is exposed on the MCP tool surface. It walks cmd and its ancestors and returns the nearest explicit decision (Exposed→true, Excluded→false), defaulting to true when no command in the chain sets one. This yields subtree exclusion by default while letting a descendant re-expose itself via IncludeInMCP. Operates on the raw *cobra.Command so it is callable from the root MCP selector closure; nil-safe.
func IsSealed ¶ added in v0.17.0
func IsSealed() bool
IsSealed reports whether the middleware registry has been sealed. Callers that register built-in middleware once per process use this to stay idempotent — a second root construction reuses the already-sealed registry instead of re-registering and panicking.
func MarkSkipUpdateCheck ¶ added in v0.33.0
MarkSkipUpdateCheck stamps cmd so SkipUpdateCheck exempts it (and, via the parent-chain walk, its whole subtree) from the pre-run update check. Used for commands where a version check is redundant or harmful: version prints its own check, mcp must not write spinner output to a protocol stdout, and doctor diagnoses the install it has. It returns cmd for chaining, mirroring SkipConfigCheck. A nil cmd is returned unchanged.
func Register ¶
func Register(feature props.FeatureCmd, ips []InitialiserProvider, sps []SubcommandProvider, fps []FeatureFlag)
Register adds initialisers, subcommands, and flags for a specific feature. Panics if the registry has been sealed.
func RegisterAssets ¶ added in v0.32.0
func RegisterAssets(feature props.FeatureCmd, name string, bundle fs.FS)
RegisterAssets adds an embedded asset bundle for a feature. The root command registers the bundles of enabled features onto props.Assets during construction, so a feature's assets/config.yaml (defaults) and assets/init/config.yaml (init template) participate in the merged reads only when the feature is enabled — see the segregated-default-config spec. Panics if the registry has been sealed.
func RegisterChecks ¶
func RegisterChecks(feature props.FeatureCmd, cps []CheckProvider)
RegisterChecks adds diagnostic check providers for a specific feature. Panics if the registry has been sealed.
func RegisterGlobalMiddleware ¶
func RegisterGlobalMiddleware(mw ...Middleware)
RegisterGlobalMiddleware adds middleware that is applied to all feature commands. Global middleware runs before feature-specific middleware in the chain.
func RegisterMiddleware ¶
func RegisterMiddleware(feature props.FeatureCmd, mw ...Middleware)
RegisterMiddleware adds middleware that will be applied to commands belonging to the specified feature. Middleware is applied in registration order.
func ResetRegistryForTesting ¶
func ResetRegistryForTesting()
ResetRegistryForTesting clears both the middleware and feature registries. This should only be used in tests to avoid state leakage between test runs.
func ResolveCheckInterval ¶ added in v0.18.0
ResolveCheckInterval resolves the update-check throttle from, in order of precedence: the `update.check_interval` config value (if a valid, non-negative Go duration — where "0"/"0s" means "check on every invocation"), then the tool author's baseline (toolDefault, if greater than zero), then DefaultCheckInterval. A toolDefault of zero is treated as "unset" and falls through to the framework default rather than meaning "every run"; runtime config is the only way to request the no-throttle behaviour.
func Seal ¶
func Seal()
Seal prevents further middleware registration. Called after all commands have been registered.
func SealRegistry ¶
func SealRegistry()
SealRegistry prevents further feature registration. Called after all commands have been registered. Subsequent Register* calls will panic.
func SetCheckedVersion ¶ added in v0.18.0
SetCheckedVersion stamps the last-checked marker and stores the latest release version that check discovered as the marker's body, so a later invocation can warn that the running binary is out of date without a network call (see GetCheckedVersion). The marker's modtime still drives the interval throttle — one file, two jobs. A blank version clears the stored value while still refreshing the check timestamp (e.g. when the tool is found up to date).
func SetTimeSinceLast ¶
SetTimeSinceLast records the current time as the last check or update timestamp (an empty marker file whose modtime is the timestamp). When the default config directory cannot be resolved (empty/unset HOME), it is a no-op: stamping a relative path would otherwise write the marker into the current working directory.
func SkipConfigCheck ¶ added in v0.29.0
SkipConfigCheck stamps cmd so the root pre-run relaxes its missing-config gate: when no config file exists, the framework falls back to the embedded default config rather than erroring, letting cmd's own PreRunE own bootstrap. It returns cmd for chaining, mirroring Wrap. A nil cmd is returned unchanged.
Bootstrap itself still runs — only the missing-config outcome is relaxed — so props.Config is always populated (see the 2026-06-12-bootstrap-prerun-traversal invariant).
func SkipUpdateCheck ¶
func SkipUpdateCheck(fs afero.Fs, name string, cmd *cobra.Command, checkInterval time.Duration) bool
SkipUpdateCheck reports whether the update check should be skipped this invocation: always for commands exempted by annotation or feature (see below), and otherwise when a prior check happened within checkInterval. A checkInterval <= 0 means check on every invocation; a missing timestamp (first run) is never skipped, regardless of the interval.
Exemption is decided by the typed command metadata, not the Use string (the old {"update","auth","init","version"} name list collided with any downstream command coincidentally named "auth"/"init" and broke when Use carried an args suffix). A command is exempt when it — or any ancestor, so a stamped or feature-owned group covers its whole subtree — carries the MarkSkipUpdateCheck annotation or is wrapped with the UpdateCmd or InitCmd feature. Built-ins stamp themselves (version, doctor, mcp); a downstream command opts out with setup.MarkSkipUpdateCheck(cmd).
func SkipsConfigCheck ¶ added in v0.29.0
SkipsConfigCheck reports whether cmd carries the SkipConfigCheck annotation. It works on the raw *cobra.Command so it is usable from the root pre-run hook.
func SkipsUpdateCheck ¶ added in v0.33.0
SkipsUpdateCheck reports whether cmd itself carries the MarkSkipUpdateCheck annotation. Subtree semantics (a stamped parent covering its children) are applied by SkipUpdateCheck's parent-chain walk, not here.
func VerifyChecksum ¶
VerifyChecksum reads a SHA-256 sidecar file and verifies it against the provided data. The sidecar format is "<hex-hash> <filename>" (matching sha256sum output and GoReleaser checksums.txt entries). Returns nil if the checksum matches, or an error with a hint on mismatch.
Hash comparison uses subtle.ConstantTimeCompare on decoded bytes. This is defence-in-depth — practical timing attacks on checksum comparison of unknown binary content are infeasible, but the constant-time primitive eliminates the class of concern at near-zero cost and makes future audits simpler.
func VerifyChecksumFromManifest ¶
VerifyChecksumFromManifest verifies data against a named entry in a GoReleaser-style checksums manifest. The manifest format is one "<hex-sha256> <filename>" entry per line; blank lines are permitted at end-of-file. Every non-blank line must match the expected shape or the manifest is rejected as malformed. A filename listed more than once rejects the whole manifest (ErrChecksumManifestDuplicate) rather than letting the last entry silently win.
Returns nil if the checksum matches, ErrChecksumAssetNotFound if the filename is not listed, ErrChecksumManifestMalformed on invalid syntax, ErrChecksumManifestDuplicate on a repeated filename, or an error wrapping errors.WithHint on mismatch.
func VerifyChecksumFromManifestReader ¶
func VerifyChecksumFromManifestReader( manifest []byte, filename string, dataReader io.Reader, dst io.Writer, maxBytes int64, ) (int64, error)
VerifyChecksumFromManifestReader is the streaming equivalent of VerifyChecksumFromManifest. It computes the SHA-256 of dataReader while copying into dst, avoiding a second pass over multi-megabyte binary data.
maxBytes bounds the total copied; exceeding it returns ErrChecksumTooLarge. A typical caller passes [MaxBinaryDownloadSize].
Returns the number of bytes copied on success, or an error on checksum mismatch, size-limit violation, or copy/IO failure. The manifest is parsed before any bytes are hashed, so a manifest- lookup failure aborts without touching dst.
func WriteExclusive ¶ added in v0.32.0
WriteExclusive commits the winning credential keys and removes every other key in all, as one transactional Apply — the single-credential-key invariant from the hardening spec, enforced atomically so an interrupted storage-mode switch cannot leave both the old and new credential behind.
Types ¶
type AssetBundle ¶ added in v0.32.0
AssetBundle names an embedded asset bundle a feature contributes to props.Assets when the feature is enabled.
type CheckFunc ¶
type CheckFunc func(ctx context.Context, props *props.Props) CheckResult
CheckFunc is the signature for individual diagnostic checks.
type CheckProvider ¶
CheckProvider is a function that returns diagnostic checks for a feature.
type CheckResult ¶
type CheckResult struct {
Name string `json:"name"`
Status string `json:"status"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
CheckResult represents the outcome of a single diagnostic check.
type Command ¶ added in v0.5.0
type Command struct {
*cobra.Command
// Feature is the middleware lookup key. The empty string means "no
// feature-specific middleware" (global middleware still applies).
Feature props.FeatureCmd
}
Command composes cobra.Command with the middleware feature key it belongs to. The feature is the lookup key Chain uses to find feature-specific middleware (registered via RegisterMiddleware).
Composing rather than wrapping means callers can use any cobra.Command method directly (the embedded pointer satisfies the interface), and code that needs the raw *cobra.Command — e.g. to pass to a cobra API or store in a parent's Commands() slice — accesses it via .Command.
Commands are typically built via Wrap in each generated NewCmd<Name> constructor and attached to a parent via the parent's Command.Register method, which wires middleware automatically. See the `2026-05-30-command-composition-registration` spec.
func ExcludeFromMCP ¶ added in v0.21.0
ExcludeFromMCP marks cmd as excluded from the MCP tool surface: when the mcp feature is enabled, cmd — and, by inheritance, descendants that do not themselves call IncludeInMCP — is omitted from `mcp tools` / `mcp start`. CLI behaviour is unaffected; the command remains fully runnable. Returns cmd for chaining.
func IncludeInMCP ¶ added in v0.21.0
IncludeInMCP marks cmd as explicitly exposed on the MCP tool surface. Its primary use is to override an excluded ancestor so a specific subcommand stays exposed; it is also stamped for any command whose exposure is explicitly Exposed. Returns cmd for chaining.
func Wrap ¶ added in v0.5.0
func Wrap(feature props.FeatureCmd, cmd *cobra.Command) *Command
Wrap pairs a cobra command with the feature it belongs to. The returned *Command embeds cmd, so it behaves as a cobra.Command for every method cobra offers; .Command exposes the underlying pointer when the cobra API needs *cobra.Command directly.
Wrap also stamps the feature onto the underlying command's Annotations (under FeatureAnnotation) so the feature is recoverable from the raw *cobra.Command via FeatureOf — even where only cobra's own type is in hand.
func (*Command) Register ¶ added in v0.5.0
Register adds each child as a subcommand and wraps the child's RunE with the middleware Chain for the child's own feature.
Each child is wrapped exactly once, at the point its parent registers it. A child's own descendants are wired when the child registers them, so Register never re-wraps a subtree.
Children with a nil RunE (pure command groups) are still attached but receive no RunE-wrapping — there is nothing to wrap.
type Editor ¶ added in v0.32.0
type Editor interface {
// View returns a pinned view of the current configuration.
View() *config.View
// Set writes one key to the target document.
Set(key string, value any) error
// Apply stages several changes as one transactional write to the target
// document — all land or none do.
Apply(changes ...config.Change) error
}
Editor is the read/write surface an initialiser uses during init. Reads resolve against the target document layered over the tool's embedded defaults; writes go through the store's Apply, which edits the target document in place, so template comments survive the wizards.
func OpenConfigEditor ¶ added in v0.32.0
func OpenConfigEditor(ctx context.Context, p *props.Props, dir string, clean bool) (Editor, string, error)
OpenConfigEditor materialises the tool's config file in dir (seeding it from the merged init template when absent or clean, merging new template keys under an existing one otherwise) and opens an Editor over it. The editor's reads resolve the file over the tool's embedded defaults, so a wizard sees the same effective values the running tool would; writes land only in the file. Shared by Initialise and the per-feature init subcommands.
type FeatureFlag ¶
FeatureFlag is a function that registers flags on a cobra command.
type FeatureRegistry ¶
type FeatureRegistry struct {
// contains filtered or unexported fields
}
FeatureRegistry holds the registered initialisers, subcommands, flags, and checks for features. All access is serialised by registryMu so concurrent init() calls and parallel tests are race-free.
type InitOptions ¶
type InitOptions struct {
Dir string
Clean bool
Initialisers []Initialiser
// Interactive overrides terminal detection for the credential wizards.
// When nil, interactivity is detected from stdin (utils.IsInteractive).
// Credential initialisers drive interactive prompts that would block on a
// non-terminal stdin, so they are skipped when this resolves to false.
// Tests set it explicitly to avoid depending on the test runner's stdin.
Interactive *bool
}
InitOptions holds the options for the Initialise function.
type Initialiser ¶
type Initialiser interface {
// Name returns a human-readable name for logging.
Name() string
// IsConfigured returns true if this initialiser's config is already present.
IsConfigured(cfg config.Reader) bool
// Configure runs the interactive config and writes values through cfg. ctx
// is the caller's (command) context: it bounds nothing by itself so
// human-paced flows (OAuth device codes, forms) can take as long as they
// need, while cancelling it (Ctrl-C) aborts any in-flight network or
// keychain operation. Implementations must derive short per-operation
// deadlines (e.g. credentials.KeychainOpTimeout) at each backend call site,
// never spanning interactive stages.
Configure(ctx context.Context, p *props.Props, cfg Editor) error
}
Initialiser is an optional config step that can check if it's already configured and, if not, interactively populate the tool's config file.
type InitialiserProvider ¶
type InitialiserProvider func(p *props.Props) Initialiser
InitialiserProvider is a function that creates an Initialiser.
type MCPExposure ¶ added in v0.21.0
type MCPExposure uint8
MCPExposure is a command's explicit decision about whether it appears on the MCP tool surface. The zero value is MCPExposureInherit, so an unset field or absent annotation naturally means "inherit from the nearest ancestor that sets one". It mirrors the generator manifest's mcp_enabled *bool: nil↔Inherit, true↔Exposed, false↔Excluded.
Exposure is build-time only: the decision is baked into the binary as a command annotation, with no runtime config lever — the MCP tool surface is fixed and auditable in the shipped binary. See docs/development/specs/2026-06-19-mcp-command-exposure-gating.md.
const ( // MCPExposureInherit means the command states no explicit preference and // inherits the nearest ancestor's; the tree default is exposed. MCPExposureInherit MCPExposure = iota // MCPExposureExposed means the command is explicitly on the MCP surface. // Its primary use is overriding an excluded ancestor. MCPExposureExposed // MCPExposureExcluded means the command is explicitly withheld from the // MCP surface. Its descendants inherit this unless they set Exposed. MCPExposureExcluded )
func MCPExposureFromBool ¶ added in v0.21.0
func MCPExposureFromBool(b *bool) MCPExposure
MCPExposureFromBool maps a tri-state *bool (the manifest/CLI representation) to the enum: nil→Inherit, true→Exposed, false→Excluded.
func MCPExposureOf ¶ added in v0.21.0
func MCPExposureOf(cmd *cobra.Command) MCPExposure
MCPExposureOf returns cmd's own explicit exposure decision, or MCPExposureInherit when cmd carries no exposure annotation. It operates on the raw *cobra.Command and is nil-safe.
type Middleware ¶
type Middleware func(next func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error
Middleware wraps a cobra RunE function with additional behaviour. The middleware receives the next handler in the chain and returns a new handler that may execute logic before and/or after calling next.
func WithAuthCheck ¶
func WithAuthCheck(p props.ConfigProvider, keys ...string) Middleware
WithAuthCheck returns middleware that validates the specified configuration keys are non-empty before allowing command execution. If any key is empty, a descriptive error is returned without executing the command.
The keys resolve against p's live store at execution time. The previous implementation read the global viper singleton, which GTB's own configuration never populated — every check passed vacuously.
func WithRecovery ¶
func WithRecovery(l logger.Logger) Middleware
WithRecovery returns middleware that catches panics in the command handler and converts them to errors. The panic value and stack trace are logged at Error level.
func WithTelemetry ¶
func WithTelemetry(p *props.Props) Middleware
WithTelemetry returns middleware that automatically tracks command invocations via the telemetry collector on Props. Records command name, duration, and exit code for every command execution. No-op when the collector is nil or telemetry is disabled (the collector is a noop in that case).
func WithTiming ¶
func WithTiming(l logger.Logger) Middleware
WithTiming returns middleware that logs command execution duration.
type SelfUpdater ¶
type SelfUpdater struct {
Tool props.Tool
CurrentVersion string
NextRelease forge.Release
Fs afero.Fs
// contains filtered or unexported fields
}
SelfUpdater manages checking for and applying tool updates.
func NewOfflineUpdater ¶
func NewOfflineUpdater(tool props.Tool, log logger.Logger, fs afero.Fs, opts ...UpdaterOption) *SelfUpdater
NewOfflineUpdater creates a SelfUpdater configured for file-based updates that do not require a VCS client or network access.
func NewUpdater ¶
func NewUpdater(ctx context.Context, p *props.Props, version string, force bool, opts ...UpdaterOption) (*SelfUpdater, error)
NewUpdater creates a SelfUpdater configured with the tools release source. The context is forwarded to forge.ResolveTokenContext for private-repository token resolution, so remote-store credential backends (Vault, SSM) honour the caller's deadline when fetching the release token.
func (*SelfUpdater) DownloadAsset ¶
func (s *SelfUpdater) DownloadAsset(ctx context.Context, asset forge.ReleaseAsset) (bytes.Buffer, error)
DownloadAsset downloads the raw bytes of a release asset.
func (*SelfUpdater) GetCurrentVersion ¶
func (s *SelfUpdater) GetCurrentVersion() string
func (*SelfUpdater) GetLatestRelease ¶
func (*SelfUpdater) GetLatestVersionString ¶
func (s *SelfUpdater) GetLatestVersionString(ctx context.Context) (string, error)
func (*SelfUpdater) GetReleaseNotes ¶
GetReleaseNotes retrieves the release notes for releases between the specified 'from' and 'to' versions (inclusive).
func (*SelfUpdater) GetStructuredReleaseNotes ¶
func (s *SelfUpdater) GetStructuredReleaseNotes(ctx context.Context, from, to string, archive ...bytes.Buffer) (*changelog.Changelog, error)
GetStructuredReleaseNotes retrieves release notes between two versions and returns them as a parsed Changelog. If an archive buffer is provided, it attempts to extract a bundled CHANGELOG.md first, falling back to per-release API calls when the archive contains no changelog.
func (*SelfUpdater) IsLatestVersion ¶
IsLatestVersion checks if the current running binary is the latest version.
func (*SelfUpdater) SignatureAssetName ¶ added in v0.12.0
func (s *SelfUpdater) SignatureAssetName() string
SignatureAssetName returns the configured signature filename, or the GoReleaser default "checksums.txt.sig" when unset.
func (*SelfUpdater) Update ¶
func (s *SelfUpdater) Update(ctx context.Context) (string, error)
Update installs the latest version of the binary to the resolved target path.
func (*SelfUpdater) UpdateFromFile ¶
func (s *SelfUpdater) UpdateFromFile(filePath string) (string, error)
UpdateFromFile installs a binary from a local .tar.gz file. If a .sha256 sidecar file exists at filePath+".sha256", the checksum is verified before extraction. Returns the installation target path.
type SubcommandProvider ¶
SubcommandProvider is a function that creates a slice of cobra subcommands.
type UpdaterOption ¶
type UpdaterOption func(*SelfUpdater)
UpdaterOption configures a SelfUpdater.
func WithEmbeddedKeys ¶ added in v0.12.0
func WithEmbeddedKeys(armoredKeys ...[]byte) UpdaterOption
WithEmbeddedKeys supplies the tool's embedded release public keys (in ASCII-armored form). NewUpdater builds the default resolver from these keys and the resolved update.key_source / external_key_email / require_external_crosscheck config. Ignored when WithKeyResolver is also supplied.
func WithExecLookPath ¶
func WithExecLookPath(fn func(string) (string, error)) UpdaterOption
WithExecLookPath overrides exec.LookPath for testing.
func WithKeyResolver ¶ added in v0.12.0
func WithKeyResolver(r verify.KeyResolver) UpdaterOption
WithKeyResolver overrides the default key resolver used for signature verification. When set, the config-driven default (built from WithEmbeddedKeys and the update.key_source family) is bypassed entirely — the tool author owns the resolver chain.
func WithMaxBinaryDownloadSize ¶ added in v0.32.0
func WithMaxBinaryDownloadSize(maxBytes int64) UpdaterOption
WithMaxBinaryDownloadSize raises the bound on a downloaded binary asset. Zero or negative keeps DefaultMaxBinaryDownloadSize.
func WithMaxChecksumsSize ¶ added in v0.32.0
func WithMaxChecksumsSize(maxBytes int64) UpdaterOption
WithMaxChecksumsSize raises the bound on a downloaded checksums manifest. Zero or negative keeps DefaultMaxChecksumsSize.
func WithOsExecutable ¶
func WithOsExecutable(fn func() (string, error)) UpdaterOption
WithOsExecutable overrides os.Executable for testing.
func WithReleaseProvider ¶ added in v0.21.0
func WithReleaseProvider(p forge.Provider) UpdaterOption
func WithRequireChecksum ¶ added in v0.32.0
func WithRequireChecksum(require bool) UpdaterOption
WithReleaseProvider injects the forge.Provider the SelfUpdater uses, bypassing the ReleaseSource.Type registry lookup (and, with it, the private-repository token gate that precedes the lookup — an injected provider is self-contained and owns its own auth). Parallel-safe: each call site receives its own provider, with no global registry mutation. Takes precedence over a props.Tool.ReleaseProvider field. WithRequireChecksum sets checksum enforcement for this updater when neither config nor environment provides a value.
Replaces the former package-level DefaultRequireChecksum: a tool wanting fail-closed verification states it where it builds its updater, rather than mutating shared state at init.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package ai provides the interactive AI-provider setup initialiser.
|
Package ai provides the interactive AI-provider setup initialiser. |
|
Package forge provides a single, provider-parameterised interactive setup initialiser for git forges.
|
Package forge provides a single, provider-parameterised interactive setup initialiser for git forges. |
|
Package telemetry registers the telemetry initialiser with the setup system.
|
Package telemetry registers the telemetry initialiser with the setup system. |