@get-bb/plugin-sdk 0.4.47 → 0.4.50
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 +12 -0
- package/bundled-types/bb-plugin-sdk-app.d.ts +203 -28
- package/bundled-types/bb-plugin-sdk-environment-provider.d.ts +266 -0
- package/bundled-types/bb-plugin-sdk-host.d.ts +33 -2
- package/bundled-types/bb-plugin-sdk-internal-composer-customization-validation.d.ts +2 -1
- package/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +231 -8
- 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 +7 -0
- package/bundled-types/bb-plugin-sdk-provider-bridge-testing.d.ts +195 -1
- package/bundled-types/bb-plugin-sdk-provider-bridge.d.ts +202 -167
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +5 -1
- package/bundled-types/bb-plugin-sdk-testing.d.ts +308 -3
- package/bundled-types/bb-plugin-sdk.d.ts +1639 -572
- package/dist/app.js +6 -0
- package/dist/environment-provider.js +0 -0
- package/dist/host.js +734 -30
- package/dist/internal/composer-customization-validation.js +9 -0
- package/dist/internal/host-policy.js +233 -64
- package/dist/internal/plugin-app-collector.js +26 -0
- package/dist/provider-bridge-acp.js +46 -2
- package/dist/provider-bridge-testing.js +62 -1
- package/dist/provider-bridge.js +23 -1
- package/dist/testing/app.js +86 -1
- package/dist/testing/index.js +254 -72
- package/package.json +7 -1
package/dist/testing/index.js
CHANGED
|
@@ -12,7 +12,7 @@ var PLUGIN_INTERACTION_MAX_TITLE_LENGTH = 160;
|
|
|
12
12
|
var PLUGIN_INTERACTION_MAX_PAYLOAD_BYTES = 64 * 1024;
|
|
13
13
|
|
|
14
14
|
// src/internal/host-policy.ts
|
|
15
|
-
import { z as
|
|
15
|
+
import { z as z4 } from "zod";
|
|
16
16
|
|
|
17
17
|
// ../domain/src/plugin-icon.ts
|
|
18
18
|
function isPluginOwnedIconPath(icon) {
|
|
@@ -36,6 +36,7 @@ function parseNamespacedGlyph(glyph) {
|
|
|
36
36
|
|
|
37
37
|
// ../domain/src/plugin-cli.ts
|
|
38
38
|
var RESERVED_BB_CLI_COMMANDS = [
|
|
39
|
+
"browser",
|
|
39
40
|
"environment",
|
|
40
41
|
"file",
|
|
41
42
|
"guide",
|
|
@@ -82,37 +83,54 @@ function isRelativeProviderSkillRootPath(value) {
|
|
|
82
83
|
return !normalized.startsWith("/") && !/^[a-zA-Z]:\//u.test(normalized) && normalized.split("/").every((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
// ../domain/src/
|
|
86
|
+
// ../domain/src/json-value.ts
|
|
86
87
|
import { z as z2 } from "zod";
|
|
88
|
+
var jsonValueSchema = z2.lazy(
|
|
89
|
+
() => z2.union([
|
|
90
|
+
z2.string(),
|
|
91
|
+
z2.number(),
|
|
92
|
+
z2.boolean(),
|
|
93
|
+
z2.null(),
|
|
94
|
+
z2.array(jsonValueSchema),
|
|
95
|
+
z2.record(z2.string(), jsonValueSchema)
|
|
96
|
+
])
|
|
97
|
+
);
|
|
98
|
+
var jsonObjectSchema = z2.record(
|
|
99
|
+
z2.string(),
|
|
100
|
+
jsonValueSchema
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// ../domain/src/native-roots.ts
|
|
104
|
+
import { z as z3 } from "zod";
|
|
87
105
|
var PROVIDER_NATIVE_ROOTS_MAX = 32;
|
|
88
106
|
var PROVIDER_NATIVE_ROOT_NAME_PREFIX_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,62}:$/u;
|
|
89
|
-
var nativeRootNamePrefixSchema =
|
|
107
|
+
var nativeRootNamePrefixSchema = z3.string().refine(
|
|
90
108
|
(value) => value === "" || PROVIDER_NATIVE_ROOT_NAME_PREFIX_PATTERN.test(value),
|
|
91
109
|
"A root name prefix is a plugin-name-like token ending in ':'"
|
|
92
110
|
);
|
|
93
|
-
var nativeRootManifestPathSchema =
|
|
111
|
+
var nativeRootManifestPathSchema = z3.string().min(1).refine(
|
|
94
112
|
isRelativeProviderSkillRootPath,
|
|
95
113
|
"A manifest marker is a relative path without dot segments"
|
|
96
114
|
);
|
|
97
|
-
var relativeNativeRootPathSchema =
|
|
115
|
+
var relativeNativeRootPathSchema = z3.string().min(1).refine(
|
|
98
116
|
isRelativeProviderSkillRootPath,
|
|
99
117
|
"Roots must be relative paths without dot segments"
|
|
100
118
|
);
|
|
101
|
-
var absoluteNativeRootPathSchema =
|
|
119
|
+
var absoluteNativeRootPathSchema = z3.string().min(1).refine(
|
|
102
120
|
isAbsoluteProviderSkillRootPath,
|
|
103
121
|
"Absolute roots must be absolute paths without dot segments"
|
|
104
122
|
);
|
|
105
|
-
var providerNativeRootInputSchema =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
path:
|
|
123
|
+
var providerNativeRootInputSchema = z3.union([
|
|
124
|
+
z3.string().min(1),
|
|
125
|
+
z3.object({
|
|
126
|
+
path: z3.string().min(1),
|
|
109
127
|
/** Skills nest in subdirectories (the agent scans recursively). */
|
|
110
|
-
recursive:
|
|
128
|
+
recursive: z3.boolean().optional(),
|
|
111
129
|
/**
|
|
112
130
|
* Scan the same relative directory in every ancestor of the workspace
|
|
113
131
|
* up to the repository root (`project` roots only).
|
|
114
132
|
*/
|
|
115
|
-
ancestors:
|
|
133
|
+
ancestors: z3.boolean().optional(),
|
|
116
134
|
/**
|
|
117
135
|
* Prepended to every name under the root, a vendor plugin's
|
|
118
136
|
* `plugin-name:`; a prefixed root is listed as a plugin root.
|
|
@@ -127,14 +145,14 @@ var providerNativeRootInputSchema = z2.union([
|
|
|
127
145
|
skipIfManifest: nativeRootManifestPathSchema.optional()
|
|
128
146
|
}).strict()
|
|
129
147
|
]);
|
|
130
|
-
var providerNativeRootsInputSchema =
|
|
131
|
-
user:
|
|
132
|
-
project:
|
|
148
|
+
var providerNativeRootsInputSchema = z3.object({
|
|
149
|
+
user: z3.array(providerNativeRootInputSchema).optional(),
|
|
150
|
+
project: z3.array(providerNativeRootInputSchema).optional()
|
|
133
151
|
}).strict();
|
|
134
|
-
var providerNativeRootSchema =
|
|
135
|
-
path:
|
|
136
|
-
recursive:
|
|
137
|
-
ancestors:
|
|
152
|
+
var providerNativeRootSchema = z3.object({
|
|
153
|
+
path: z3.string().min(1),
|
|
154
|
+
recursive: z3.boolean(),
|
|
155
|
+
ancestors: z3.boolean(),
|
|
138
156
|
namePrefix: nativeRootNamePrefixSchema,
|
|
139
157
|
/** Absent: every skill-shaped directory under the root is a skill. */
|
|
140
158
|
skipIfManifest: nativeRootManifestPathSchema.optional()
|
|
@@ -143,7 +161,7 @@ function uniqueByPath(roots) {
|
|
|
143
161
|
return new Set(roots.map((root) => root.path)).size === roots.length;
|
|
144
162
|
}
|
|
145
163
|
function nativeRootSideSchema(side) {
|
|
146
|
-
return
|
|
164
|
+
return z3.array(
|
|
147
165
|
providerNativeRootSchema.extend({ path: relativeNativeRootPathSchema }).superRefine((root, context) => {
|
|
148
166
|
if (root.ancestors && side !== "project") {
|
|
149
167
|
context.addIssue({
|
|
@@ -154,7 +172,7 @@ function nativeRootSideSchema(side) {
|
|
|
154
172
|
})
|
|
155
173
|
).max(PROVIDER_NATIVE_ROOTS_MAX).refine(uniqueByPath, "Roots must not repeat a path");
|
|
156
174
|
}
|
|
157
|
-
var providerNativeRootsSchema =
|
|
175
|
+
var providerNativeRootsSchema = z3.object({
|
|
158
176
|
user: nativeRootSideSchema("user"),
|
|
159
177
|
project: nativeRootSideSchema("project")
|
|
160
178
|
}).strict();
|
|
@@ -180,19 +198,19 @@ function normalizeProviderNativeRoots(roots) {
|
|
|
180
198
|
project: (roots?.project ?? []).map(normalizeProviderNativeRoot)
|
|
181
199
|
};
|
|
182
200
|
}
|
|
183
|
-
var providerResolvedNativeRootShapeSchema =
|
|
201
|
+
var providerResolvedNativeRootShapeSchema = z3.enum([
|
|
184
202
|
"skills",
|
|
185
203
|
"skill",
|
|
186
204
|
"skill-file",
|
|
187
205
|
"commands",
|
|
188
206
|
"command-file"
|
|
189
207
|
]);
|
|
190
|
-
var resolvedNativeRootFieldsSchema =
|
|
208
|
+
var resolvedNativeRootFieldsSchema = z3.object({
|
|
191
209
|
path: absoluteNativeRootPathSchema,
|
|
192
|
-
origin:
|
|
193
|
-
recursive:
|
|
210
|
+
origin: z3.enum(["user", "project"]),
|
|
211
|
+
recursive: z3.boolean(),
|
|
194
212
|
/** Only with origin `project`, for a path inside the workspace. */
|
|
195
|
-
ancestors:
|
|
213
|
+
ancestors: z3.boolean(),
|
|
196
214
|
namePrefix: nativeRootNamePrefixSchema,
|
|
197
215
|
shape: providerResolvedNativeRootShapeSchema,
|
|
198
216
|
/**
|
|
@@ -200,7 +218,7 @@ var resolvedNativeRootFieldsSchema = z2.object({
|
|
|
200
218
|
* none. A vendor plugin's root SKILL.md takes the plugin's name; absent
|
|
201
219
|
* means the parent directory's name.
|
|
202
220
|
*/
|
|
203
|
-
fallbackName:
|
|
221
|
+
fallbackName: z3.string().min(1).optional(),
|
|
204
222
|
/**
|
|
205
223
|
* `skills` only: a file, relative to a skill directory under this root,
|
|
206
224
|
* that marks the directory as a vendor plugin rather than a skill; the
|
|
@@ -244,14 +262,14 @@ var resolvedCommandShapes = /* @__PURE__ */ new Set([
|
|
|
244
262
|
"command-file"
|
|
245
263
|
]);
|
|
246
264
|
var PROVIDER_RESOLVED_NATIVE_ROOTS_MAX = 256;
|
|
247
|
-
var providerResolvedNativeRootsSchema =
|
|
248
|
-
skills:
|
|
265
|
+
var providerResolvedNativeRootsSchema = z3.object({
|
|
266
|
+
skills: z3.array(
|
|
249
267
|
providerResolvedNativeRootSchema.refine(
|
|
250
268
|
(root) => resolvedSkillShapes.has(root.shape),
|
|
251
269
|
"A skills root needs a skill shape"
|
|
252
270
|
)
|
|
253
271
|
).max(PROVIDER_RESOLVED_NATIVE_ROOTS_MAX),
|
|
254
|
-
commands:
|
|
272
|
+
commands: z3.array(
|
|
255
273
|
providerResolvedNativeRootSchema.refine(
|
|
256
274
|
(root) => resolvedCommandShapes.has(root.shape),
|
|
257
275
|
"A commands root needs a command shape"
|
|
@@ -262,7 +280,7 @@ var EMPTY_PROVIDER_RESOLVED_NATIVE_ROOTS = Object.freeze({
|
|
|
262
280
|
skills: Object.freeze([]),
|
|
263
281
|
commands: Object.freeze([])
|
|
264
282
|
});
|
|
265
|
-
var providerNativeRootSetSchema =
|
|
283
|
+
var providerNativeRootSetSchema = z3.object({
|
|
266
284
|
skills: providerNativeRootsSchema,
|
|
267
285
|
commands: providerNativeRootsSchema,
|
|
268
286
|
resolved: providerResolvedNativeRootsSchema
|
|
@@ -295,16 +313,16 @@ var CLI_COMMAND_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
|
295
313
|
var AGENT_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
296
314
|
var PLUGIN_PROVIDER_ENV_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
297
315
|
var PLUGIN_PROVIDER_ENV_MAX_ENTRIES = 32;
|
|
298
|
-
var pluginProviderEnvEntrySchema =
|
|
299
|
-
name:
|
|
300
|
-
value:
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
var pluginProviderEnvEntrySchema = z4.object({
|
|
317
|
+
name: z4.string().regex(PLUGIN_PROVIDER_ENV_NAME_PATTERN),
|
|
318
|
+
value: z4.union([
|
|
319
|
+
z4.string(),
|
|
320
|
+
z4.object({ serverPath: z4.string().startsWith("/") }).strict()
|
|
303
321
|
]),
|
|
304
|
-
reason:
|
|
305
|
-
secret:
|
|
322
|
+
reason: z4.string(),
|
|
323
|
+
secret: z4.boolean()
|
|
306
324
|
}).strict();
|
|
307
|
-
var pluginProviderEnvEntriesSchema =
|
|
325
|
+
var pluginProviderEnvEntriesSchema = z4.array(pluginProviderEnvEntrySchema).max(PLUGIN_PROVIDER_ENV_MAX_ENTRIES).superRefine((entries, context) => {
|
|
308
326
|
const names = /* @__PURE__ */ new Set();
|
|
309
327
|
for (let index = 0; index < entries.length; index += 1) {
|
|
310
328
|
const name = entries[index]?.name;
|
|
@@ -339,26 +357,26 @@ var PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
|
|
|
339
357
|
var PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES = 64 * 1024;
|
|
340
358
|
var SETTING_KEY_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
341
359
|
var settingsBaseFields = {
|
|
342
|
-
label:
|
|
343
|
-
description:
|
|
360
|
+
label: z4.string().min(1),
|
|
361
|
+
description: z4.string().min(1).optional()
|
|
344
362
|
};
|
|
345
|
-
var stringSettingSchemaSchema =
|
|
363
|
+
var stringSettingSchemaSchema = z4.custom(
|
|
346
364
|
(value) => isStandardSchema(value)
|
|
347
365
|
);
|
|
348
|
-
var booleanSettingSchemaSchema =
|
|
366
|
+
var booleanSettingSchemaSchema = z4.custom(
|
|
349
367
|
(value) => isStandardSchema(value)
|
|
350
368
|
);
|
|
351
|
-
var numberSettingSchemaSchema =
|
|
369
|
+
var numberSettingSchemaSchema = z4.custom(
|
|
352
370
|
(value) => isStandardSchema(value)
|
|
353
371
|
);
|
|
354
|
-
var settingDescriptorSchema =
|
|
355
|
-
|
|
356
|
-
type:
|
|
372
|
+
var settingDescriptorSchema = z4.discriminatedUnion("type", [
|
|
373
|
+
z4.object({
|
|
374
|
+
type: z4.literal("string"),
|
|
357
375
|
...settingsBaseFields,
|
|
358
|
-
secret:
|
|
359
|
-
experimental_multiline:
|
|
376
|
+
secret: z4.literal(true).optional(),
|
|
377
|
+
experimental_multiline: z4.boolean().optional(),
|
|
360
378
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
361
|
-
default:
|
|
379
|
+
default: z4.string().optional()
|
|
362
380
|
}).strict().refine(
|
|
363
381
|
(descriptor) => !(descriptor.secret === true && descriptor.experimental_multiline === true),
|
|
364
382
|
{
|
|
@@ -366,30 +384,30 @@ var settingDescriptorSchema = z3.discriminatedUnion("type", [
|
|
|
366
384
|
path: ["experimental_multiline"]
|
|
367
385
|
}
|
|
368
386
|
),
|
|
369
|
-
|
|
370
|
-
type:
|
|
387
|
+
z4.object({
|
|
388
|
+
type: z4.literal("boolean"),
|
|
371
389
|
...settingsBaseFields,
|
|
372
390
|
experimental_schema: booleanSettingSchemaSchema.optional(),
|
|
373
|
-
default:
|
|
391
|
+
default: z4.boolean().optional()
|
|
374
392
|
}).strict(),
|
|
375
|
-
|
|
376
|
-
type:
|
|
393
|
+
z4.object({
|
|
394
|
+
type: z4.literal("number"),
|
|
377
395
|
...settingsBaseFields,
|
|
378
396
|
experimental_schema: numberSettingSchemaSchema.optional(),
|
|
379
|
-
default:
|
|
397
|
+
default: z4.number().finite().optional()
|
|
380
398
|
}).strict(),
|
|
381
|
-
|
|
382
|
-
type:
|
|
399
|
+
z4.object({
|
|
400
|
+
type: z4.literal("select"),
|
|
383
401
|
...settingsBaseFields,
|
|
384
|
-
options:
|
|
402
|
+
options: z4.array(z4.string().min(1)).min(1),
|
|
385
403
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
386
|
-
default:
|
|
404
|
+
default: z4.string().optional()
|
|
387
405
|
}).strict(),
|
|
388
|
-
|
|
389
|
-
type:
|
|
406
|
+
z4.object({
|
|
407
|
+
type: z4.literal("project"),
|
|
390
408
|
...settingsBaseFields,
|
|
391
409
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
392
|
-
default:
|
|
410
|
+
default: z4.string().optional()
|
|
393
411
|
}).strict()
|
|
394
412
|
]);
|
|
395
413
|
function registerSettingDescriptors(target, added) {
|
|
@@ -1409,11 +1427,21 @@ function readRpcMethodContract(method, value) {
|
|
|
1409
1427
|
function isZodSchemaLike(value) {
|
|
1410
1428
|
return typeof value === "object" && value !== null && typeof value.safeParse === "function";
|
|
1411
1429
|
}
|
|
1430
|
+
function standardSchemaToJsonSchema(schema) {
|
|
1431
|
+
if (isZodSchemaLike(schema)) {
|
|
1432
|
+
return zodSchemaToJsonSchema(schema);
|
|
1433
|
+
}
|
|
1434
|
+
const convertible = schema;
|
|
1435
|
+
if (typeof convertible.toJSONSchema === "function") {
|
|
1436
|
+
return convertible.toJSONSchema();
|
|
1437
|
+
}
|
|
1438
|
+
throw new Error("the validator exposes no JSON Schema conversion");
|
|
1439
|
+
}
|
|
1412
1440
|
function zodSchemaToJsonSchema(schema) {
|
|
1413
1441
|
if (typeof schema.toJSONSchema === "function") {
|
|
1414
1442
|
return schema.toJSONSchema({ io: "input" });
|
|
1415
1443
|
}
|
|
1416
|
-
return
|
|
1444
|
+
return z4.toJSONSchema(schema, { io: "input" });
|
|
1417
1445
|
}
|
|
1418
1446
|
var SINGLE_SCHEMA_KEYWORDS = [
|
|
1419
1447
|
"additionalItems",
|
|
@@ -1739,6 +1767,130 @@ function storePluginHook(records, hook, handler) {
|
|
|
1739
1767
|
function pluginHookAlreadyRegisteredMessage(hook) {
|
|
1740
1768
|
return `a "${hook}" hook handler is already registered by this plugin`;
|
|
1741
1769
|
}
|
|
1770
|
+
var ENVIRONMENT_PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
|
|
1771
|
+
var ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS = 80;
|
|
1772
|
+
var ENVIRONMENT_PROVIDER_REQUIREMENT_NAMES = [
|
|
1773
|
+
"projectCheckout",
|
|
1774
|
+
"gitCheckout",
|
|
1775
|
+
"gitRemote",
|
|
1776
|
+
"projectless"
|
|
1777
|
+
];
|
|
1778
|
+
function validatePluginEnvironmentProviderDeclaration(declaration) {
|
|
1779
|
+
if (typeof declaration !== "object" || declaration === null) {
|
|
1780
|
+
throw new Error("environment provider declaration must be an object");
|
|
1781
|
+
}
|
|
1782
|
+
const id = declaration.id;
|
|
1783
|
+
if (typeof id !== "string" || !ENVIRONMENT_PROVIDER_ID_PATTERN.test(id)) {
|
|
1784
|
+
throw new Error(
|
|
1785
|
+
`invalid environment provider id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, or "-", starting with a letter or digit`
|
|
1786
|
+
);
|
|
1787
|
+
}
|
|
1788
|
+
const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
|
|
1789
|
+
if (displayName.length === 0 || displayName.length > ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS) {
|
|
1790
|
+
throw new Error(
|
|
1791
|
+
`environment provider "${id}" needs a displayName of 1-${ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS} characters`
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
const icon = declaration.icon === void 0 ? null : z4.string().min(1).parse(declaration.icon).trim();
|
|
1795
|
+
if (icon !== null) {
|
|
1796
|
+
if (isPluginOwnedIconPath(icon))
|
|
1797
|
+
validateProviderRelativePath(icon, `"${id}" icon`);
|
|
1798
|
+
else if (!isNamespacedGlyph(icon) && /[/\\]/u.test(icon))
|
|
1799
|
+
throw new Error(
|
|
1800
|
+
`environment provider "${id}" icon must be a glyph, declared icon, or plugin-relative path`
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
if (icon !== null && icon.length === 0) {
|
|
1804
|
+
throw new Error(`environment provider "${id}" declares an empty icon`);
|
|
1805
|
+
}
|
|
1806
|
+
const requires = normalizeEnvironmentProviderRequirements(id, declaration);
|
|
1807
|
+
const inputs = normalizeEnvironmentProviderInputs(id, declaration);
|
|
1808
|
+
if (typeof declaration.create !== "function" || typeof declaration.remove !== "function") {
|
|
1809
|
+
throw new Error(
|
|
1810
|
+
`environment provider "${id}" must declare create and remove functions`
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
if (declaration.validate !== void 0 && typeof declaration.validate !== "function") {
|
|
1814
|
+
throw new Error(
|
|
1815
|
+
`environment provider "${id}" declares a validate that is not a function`
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
if (declaration.availability !== void 0 && typeof declaration.availability !== "function") {
|
|
1819
|
+
throw new Error(
|
|
1820
|
+
`environment provider "${id}" declares availability that is not a function`
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1823
|
+
return {
|
|
1824
|
+
id,
|
|
1825
|
+
displayName,
|
|
1826
|
+
icon,
|
|
1827
|
+
requires,
|
|
1828
|
+
inputs: inputs === null ? null : inputs.schema,
|
|
1829
|
+
inputsJsonSchema: inputs === null ? null : inputs.jsonSchema,
|
|
1830
|
+
availability: declaration.availability ?? null,
|
|
1831
|
+
validate: declaration.validate ?? null,
|
|
1832
|
+
create: declaration.create,
|
|
1833
|
+
remove: declaration.remove,
|
|
1834
|
+
policy: environmentProviderPolicySchema.parse(declaration.policy ?? {})
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
function normalizeEnvironmentProviderInputs(id, declaration) {
|
|
1838
|
+
const inputs = declaration.inputs;
|
|
1839
|
+
if (inputs === void 0) {
|
|
1840
|
+
return null;
|
|
1841
|
+
}
|
|
1842
|
+
if (!isStandardSchema(inputs)) {
|
|
1843
|
+
throw new Error(
|
|
1844
|
+
`environment provider "${id}" declares an inputs that is not a Standard Schema v1 validator`
|
|
1845
|
+
);
|
|
1846
|
+
}
|
|
1847
|
+
let converted;
|
|
1848
|
+
try {
|
|
1849
|
+
converted = JSON.parse(JSON.stringify(standardSchemaToJsonSchema(inputs)));
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
throw new Error(
|
|
1852
|
+
`environment provider "${id}" declares an inputs validator that cannot be published as JSON Schema (${error instanceof Error ? error.message : String(error)}) \u2014 declare it with zod 4 or a validator exposing toJSONSchema()`
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
const jsonSchema = jsonValueSchema.safeParse(converted);
|
|
1856
|
+
if (!jsonSchema.success) {
|
|
1857
|
+
throw new Error(
|
|
1858
|
+
`environment provider "${id}" declares an inputs schema whose JSON Schema is not JSON-serializable`
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
return { schema: inputs, jsonSchema: jsonSchema.data };
|
|
1862
|
+
}
|
|
1863
|
+
function normalizeEnvironmentProviderRequirements(id, declaration) {
|
|
1864
|
+
const requires = declaration.requires ?? {};
|
|
1865
|
+
if (typeof requires !== "object" || requires === null || Array.isArray(requires)) {
|
|
1866
|
+
throw new Error(
|
|
1867
|
+
`environment provider "${id}" declares a requires that is not an object`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
const normalized = {};
|
|
1871
|
+
for (const name of ENVIRONMENT_PROVIDER_REQUIREMENT_NAMES) {
|
|
1872
|
+
const value = requires[name];
|
|
1873
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
1874
|
+
throw new Error(
|
|
1875
|
+
`environment provider "${id}" declares a requires.${name} that is not a boolean`
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
normalized[name] = value === true;
|
|
1879
|
+
}
|
|
1880
|
+
if (normalized.gitCheckout) {
|
|
1881
|
+
normalized.projectCheckout = true;
|
|
1882
|
+
}
|
|
1883
|
+
if (normalized.projectless && (normalized.projectCheckout || normalized.gitRemote)) {
|
|
1884
|
+
throw new Error(
|
|
1885
|
+
`environment provider "${id}" declares requires.projectless together with a project requirement \u2014 a projectless thread has no checkout or remote`
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1888
|
+
return normalized;
|
|
1889
|
+
}
|
|
1890
|
+
var environmentProviderPolicySchema = z4.object({
|
|
1891
|
+
retireGraceMs: z4.number().int().nonnegative().nullable().default(3e5),
|
|
1892
|
+
pathKeys: z4.enum(["per-thread", "per-attempt"]).default("per-thread")
|
|
1893
|
+
}).strict();
|
|
1742
1894
|
|
|
1743
1895
|
// src/testing/fake-sdk.ts
|
|
1744
1896
|
function withSpawnAttribution(pluginId, args) {
|
|
@@ -2777,11 +2929,14 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
2777
2929
|
"interaction.pending": [],
|
|
2778
2930
|
"message.queued": [],
|
|
2779
2931
|
"message.dispatched": [],
|
|
2780
|
-
"turn.failed": []
|
|
2932
|
+
"turn.failed": [],
|
|
2933
|
+
"message.cancelled": [],
|
|
2934
|
+
"thread.unarchived": []
|
|
2781
2935
|
};
|
|
2782
2936
|
const hooks = {
|
|
2783
2937
|
"message.dispatch": null
|
|
2784
2938
|
};
|
|
2939
|
+
const environmentProviders = /* @__PURE__ */ new Map();
|
|
2785
2940
|
const disposeHooks = [];
|
|
2786
2941
|
const serviceControllers = [];
|
|
2787
2942
|
let nextInteractionId = 1;
|
|
@@ -3048,6 +3203,20 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3048
3203
|
requestedDrains += 1;
|
|
3049
3204
|
}
|
|
3050
3205
|
};
|
|
3206
|
+
const experimental_environments = {
|
|
3207
|
+
register(declaration) {
|
|
3208
|
+
assertLive();
|
|
3209
|
+
const target = validatePluginEnvironmentProviderDeclaration(declaration);
|
|
3210
|
+
const problem = target.icon === null ? null : undeclaredIconProblem(pluginId, declaredIconNames, target.icon);
|
|
3211
|
+
if (problem !== null)
|
|
3212
|
+
throw new Error(providerIconRefusalMessage(target.id, problem));
|
|
3213
|
+
environmentProviders.set(target.id, target);
|
|
3214
|
+
},
|
|
3215
|
+
async recheck() {
|
|
3216
|
+
assertLive();
|
|
3217
|
+
requestedDrains += 1;
|
|
3218
|
+
}
|
|
3219
|
+
};
|
|
3051
3220
|
const bb = {
|
|
3052
3221
|
pluginId,
|
|
3053
3222
|
log,
|
|
@@ -3063,6 +3232,7 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3063
3232
|
ui,
|
|
3064
3233
|
events,
|
|
3065
3234
|
experimental_hooks,
|
|
3235
|
+
experimental_environments,
|
|
3066
3236
|
status,
|
|
3067
3237
|
server,
|
|
3068
3238
|
hosts,
|
|
@@ -3159,12 +3329,17 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3159
3329
|
"interaction.pending": threadEventHandlers["interaction.pending"].length,
|
|
3160
3330
|
"message.queued": threadEventHandlers["message.queued"].length,
|
|
3161
3331
|
"message.dispatched": threadEventHandlers["message.dispatched"].length,
|
|
3162
|
-
"turn.failed": threadEventHandlers["turn.failed"].length
|
|
3332
|
+
"turn.failed": threadEventHandlers["turn.failed"].length,
|
|
3333
|
+
"message.cancelled": threadEventHandlers["message.cancelled"].length,
|
|
3334
|
+
"thread.unarchived": threadEventHandlers["thread.unarchived"].length
|
|
3163
3335
|
};
|
|
3164
3336
|
},
|
|
3165
3337
|
get hooks() {
|
|
3166
3338
|
return { ...hooks };
|
|
3167
3339
|
},
|
|
3340
|
+
get environmentProviders() {
|
|
3341
|
+
return new Map(environmentProviders);
|
|
3342
|
+
},
|
|
3168
3343
|
mentionProviders,
|
|
3169
3344
|
providerRegistrations,
|
|
3170
3345
|
providerEnvResolvers,
|
|
@@ -3633,8 +3808,8 @@ function makePluginAgentConfigurationContext(overrides = {}) {
|
|
|
3633
3808
|
id: "environment-test",
|
|
3634
3809
|
name: null,
|
|
3635
3810
|
path: "/tmp/test",
|
|
3636
|
-
|
|
3637
|
-
|
|
3811
|
+
branchName: null,
|
|
3812
|
+
workspaceProvisionType: null
|
|
3638
3813
|
},
|
|
3639
3814
|
host: { id: "host-test", name: "Test host" },
|
|
3640
3815
|
provider: {
|
|
@@ -3693,7 +3868,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3693
3868
|
origin: null,
|
|
3694
3869
|
originPluginId: null,
|
|
3695
3870
|
startedOnBehalfOf: null,
|
|
3696
|
-
parentThreadId: null
|
|
3871
|
+
parentThreadId: null,
|
|
3872
|
+
environmentIntent: null
|
|
3697
3873
|
};
|
|
3698
3874
|
const environmentDefaults = {
|
|
3699
3875
|
id: "environment-1",
|
|
@@ -3701,14 +3877,18 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3701
3877
|
projectId: "project-1",
|
|
3702
3878
|
hostId: "host-1",
|
|
3703
3879
|
path: "/tmp/test",
|
|
3704
|
-
managed: true,
|
|
3705
3880
|
isGitRepo: true,
|
|
3706
3881
|
isWorktree: false,
|
|
3707
|
-
workspaceProvisionType: "unmanaged",
|
|
3708
3882
|
branchName: "main",
|
|
3709
3883
|
baseBranch: null,
|
|
3710
3884
|
defaultBranch: "main",
|
|
3711
3885
|
mergeBaseBranch: null,
|
|
3886
|
+
environmentProviderId: null,
|
|
3887
|
+
environmentProviderSelection: null,
|
|
3888
|
+
environmentProviderInstanceKey: null,
|
|
3889
|
+
lifecycle: { phase: "active", retireAt: null, teardown: null },
|
|
3890
|
+
managed: false,
|
|
3891
|
+
workspaceProvisionType: null,
|
|
3712
3892
|
status: "ready",
|
|
3713
3893
|
createdAt: 0,
|
|
3714
3894
|
updatedAt: 0
|
|
@@ -3716,8 +3896,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3716
3896
|
const hostDefaults = {
|
|
3717
3897
|
id: "host-1",
|
|
3718
3898
|
name: "Test host",
|
|
3719
|
-
type: "persistent",
|
|
3720
3899
|
status: "connected",
|
|
3900
|
+
type: "persistent",
|
|
3721
3901
|
maxPermissionMode: "full",
|
|
3722
3902
|
lastSeenAt: null,
|
|
3723
3903
|
lastRejectedProtocolVersion: null,
|
|
@@ -3763,6 +3943,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3763
3943
|
function makeQueueEntry(overrides = {}) {
|
|
3764
3944
|
return {
|
|
3765
3945
|
id: "queued_1",
|
|
3946
|
+
initiator: "user",
|
|
3947
|
+
senderThreadId: null,
|
|
3766
3948
|
threadId: "thread-1",
|
|
3767
3949
|
content: [{ type: "text", text: "Queued turn", mentions: [] }],
|
|
3768
3950
|
model: "test-model",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@get-bb/plugin-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.50",
|
|
4
4
|
"homepage": "https://github.com/get-bb/bb#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/get-bb/bb/issues"
|
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
"import": "./dist/provider-bridge-acp.js",
|
|
51
51
|
"default": "./dist/provider-bridge-acp.js"
|
|
52
52
|
},
|
|
53
|
+
"./environment-provider": {
|
|
54
|
+
"source": "./src/environment-provider.ts",
|
|
55
|
+
"types": "./bundled-types/bb-plugin-sdk-environment-provider.d.ts",
|
|
56
|
+
"import": "./dist/environment-provider.js",
|
|
57
|
+
"default": "./dist/environment-provider.js"
|
|
58
|
+
},
|
|
53
59
|
"./app": {
|
|
54
60
|
"source": "./src/app.ts",
|
|
55
61
|
"types": "./bundled-types/bb-plugin-sdk-app.d.ts",
|