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 only `direct`, the plain download source that ships inside the forge module itself. Forge adapters (github, gitlab, gitea, bitbucket) are registered by the binary that ships them (spec 0194 D3): gtb's own main links every one, and a generated tool links the ones its enabled forge features need. forge.ModuleFor names the module for each.
Index ¶
- Constants
- Variables
- func AssetDocument(p *props.Props, path string) []byte
- func AssetSource(p *props.Props, path string) *config.NamedSource
- func AssetsIn(s features.Snapshot) map[props.FeatureID][]AssetBundle
- func CIDefault() bool
- func ChecksIn(s features.Snapshot) map[props.FeatureID][]CheckProvider
- func CloseWithStore(b ConfigBootstrap, c io.Closer)
- func ConfigCodecFor(codecs []ConfigCodec, path string) (config.Codec, error)
- func ConfigFormatChangedError(p *props.Props, old, want string) error
- func ConfigFormatDescriptor(format string) props.FeatureDescriptor
- func ConfigSourceDescriptor(kind string) props.FeatureDescriptor
- func ConfigSourceKindsIn(s features.Set) map[string]ConfigSourceKind
- func ConfigSourceOverridesIn(s features.Set) map[string]SourceFactory
- func ConfigSourceUnconfiguredError(p *props.Props, slot props.ConfigSource) error
- func ContextWithProps(ctx context.Context, p *props.Props) context.Context
- func DeclareEnvVariable(name string)
- func DeclareEnvVariableOn(r features.Registry, name string)
- func DeclaredEnvVariables(set features.Set) []string
- func DecodeConfig(codec config.Codec, path string, src []byte) (map[string]any, error)
- func DefaultConfigPaths(p *props.Props) []string
- func DiscoverProjectConfig(fs afero.Fs, toolName, startDir string) stringdeprecated
- func EncodeConfig(codec config.Codec, path string, doc map[string]any) ([]byte, error)
- func EnsureDefaultConfigDir(fs afero.Fs, name string) (string, error)
- func EnvVariablesFor(snap *config.Snapshot, key string) []string
- func ExclusiveChanges(winning map[string]any, all []string) []config.Change
- func FeatureFlagsIn(s features.Snapshot) map[props.FeatureID][]FeatureFlag
- func FeatureOf(cmd *cobra.Command) props.FeatureID
- func FindProjectConfig(fs afero.Fs, toolName, startDir string, codecs []ConfigCodec) (string, error)
- func FlagSkips(flags *pflag.FlagSet, names ...string) map[string]bool
- func FormTheme() huh.Theme
- func GetCheckedVersion(fs afero.Fs, name string) string
- func GetDefaultConfigDir(_ afero.Fs, name string) string
- func GetPinnedVersion(fs afero.Fs, name string) (string, error)
- func GetTimeSinceLast(fs afero.Fs, name string, status timeSinceKey) time.Duration
- func GroupRunE(cmd *cobra.Command, args []string) error
- func Initialise(ctx context.Context, p *props.Props, opts InitOptions) (string, error)
- func InitialisersIn(s features.Snapshot) map[props.FeatureID][]InitialiserProvider
- func IsExposedToMCP(cmd *cobra.Command) bool
- func IsGroup(cmd *cobra.Command) bool
- func IsOverrideOnlyKind(kind string) bool
- func IsProjectConfigName(path, toolName string) bool
- func IsProjectConfigTrusted(fs afero.Fs, toolName, path string) (bool, error)
- func IsProtocolStdout(cmd *cobra.Command) bool
- func ListTrustedProjects(fs afero.Fs, toolName string) ([]string, error)
- func MarkProtocolStdout(cmd *cobra.Command) *cobra.Command
- func MarkSkipUpdateCheck(cmd *cobra.Command) *cobra.Command
- func OverrideConfigSource(name string, f SourceFactory)
- func OverrideConfigSourceOn(r features.Registry, name string, f SourceFactory) error
- func PrepareForm(io props.IO, f *huh.Form) *huh.Form
- func Promptable(io props.IO) bool
- func PropsFromContext(ctx context.Context) *props.Props
- func Register(feature props.FeatureID, ips []InitialiserProvider, sps []SubcommandProvider, ...)
- func RegisterAssets(feature props.FeatureID, name string, bundle fs.FS)
- func RegisterChecks(feature props.FeatureID, cps []CheckProvider)
- func RegisterConfigCodec(format string, codec config.Codec, extensions ...string)
- func RegisterConfigCodecOn(r features.Registry, format string, codec config.Codec, extensions ...string)
- func RegisterConfigSourceKind(kind string, f SourceFactory, init ConfigSourceInitialiser, ...)
- func RegisterConfigSourceKindOn(r features.Registry, kind string, f SourceFactory, ...)
- func RegisterGlobalMiddleware(mw ...Middleware)
- func RegisterMiddleware(feature props.FeatureID, mw ...Middleware)
- func RegisterOn(r features.Registry, feature props.FeatureID, ips []InitialiserProvider, ...)
- func RegisterRootCommands(feature props.FeatureID, providers ...RootCommandProvider)
- func RegisterRootCommandsOn(r features.Registry, feature props.FeatureID, providers ...RootCommandProvider)
- func ReportSourceCredential(b ConfigBootstrap, origin string)
- func ResolveCheckInterval(toolDefault time.Duration, configValue string) time.Duration
- func RootCommandsIn(s features.Snapshot) map[props.FeatureID][]RootCommandProvider
- func RunConfigSourceInit(ctx context.Context, p *props.Props, slot props.ConfigSource, dir string) error
- func RunForm(ctx context.Context, p *props.Props, f *huh.Form) error
- func RunFormOn(ctx context.Context, io props.IO, f *huh.Form) error
- func SecretEchoMode(io props.IO) huh.EchoMode
- func SetCheckedVersion(fs afero.Fs, name, version string) error
- func SetPinnedVersion(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 StorageModeGroup(ctx context.Context, p *props.Props, mode *credentials.Mode, hide func() bool) *huh.Group
- func StrandedConfig(fs afero.Fs, tool props.Tool, paths []string) (old, want string)
- func SubcommandsIn(s features.Snapshot) map[props.FeatureID][]SubcommandProvider
- func TimeSinceLast(fs afero.Fs, name string, status timeSinceKey) (time.Duration, bool)
- func TrustProjectConfig(fs afero.Fs, toolName, path string) error
- func UntrustProjectConfig(fs afero.Fs, toolName, path string) error
- 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 Chainer
- type CheckFunc
- type CheckProvider
- type CheckResult
- type Command
- type ConfigBootstrap
- type ConfigCodec
- type ConfigKeyRecogniser
- type ConfigSourceInitialiser
- type ConfigSourceKind
- type Editor
- type EnvKey
- type FeatureFlag
- type InitOptions
- type Initialiser
- type InitialiserProvider
- type MCPExposure
- type MCPHints
- type Middleware
- type MiddlewareChain
- type ReleaseChannel
- type RootCommandProvider
- type RunE
- 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) ReleaseBefore(ctx context.Context, current string) (string, error)
- func (s *SelfUpdater) SignatureAssetName() string
- func (s *SelfUpdater) Update(ctx context.Context) (string, error)
- func (s *SelfUpdater) UpdateFromFile(ctx context.Context, filePath string) (string, error)
- type SourceCloserRegistrar
- type SourceCredentialReporter
- type SourceFactory
- type SourceKindOption
- type SourceSetting
- type SubcommandProvider
- type 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 )
Size bounds on untrusted inputs. Generous, but they stop a hostile server streaming an unbounded response into memory.
These are constants rather than package variables: the previous mutable globals raced under t.Parallel and scoped a bound to the whole process. No tool has needed a different bound; one that does asks for a Tool field.
const ( // ConfigKeyUpdatePolicy selects the self-update posture (props.UpdatePolicy). ConfigKeyUpdatePolicy = "update.policy" // ConfigKeyUpdateCheckInterval throttles the update check, as a Go duration. ConfigKeyUpdateCheckInterval = "update.check_interval" // ConfigKeyUpdateRequireSignature refuses an unsigned update asset. ConfigKeyUpdateRequireSignature = "update.require_signature" // ConfigKeyUpdateRequireChecksum refuses an asset with no checksum entry. ConfigKeyUpdateRequireChecksum = "update.require_checksum" // ConfigKeyUpdateRequireExternalCrosscheck fails closed when the WKD resolver is unreachable. ConfigKeyUpdateRequireExternalCrosscheck = "update.require_external_crosscheck" // ConfigKeyUpdateKeySource selects embedded, external or both trust anchors. ConfigKeyUpdateKeySource = "update.key_source" // ConfigKeyUpdateExternalKeyEmail names the WKD identity of the release key. ConfigKeyUpdateExternalKeyEmail = "update.external_key_email" // ConfigKeyUpdateChecksumAssetName overrides the checksums asset file name. ConfigKeyUpdateChecksumAssetName = "update.checksum_asset_name" // ConfigKeyUpdateSignatureAssetName overrides the signature asset file name. ConfigKeyUpdateSignatureAssetName = "update.signature_asset_name" // ConfigKeyTelemetryEnabled is the opt-in switch for usage telemetry. ConfigKeyTelemetryEnabled = "telemetry.enabled" // ConfigKeyTelemetryLocalOnly keeps events on disk and never exports them. ConfigKeyTelemetryLocalOnly = "telemetry.local_only" // ConfigKeyTelemetryConsent records that the consent prompt was answered. ConfigKeyTelemetryConsent = "telemetry.consent" // ConfigKeyLogLevel is the logger verbosity the root pre-run applies. ConfigKeyLogLevel = "log.level" // ConfigKeyLogFormat selects the log backend (text or json). ConfigKeyLogFormat = "log.format" )
Config keys for the self-update and telemetry sections. Declared once here so the root pre-run, the wizards and the doctor checks cannot drift apart on the spelling of a key that is part of a tool's config contract.
const ( // DefaultConfigFilename is a YAML tool's own config file name. // // Deprecated: use props.Tool.ConfigFilename, which names the file for the // tool's own format (spec 0204 D23). 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 ( MCPTitleAnnotation = "title" MCPReadOnlyAnnotation = "readOnlyHint" MCPDestructiveAnnotation = "destructiveHint" MCPIdempotentAnnotation = "idempotentHint" MCPOpenWorldAnnotation = "openWorldHint" )
The annotation keys are ophis's spellings (ophis v1.1.4 annotations.go), so a consumer that sets them by hand today keeps working, and go/mcp's Cobra binding reads the same keys after the replacement (spec 0201 D4).
const ( SlotInitialiser features.Slot = "initialiser" SlotSubcommand features.Slot = "subcommand" SlotInitFlag features.Slot = "init-flag" SlotCheck features.Slot = "check" SlotAssets features.Slot = "assets" SlotMiddleware features.Slot = "middleware" SlotRootCommand features.Slot = "root-command" )
The contribution slots GTB reads from the feature registry (spec 0199 D2). A package contributes under its feature's ID at init; the root and the commands read the contributions of enabled features.
const ( UpdatedKey = timeSinceKey("updated") CheckedKey = timeSinceKey("checked") )
const AccessibleEnvVariable = "GTB_ACCESSIBLE"
AccessibleEnvVariable asks for line prompts on any stdin. Every tool reads it by this name, whatever its prefix (spec 0198 D1).
const ChainedAnnotation = "gtb.chained"
ChainedAnnotation marks a cobra command whose RunE has been wrapped by a Chainer, so a subtree that joins a tree later is wrapped exactly once.
const ConfigFormatPrefix = "config-format-"
ConfigFormatPrefix prefixes a linked format's feature ID; see props.LinkedNames.
const ConfigSourcePrefix = "config-source-"
ConfigSourcePrefix prefixes a linked source kind's feature ID; see props.LinkedNames.
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 GroupAnnotation = "gtb.group"
GroupAnnotation marks a command whose RunE was GroupRunE before the root's middleware chain wrapped it, so IsGroup still answers afterwards.
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 ProtocolStdoutAnnotation = "gtb.protocol_stdout"
ProtocolStdoutAnnotation is the cobra.Command.Annotations key under which MarkProtocolStdout records that a command's stdout carries a wire protocol, so the root withholds interactive UI (the telemetry consent prompt) from it and its subtree (spec 0202 D5).
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 SkipKeyFlag = "skip-key"
SkipKeyFlag is the init flag every profile that offers an SSH key honours. The init command binds it; a provider reads it through FlagSkips.
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 SlotConfigCodec features.Slot = "config-codec"
SlotConfigCodec is where a format's link package contributes its codec.
const SlotConfigSource features.Slot = "config-source"
SlotConfigSource is where a source kind's link package contributes its factory and initialiser (spec 0204 D3).
const SlotEnvVariable features.Slot = "env-variable"
SlotEnvVariable carries the name of an environment variable a binary reads directly rather than through the config store.
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 // https://gitlab.com/phpboyscout/go-tool-base/-/wikis/specs/0173-version-command-offline-degradation // §2, "Related but out of scope"). VersionCheckTimeout = 10 * time.Second )
Variables ¶
var ( // ErrConfigSourceUnconfigured is a required slot nobody has configured. ErrConfigSourceUnconfigured = errors.NewSentinel("gtb.setup.config_source_unconfigured", "config source not configured") // ErrConfigSourceNeedsOverride is an override-only slot with no override. ErrConfigSourceNeedsOverride = errors.NewSentinel("gtb.setup.config_source_needs_override", "config source needs an author override") // ErrConfigSourceKindNotLinked is a slot whose kind the binary does not // link. ErrConfigSourceKindNotLinked = errors.NewSentinel("gtb.setup.config_source_kind_not_linked", "config source kind not linked") // ErrConfigSourceOverrideUndeclared is an override for a slot the tool // does not declare, refused so a stale override cannot add a layer. ErrConfigSourceOverrideUndeclared = errors.NewSentinel("gtb.setup.config_source_override_undeclared", "override for an undeclared config source") // be built. ErrConfigSourceUnavailable = errors.NewSentinel("gtb.setup.config_source_unavailable", "config source unavailable") )
var ErrAlreadyCurrent = errors.NewSentinel("gtb.setup.already_current", "already running the current version; nothing replaced")
ErrAlreadyCurrent is what Update returns when there is nothing to install: the running binary is already the latest release (or a development build without --force). Nothing was replaced, and the caller must not say it was (#95). It is not a failure; the command maps it to a no-op result.
var ErrAmbiguousProjectConfig = errors.NewSentinel("gtb.setup.ambiguous_project_config", "more than one project-local config file")
ErrAmbiguousProjectConfig is two project-local config files in one directory (spec 0204 D16).
var ErrBinaryNotInArchive = errors.NewSentinel("gtb.setup.binary_not_in_archive", "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.NewSentinel("gtb.setup.binary_too_large", "binary download exceeds maximum size")
ErrBinaryTooLarge is returned when a downloaded release binary exceeds MaxBinaryDownloadSize. Indicates a hostile or misbehaving server.
var ErrChecksumAssetNotFound = errors.NewSentinel("gtb.setup.checksum_asset_not_found", "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.NewSentinel("gtb.setup.checksum_manifest_duplicate", "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.NewSentinel("gtb.setup.checksum_manifest_malformed", "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.NewSentinel("gtb.setup.checksum_too_large", "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 ErrConfigFormatChanged = errors.NewSentinel("gtb.setup.config_format_changed", "config file is in the tool's previous format")
ErrConfigFormatChanged is a tool whose own config file is in its previous format and absent in its current one (spec 0204 D14).
var ErrDowngradeNotConfirmed = errors.NewSentinel("gtb.setup.downgrade_not_confirmed", "a downgrade needs confirmation")
ErrDowngradeNotConfirmed is a downgrade nobody confirmed: declined at the prompt, or asked for unattended without --force.
var ErrDowngradeRefused = errors.NewSentinel("gtb.setup.downgrade_refused", "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).
var ErrInputEnded = errors.NewSentinel("gtb.setup.input_ended", "input ended before every question was answered")
ErrInputEnded is an accessible form whose stdin ran out before every question was answered.
var ErrInvalidPinnedVersion = errors.NewSentinel("gtb.setup.invalid_pinned_version", "the pinned version is not a release tag")
ErrInvalidPinnedVersion is a pin that does not name a release tag.
var ErrManagedInstall = errors.NewSentinel("gtb.setup.managed_install", "refusing to replace a package-managed binary")
ErrManagedInstall is a binary a package manager installed. Replacing it would leave the manager's record of the install describing a file that is no longer on disk, so a later upgrade or uninstall would act on the wrong one.
var ErrNoEarlierRelease = errors.NewSentinel("gtb.setup.no_earlier_release", "no earlier release to roll back to")
ErrNoEarlierRelease is a rollback with no release below the running version among the newest releases the channel lists.
var ErrNonInteractive = errors.NewSentinel("gtb.setup.non_interactive", "an interactive terminal is needed")
ErrNonInteractive is a wizard asked for where nobody can answer it: stdin is not a terminal and accessible mode is off.
var ErrReadOnlyConfigFormat = errors.NewSentinel("gtb.setup.read_only_config_format", "config format is read-only")
ErrReadOnlyConfigFormat is a document that cannot be written because its format's codec cannot edit.
var ErrUnlinkedConfigFormat = errors.NewSentinel("gtb.setup.unlinked_config_format", "config file format not linked")
ErrUnlinkedConfigFormat is a config file whose extension names a format the tool does not link (spec 0204 D2).
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 AssetsIn ¶ added in v0.43.0
func AssetsIn(s features.Snapshot) map[props.FeatureID][]AssetBundle
AssetsIn is GetAssets over a snapshot.
func CIDefault ¶ added in v0.43.0
func CIDefault() bool
CIDefault is the default an init skip flag takes: on under CI, where nobody can answer a wizard.
func ChecksIn ¶ added in v0.43.0
func ChecksIn(s features.Snapshot) map[props.FeatureID][]CheckProvider
ChecksIn is GetChecks over a snapshot.
func CloseWithStore ¶ added in v0.46.0
func CloseWithStore(b ConfigBootstrap, c io.Closer)
CloseWithStore hands c to the store b builds for, which closes it when it is closed, or at once if the build fails. A bootstrap that does not listen leaves c to its caller.
func ConfigCodecFor ¶ added in v0.46.0
func ConfigCodecFor(codecs []ConfigCodec, path string) (config.Codec, error)
ConfigCodecFor returns the codec that reads path, chosen by its extension. A linked format's extension gets its codec. Another format's extension is refused, naming what the tool accepts and the link that would read it. Any other path is YAML.
func ConfigFormatChangedError ¶ added in v0.46.0
ConfigFormatChangedError refuses a stranded config file, naming both files and the way out. The old file is never converted for the user: comments and formatting do not survive, and nobody would be watching.
func ConfigFormatDescriptor ¶ added in v0.46.0
func ConfigFormatDescriptor(format string) props.FeatureDescriptor
ConfigFormatDescriptor is the link feature a format's package declares. Like every link it defaults on, since its presence in the binary is its enablement (spec 0199 OQ3).
func ConfigSourceDescriptor ¶ added in v0.46.0
func ConfigSourceDescriptor(kind string) props.FeatureDescriptor
ConfigSourceDescriptor is the link feature a source kind's package declares. Like every link it defaults on.
func ConfigSourceKindsIn ¶ added in v0.46.0
func ConfigSourceKindsIn(s features.Set) map[string]ConfigSourceKind
ConfigSourceKindsIn returns every enabled kind in s, by kind.
func ConfigSourceOverridesIn ¶ added in v0.46.0
func ConfigSourceOverridesIn(s features.Set) map[string]SourceFactory
ConfigSourceOverridesIn returns the overrides registered in s, by slot name.
func ConfigSourceUnconfiguredError ¶ added in v0.46.0
func ConfigSourceUnconfiguredError(p *props.Props, slot props.ConfigSource) error
ConfigSourceUnconfiguredError refuses a required slot nobody configured, naming the command that configures it (spec 0204 D6).
func ContextWithProps ¶ added in v0.34.0
ContextWithProps returns a copy of ctx carrying p. The root pre-run stamps the command context with its own Props so the process-global middleware chain resolves the RIGHT Props at execution time rather than closing over whichever root was constructed first. A nil ctx is treated as context.Background.
func DeclareEnvVariable ¶ added in v0.46.0
func DeclareEnvVariable(name string)
DeclareEnvVariable records on the default registry that this binary reads name directly. When name also falls under the tool's prefix it maps to a config key nobody declares, and doctor would otherwise report it as stray (spec 0205 D4).
func DeclareEnvVariableOn ¶ added in v0.46.0
DeclareEnvVariableOn is DeclareEnvVariable on r.
func DeclaredEnvVariables ¶ added in v0.46.0
DeclaredEnvVariables lists the variables read by name: the framework's own and every one declared in set, sorted and once each.
func DecodeConfig ¶ added in v0.46.0
DecodeConfig reads src through codec into one document, later documents overriding earlier ones.
func DefaultConfigPaths ¶ added in v0.46.0
DefaultConfigPaths are where a tool looks for its own config file when --config names none, lowest precedence first: the system-wide file, then the user's.
func DiscoverProjectConfig
deprecated
added in
v0.34.0
DiscoverProjectConfig walks up from startDir looking for a project-local ".<tool>.yaml", returning its path or "".
Deprecated: use FindProjectConfig, which also finds the project file in the tool's linked formats (spec 0204 D16).
func EncodeConfig ¶ added in v0.46.0
EncodeConfig writes doc as a new document through codec: YAML as the core marshals it, any other writable format by setting each leaf on an empty document.
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 EnvVariablesFor ¶ added in v0.46.0
EnvVariablesFor returns the environment variables that supplied key or any key beneath it in snap, sorted; empty when the environment supplied none. A refusal about a key names them, so a stray variable is not blamed on the config file (spec 0205 D1).
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 FeatureFlagsIn ¶ added in v0.43.0
func FeatureFlagsIn(s features.Snapshot) map[props.FeatureID][]FeatureFlag
FeatureFlagsIn is GetFeatureFlags over a snapshot.
func FeatureOf ¶ added in v0.17.0
FeatureOf returns the feature a command was wrapped with via Wrap, or the empty FeatureID 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 FindProjectConfig ¶ added in v0.46.0
func FindProjectConfig(fs afero.Fs, toolName, startDir string, codecs []ConfigCodec) (string, error)
FindProjectConfig walks up from startDir looking for a project-local config file, ".<tool>.yaml" or ".<tool>" plus a linked format's extension, and returns the one in the nearest directory holding any, or "" when none is found before the filesystem root. This is a repo-root config layer, a convention like .editorconfig; a tool opts out simply by not having the file. Two candidates in one directory are refused rather than one picked.
func FlagSkips ¶ added in v0.43.0
FlagSkips reads a set of boolean init flags by name. A flag that was not bound (its feature is off) reads as false, so a provider can ask for a flag another feature owns without caring whether that feature is linked.
func FormTheme ¶ added in v0.43.0
FormTheme is the theme every wizard renders with: huh's Charm theme with the form set in from the terminal's left edge by two columns and one line, the way huh's own examples render. A form against the edge reads as a stray print; the margin is what makes it read as a dialogue. Every framework wizard gets it through RunForm; a form the gtb CLI runs itself sets it.
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 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 GetPinnedVersion ¶ added in v0.49.0
GetPinnedVersion returns the version the tool is pinned to, or "" when it is not pinned. A marker that does not hold a release tag reads as unpinned and returns an error naming the file, so a corrupt marker can never wedge the tool.
func GetTimeSinceLast ¶
GetTimeSinceLast returns the duration since the last update check or update, or DefaultCheckInterval when no timestamp has been recorded yet.
func GroupRunE ¶ added in v0.39.0
GroupRunE is the RunE for a command that only groups subcommands: it prints usage for a bare invocation and reports a verb the group does not have.
cmd := &cobra.Command{
Use: "config",
RunE: setup.GroupRunE,
}
A bare invocation is a request for help, so it prints usage and succeeds — cobra's Usage returns nil. A verb the group does not have is a mistake, so it is named and the command fails with errorhandling.ErrUnknownSubCommand, whose outcome prints usage and yields exit code 2.
Why a group needs a RunE at all ¶
Cobra cannot express this through Args. A command with no Run or RunE returns flag.ErrHelp from execute() BEFORE ValidateArgs is reached, so Args is never evaluated and cobra.NoArgs on a group is silently inert. Cobra's own unknown-command report is no help either: legacyArgs only produces it for the root command (`!cmd.HasParent()`), so every group below the root answers a mistyped verb with help and success unless it checks for itself.
The message itself comes from errorhandling.UnknownSubCommand, so that CLIs in this estate that build cobra commands without this framework — go/signing-cli does, deliberately — report a mistyped verb in the same words. What is shared is the message and the sentinel; the three lines of cobra glue are not, and cannot be, since go/errorhandling imports no CLI framework.
Why the generator emits a call to this rather than a copy of it ¶
A generated cmd.go is a wiring file that calls into this package for everything it does — Wrap, Register, the pre-run hooks. Emitting a copy of this body into every generated group would make behaviour the one thing that file states for itself, and would pin every project's group behaviour to the gtb build that scaffolded it. A reference to a published function cannot be sealed, deleted or drifted the way a same-package Run<Name> reference could — which is the failure mode that produced go-tool-base issues #21 and #22.
See spec 0190.
func Initialise ¶
Initialise creates the tool's configuration file in the specified directory and runs the supplied initialisers over it.
func InitialisersIn ¶ added in v0.43.0
func InitialisersIn(s features.Snapshot) map[props.FeatureID][]InitialiserProvider
InitialisersIn is GetInitialisers over a snapshot.
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 IsGroup ¶ added in v0.43.0
IsGroup reports whether cmd only groups subcommands, that is, its RunE is GroupRunE (or was, before the chain wrapped it). Cobra counts such a command as runnable, so anything publishing "runnable commands" (the MCP surface) asks this to leave groups out: a tool that prints usage is noise to a client.
func IsOverrideOnlyKind ¶ added in v0.46.0
IsOverrideOnlyKind reports whether only an author override can build kind.
func IsProjectConfigName ¶ added in v0.46.0
IsProjectConfigName reports whether path is named like a project-local config file, ".<tool>" plus a YAML or family format extension, whether or not the format is linked.
func IsProjectConfigTrusted ¶ added in v0.34.0
IsProjectConfigTrusted reports whether the project-local config file at path is currently trusted for the named tool: it must be recorded in the trust store AND its content hash must still match what was trusted. A file that was trusted and then edited (or swapped by a fresh clone) is no longer trusted, so its security-sensitive keys go back to being ignored.
A missing store, a path not in the store, or an unreadable file all resolve to "not trusted" — the safe default. Only an unexpected I/O fault reading the store surfaces as an error.
func IsProtocolStdout ¶ added in v0.43.0
IsProtocolStdout reports whether cmd or any ancestor carries the MarkProtocolStdout stamp. A feature match or a name match would tie the root to the features that have such commands; the stamp does not.
func ListTrustedProjects ¶ added in v0.34.0
ListTrustedProjects returns the absolute paths of every trusted project-local config file for the named tool, sorted for stable output.
func MarkProtocolStdout ¶ added in v0.43.0
MarkProtocolStdout stamps cmd as a command whose stdout is a protocol stream: an MCP server's JSON-RPC frames, for one. IsProtocolStdout recognises the stamp across the subtree. It says nothing about the update check; a server stamps MarkSkipUpdateCheck as well. A nil cmd is returned unchanged.
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 OverrideConfigSource ¶ added in v0.46.0
func OverrideConfigSource(name string, f SourceFactory)
OverrideConfigSource replaces the factory for one named slot (spec 0204 D19). Call it from hand-written code in the tool's main package; the generator never writes one. It panics only on a registry the framework itself corrupted, as feature registration at init does.
func OverrideConfigSourceOn ¶ added in v0.46.0
func OverrideConfigSourceOn(r features.Registry, name string, f SourceFactory) error
OverrideConfigSourceOn is OverrideConfigSource against a caller's registry.
func PrepareForm ¶ added in v0.43.0
PrepareForm binds f to the IO's streams the way RunFormOn does, without running it: the accessible decision, the theme, and the headless program options. It is for the few prompts reached from code that carries no context, which then call Run themselves; everything else uses RunFormOn.
func Promptable ¶ added in v0.43.0
Promptable reports whether a wizard can run on these streams: stdin is a terminal, or accessible line prompts were asked for (--accessible, GTB_ACCESSIBLE=true, TERM=dumb), which read any stdin. It is the one rule every prompt gate in the framework and the gtb CLI applies; a gate that demanded a terminal refused a piped stdin that had asked for line prompts.
func PropsFromContext ¶ added in v0.34.0
PropsFromContext returns the Props stamped onto ctx by ContextWithProps, or nil when none is present (an auxiliary/fast-path command, or a context built outside the root pre-run). Middleware falls back to its registration-time Props in that case.
func Register ¶
func Register(feature props.FeatureID, ips []InitialiserProvider, sps []SubcommandProvider, fps []FeatureFlag)
Register contributes initialisers, subcommands and init flags for a feature to the default registry. Nil slices contribute nothing.
func RegisterAssets ¶ added in v0.32.0
RegisterAssets contributes an embedded asset bundle for a feature. The root 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.
func RegisterChecks ¶
func RegisterChecks(feature props.FeatureID, cps []CheckProvider)
RegisterChecks contributes diagnostic check providers for a feature.
func RegisterConfigCodec ¶ added in v0.46.0
RegisterConfigCodec declares a format's link feature on the default registry and contributes its codec for the given extensions. A format's link package calls it from init.
func RegisterConfigCodecOn ¶ added in v0.46.0
func RegisterConfigCodecOn(r features.Registry, format string, codec config.Codec, extensions ...string)
RegisterConfigCodecOn contributes a format's codec to a caller's registry, which must already declare ConfigFormatDescriptor(format).
func RegisterConfigSourceKind ¶ added in v0.46.0
func RegisterConfigSourceKind(kind string, f SourceFactory, init ConfigSourceInitialiser, opts ...SourceKindOption)
RegisterConfigSourceKind declares a kind's link feature on the default registry and contributes its factory and initialiser. A kind's link package calls it from init.
func RegisterConfigSourceKindOn ¶ added in v0.46.0
func RegisterConfigSourceKindOn(r features.Registry, kind string, f SourceFactory, init ConfigSourceInitialiser, opts ...SourceKindOption)
RegisterConfigSourceKindOn contributes a kind to a caller's registry, which must already declare ConfigSourceDescriptor(kind).
func RegisterGlobalMiddleware ¶
func RegisterGlobalMiddleware(mw ...Middleware)
RegisterGlobalMiddleware contributes middleware applied to every feature command. Global middleware runs before feature-specific middleware.
func RegisterMiddleware ¶
func RegisterMiddleware(feature props.FeatureID, mw ...Middleware)
RegisterMiddleware contributes middleware for the commands of one feature to the default registry. Middleware is applied in registration order. Call it at init; the root snapshots the registry when it builds its chain.
func RegisterOn ¶ added in v0.43.0
func RegisterOn(r features.Registry, feature props.FeatureID, ips []InitialiserProvider, sps []SubcommandProvider, fps []FeatureFlag)
RegisterOn is Register against a caller's registry.
func RegisterRootCommands ¶ added in v0.43.0
func RegisterRootCommands(feature props.FeatureID, providers ...RootCommandProvider)
RegisterRootCommands contributes top-level commands for a feature to the default registry. A linked package (pkg/mcp) calls it from init so the root need not name the package.
func RegisterRootCommandsOn ¶ added in v0.43.0
func RegisterRootCommandsOn(r features.Registry, feature props.FeatureID, providers ...RootCommandProvider)
RegisterRootCommandsOn is RegisterRootCommands against a caller's registry. Nil providers contribute nothing.
func ReportSourceCredential ¶ added in v0.46.0
func ReportSourceCredential(b ConfigBootstrap, origin string)
ReportSourceCredential tells b which link of a slot's credential chain answered, when b listens.
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 RootCommandsIn ¶ added in v0.43.0
func RootCommandsIn(s features.Snapshot) map[props.FeatureID][]RootCommandProvider
RootCommandsIn is the root-command providers of every contributing feature.
func RunConfigSourceInit ¶ added in v0.46.0
func RunConfigSourceInit(ctx context.Context, p *props.Props, slot props.ConfigSource, dir string) error
RunConfigSourceInit configures one declared slot: its kind's initialiser asks for the settings and writes them under config.sources.<name> in the tool's config file in dir (spec 0204 D3). An override-only slot has nothing to ask, since the tool's own code builds it.
func RunForm ¶ added in v0.43.0
RunForm runs a huh form on the invocation's streams (spec 0198 D2). The accessible decision is the IO's, applied to the form here, because huh decides it per form from TERM=dumb and offers no way to ask. A stdin that is neither a terminal nor in accessible mode is refused before the form opens, with the accessible route in the hint. The hint names no answer flags, because not every command has them (#101).
func RunFormOn ¶ added in v0.43.0
RunFormOn is RunForm for a caller that holds the streams rather than the Props (the self-updater, built without them).
func SecretEchoMode ¶ added in v0.46.0
SecretEchoMode is the echo mode for a field that takes a secret. huh hides an accessible password by reading the terminal, which a piped stdin does not have; there it is read as a plain line, since nothing echoes on a pipe.
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 SetPinnedVersion ¶ added in v0.49.0
SetPinnedVersion pins the tool to version, so neither update nor the pre-run check moves it. An empty version clears the pin. Like the other markers it is a no-op when the config directory cannot be resolved.
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 StorageModeGroup ¶ added in v0.43.0
func StorageModeGroup(ctx context.Context, p *props.Props, mode *credentials.Mode, hide func() bool) *huh.Group
StorageModeGroup is the one storage-mode selector every credential wizard asks (spec 0198 D5): environment variable reference, OS keychain when a backend is linked and answers a probe, and a literal in the config file unless the process runs under CI. The probe takes the caller's context. The current mode is left as the caller set it, or defaulted to the recommended one; hide decides whether the page is asked at all.
func StrandedConfig ¶ added in v0.46.0
StrandedConfig returns the first of paths that names the tool's own config file, is absent, and has a file in another own format beside it: the file left in the old format and the one the tool now reads. Both are empty when nothing is stranded.
func SubcommandsIn ¶ added in v0.43.0
func SubcommandsIn(s features.Snapshot) map[props.FeatureID][]SubcommandProvider
SubcommandsIn is GetSubcommands over a snapshot.
func TimeSinceLast ¶ added in v0.43.0
TimeSinceLast returns the duration since the last update check or update, and whether one has been recorded at all.
func TrustProjectConfig ¶ added in v0.34.0
TrustProjectConfig records the current content of the project-local config file at path as trusted for the named tool. This is the explicit user action — the `config trust` command — that unlocks the file's security-sensitive keys.
func UntrustProjectConfig ¶ added in v0.34.0
UntrustProjectConfig removes any trust record for the file at path. It is a no-op (nil error) when the path was not trusted.
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 Chainer ¶ added in v0.43.0
Chainer wraps a command's RunE with the middleware that applies to its feature. The root owns one (spec 0199 D3); a test or a consumer hands in its own through root.WithChain.
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"`
// Gating marks a WARN that is a policy violation rather than an advisory,
// so it can fail a run under a warn threshold.
//
// Most warnings are advice: "no AI provider API keys configured" is a
// perfectly good state for a tool that does not use AI, and failing its
// pipeline over that would be absurd, which is exactly what happened when
// the exit code keyed on severity alone. A warning gates only when the
// check says the condition is a policy failure, and a check author has to
// opt in deliberately.
//
// It has no effect on a pass, a skip, or a fail: a failed check gates
// regardless, because there is nothing advisory about one.
Gating bool `json:"gating,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.FeatureID
// contains filtered or unexported fields
}
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 AnnotateMCP ¶ added in v0.43.0
AnnotateMCP applies hints to the embedded cobra command, the way ExcludeFromMCP stamps exposure. Generated commands call it after their exposure marker. Returns cmd for chaining; a nil *Command is a no-op.
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
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 ConfigBootstrap ¶ added in v0.46.0
type ConfigBootstrap interface {
View() *config.View
FS() config.FS
CodecFor(path string) (config.Codec, error)
}
ConfigBootstrap is what a factory is given beside its settings: the view it may read, which holds only the layers a repository cannot plant (embedded defaults, the tool's own files, the environment and flags, spec 0204 D5), the tool's config filesystem, and the codec a path's extension names among the formats the tool links (D2).
type ConfigCodec ¶ added in v0.46.0
ConfigCodec binds a linked format's codec to the file extensions it reads.
func ConfigCodecsIn ¶ added in v0.46.0
func ConfigCodecsIn(s features.Set) []ConfigCodec
ConfigCodecsIn returns the codecs of every enabled feature in s.
type ConfigKeyRecogniser ¶ added in v0.46.0
type ConfigKeyRecogniser struct {
// contains filtered or unexported fields
}
ConfigKeyRecogniser answers whether a config key is one the framework or the tool owns, at section grain: config validate does not call such a key unknown, and doctor does not call a variable that set one stray (spec 0205 D3).
func NewConfigKeyRecogniser ¶ added in v0.46.0
func NewConfigKeyRecogniser(p *props.Props) ConfigKeyRecogniser
NewConfigKeyRecogniser builds the recogniser for p's embedded assets and resolved features.
func (ConfigKeyRecogniser) CaseVariant ¶ added in v0.48.0
func (r ConfigKeyRecogniser) CaseVariant(key string) (string, bool)
CaseVariant returns the recognised key that key differs from only in case: a key the tool declares, or the framework key, which is all lower case. It is what an exact-mode tool's user most likely meant (spec 0209 D6).
func (ConfigKeyRecogniser) Recognises ¶ added in v0.46.0
func (r ConfigKeyRecogniser) Recognises(key string) bool
Recognises reports whether key's top-level section is a framework section or a declared credential root, or the tool declares key or an ancestor.
type ConfigSourceInitialiser ¶ added in v0.46.0
type ConfigSourceInitialiser func(p *props.Props, slot props.ConfigSource) Initialiser
ConfigSourceInitialiser builds the initialiser that asks for a slot's settings and writes them under config.sources.<slot name>. A kind is told the slot because a tool may declare the same kind twice.
func ConfigSourceInitialiserFor ¶ added in v0.46.0
func ConfigSourceInitialiserFor(kind string) ConfigSourceInitialiser
ConfigSourceInitialiserFor is the initialiser a shipped kind registers: it asks the kind's catalogue settings for the slot it is given.
type ConfigSourceKind ¶ added in v0.46.0
type ConfigSourceKind struct {
Kind string
Factory SourceFactory
Initialiser ConfigSourceInitialiser
WritableByDefault bool
}
ConfigSourceKind is what a kind's link package registers.
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 InitOptions ¶
type InitOptions struct {
Dir string
Clean bool
Initialisers []Initialiser
}
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.
func SettingsInitialiser ¶ added in v0.46.0
func SettingsInitialiser(slot props.ConfigSource, settings ...SourceSetting) Initialiser
SettingsInitialiser asks for a slot's settings and writes each answer under config.sources.<slot name>. An empty answer to an optional setting writes nothing, leaving any default the tool ships in place.
type InitialiserProvider ¶
type InitialiserProvider func(p *props.Props, flags *pflag.FlagSet) Initialiser
InitialiserProvider creates an Initialiser for one init run, reading the run's flags (the ones a FeatureFlag bound on the init command) rather than package state, so two roots never share a flag target (spec 0199 D3, #37). It returns nil when its feature asks to be skipped.
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 https://gitlab.com/phpboyscout/go-tool-base/-/wikis/specs/0089-mcp-command-exposure-gating.
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 MCPHints ¶ added in v0.43.0
type MCPHints struct {
Title string
ReadOnly *bool
Destructive *bool
Idempotent *bool
OpenWorld *bool
}
MCPHints are the MCP tool annotations a command declares about itself: a display title and the four behavioural hints. A nil hint states nothing and writes no key. Hints describe one command and do not inherit down a subtree, unlike MCPExposure.
func MCPDestructive ¶ added in v0.43.0
func MCPDestructive() MCPHints
MCPDestructive describes a command that may remove or rewrite state in a way the caller should confirm first.
func MCPHintsOf ¶ added in v0.43.0
MCPHintsOf reads cmd's own hints back. A key holding anything other than "true" or "false" is treated as unset rather than guessed at. Nil-safe.
func MCPLocalWrite ¶ added in v0.43.0
func MCPLocalWrite() MCPHints
MCPLocalWrite describes a command that mutates local state additively and can be repeated with the same arguments to the same effect.
func MCPOpenWorld ¶ added in v0.43.0
func MCPOpenWorld() MCPHints
MCPOpenWorld describes a command that reaches outside the tool (a release source, a provider, a wizard) and cannot promise the same result twice.
func MCPReadOnly ¶ added in v0.43.0
func MCPReadOnly() MCPHints
MCPReadOnly describes a command that reads and never mutates anything.
type Middleware ¶
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 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).
The Props used is the one the root pre-run stamped onto the command context when present, so a second root constructed in the same process reports through its OWN collector rather than the first root's (the registry is process-global and would otherwise bind the first root forever). The registration-time p is the fallback for commands that never entered the pre-run.
func WithTiming ¶
func WithTiming(l logger.Logger) Middleware
WithTiming returns middleware that logs command execution duration.
type MiddlewareChain ¶ added in v0.43.0
type MiddlewareChain struct {
// contains filtered or unexported fields
}
MiddlewareChain is the default Chainer: the root's built-in middleware first, then the Set's global contributions, then the feature's own, each in registration order. It is exported so a consumer can embed it.
func NewMiddlewareChain ¶ added in v0.43.0
func NewMiddlewareChain(builtin []Middleware, set features.Set) *MiddlewareChain
NewMiddlewareChain builds a chain from the root's built-in middleware and the contributions of the enabled features in set.
type ReleaseChannel ¶ added in v0.45.0
type ReleaseChannel interface {
// Latest is the newest release the channel offers.
Latest(ctx context.Context) (forge.Release, error)
// ByTag is one named release.
ByTag(ctx context.Context, tag string) (forge.Release, error)
// List is up to limit releases, newest first; limit <= 0 is the channel's
// natural first page (the forge.Provider contract).
List(ctx context.Context, limit int) ([]forge.Release, error)
// Download opens an asset's bytes. The string is a redirect the caller
// refuses to follow, as the forge providers report one.
Download(ctx context.Context, asset forge.ReleaseAsset) (io.ReadCloser, string, error)
// Checksums is the checksums manifest for rel, bounded by maxBytes, or an
// error wrapping forge.ErrNotSupported when the channel has no direct
// route to it and the caller should look among the assets.
Checksums(ctx context.Context, rel forge.Release, maxBytes int64) ([]byte, error)
// Signature is the detached signature over the checksums manifest, with
// the same not-supported contract.
Signature(ctx context.Context, rel forge.Release, maxBytes int64) ([]byte, error)
}
ReleaseChannel is what SelfUpdater needs from wherever releases come from (spec 0203 D4): a forge's release objects today, a static location's pointer and manifests once that branch lands. It is deliberately the exact set of calls the updater makes and no more, with the release and asset values kept as forge's small interfaces so the updater's verification path is untouched; a non-forge branch satisfies those interfaces with its own values.
type RootCommandProvider ¶ added in v0.43.0
RootCommandProvider builds a top-level command for the root, or returns nil when its feature has nothing to add for this tool. The root registers what it returns and stamps it with the contributing feature when it carries no stamp of its own (spec 0202 D2).
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) ReleaseBefore ¶ added in v0.49.0
ReleaseBefore is the highest released version below current, among the newest releases the channel lists. From a stable version, prereleases are not candidates. Version order rather than the static channel's publish order, so a backport published later is still found by its 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 ¶
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 SourceCloserRegistrar ¶ added in v0.46.0
SourceCloserRegistrar is what the root's bootstrap implements so a factory can hand the store a client it built, for the store to close with itself.
type SourceCredentialReporter ¶ added in v0.46.0
type SourceCredentialReporter interface {
ReportCredential(origin string)
}
SourceCredentialReporter is what the root's bootstrap implements so a factory can say which link of its credential chain answered (spec 0204 D10). It is separate from ConfigBootstrap so a test's fake needs nothing.
type SourceFactory ¶ added in v0.46.0
type SourceFactory func(ctx context.Context, settings config.Reader, b ConfigBootstrap) (config.Backend, error)
SourceFactory builds one slot's backend from its settings, the config.sources.<name> subtree of the bootstrap view. Settings are nil for an override of a slot nobody configured.
type SourceKindOption ¶ added in v0.46.0
type SourceKindOption func(*ConfigSourceKind)
SourceKindOption adjusts a kind's registration.
func WritableByDefault ¶ added in v0.46.0
func WritableByDefault() SourceKindOption
WritableByDefault makes a kind's slots writable unless they say otherwise, which only the keychain is (spec 0204 D12).
type SourceSetting ¶ added in v0.46.0
type SourceSetting struct {
Key string
Title string
Description string
// Default fills the answer when nothing is configured yet.
Default string
Required bool
}
SourceSetting is one setting a kind's initialiser asks for.
func ConfigSourceSettings ¶ added in v0.46.0
func ConfigSourceSettings(kind, tool, slot string) []SourceSetting
ConfigSourceSettings returns what `<tool> init config <slot>` asks for a shipped source kind, each written under config.sources.<slot>. It is nil for an override-only or unknown kind, whose own code reads its settings. The catalogue lives here rather than in each kind's package so the generator can describe a slot without linking the kind and its SDK.
type SubcommandProvider ¶
SubcommandProvider is a function that creates a slice of cobra subcommands.
type UpdaterOption ¶
type UpdaterOption func(*SelfUpdater)
UpdaterOption configures a SelfUpdater.
func WithIO ¶ added in v0.43.0
func WithIO(io props.IO) UpdaterOption
WithIO runs the updater's prompt on io, the invocation's streams (Props.GetIO()). NewUpdater takes them from its Props; the offline updater is built without Props, so its caller passes them.
Source Files
¶
- checksum.go
- command.go
- config_codec.go
- config_key_recogniser.go
- config_keys.go
- config_source.go
- config_source_settings.go
- context.go
- doc.go
- env_origin.go
- env_variable.go
- form.go
- form_refocus.go
- format_change.go
- group.go
- init.go
- mcp_exposure.go
- mcp_hints.go
- middleware.go
- middleware_builtin.go
- providers.go
- registry.go
- release_channel.go
- release_channel_static.go
- trust.go
- update.go
- update_refusal.go
- update_rollback.go
- update_signature.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package ai provides the interactive AI-provider setup initialiser.
|
Package ai provides the interactive AI-provider setup initialiser. |
|
Package flags is GTB's wiring for dynamic feature flags (spec 0199 D10, D11): a features.Backend over the tool's own config store, so a service's flags can be flipped by editing its config with no vendor at all, and the controls registration that gives any backend the controller's lifecycle.
|
Package flags is GTB's wiring for dynamic feature flags (spec 0199 D10, D11): a features.Backend over the tool's own config store, so a service's flags can be flipped by editing its config with no vendor at all, and the controls registration that gives any backend the controller's lifecycle. |
|
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 keychain links the OS keychain credential backend and declares it as a feature.
|
Package keychain links the OS keychain credential backend and declares it as a feature. |
|
Package telemetry registers the telemetry initialiser with the setup system.
|
Package telemetry registers the telemetry initialiser with the setup system. |