@get-bb/plugin-sdk 0.4.14 → 0.4.16
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.
- package/README.md +3 -3
- package/bundled-types/bb-plugin-sdk-ai-services.d.ts +141 -0
- package/bundled-types/bb-plugin-sdk-app.d.ts +144 -21
- package/bundled-types/bb-plugin-sdk-host.d.ts +479 -2
- package/bundled-types/bb-plugin-sdk-internal-composer-customization-validation.d.ts +10 -1
- package/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +339 -32
- package/bundled-types/bb-plugin-sdk-internal-plugin-app-collector.d.ts +2 -1
- package/bundled-types/bb-plugin-sdk-provider-bridge-acp.d.ts +807 -0
- package/bundled-types/bb-plugin-sdk-provider-bridge-testing.d.ts +1742 -211
- package/bundled-types/bb-plugin-sdk-provider-bridge.d.ts +2985 -2442
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +4 -3
- package/bundled-types/bb-plugin-sdk-testing.d.ts +551 -9
- package/bundled-types/bb-plugin-sdk.d.ts +1335 -1350
- package/dist/ai-services.js +91 -0
- package/dist/app.js +2 -2
- package/dist/host.js +14547 -1
- package/dist/internal/composer-customization-validation.js +11 -0
- package/dist/internal/host-policy.js +656 -91
- package/dist/internal/plugin-app-collector.js +58 -14
- package/dist/provider-bridge-acp.js +9753 -0
- package/dist/provider-bridge-testing.js +3355 -1771
- package/dist/provider-bridge-worker-entry.mjs +917 -0
- package/dist/provider-bridge.js +2255 -3718
- package/dist/replay-provider-child.mjs +650 -0
- package/dist/testing/app.js +63 -19
- package/dist/testing/index.js +803 -115
- package/package.json +14 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { ReactNode, ComponentType } from 'react';
|
|
9
9
|
import { RenderResult } from '@testing-library/react';
|
|
10
|
-
import { PluginHomepageSectionRegistration, PluginSettingsSectionRegistration, PluginNavPanelRegistration, PluginThreadPanelActionRegistration, PluginNewThreadPanelActionRegistration, ComposerCustomization, PluginPendingInteractionRegistration, PluginSidebarFooterActionRegistration, PluginThreadListRegistration, PluginThreadHeaderActionRegistration, PluginFileOpenerRegistration, PluginSourceCodeRendererRegistration, PluginDiffRendererRegistration, PluginMessageDirectiveRegistration, PluginMessageActionRegistration, PluginProviderIconRegistration, PluginContentScriptRegistration, PluginComposerScope, PluginComposerTextEffect, PluginComposerMention, PluginComposerThreadRowStatus, ExperimentalOpenFixedTabOptions, JsonValue, BbNavigate, ExperimentalFileOpenOptions, PluginAppDefinition, PluginRpcContract, StandardSchemaV1InferInput, PluginRpcResult, PluginRealtimeConnectionState, PluginSidebarThreadsState, PluginProvidersState, PluginSidebarPullRequest, PluginSidebarThreadActions } from '@get-bb/plugin-sdk';
|
|
10
|
+
import { PluginHomepageSectionRegistration, PluginSettingsSectionRegistration, PluginNavPanelRegistration, PluginThreadPanelActionRegistration, PluginNewThreadPanelActionRegistration, ComposerCustomization, PluginPendingInteractionRegistration, PluginSidebarFooterActionRegistration, PluginThreadListRegistration, PluginThreadHeaderActionRegistration, PluginFileOpenerRegistration, PluginSourceCodeRendererRegistration, PluginDiffRendererRegistration, PluginMessageDirectiveRegistration, PluginMessageActionRegistration, PluginProviderIconRegistration, PluginTimelineRendererRegistration, PluginContentScriptRegistration, PluginComposerScope, PluginComposerTextEffect, PluginComposerMention, PluginComposerThreadRowStatus, ExperimentalOpenFixedTabOptions, JsonValue, BbNavigate, ExperimentalFileOpenOptions, PluginAppDefinition, PluginRpcContract, StandardSchemaV1InferInput, PluginRpcResult, PluginRealtimeConnectionState, PluginSidebarThreadsState, PluginProvidersState, PluginSidebarPullRequest, PluginSidebarThreadActions } from '@get-bb/plugin-sdk';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* `@get-bb/plugin-sdk/testing/app` — the frontend plugin test harness. Tests a
|
|
@@ -60,7 +60,7 @@ type NavigateCall = {
|
|
|
60
60
|
method: "openThreadPanel";
|
|
61
61
|
options: Parameters<BbNavigate["openThreadPanel"]>[0];
|
|
62
62
|
} | {
|
|
63
|
-
method: "
|
|
63
|
+
method: "openUrl";
|
|
64
64
|
url: string;
|
|
65
65
|
} | {
|
|
66
66
|
method: "experimental_openFilePreview";
|
|
@@ -124,6 +124,7 @@ interface CapturedPluginApp {
|
|
|
124
124
|
messageDirectives: PluginMessageDirectiveRegistration[];
|
|
125
125
|
messageActions: PluginMessageActionRegistration[];
|
|
126
126
|
providerIcons: PluginProviderIconRegistration[];
|
|
127
|
+
timelineRenderers: PluginTimelineRendererRegistration[];
|
|
127
128
|
contentScripts: PluginContentScriptRegistration[];
|
|
128
129
|
}
|
|
129
130
|
type PluginAppModule = {
|
|
@@ -213,7 +214,7 @@ interface RenderSlotOptions<Contract extends PluginRpcContract = PluginRpcContra
|
|
|
213
214
|
sidebarPullRequests?: Record<string, PluginSidebarPullRequest>;
|
|
214
215
|
/** Host acceptance for `useBbNavigate().openThreadPanel`. */
|
|
215
216
|
openThreadPanel?: (options: Parameters<BbNavigate["openThreadPanel"]>[0]) => boolean;
|
|
216
|
-
/** Host acceptance for URL intents from the hook or `
|
|
217
|
+
/** Host acceptance for URL intents from the hook or `UrlLink`. */
|
|
217
218
|
openUrl?: (url: string) => boolean;
|
|
218
219
|
/** Host acceptance for preview intents from the hook or file link. */
|
|
219
220
|
openFilePreview?: (options: ExperimentalFileOpenOptions) => boolean;
|
|
@@ -5,7 +5,488 @@
|
|
|
5
5
|
// Confused by the API, or need a symbol that isn't here? Clone the BB repo
|
|
6
6
|
// and read the real source: https://github.com/get-bb/bb
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { BbPluginApi, PluginSettingValue as PluginSettingValue$1, PluginSharedPortTunnelIdentity, PluginAgentToolPresentation, PluginAgentToolContext, PluginAgentToolResult, PluginCliCommandInfo, PluginCliContext, PluginCliResult, PluginHttpAuthMode, PluginHttpHandler, PluginMentionTrigger, PluginMentionSearchContext, PluginMentionItem, JsonValue as JsonValue$1, PluginCliExecutionResult, PluginThreadEventName, PluginThreadEventPayloads, PluginAgentConfigurationContext, PluginSettingDescriptors, PluginAgentConfiguration, PluginAiServiceDeclaration, PluginInteractionRequest } from '@get-bb/plugin-sdk';
|
|
10
|
+
|
|
11
|
+
/** Input-form entry: a path, or a path with options. */
|
|
12
|
+
declare const providerNativeRootInputSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
13
|
+
ancestors: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
namePrefix: z.ZodOptional<z.ZodString>;
|
|
15
|
+
path: z.ZodString;
|
|
16
|
+
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
skipIfManifest: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, z.core.$strict>]>;
|
|
19
|
+
/**
|
|
20
|
+
* One provider-native root as a plugin declares it: a path, or a path with
|
|
21
|
+
* options. `recursive`: the agent scans nested skill directories. `ancestors`
|
|
22
|
+
* (project roots only): scan the same relative directory in every ancestor of
|
|
23
|
+
* the workspace up to the repository root. `namePrefix`: prepended to every
|
|
24
|
+
* name under the root, a vendor plugin's `plugin-name:`; a prefixed root is
|
|
25
|
+
* listed as a plugin root. `skipIfManifest`: a vendor-plugin marker file to
|
|
26
|
+
* skip by.
|
|
27
|
+
*/
|
|
28
|
+
type ProviderNativeRootInput = z.infer<typeof providerNativeRootInputSchema>;
|
|
29
|
+
/**
|
|
30
|
+
* Normalized roots: relative to the host home (`user`) or to the workspace
|
|
31
|
+
* (`project`). The daemon parses this off the wire; the server produces it
|
|
32
|
+
* from a declaration.
|
|
33
|
+
*/
|
|
34
|
+
declare const providerNativeRootsSchema: z.ZodObject<{
|
|
35
|
+
project: z.ZodArray<z.ZodObject<{
|
|
36
|
+
ancestors: z.ZodBoolean;
|
|
37
|
+
namePrefix: z.ZodString;
|
|
38
|
+
path: z.ZodString;
|
|
39
|
+
recursive: z.ZodBoolean;
|
|
40
|
+
skipIfManifest: z.ZodOptional<z.ZodString>;
|
|
41
|
+
}, z.core.$strict>>;
|
|
42
|
+
user: z.ZodArray<z.ZodObject<{
|
|
43
|
+
ancestors: z.ZodBoolean;
|
|
44
|
+
namePrefix: z.ZodString;
|
|
45
|
+
path: z.ZodString;
|
|
46
|
+
recursive: z.ZodBoolean;
|
|
47
|
+
skipIfManifest: z.ZodOptional<z.ZodString>;
|
|
48
|
+
}, z.core.$strict>>;
|
|
49
|
+
}, z.core.$strict>;
|
|
50
|
+
type ProviderNativeRoots = z.infer<typeof providerNativeRootsSchema>;
|
|
51
|
+
/**
|
|
52
|
+
* Provider-native roots as a plugin's frozen declaration holds them: relative
|
|
53
|
+
* to the target host's home (`user`) or to the workspace (`project`). Paths
|
|
54
|
+
* are relative without dot segments, unique per side, at most 32 per side. A
|
|
55
|
+
* root only one host can name — a moved config directory, a settings entry —
|
|
56
|
+
* is the resolver's answer (`resolveNativeRoots`), never a declared root.
|
|
57
|
+
*/
|
|
58
|
+
interface ProviderNativeRootsInputLike {
|
|
59
|
+
readonly user?: readonly ProviderNativeRootInput[];
|
|
60
|
+
readonly project?: readonly ProviderNativeRootInput[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* How completely a provider can clone one of its sessions — the single
|
|
65
|
+
* vocabulary shared by the provider declaration
|
|
66
|
+
* (`bb.providers.register`), the server→daemon
|
|
67
|
+
* `bridgeLaunch`, and the bridge's `initialize` handshake.
|
|
68
|
+
*
|
|
69
|
+
* - `"none"`: sessions cannot be cloned at all.
|
|
70
|
+
* - `"tip"`: only the current end of a session can be cloned (ACP
|
|
71
|
+
* `session/fork`), so thread fork works but edit-past-message rewind
|
|
72
|
+
* cannot.
|
|
73
|
+
* - `"checkpoint"`: a session can be recreated at an earlier point, which is
|
|
74
|
+
* what edit-past-message rewind needs.
|
|
75
|
+
*
|
|
76
|
+
* The values are ordered least to most capable: a declaration is a ceiling
|
|
77
|
+
* the handshake may narrow but never widen.
|
|
78
|
+
*/
|
|
79
|
+
declare const PROVIDER_FORK_VALUES: readonly ["none", "tip", "checkpoint"];
|
|
80
|
+
type ProviderFork = (typeof PROVIDER_FORK_VALUES)[number];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A value that survives a JSON round trip without coercion or data loss.
|
|
84
|
+
*
|
|
85
|
+
* Host boundaries still validate values at runtime because TypeScript cannot
|
|
86
|
+
* exclude non-finite numbers and plugin bundles can bypass static types.
|
|
87
|
+
*/
|
|
88
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
89
|
+
[key: string]: JsonValue;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The validator-neutral subset of Standard Schema v1 used by plugin RPC.
|
|
94
|
+
* Zod 4 schemas implement this interface directly; other validators can do
|
|
95
|
+
* the same without becoming part of BB's public protocol.
|
|
96
|
+
*/
|
|
97
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
98
|
+
readonly "~standard": {
|
|
99
|
+
readonly version: 1;
|
|
100
|
+
readonly vendor: string;
|
|
101
|
+
readonly validate: (value: unknown) => StandardSchemaV1Result<Output> | Promise<StandardSchemaV1Result<Output>>;
|
|
102
|
+
readonly types?: {
|
|
103
|
+
readonly input: Input;
|
|
104
|
+
readonly output: Output;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
type StandardSchemaV1Result<Output> = {
|
|
109
|
+
readonly value: Output;
|
|
110
|
+
readonly issues?: undefined;
|
|
111
|
+
} | {
|
|
112
|
+
readonly issues: readonly StandardSchemaV1Issue[];
|
|
113
|
+
};
|
|
114
|
+
interface StandardSchemaV1Issue {
|
|
115
|
+
readonly message: string;
|
|
116
|
+
readonly path?: PropertyKey | readonly (PropertyKey | {
|
|
117
|
+
readonly key: PropertyKey;
|
|
118
|
+
})[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type PluginSettingValue = string | boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Permission modes a provider can run a session in — BB's own permission
|
|
124
|
+
* vocabulary, ordered least ("accept-edits") to most ("full") privileged.
|
|
125
|
+
*/
|
|
126
|
+
type PluginProviderPermissionMode = "accept-edits" | "auto" | "full";
|
|
127
|
+
/**
|
|
128
|
+
* Coarse reasoning-effort ladder entries, ordered lowest to highest. The
|
|
129
|
+
* declared ladder is a fallback only: precise per-model reasoning sets come
|
|
130
|
+
* from the provider's model list at runtime.
|
|
131
|
+
*/
|
|
132
|
+
type PluginProviderReasoningLevel = "high" | "low" | "max" | "medium" | "none" | "ultra" | "ultracode" | "xhigh";
|
|
133
|
+
/**
|
|
134
|
+
* Composer actions a provider supports, by name only. The skills
|
|
135
|
+
* slash-command typeahead is universal — BB injects skills into every
|
|
136
|
+
* provider — so it is implicit and never declared, and the composer owns the
|
|
137
|
+
* trigger syntax (`/plan `, `/goal `) rather than each declaration repeating
|
|
138
|
+
* it.
|
|
139
|
+
*/
|
|
140
|
+
type PluginProviderComposerAction = "goal" | "plan";
|
|
141
|
+
/**
|
|
142
|
+
* Pre-session capability facts about a provider. A capability earns a field
|
|
143
|
+
* here only when it passes BOTH tests: (1) a consumer outside the provider's
|
|
144
|
+
* own plugin needs the fact, and (2) the fact is needed before / without a
|
|
145
|
+
* live session (picker rendering, route gating, cross-plugin tool
|
|
146
|
+
* composition — including with the host offline). Every boolean is a
|
|
147
|
+
* provider-native fact — the provider implements the feature; the flag only
|
|
148
|
+
* tells external consumers it exists. Session-behavior facts remain handshake
|
|
149
|
+
* capabilities reported by the running bridge. Sessionless maintenance
|
|
150
|
+
* methods are declared here so callers can decide whether to probe without
|
|
151
|
+
* starting the bridge first.
|
|
152
|
+
*/
|
|
153
|
+
interface PluginProviderCapabilities {
|
|
154
|
+
/** The provider accepts a fast/priority service-tier choice — shows the
|
|
155
|
+
* service-tier toggle in the picker. */
|
|
156
|
+
supportsServiceTier: boolean;
|
|
157
|
+
/** The provider ships its own native ask-user-question tool — the
|
|
158
|
+
* ask-user-question plugin skips registering its duplicate. */
|
|
159
|
+
supportsNativeUserQuestion: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* How completely the provider can clone a session: `"none"` (not at all),
|
|
162
|
+
* `"tip"` (only the current end, so thread fork works but edit-past-message
|
|
163
|
+
* rewind cannot), or `"checkpoint"` (recreate the session at an earlier
|
|
164
|
+
* point, which rewind needs). Gates the fork and edit-past-message
|
|
165
|
+
* affordances. The bridge reports the same fact at `initialize`, where it
|
|
166
|
+
* may narrow this declaration but never widen it.
|
|
167
|
+
*/
|
|
168
|
+
fork: ProviderFork;
|
|
169
|
+
/** The provider accepts an explicit context-compaction request — gates the
|
|
170
|
+
* compact affordance. */
|
|
171
|
+
supportsManualCompaction: boolean;
|
|
172
|
+
/** The provider keeps its own thread archive, so BB mirrors archive and
|
|
173
|
+
* unarchive onto it instead of tracking the state only in bb's own rows. */
|
|
174
|
+
supportsThreadArchive: boolean;
|
|
175
|
+
/** The provider stores a thread name of its own, so BB forwards renames to
|
|
176
|
+
* it. */
|
|
177
|
+
supportsThreadRename: boolean;
|
|
178
|
+
/** Permission modes the provider can actually run in. Non-empty, no
|
|
179
|
+
* duplicates. */
|
|
180
|
+
permissionModes: readonly PluginProviderPermissionMode[];
|
|
181
|
+
/** The provider's coarse fallback reasoning ladder (see
|
|
182
|
+
* {@link PluginProviderReasoningLevel}). Non-empty, no duplicates. */
|
|
183
|
+
reasoningLevels: readonly PluginProviderReasoningLevel[];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Provider copy core surfaces render from per-provider tables today (usage
|
|
187
|
+
* banners, sign-in hints, the mobile picker, the agent guide). Declared once
|
|
188
|
+
* here so no core surface keys copy on a provider id. Mirrors
|
|
189
|
+
* `ProviderStrings` in `@bb/domain`, which is the client projection.
|
|
190
|
+
*/
|
|
191
|
+
interface PluginProviderStrings {
|
|
192
|
+
/** How to sign in on the host ("Run `claude` on the machine to sign in."). */
|
|
193
|
+
signInHint: string;
|
|
194
|
+
/** Shown when a session's credentials expired. */
|
|
195
|
+
expiredHint: string;
|
|
196
|
+
/** Where to install the agent. */
|
|
197
|
+
installUrl: string;
|
|
198
|
+
/** Brand prefix stripped from model display names ("Claude "). */
|
|
199
|
+
brandPrefix?: string;
|
|
200
|
+
/** Plan-mode banner copy for providers that declare the `plan` action. */
|
|
201
|
+
planModeCopy?: string;
|
|
202
|
+
/** Per-theme tint for the provider icon. */
|
|
203
|
+
iconTint?: {
|
|
204
|
+
light: string;
|
|
205
|
+
dark: string;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* One selectable option for a picker — a service tier or a reasoning level.
|
|
210
|
+
* `id` is the wire value the bridge receives; `label` is what the picker
|
|
211
|
+
* shows. Declared lists are the cold-cache fallback; `model/list` is precise
|
|
212
|
+
* per model.
|
|
213
|
+
*/
|
|
214
|
+
interface PluginProviderOptionDescriptor {
|
|
215
|
+
id: string;
|
|
216
|
+
label: string;
|
|
217
|
+
description?: string;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Payload schemas for one extension kind this provider emits, keyed by the
|
|
221
|
+
* kind's local name (the server prefixes the plugin id to form the
|
|
222
|
+
* namespaced `"<pluginId>/<name>"`). `item` validates `item.open` payloads
|
|
223
|
+
* with `type: "extension"`, `state` validates `extension.state` payloads;
|
|
224
|
+
* each is optional so a kind can be item-only or state-only. Schemas are
|
|
225
|
+
* Standard Schema v1 validators (zod 4 schemas qualify).
|
|
226
|
+
*/
|
|
227
|
+
interface PluginProviderExtensionKindDeclaration {
|
|
228
|
+
item?: StandardSchemaV1;
|
|
229
|
+
state?: StandardSchemaV1;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Per-command context handed to
|
|
233
|
+
* {@link PluginProviderDeclaration.deriveProviderOptions}. The
|
|
234
|
+
* server builds one for every session and turn command it dispatches on a
|
|
235
|
+
* thread of this provider.
|
|
236
|
+
*/
|
|
237
|
+
interface PluginProviderOptionsContext {
|
|
238
|
+
threadId: string;
|
|
239
|
+
projectId: string;
|
|
240
|
+
/** The resolved model id for this command. */
|
|
241
|
+
model: string;
|
|
242
|
+
/** BB's permission mode for this command (already clamped to the host). */
|
|
243
|
+
permissionMode: PluginProviderPermissionMode;
|
|
244
|
+
/**
|
|
245
|
+
* `"plan"` when the prompt entered plan mode through this provider's
|
|
246
|
+
* declared `plan` composer action. Absent for an ordinary prompt — plan
|
|
247
|
+
* mode is a BB prompt mode, so the bridge maps it onto whatever the agent
|
|
248
|
+
* calls it natively.
|
|
249
|
+
*/
|
|
250
|
+
promptMode?: "plan";
|
|
251
|
+
/**
|
|
252
|
+
* This plugin's own settings values (`bb.settings.define`), read at call
|
|
253
|
+
* time. Secret settings are omitted — provider options ride the daemon
|
|
254
|
+
* wire and are persisted with the session, so a secret must never be
|
|
255
|
+
* derived into them.
|
|
256
|
+
*/
|
|
257
|
+
settings: Readonly<Record<string, PluginSettingValue | undefined>>;
|
|
258
|
+
}
|
|
259
|
+
/** See {@link PluginProviderDeclaration.models}. */
|
|
260
|
+
type PluginProviderModelCatalogScope = "host" | "workspace";
|
|
261
|
+
/**
|
|
262
|
+
* One cold-cache fallback model. The provider's live `model/list` result is
|
|
263
|
+
* the only real model source; this list stands in only while no probe has
|
|
264
|
+
* completed, or when a probe fails transiently, so the picker is not empty.
|
|
265
|
+
* `id` is the wire model id the bridge receives.
|
|
266
|
+
*/
|
|
267
|
+
interface PluginProviderFallbackModel {
|
|
268
|
+
id: string;
|
|
269
|
+
/** Picker display name ("Opus 5 (1M)"). */
|
|
270
|
+
displayName: string;
|
|
271
|
+
description: string;
|
|
272
|
+
/** Reasoning levels this model supports, lowest to highest. Non-empty. */
|
|
273
|
+
supportedReasoningEfforts: readonly {
|
|
274
|
+
reasoningEffort: PluginProviderReasoningLevel;
|
|
275
|
+
description: string;
|
|
276
|
+
}[];
|
|
277
|
+
/** Must be one of `supportedReasoningEfforts`. */
|
|
278
|
+
defaultReasoningEffort: PluginProviderReasoningLevel;
|
|
279
|
+
/** Exactly one entry in the list is the default. */
|
|
280
|
+
isDefault: boolean;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Which sessionless maintenance requests a provider bridge implements. The
|
|
284
|
+
* server skips the requests a provider does not declare, and clients omit
|
|
285
|
+
* the matching surfaces, without starting the bridge first.
|
|
286
|
+
*/
|
|
287
|
+
interface PluginProviderMaintenance {
|
|
288
|
+
/** `provider/health`: host-local readiness, never a network health check. */
|
|
289
|
+
health?: boolean;
|
|
290
|
+
/** `provider/usage`: subscription usage windows. False means usage settings
|
|
291
|
+
* omit the provider. A shared bridge that declares true may still report
|
|
292
|
+
* usage unavailable for one provider id or return no windows. */
|
|
293
|
+
usage?: boolean;
|
|
294
|
+
/** `provider/installation/status` and `provider/installation/run`:
|
|
295
|
+
* host-local installation management. */
|
|
296
|
+
installation?: boolean;
|
|
297
|
+
}
|
|
298
|
+
/** Provider-native roots as a plugin declares them, one list per side. */
|
|
299
|
+
type PluginProviderNativeRoots = ProviderNativeRootsInputLike;
|
|
300
|
+
/**
|
|
301
|
+
* One provider this plugin contributes to BB's provider registry.
|
|
302
|
+
*
|
|
303
|
+
* Ids are stable public identifiers — thread rows and routes reference them —
|
|
304
|
+
* and are collision-rejected: a declaration whose id matches another plugin's
|
|
305
|
+
* live registration is refused; the first registration wins and no id is
|
|
306
|
+
* reserved ahead of time. Registrations are replaced wholesale on plugin
|
|
307
|
+
* reload, like every other plugin surface.
|
|
308
|
+
*
|
|
309
|
+
* A declaration owns the provider's static metadata and bridge options. The
|
|
310
|
+
* executable implementation is the plugin's own provider bridge: the
|
|
311
|
+
* `experimental_providerBridge` export of the `bb.host` artifact the manifest
|
|
312
|
+
* names (`PROVIDER_BRIDGE_EXPORT_NAME` in the bridge kit), built into the
|
|
313
|
+
* artifact BB ships to hosts. Declaring a provider in a plugin with no
|
|
314
|
+
* `bb.host` entry is refused, because the picker entry would exist and no
|
|
315
|
+
* turn on it could ever run; a `bb.host` entry whose artifact failed to
|
|
316
|
+
* build still stages the declaration so the provider is listed as
|
|
317
|
+
* unavailable.
|
|
318
|
+
*/
|
|
319
|
+
interface PluginProviderDeclaration {
|
|
320
|
+
/** Stable provider id: 2–64 characters of lowercase letters, digits, and
|
|
321
|
+
* "-", starting with a letter or digit. Existing ids must never change —
|
|
322
|
+
* threads persist them. */
|
|
323
|
+
id: string;
|
|
324
|
+
/** Picker display name: 1–80 characters, non-blank. */
|
|
325
|
+
displayName: string;
|
|
326
|
+
/**
|
|
327
|
+
* Optional grouping key (same grammar as `id`) for providers that share a
|
|
328
|
+
* family — the ACP agents, for example — so clients can group them without
|
|
329
|
+
* parsing a prefix out of the id. Grouping only: no policy keys on it.
|
|
330
|
+
*/
|
|
331
|
+
family?: string;
|
|
332
|
+
/**
|
|
333
|
+
* Optional picker icon: a named host glyph (`"Zap"`) or a plugin-relative
|
|
334
|
+
* path starting with `"./"` (`"./icons/agent.svg"`) — the two forms
|
|
335
|
+
* `bb.branding.icon` takes — or, unlike `bb.branding.icon`, one of this
|
|
336
|
+
* plugin's declared icons by its namespaced glyph (`"<pluginId>/<name>"`,
|
|
337
|
+
* an entry of the manifest's `bb.branding.experimental_icons` map; the
|
|
338
|
+
* plugin id must be this plugin's and the name must be declared, else the
|
|
339
|
+
* plugin fails to load). Paths follow the manifest entry-path escape rules
|
|
340
|
+
* — no leading "/", no ".." segments, no backslashes.
|
|
341
|
+
*/
|
|
342
|
+
icon?: string;
|
|
343
|
+
/**
|
|
344
|
+
* Provider-owned static options passed opaquely to this plugin's bridge on
|
|
345
|
+
* every sessionless and session request. Core validates that the value is
|
|
346
|
+
* JSON, but does not interpret its keys. This is intended for immutable
|
|
347
|
+
* launch metadata shared by every host (for example an ACP command spec),
|
|
348
|
+
* not user or machine configuration.
|
|
349
|
+
*/
|
|
350
|
+
experimental_bridgeOptions?: Readonly<Record<string, JsonValue>>;
|
|
351
|
+
/**
|
|
352
|
+
* Whether the provider is always listed or only listed on hosts where its
|
|
353
|
+
* bridge reports it installed. Defaults to `"always"`.
|
|
354
|
+
*/
|
|
355
|
+
experimental_visibility?: "always" | "installed";
|
|
356
|
+
/**
|
|
357
|
+
* The sessionless maintenance requests the provider's bridge implements
|
|
358
|
+
* (docs/provider-plugin-api.md §1). Each defaults to false when omitted.
|
|
359
|
+
*/
|
|
360
|
+
maintenance?: PluginProviderMaintenance;
|
|
361
|
+
/** Pre-session capability facts (see the declaration tests on
|
|
362
|
+
* {@link PluginProviderCapabilities}). */
|
|
363
|
+
capabilities: PluginProviderCapabilities;
|
|
364
|
+
/** Composer actions this provider supports. No duplicates; may be empty
|
|
365
|
+
* (the universal skills typeahead is implicit). */
|
|
366
|
+
composerActions: readonly PluginProviderComposerAction[];
|
|
367
|
+
/** Provider copy for core surfaces ({@link PluginProviderStrings}). */
|
|
368
|
+
strings?: PluginProviderStrings;
|
|
369
|
+
/** Service tiers this provider accepts, as picker options. Non-empty when
|
|
370
|
+
* present, unique ids. The coarse `capabilities.supportsServiceTier` stays
|
|
371
|
+
* until WS2a stabilizes. */
|
|
372
|
+
serviceTiers?: readonly PluginProviderOptionDescriptor[];
|
|
373
|
+
/** Reasoning levels as picker options with labels, beside the coarse
|
|
374
|
+
* `capabilities.reasoningLevels` ladder (ids only). Non-empty when present,
|
|
375
|
+
* unique ids. WS2a merges the two. */
|
|
376
|
+
reasoningLevels?: readonly PluginProviderOptionDescriptor[];
|
|
377
|
+
/** Extension kinds this provider's bridge may emit, keyed by local name
|
|
378
|
+
* (`[a-z0-9-]+`). The server validates extension payloads against these
|
|
379
|
+
* schemas at ingest and persists a `provider/unhandled` on a miss. */
|
|
380
|
+
extensionKinds?: Readonly<Record<string, PluginProviderExtensionKindDeclaration>>;
|
|
381
|
+
/**
|
|
382
|
+
* Cold-cache fallback models ({@link PluginProviderFallbackModel}). The
|
|
383
|
+
* server offers them only while a model probe has not completed or failed
|
|
384
|
+
* transiently; the live `model/list` result always replaces them. Ids must
|
|
385
|
+
* be unique and exactly one entry must be the default.
|
|
386
|
+
*/
|
|
387
|
+
models?: {
|
|
388
|
+
/**
|
|
389
|
+
* Optional: a provider that only declares a catalog `scope` needs no
|
|
390
|
+
* fallback list, and an omitted list reads as no fallbacks at all.
|
|
391
|
+
*/
|
|
392
|
+
fallback?: readonly PluginProviderFallbackModel[];
|
|
393
|
+
/**
|
|
394
|
+
* How far one `model/list` answer travels. `"host"` means the catalog is
|
|
395
|
+
* the same everywhere on a machine — the bridge answers from account or
|
|
396
|
+
* agent state and ignores the workspace path — so bb probes once per host
|
|
397
|
+
* and reuses the answer for every environment on it. `"workspace"` (the
|
|
398
|
+
* default) means project configuration can change the answer, so bb
|
|
399
|
+
* probes per workspace and sends the path.
|
|
400
|
+
*
|
|
401
|
+
* Declaring `"host"` wrongly is a stale catalog in a workspace that
|
|
402
|
+
* configured its own models; declaring `"workspace"` wrongly costs a
|
|
403
|
+
* redundant probe. The default is therefore the safe one.
|
|
404
|
+
*/
|
|
405
|
+
scope?: PluginProviderModelCatalogScope;
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* Daemon environment variables this provider's bridge may read. Provider
|
|
409
|
+
* processes are spawned with every inherited `BB_*` variable stripped, so a
|
|
410
|
+
* bridge that honors an operator override (a CLI path, say) names it here
|
|
411
|
+
* and the daemon forwards exactly those variables. Names are
|
|
412
|
+
* `[A-Z_][A-Z0-9_]*`, at most 32.
|
|
413
|
+
*/
|
|
414
|
+
env?: {
|
|
415
|
+
passthrough: readonly string[];
|
|
416
|
+
};
|
|
417
|
+
/**
|
|
418
|
+
* Directories this provider's agent reads its own skills from, relative to
|
|
419
|
+
* the target host's home directory (`user`) or to the workspace
|
|
420
|
+
* (`project`). An agent with skills of its own — an ACP agent pointed at
|
|
421
|
+
* `.cursor/skills`, say — names them here so bb can list them beside its
|
|
422
|
+
* own; core never guesses a provider's skill layout. Paths are relative
|
|
423
|
+
* and may not contain dot segments; each side holds at most 32 roots. One
|
|
424
|
+
* declaration is global, so a directory only one host can name (an agent's
|
|
425
|
+
* settings-configured skills directory, say) is not declared here but
|
|
426
|
+
* resolved on that host (`experimental_resolvesNativeRoots`).
|
|
427
|
+
*/
|
|
428
|
+
experimental_nativeSkillRoots?: PluginProviderNativeRoots;
|
|
429
|
+
/**
|
|
430
|
+
* Directories this provider's agent reads its own slash commands from —
|
|
431
|
+
* flat directories of `*.md` prompt files (`.claude/commands`, say) — in
|
|
432
|
+
* the same two-sided shape as `experimental_nativeSkillRoots`. bb offers
|
|
433
|
+
* them in the composer beside the agent's skills.
|
|
434
|
+
*/
|
|
435
|
+
experimental_nativeCommandRoots?: PluginProviderNativeRoots;
|
|
436
|
+
/**
|
|
437
|
+
* This plugin's `bb.host` entry implements
|
|
438
|
+
* `experimental_nativeRootsHostContract` (`@get-bb/plugin-sdk/host`): core
|
|
439
|
+
* calls `resolveNativeRoots({ cwd })` on the workspace host when it lists
|
|
440
|
+
* commands or skills, and scans what comes back beside the declared roots.
|
|
441
|
+
* This is where a provider's host-only knowledge goes — a config-moved
|
|
442
|
+
* directory, an installed vendor plugin, a config-file entry — including
|
|
443
|
+
* project-scoped entries, which a global declaration cannot carry.
|
|
444
|
+
*/
|
|
445
|
+
experimental_resolvesNativeRoots?: boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Derive this provider's opaque per-command options. Called synchronously
|
|
448
|
+
* by the server for every session and turn command on a thread of this
|
|
449
|
+
* provider, with the command's {@link PluginProviderOptionsContext}; the
|
|
450
|
+
* returned JSON object reaches this plugin's bridge as
|
|
451
|
+
* `options.providerOptions`, merged over `experimental_bridgeOptions`. Core
|
|
452
|
+
* never interprets its keys — this is where a provider's own knobs (memory,
|
|
453
|
+
* native subagents, a native plan flag) travel instead of on the shared
|
|
454
|
+
* execution contract. A throw fails the command with the plugin named, so
|
|
455
|
+
* a buggy hook cannot silently run a turn with default knobs. Must be fast:
|
|
456
|
+
* it sits on the turn-submit path.
|
|
457
|
+
*/
|
|
458
|
+
deriveProviderOptions?: (context: PluginProviderOptionsContext) => Readonly<Record<string, JsonValue>>;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Validate one `bb.providers.register` declaration. Plugin
|
|
463
|
+
* sources are untyped at runtime, so every field is checked; the production
|
|
464
|
+
* host and the fake host both call this, so they accept and reject provider
|
|
465
|
+
* declarations identically. Throws a descriptive error on the first problem;
|
|
466
|
+
* returns a normalized, deeply frozen copy carrying only contract fields.
|
|
467
|
+
*/
|
|
468
|
+
/**
|
|
469
|
+
* A declaration that has been through {@link validatePluginProviderDeclaration}.
|
|
470
|
+
*
|
|
471
|
+
* The validator fills the defaults it owns, so a consumer reads one explicit
|
|
472
|
+
* value rather than re-deciding what an absent field means. Only the fields
|
|
473
|
+
* the validator GUARANTEES are narrowed here; everything else keeps the
|
|
474
|
+
* author-facing shape.
|
|
475
|
+
*/
|
|
476
|
+
type NormalizedPluginProviderDeclaration = Omit<PluginProviderDeclaration, "experimental_nativeCommandRoots" | "experimental_nativeSkillRoots" | "experimental_resolvesNativeRoots"> & {
|
|
477
|
+
readonly experimental_nativeSkillRoots?: ProviderNativeRoots;
|
|
478
|
+
readonly experimental_nativeCommandRoots?: ProviderNativeRoots;
|
|
479
|
+
readonly experimental_resolvesNativeRoots: boolean;
|
|
480
|
+
readonly maintenance: {
|
|
481
|
+
readonly health: boolean;
|
|
482
|
+
readonly usage: boolean;
|
|
483
|
+
readonly installation: boolean;
|
|
484
|
+
};
|
|
485
|
+
readonly models: {
|
|
486
|
+
readonly fallback?: readonly PluginProviderFallbackModel[];
|
|
487
|
+
readonly scope: PluginProviderModelCatalogScope;
|
|
488
|
+
};
|
|
489
|
+
};
|
|
9
490
|
|
|
10
491
|
type BbSdk = BbPluginApi["sdk"];
|
|
11
492
|
/**
|
|
@@ -108,8 +589,14 @@ interface FakeCliRecord {
|
|
|
108
589
|
interface FakeAgentToolRecord {
|
|
109
590
|
name: string;
|
|
110
591
|
description: string;
|
|
111
|
-
experimentalStatusLabels: PluginAgentToolExperimentalStatusLabels | null;
|
|
112
592
|
instructions: string | null;
|
|
593
|
+
/**
|
|
594
|
+
* The plugin's declared row presentation, null when it declared none.
|
|
595
|
+
* Parsed by the shared `parsePluginAgentToolPresentation`, so the record
|
|
596
|
+
* holds exactly what the production host stores and a presentation bb
|
|
597
|
+
* rejects is rejected here with the same message.
|
|
598
|
+
*/
|
|
599
|
+
presentation: PluginAgentToolPresentation | null;
|
|
113
600
|
/** JSON-schema object the host would send providers. */
|
|
114
601
|
inputSchema: unknown;
|
|
115
602
|
parse(input: unknown): {
|
|
@@ -161,9 +648,12 @@ interface FakePluginRegistrations {
|
|
|
161
648
|
}) => string | null) | null;
|
|
162
649
|
threadEventHandlers: Record<PluginThreadEventName, number>;
|
|
163
650
|
mentionProviders: FakeMentionProviderRecord[];
|
|
164
|
-
/** Live provider registrations from `
|
|
651
|
+
/** Live provider registrations from `bb.providers.register`
|
|
165
652
|
* (normalized declarations, registration order; dispose removes). */
|
|
166
|
-
providerRegistrations:
|
|
653
|
+
providerRegistrations: NormalizedPluginProviderDeclaration[];
|
|
654
|
+
/** Live AI-service registrations from `experimental_aiServices.register`
|
|
655
|
+
* (normalized declarations, registration order; dispose removes). */
|
|
656
|
+
aiServiceRegistrations: PluginAiServiceDeclaration[];
|
|
167
657
|
}
|
|
168
658
|
/** Read-only state for assertions after a plugin registers or handles work. */
|
|
169
659
|
interface FakePluginInspectionState {
|
|
@@ -193,7 +683,7 @@ interface FakePluginBehaviorDrivers {
|
|
|
193
683
|
experimental_emitHostWorkerExit(hostId: string): Promise<void>;
|
|
194
684
|
/** Deliver a host signal through its registered payload schema. */
|
|
195
685
|
experimental_emitHostSignal(hostId: string, signal: string, payload: unknown): Promise<void>;
|
|
196
|
-
submitInteraction(id: string, value: JsonValue): void;
|
|
686
|
+
submitInteraction(id: string, value: JsonValue$1): void;
|
|
197
687
|
cancelInteraction(id: string): void;
|
|
198
688
|
/**
|
|
199
689
|
* Apply a settings update the way the host's settings save does:
|
|
@@ -201,7 +691,7 @@ interface FakePluginBehaviorDrivers {
|
|
|
201
691
|
* fire `onChange` listeners when effective values changed. Throws on
|
|
202
692
|
* unknown keys or wrong value types.
|
|
203
693
|
*/
|
|
204
|
-
setSettings(values: Record<string, PluginSettingValue | null>): Promise<void>;
|
|
694
|
+
setSettings(values: Record<string, PluginSettingValue$1 | null>): Promise<void>;
|
|
205
695
|
/**
|
|
206
696
|
* Invoke a registered rpc method with host semantics: input/output schemas,
|
|
207
697
|
* strict JSON result normalization, and structured failure codes. Rejects
|
|
@@ -291,19 +781,42 @@ interface CreateFakePluginHostOptions {
|
|
|
291
781
|
* `bb.sdk`). Defaults to "http://127.0.0.1:38886".
|
|
292
782
|
*/
|
|
293
783
|
loopbackBaseUrl?: string;
|
|
784
|
+
/**
|
|
785
|
+
* Value served by `bb.server.experimental_dataDir`. Defaults to
|
|
786
|
+
* "/tmp/bb-fake-data-dir".
|
|
787
|
+
*/
|
|
788
|
+
dataDir?: string;
|
|
294
789
|
/**
|
|
295
790
|
* Pre-seeded stored settings values (as if saved before this load) —
|
|
296
791
|
* including secret ones, which the fake keeps in memory instead of
|
|
297
792
|
* files. Values with the wrong type for their descriptor fall back to
|
|
298
793
|
* the descriptor default on read, like the host.
|
|
299
794
|
*/
|
|
300
|
-
settings?: Record<string, PluginSettingValue>;
|
|
795
|
+
settings?: Record<string, PluginSettingValue$1>;
|
|
301
796
|
/** Initial `bb.sdk` stubs; extend later via `harness.sdk.stub`. */
|
|
302
797
|
sdk?: FakeSdkOverrides;
|
|
303
798
|
/** Static manifest skill ids available to configure() in this fake host. */
|
|
304
799
|
agentSkillIds?: readonly string[];
|
|
305
800
|
/** Read-only identities returned by bb.hosts.ensureSharedPortTunnel. */
|
|
306
801
|
sharedPortTunnelIdentities?: Record<string, PluginSharedPortTunnelIdentity>;
|
|
802
|
+
/**
|
|
803
|
+
* Whether the plugin's manifest declares a `bb.host` entry. Production
|
|
804
|
+
* refuses `bb.providers.register` (the provider would have no bridge to
|
|
805
|
+
* run on) and `experimental_aiServices.register` (the service would have
|
|
806
|
+
* nothing to run on) without one; the fake applies the same rules.
|
|
807
|
+
* Defaults to true.
|
|
808
|
+
*/
|
|
809
|
+
experimental_hostEntry?: boolean;
|
|
810
|
+
/**
|
|
811
|
+
* The icon names the plugin's manifest declares under
|
|
812
|
+
* `bb.branding.experimental_icons`. Production refuses a provider `icon`
|
|
813
|
+
* or a tool `presentation.icon.glyph` that is a namespaced glyph
|
|
814
|
+
* (`"<pluginId>/<name>"`) naming another plugin or a name not declared
|
|
815
|
+
* there; the fake applies the same rule against this list. Defaults to
|
|
816
|
+
* none declared, so every namespaced glyph is refused until the test
|
|
817
|
+
* names the icons the manifest would.
|
|
818
|
+
*/
|
|
819
|
+
experimental_declaredIconNames?: readonly string[];
|
|
307
820
|
/** Deterministic stand-in for the targeted daemon host entry. */
|
|
308
821
|
experimental_callHostRpc?: (call: ExperimentalFakeHostRpcCall) => unknown | Promise<unknown>;
|
|
309
822
|
}
|
|
@@ -322,5 +835,34 @@ type ThreadResponse = PluginThreadEventPayloads["thread.created"]["thread"];
|
|
|
322
835
|
*/
|
|
323
836
|
declare function makeThreadResponse(overrides?: Partial<ThreadResponse>): ThreadResponse;
|
|
324
837
|
|
|
325
|
-
|
|
326
|
-
|
|
838
|
+
interface PublicSdkOnlyScanOptions {
|
|
839
|
+
/**
|
|
840
|
+
* Public packages the plugin depends on beyond the SDK (a config-file
|
|
841
|
+
* parser, say), matched against the whole specifier. Plugin code and tests
|
|
842
|
+
* alike may import them.
|
|
843
|
+
*/
|
|
844
|
+
allow?: readonly RegExp[];
|
|
845
|
+
}
|
|
846
|
+
interface PublicSdkOnlyViolation {
|
|
847
|
+
/** The importing file, relative to the package root. */
|
|
848
|
+
file: string;
|
|
849
|
+
/** The import specifier, or the argument text of a dynamic one. */
|
|
850
|
+
specifier: string;
|
|
851
|
+
reason: "dynamic-specifier" | "outside-allowlist" | "outside-package" | "private-package";
|
|
852
|
+
}
|
|
853
|
+
interface PublicSdkOnlyScan {
|
|
854
|
+
/** Every source file scanned, relative to the package root, in walk order. */
|
|
855
|
+
files: string[];
|
|
856
|
+
violations: PublicSdkOnlyViolation[];
|
|
857
|
+
/** `@bb/*` names in the package.json dependencies and devDependencies. */
|
|
858
|
+
privateDependencies: string[];
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Scan a plugin package for imports outside the public SDK. `packageRoot`
|
|
862
|
+
* is the directory holding its package.json; every `.ts`/`.tsx`/`.js`
|
|
863
|
+
* file below it except `node_modules` and `dist` is read.
|
|
864
|
+
*/
|
|
865
|
+
declare function scanPublicSdkOnly(packageRoot: string, options?: PublicSdkOnlyScanOptions): PublicSdkOnlyScan;
|
|
866
|
+
|
|
867
|
+
export { PluginContextStaleError, createFakePluginHost, createFakeSdk, scanPublicSdkOnly as experimental_scanPublicSdkOnly, makeThreadResponse };
|
|
868
|
+
export type { CreateFakePluginHostOptions, FakeAgentToolRecord, FakeCliRecord, FakeHttpRouteRecord, FakeLogEntry, FakeLogLevel, FakeMentionProviderRecord, FakePluginBehaviorDrivers, FakePluginHarness, FakePluginHost, FakePluginInspectionState, FakePluginLifecycleControls, FakePluginRegistrations, FakeRealtimeSignal, FakeScheduleRecord, FakeSdkCall, FakeSdkHarness, FakeSdkOverrides, FakeServiceRecord, PublicSdkOnlyScan, PublicSdkOnlyScanOptions, PublicSdkOnlyViolation };
|