Create an instance of the service provider with the specified details.
the priority of the service.
the ConfigurationServiceProvider whose config file backs this provider's data - an internal wiring reference, never exposed further.
optionally provide a KeyValueService implementation: configurationServiceProvider.configEnabled must be true in this case
optionally enable OS-native secret storage via Bun.secrets: configurationServiceProvider.configEnabled must be true in this case
ReadonlykeyReadonlysecretReadonlyserviceThe ID which identifies the service provided.
ReadonlyserviceUsed to determine the order in which multiple service instances will be initialised. Higher values will be initialised before lower values.
Return a Context which delegates every lookup to context unchanged, except
getServiceById(KEY_VALUE_SERVICE_ID), which resolves to the scope-bound instance from
getScopedKeyValueService for the given scope. Used by runner.ts to give each
command/service/task a KeyValueService isolated to its own scope, invisibly at the call site.
Returns context itself, unchanged, if neither keyValueServiceEnabled nor
secretServiceEnabled is set.
Also forwards addServiceInstance, even though it is not part of the Context
interface: runner.ts applies this same scoping to every ServiceProvider's initService()
call (scope "service"), and PluginServiceProvider.initService() relies on casting its
received context to DefaultContext to register services discovered from plugins at
runtime - a capability every ServiceProvider already had before this scoping was
introduced, since initService() always received the real DefaultContext directly.
Return the KeyValueService bound to the given scope, creating (and caching) it on first request. The returned instance is permanently bound to that scope's data and secret prefix - it is never re-pointed, so it may be held and used for as long as its owning command/service/task is alive without racing any other scope's window.
whether scopeKey is a command name or a service/task ID.
the command name or service/task ID to scope the key-value data to.
Return ServiceInfo containing the service and any commands it provides which should be registered in the CLI.
Initialise the service. This will be invoked AFTER any GlobalModifierCommand provided in the ServiceInfo have been invoked (if specified as CLI arguments or CLI configuration).
NOTE: Other services within the provided context will only have been initialised if they have a higher servicePriority value than the current service.
Provides a generic, per-scope key-value store for commands and services (KeyValueService).
The underlying data is read from/written to the same configuration file managed by ConfigurationServiceProvider - see ConfigurationServiceProvider.getKeyValueData and ConfigurationServiceProvider.flushIfDirty, reached via a direct constructor reference wired up by
BaseCLI(never via Context, since that would expose config-file read/write access more broadly than intended).Its
serviceIdis KEY_VALUE_SERVICE_ID and its ServiceInfo.service is a placeholder (UnreachableKeyValueService) - real access always goes through a per-consumer decorated Context from getContextForScope, applied byrunner.ts.Any node within a value passed to KeyValueService.set can be wrapped in Secret - at any depth - to have that node, and only that node, stored as an OS-native secret. When a node is wrapped in Secret, its value (of any shape) is JSON-serialized and stored as a single OS-native secret via Bun.secrets, with a sentinel value of the format
__SECRET__:<bun_secret_name>substituted in its place in the structure that gets stored in the config file. Everything else in the value is stored as plain (unencrypted) config data. The sentinel prefix__SECRET__:is reserved and must not be used for regular key-value data.Independently of how a value was written, KeyValueService.get recursively resolves any string leaf - at any depth within the retrieved value - which starts with the sentinel prefix, via the OS secret store. This means a secret reference may also be hand-embedded (nested arbitrarily deep) directly within a plain, non-secret value in the config file.
Secret support requires
secretServiceEnabled=truein the constructor (which also requireskeyValueServiceEnabled=trueon the ConfigurationServiceProvider to have config enabled).As an example of the underlying config file structure: