@get-bb/plugin-sdk 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ declare const RESERVED_BB_CLI_COMMANDS: readonly string[];
19
19
  /**
20
20
  * How completely a provider can clone one of its sessions — the single
21
21
  * vocabulary shared by the provider declaration
22
- * (`bb.agents.experimental_registerProvider`), the server→daemon
22
+ * (`bb.providers.register`), the server→daemon
23
23
  * `bridgeLaunch`, and the bridge's `initialize` handshake.
24
24
  *
25
25
  * - `"none"`: sessions cannot be cloned at all.
@@ -35,6 +35,16 @@ declare const RESERVED_BB_CLI_COMMANDS: readonly string[];
35
35
  declare const PROVIDER_FORK_VALUES: readonly ["none", "tip", "checkpoint"];
36
36
  type ProviderFork = (typeof PROVIDER_FORK_VALUES)[number];
37
37
 
38
+ /**
39
+ * A value that survives a JSON round trip without coercion or data loss.
40
+ *
41
+ * Host boundaries still validate values at runtime because TypeScript cannot
42
+ * exclude non-finite numbers and plugin bundles can bypass static types.
43
+ */
44
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
45
+ [key: string]: JsonValue;
46
+ };
47
+
38
48
  /**
39
49
  * The validator-neutral subset of Standard Schema v1 used by plugin RPC.
40
50
  * Zod 4 schemas implement this interface directly; other validators can do
@@ -98,6 +108,7 @@ type PluginSettingDescriptor = {
98
108
  default?: string;
99
109
  };
100
110
  type PluginSettingDescriptors = Record<string, PluginSettingDescriptor>;
111
+ type PluginSettingValue = string | boolean;
101
112
  interface PluginCliOutputLimitError {
102
113
  code: "plugin_cli_output_too_large";
103
114
  message: string;
@@ -139,10 +150,23 @@ type PluginProviderComposerAction = "goal" | "plan";
139
150
  * live session (picker rendering, route gating, cross-plugin tool
140
151
  * composition — including with the host offline). Every boolean is a
141
152
  * provider-native fact — the provider implements the feature; the flag only
142
- * tells external consumers it exists. Everything else is a handshake fact the
143
- * bridge reports at `initialize`, where it cannot drift from behavior.
153
+ * tells external consumers it exists. Session-behavior facts remain handshake
154
+ * capabilities reported by the running bridge. Sessionless maintenance
155
+ * methods are declared here so callers can decide whether to probe without
156
+ * starting the bridge first.
144
157
  */
145
158
  interface PluginProviderCapabilities {
159
+ /** The provider bridge implements the sessionless `provider/health`
160
+ * request. This is host-local readiness, not a network health check. */
161
+ experimental_providerHealth: boolean;
162
+ /** The provider exposes subscription usage through the sessionless
163
+ * `provider/usage` request. False means callers skip the request and usage
164
+ * settings omit the provider. A shared bridge that declares true may still
165
+ * report usage unavailable for one provider id or return no windows. */
166
+ experimental_providerUsage: boolean;
167
+ /** The provider bridge implements `provider/installation/status` and
168
+ * `provider/installation/run` for host-local installation management. */
169
+ experimental_providerInstallation: boolean;
146
170
  /** The provider accepts a fast/priority service-tier choice — shows the
147
171
  * service-tier toggle in the picker. */
148
172
  supportsServiceTier: boolean;
@@ -167,9 +191,6 @@ interface PluginProviderCapabilities {
167
191
  /** The provider stores a thread name of its own, so BB forwards renames to
168
192
  * it. */
169
193
  supportsThreadRename: boolean;
170
- /** The provider can run BB's Workflow tools — gates the workflows opt-in on
171
- * new threads. */
172
- supportsWorkflows: boolean;
173
194
  /** Permission modes the provider can actually run in. Non-empty, no
174
195
  * duplicates. */
175
196
  permissionModes: readonly PluginProviderPermissionMode[];
@@ -177,20 +198,115 @@ interface PluginProviderCapabilities {
177
198
  * {@link PluginProviderReasoningLevel}). Non-empty, no duplicates. */
178
199
  reasoningLevels: readonly PluginProviderReasoningLevel[];
179
200
  }
201
+ /**
202
+ * Provider copy core surfaces render from per-provider tables today (usage
203
+ * banners, sign-in hints, the mobile picker, the agent guide). Declared once
204
+ * here so no core surface keys copy on a provider id. Mirrors
205
+ * `ProviderStrings` in `@bb/domain`, which is the client projection.
206
+ */
207
+ interface PluginProviderStrings {
208
+ /** How to sign in on the host ("Run `claude` on the machine to sign in."). */
209
+ signInHint: string;
210
+ /** Shown when a session's credentials expired. */
211
+ expiredHint: string;
212
+ /** Where to install the agent. */
213
+ installUrl: string;
214
+ /** Brand prefix stripped from model display names ("Claude "). */
215
+ brandPrefix?: string;
216
+ /** Plan-mode banner copy for providers that declare the `plan` action. */
217
+ planModeCopy?: string;
218
+ /** Per-theme tint for the provider icon. */
219
+ iconTint?: {
220
+ light: string;
221
+ dark: string;
222
+ };
223
+ }
224
+ /**
225
+ * One selectable option for a picker — a service tier or a reasoning level.
226
+ * `id` is the wire value the bridge receives; `label` is what the picker
227
+ * shows. Declared lists are the cold-cache fallback; `model/list` is precise
228
+ * per model.
229
+ */
230
+ interface PluginProviderOptionDescriptor {
231
+ id: string;
232
+ label: string;
233
+ description?: string;
234
+ }
235
+ /**
236
+ * Payload schemas for one extension kind this provider emits, keyed by the
237
+ * kind's local name (the server prefixes the plugin id to form the
238
+ * namespaced `"<pluginId>/<name>"`). `item` validates `item.open` payloads
239
+ * with `type: "extension"`, `state` validates `extension.state` payloads;
240
+ * each is optional so a kind can be item-only or state-only. Schemas are
241
+ * Standard Schema v1 validators (zod 4 schemas qualify).
242
+ */
243
+ interface PluginProviderExtensionKindDeclaration {
244
+ item?: StandardSchemaV1;
245
+ state?: StandardSchemaV1;
246
+ }
247
+ /**
248
+ * Per-command context handed to
249
+ * {@link PluginProviderDeclaration.experimental_deriveProviderOptions}. The
250
+ * server builds one for every session and turn command it dispatches on a
251
+ * thread of this provider.
252
+ */
253
+ interface PluginProviderOptionsContext {
254
+ threadId: string;
255
+ projectId: string;
256
+ /** The resolved model id for this command. */
257
+ model: string;
258
+ /** BB's permission mode for this command (already clamped to the host). */
259
+ permissionMode: PluginProviderPermissionMode;
260
+ /**
261
+ * `"plan"` when the prompt entered plan mode through this provider's
262
+ * declared `plan` composer action. Absent for an ordinary prompt — plan
263
+ * mode is a BB prompt mode, so the bridge maps it onto whatever the agent
264
+ * calls it natively.
265
+ */
266
+ promptMode?: "plan";
267
+ /**
268
+ * This plugin's own settings values (`bb.settings.define`), read at call
269
+ * time. Secret settings are omitted — provider options ride the daemon
270
+ * wire and are persisted with the session, so a secret must never be
271
+ * derived into them.
272
+ */
273
+ settings: Readonly<Record<string, PluginSettingValue | undefined>>;
274
+ }
275
+ /**
276
+ * One cold-cache fallback model. The provider's live `model/list` result is
277
+ * the only real model source; this list stands in only while no probe has
278
+ * completed, or when a probe fails transiently, so the picker is not empty.
279
+ * `id` is the wire model id the bridge receives.
280
+ */
281
+ interface PluginProviderFallbackModel {
282
+ id: string;
283
+ /** Picker display name ("Opus 5 (1M)"). */
284
+ displayName: string;
285
+ description: string;
286
+ /** Reasoning levels this model supports, lowest to highest. Non-empty. */
287
+ supportedReasoningEfforts: readonly {
288
+ reasoningEffort: PluginProviderReasoningLevel;
289
+ description: string;
290
+ }[];
291
+ /** Must be one of `supportedReasoningEfforts`. */
292
+ defaultReasoningEffort: PluginProviderReasoningLevel;
293
+ /** Exactly one entry in the list is the default. */
294
+ isDefault: boolean;
295
+ }
180
296
  /**
181
297
  * One provider this plugin contributes to BB's provider registry.
182
298
  *
183
299
  * Ids are stable public identifiers — thread rows and routes reference them —
184
300
  * and are collision-rejected: a declaration whose id matches another plugin's
185
- * live registration, or reserves a first-party provider it does not own, is
186
- * refused. Registrations are replaced wholesale on plugin reload, like every
187
- * other plugin surface.
301
+ * live registration is refused; the first registration wins and no id is
302
+ * reserved ahead of time. Registrations are replaced wholesale on plugin
303
+ * reload, like every other plugin surface.
188
304
  *
189
- * A declaration is metadata only. The implementation is the plugin's own
190
- * provider bridge, named by `bb.providerBridge` in the manifest and built into
191
- * the artifact BB ships to hosts declaring a provider without one is
192
- * refused, because the picker entry would exist and no turn on it could ever
193
- * run.
305
+ * A declaration owns the provider's static metadata and bridge options. The
306
+ * executable implementation is the plugin's own provider bridge, named by
307
+ * `bb.providerBridge` in the manifest and built into the artifact BB ships to
308
+ * hosts declaring a provider without one is refused, because the picker
309
+ * entry would exist and no turn on it could ever run.
194
310
  */
195
311
  interface PluginProviderDeclaration {
196
312
  /** Stable provider id: 2–64 characters of lowercase letters, digits, and
@@ -199,6 +315,12 @@ interface PluginProviderDeclaration {
199
315
  id: string;
200
316
  /** Picker display name: 1–80 characters, non-blank. */
201
317
  displayName: string;
318
+ /**
319
+ * Optional grouping key (same grammar as `id`) for providers that share a
320
+ * family — the ACP agents, for example — so clients can group them without
321
+ * parsing a prefix out of the id. Grouping only: no policy keys on it.
322
+ */
323
+ experimental_family?: string;
202
324
  /**
203
325
  * Optional picker icon, in the same grammar as `bb.branding.icon`: either a
204
326
  * named host glyph (`"Zap"`) or a plugin-relative path starting with `"./"`
@@ -206,12 +328,71 @@ interface PluginProviderDeclaration {
206
328
  * — no leading "/", no ".." segments, no backslashes.
207
329
  */
208
330
  icon?: string;
331
+ /**
332
+ * Provider-owned static options passed opaquely to this plugin's bridge on
333
+ * every sessionless and session request. Core validates that the value is
334
+ * JSON, but does not interpret its keys. This is intended for immutable
335
+ * launch metadata shared by every host (for example an ACP command spec),
336
+ * not user or machine configuration.
337
+ */
338
+ experimental_bridgeOptions?: Readonly<Record<string, JsonValue>>;
339
+ /**
340
+ * Whether the provider is always listed or only listed on hosts where its
341
+ * bridge reports it installed. Defaults to `"always"`.
342
+ */
343
+ experimental_visibility?: "always" | "installed";
209
344
  /** Pre-session capability facts (see the declaration tests on
210
345
  * {@link PluginProviderCapabilities}). */
211
346
  capabilities: PluginProviderCapabilities;
212
347
  /** Composer actions this provider supports. No duplicates; may be empty
213
348
  * (the universal skills typeahead is implicit). */
214
349
  composerActions: readonly PluginProviderComposerAction[];
350
+ /** Provider copy for core surfaces ({@link PluginProviderStrings}). */
351
+ experimental_strings?: PluginProviderStrings;
352
+ /** Service tiers this provider accepts, as picker options. Non-empty when
353
+ * present, unique ids. The coarse `capabilities.supportsServiceTier` stays
354
+ * until WS2a stabilizes. */
355
+ experimental_serviceTiers?: readonly PluginProviderOptionDescriptor[];
356
+ /** Reasoning levels as picker options with labels, beside the coarse
357
+ * `capabilities.reasoningLevels` ladder (ids only). Non-empty when present,
358
+ * unique ids. WS2a merges the two. */
359
+ experimental_reasoningLevels?: readonly PluginProviderOptionDescriptor[];
360
+ /** Extension kinds this provider's bridge may emit, keyed by local name
361
+ * (`[a-z0-9-]+`). The server validates extension payloads against these
362
+ * schemas at ingest and persists a `provider/unhandled` on a miss. */
363
+ experimental_extensionKinds?: Readonly<Record<string, PluginProviderExtensionKindDeclaration>>;
364
+ /**
365
+ * Cold-cache fallback models ({@link PluginProviderFallbackModel}). The
366
+ * server offers them only while a model probe has not completed or failed
367
+ * transiently; the live `model/list` result always replaces them. Ids must
368
+ * be unique and exactly one entry must be the default.
369
+ */
370
+ experimental_models?: {
371
+ fallback: readonly PluginProviderFallbackModel[];
372
+ };
373
+ /**
374
+ * Daemon environment variables this provider's bridge may read. Provider
375
+ * processes are spawned with every inherited `BB_*` variable stripped, so a
376
+ * bridge that honors an operator override (a CLI path, say) names it here
377
+ * and the daemon forwards exactly those variables. Names are
378
+ * `[A-Z_][A-Z0-9_]*`, at most 32.
379
+ */
380
+ experimental_env?: {
381
+ passthrough: readonly string[];
382
+ };
383
+ /**
384
+ * Derive this provider's opaque per-command options. Called synchronously
385
+ * by the server for every session and turn command on a thread of this
386
+ * provider, with the command's {@link PluginProviderOptionsContext}; the
387
+ * returned JSON object reaches this plugin's bridge as
388
+ * `options.providerOptions`, merged over `experimental_bridgeOptions`. Core
389
+ * never interprets its keys — this is where a provider's own knobs (memory,
390
+ * native subagents, a native plan flag) travel instead of on the shared
391
+ * execution contract. A throw fails the command with the plugin named, so
392
+ * a buggy hook cannot silently run a turn with default knobs. Must be fast:
393
+ * it sits on the turn-submit path.
394
+ */
395
+ experimental_deriveProviderOptions?: (context: PluginProviderOptionsContext) => Readonly<Record<string, JsonValue>>;
215
396
  }
216
397
  type PluginMentionTrigger = "!" | "#" | "$" | "@" | "~";
217
398
 
@@ -237,6 +418,7 @@ declare const PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS = 4096;
237
418
  declare const PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES: number;
238
419
  declare const MENTION_PROVIDER_ID_PATTERN: RegExp;
239
420
  declare const PROVIDER_ID_PATTERN: RegExp;
421
+ declare const PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES: number;
240
422
  declare const SETTING_KEY_PATTERN: RegExp;
241
423
  /**
242
424
  * Validate freeform descriptors from plugin code and merge them into the
@@ -254,13 +436,24 @@ declare const PLUGIN_PROVIDER_PERMISSION_MODE_VALUES: readonly ["accept-edits",
254
436
  declare const PLUGIN_PROVIDER_REASONING_LEVEL_VALUES: readonly ["none", "low", "medium", "high", "xhigh", "ultracode", "max", "ultra"];
255
437
  declare const PLUGIN_PROVIDER_COMPOSER_ACTION_VALUES: readonly ["plan", "goal"];
256
438
  /**
257
- * Validate one `bb.agents.experimental_registerProvider` declaration. Plugin
439
+ * Validate one `bb.providers.register` declaration. Plugin
258
440
  * sources are untyped at runtime, so every field is checked; the production
259
441
  * host and the fake host both call this, so they accept and reject provider
260
442
  * declarations identically. Throws a descriptive error on the first problem;
261
443
  * returns a normalized, deeply frozen copy carrying only contract fields.
262
444
  */
263
445
  declare function validatePluginProviderDeclaration(declaration: PluginProviderDeclaration): PluginProviderDeclaration;
446
+ /**
447
+ * Run a declaration's `experimental_deriveProviderOptions` hook for one
448
+ * command and validate its result as a bounded, plain-JSON object — the same
449
+ * rules as `experimental_bridgeOptions`, because the result rides the same
450
+ * wire slot. Shared by the real host and the fake so a hook that works in
451
+ * tests works in production.
452
+ */
453
+ declare function deriveValidatedProviderOptions(args: {
454
+ declaration: PluginProviderDeclaration;
455
+ context: Parameters<NonNullable<PluginProviderDeclaration["experimental_deriveProviderOptions"]>>[0];
456
+ }): Readonly<Record<string, JsonValue>>;
264
457
  declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
265
458
  declare function readRpcMethodContract(method: string, value: unknown): PluginRpcMethodContract;
266
459
  /** Duck-typed zod detection: plugin sources may carry their own zod copy,
@@ -290,4 +483,4 @@ declare function enforcePluginCliOutputLimit(result: Omit<PluginCliExecutionResu
290
483
  */
291
484
  declare function adoptHttpRouteResponse(value: unknown): Response;
292
485
 
293
- export { AGENT_TOOL_NAME_PATTERN, BACKGROUND_NAME_PATTERN, CLI_COMMAND_NAME_PATTERN, KV_VALUE_MAX_BYTES, MENTION_PROVIDER_ID_PATTERN, PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_SELECTION_MAX_IDS, PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS, PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES, PLUGIN_HTTP_METHODS, PLUGIN_MENTION_TRIGGER_VALUES, PLUGIN_PROVIDER_COMPOSER_ACTION_VALUES, PLUGIN_PROVIDER_DISPLAY_NAME_MAX_CHARS, PLUGIN_PROVIDER_PERMISSION_MODE_VALUES, PLUGIN_PROVIDER_REASONING_LEVEL_VALUES, PROVIDER_ID_PATTERN, RESERVED_AGENT_TOOL_NAMES, RESERVED_BB_CLI_COMMANDS, RPC_METHOD_PATTERN, SETTING_KEY_PATTERN, adoptHttpRouteResponse, assertNoRecursiveJsonSchemaReferences, enforcePluginCliOutputLimit, isPluginMentionTrigger, isStandardSchema, isZodSchemaLike, normalizeMentionProviderTriggers, readRpcMethodContract, registerSettingDescriptors, summarizeParseIssues, validatePluginProviderDeclaration, validateSettingsUpdate };
486
+ export { AGENT_TOOL_NAME_PATTERN, BACKGROUND_NAME_PATTERN, CLI_COMMAND_NAME_PATTERN, KV_VALUE_MAX_BYTES, MENTION_PROVIDER_ID_PATTERN, PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_SELECTION_MAX_IDS, PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS, PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES, PLUGIN_HTTP_METHODS, PLUGIN_MENTION_TRIGGER_VALUES, PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES, PLUGIN_PROVIDER_COMPOSER_ACTION_VALUES, PLUGIN_PROVIDER_DISPLAY_NAME_MAX_CHARS, PLUGIN_PROVIDER_PERMISSION_MODE_VALUES, PLUGIN_PROVIDER_REASONING_LEVEL_VALUES, PROVIDER_ID_PATTERN, RESERVED_AGENT_TOOL_NAMES, RESERVED_BB_CLI_COMMANDS, RPC_METHOD_PATTERN, SETTING_KEY_PATTERN, adoptHttpRouteResponse, assertNoRecursiveJsonSchemaReferences, deriveValidatedProviderOptions, enforcePluginCliOutputLimit, isPluginMentionTrigger, isStandardSchema, isZodSchemaLike, normalizeMentionProviderTriggers, readRpcMethodContract, registerSettingDescriptors, summarizeParseIssues, validatePluginProviderDeclaration, validateSettingsUpdate };