@get-bb/plugin-sdk 0.4.48 → 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 +1587 -924
- 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 +232 -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 +253 -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) {
|
|
@@ -83,37 +83,54 @@ function isRelativeProviderSkillRootPath(value) {
|
|
|
83
83
|
return !normalized.startsWith("/") && !/^[a-zA-Z]:\//u.test(normalized) && normalized.split("/").every((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
// ../domain/src/
|
|
86
|
+
// ../domain/src/json-value.ts
|
|
87
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";
|
|
88
105
|
var PROVIDER_NATIVE_ROOTS_MAX = 32;
|
|
89
106
|
var PROVIDER_NATIVE_ROOT_NAME_PREFIX_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,62}:$/u;
|
|
90
|
-
var nativeRootNamePrefixSchema =
|
|
107
|
+
var nativeRootNamePrefixSchema = z3.string().refine(
|
|
91
108
|
(value) => value === "" || PROVIDER_NATIVE_ROOT_NAME_PREFIX_PATTERN.test(value),
|
|
92
109
|
"A root name prefix is a plugin-name-like token ending in ':'"
|
|
93
110
|
);
|
|
94
|
-
var nativeRootManifestPathSchema =
|
|
111
|
+
var nativeRootManifestPathSchema = z3.string().min(1).refine(
|
|
95
112
|
isRelativeProviderSkillRootPath,
|
|
96
113
|
"A manifest marker is a relative path without dot segments"
|
|
97
114
|
);
|
|
98
|
-
var relativeNativeRootPathSchema =
|
|
115
|
+
var relativeNativeRootPathSchema = z3.string().min(1).refine(
|
|
99
116
|
isRelativeProviderSkillRootPath,
|
|
100
117
|
"Roots must be relative paths without dot segments"
|
|
101
118
|
);
|
|
102
|
-
var absoluteNativeRootPathSchema =
|
|
119
|
+
var absoluteNativeRootPathSchema = z3.string().min(1).refine(
|
|
103
120
|
isAbsoluteProviderSkillRootPath,
|
|
104
121
|
"Absolute roots must be absolute paths without dot segments"
|
|
105
122
|
);
|
|
106
|
-
var providerNativeRootInputSchema =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
path:
|
|
123
|
+
var providerNativeRootInputSchema = z3.union([
|
|
124
|
+
z3.string().min(1),
|
|
125
|
+
z3.object({
|
|
126
|
+
path: z3.string().min(1),
|
|
110
127
|
/** Skills nest in subdirectories (the agent scans recursively). */
|
|
111
|
-
recursive:
|
|
128
|
+
recursive: z3.boolean().optional(),
|
|
112
129
|
/**
|
|
113
130
|
* Scan the same relative directory in every ancestor of the workspace
|
|
114
131
|
* up to the repository root (`project` roots only).
|
|
115
132
|
*/
|
|
116
|
-
ancestors:
|
|
133
|
+
ancestors: z3.boolean().optional(),
|
|
117
134
|
/**
|
|
118
135
|
* Prepended to every name under the root, a vendor plugin's
|
|
119
136
|
* `plugin-name:`; a prefixed root is listed as a plugin root.
|
|
@@ -128,14 +145,14 @@ var providerNativeRootInputSchema = z2.union([
|
|
|
128
145
|
skipIfManifest: nativeRootManifestPathSchema.optional()
|
|
129
146
|
}).strict()
|
|
130
147
|
]);
|
|
131
|
-
var providerNativeRootsInputSchema =
|
|
132
|
-
user:
|
|
133
|
-
project:
|
|
148
|
+
var providerNativeRootsInputSchema = z3.object({
|
|
149
|
+
user: z3.array(providerNativeRootInputSchema).optional(),
|
|
150
|
+
project: z3.array(providerNativeRootInputSchema).optional()
|
|
134
151
|
}).strict();
|
|
135
|
-
var providerNativeRootSchema =
|
|
136
|
-
path:
|
|
137
|
-
recursive:
|
|
138
|
-
ancestors:
|
|
152
|
+
var providerNativeRootSchema = z3.object({
|
|
153
|
+
path: z3.string().min(1),
|
|
154
|
+
recursive: z3.boolean(),
|
|
155
|
+
ancestors: z3.boolean(),
|
|
139
156
|
namePrefix: nativeRootNamePrefixSchema,
|
|
140
157
|
/** Absent: every skill-shaped directory under the root is a skill. */
|
|
141
158
|
skipIfManifest: nativeRootManifestPathSchema.optional()
|
|
@@ -144,7 +161,7 @@ function uniqueByPath(roots) {
|
|
|
144
161
|
return new Set(roots.map((root) => root.path)).size === roots.length;
|
|
145
162
|
}
|
|
146
163
|
function nativeRootSideSchema(side) {
|
|
147
|
-
return
|
|
164
|
+
return z3.array(
|
|
148
165
|
providerNativeRootSchema.extend({ path: relativeNativeRootPathSchema }).superRefine((root, context) => {
|
|
149
166
|
if (root.ancestors && side !== "project") {
|
|
150
167
|
context.addIssue({
|
|
@@ -155,7 +172,7 @@ function nativeRootSideSchema(side) {
|
|
|
155
172
|
})
|
|
156
173
|
).max(PROVIDER_NATIVE_ROOTS_MAX).refine(uniqueByPath, "Roots must not repeat a path");
|
|
157
174
|
}
|
|
158
|
-
var providerNativeRootsSchema =
|
|
175
|
+
var providerNativeRootsSchema = z3.object({
|
|
159
176
|
user: nativeRootSideSchema("user"),
|
|
160
177
|
project: nativeRootSideSchema("project")
|
|
161
178
|
}).strict();
|
|
@@ -181,19 +198,19 @@ function normalizeProviderNativeRoots(roots) {
|
|
|
181
198
|
project: (roots?.project ?? []).map(normalizeProviderNativeRoot)
|
|
182
199
|
};
|
|
183
200
|
}
|
|
184
|
-
var providerResolvedNativeRootShapeSchema =
|
|
201
|
+
var providerResolvedNativeRootShapeSchema = z3.enum([
|
|
185
202
|
"skills",
|
|
186
203
|
"skill",
|
|
187
204
|
"skill-file",
|
|
188
205
|
"commands",
|
|
189
206
|
"command-file"
|
|
190
207
|
]);
|
|
191
|
-
var resolvedNativeRootFieldsSchema =
|
|
208
|
+
var resolvedNativeRootFieldsSchema = z3.object({
|
|
192
209
|
path: absoluteNativeRootPathSchema,
|
|
193
|
-
origin:
|
|
194
|
-
recursive:
|
|
210
|
+
origin: z3.enum(["user", "project"]),
|
|
211
|
+
recursive: z3.boolean(),
|
|
195
212
|
/** Only with origin `project`, for a path inside the workspace. */
|
|
196
|
-
ancestors:
|
|
213
|
+
ancestors: z3.boolean(),
|
|
197
214
|
namePrefix: nativeRootNamePrefixSchema,
|
|
198
215
|
shape: providerResolvedNativeRootShapeSchema,
|
|
199
216
|
/**
|
|
@@ -201,7 +218,7 @@ var resolvedNativeRootFieldsSchema = z2.object({
|
|
|
201
218
|
* none. A vendor plugin's root SKILL.md takes the plugin's name; absent
|
|
202
219
|
* means the parent directory's name.
|
|
203
220
|
*/
|
|
204
|
-
fallbackName:
|
|
221
|
+
fallbackName: z3.string().min(1).optional(),
|
|
205
222
|
/**
|
|
206
223
|
* `skills` only: a file, relative to a skill directory under this root,
|
|
207
224
|
* that marks the directory as a vendor plugin rather than a skill; the
|
|
@@ -245,14 +262,14 @@ var resolvedCommandShapes = /* @__PURE__ */ new Set([
|
|
|
245
262
|
"command-file"
|
|
246
263
|
]);
|
|
247
264
|
var PROVIDER_RESOLVED_NATIVE_ROOTS_MAX = 256;
|
|
248
|
-
var providerResolvedNativeRootsSchema =
|
|
249
|
-
skills:
|
|
265
|
+
var providerResolvedNativeRootsSchema = z3.object({
|
|
266
|
+
skills: z3.array(
|
|
250
267
|
providerResolvedNativeRootSchema.refine(
|
|
251
268
|
(root) => resolvedSkillShapes.has(root.shape),
|
|
252
269
|
"A skills root needs a skill shape"
|
|
253
270
|
)
|
|
254
271
|
).max(PROVIDER_RESOLVED_NATIVE_ROOTS_MAX),
|
|
255
|
-
commands:
|
|
272
|
+
commands: z3.array(
|
|
256
273
|
providerResolvedNativeRootSchema.refine(
|
|
257
274
|
(root) => resolvedCommandShapes.has(root.shape),
|
|
258
275
|
"A commands root needs a command shape"
|
|
@@ -263,7 +280,7 @@ var EMPTY_PROVIDER_RESOLVED_NATIVE_ROOTS = Object.freeze({
|
|
|
263
280
|
skills: Object.freeze([]),
|
|
264
281
|
commands: Object.freeze([])
|
|
265
282
|
});
|
|
266
|
-
var providerNativeRootSetSchema =
|
|
283
|
+
var providerNativeRootSetSchema = z3.object({
|
|
267
284
|
skills: providerNativeRootsSchema,
|
|
268
285
|
commands: providerNativeRootsSchema,
|
|
269
286
|
resolved: providerResolvedNativeRootsSchema
|
|
@@ -296,16 +313,16 @@ var CLI_COMMAND_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
|
296
313
|
var AGENT_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
297
314
|
var PLUGIN_PROVIDER_ENV_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
298
315
|
var PLUGIN_PROVIDER_ENV_MAX_ENTRIES = 32;
|
|
299
|
-
var pluginProviderEnvEntrySchema =
|
|
300
|
-
name:
|
|
301
|
-
value:
|
|
302
|
-
|
|
303
|
-
|
|
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()
|
|
304
321
|
]),
|
|
305
|
-
reason:
|
|
306
|
-
secret:
|
|
322
|
+
reason: z4.string(),
|
|
323
|
+
secret: z4.boolean()
|
|
307
324
|
}).strict();
|
|
308
|
-
var pluginProviderEnvEntriesSchema =
|
|
325
|
+
var pluginProviderEnvEntriesSchema = z4.array(pluginProviderEnvEntrySchema).max(PLUGIN_PROVIDER_ENV_MAX_ENTRIES).superRefine((entries, context) => {
|
|
309
326
|
const names = /* @__PURE__ */ new Set();
|
|
310
327
|
for (let index = 0; index < entries.length; index += 1) {
|
|
311
328
|
const name = entries[index]?.name;
|
|
@@ -340,26 +357,26 @@ var PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
|
|
|
340
357
|
var PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES = 64 * 1024;
|
|
341
358
|
var SETTING_KEY_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
342
359
|
var settingsBaseFields = {
|
|
343
|
-
label:
|
|
344
|
-
description:
|
|
360
|
+
label: z4.string().min(1),
|
|
361
|
+
description: z4.string().min(1).optional()
|
|
345
362
|
};
|
|
346
|
-
var stringSettingSchemaSchema =
|
|
363
|
+
var stringSettingSchemaSchema = z4.custom(
|
|
347
364
|
(value) => isStandardSchema(value)
|
|
348
365
|
);
|
|
349
|
-
var booleanSettingSchemaSchema =
|
|
366
|
+
var booleanSettingSchemaSchema = z4.custom(
|
|
350
367
|
(value) => isStandardSchema(value)
|
|
351
368
|
);
|
|
352
|
-
var numberSettingSchemaSchema =
|
|
369
|
+
var numberSettingSchemaSchema = z4.custom(
|
|
353
370
|
(value) => isStandardSchema(value)
|
|
354
371
|
);
|
|
355
|
-
var settingDescriptorSchema =
|
|
356
|
-
|
|
357
|
-
type:
|
|
372
|
+
var settingDescriptorSchema = z4.discriminatedUnion("type", [
|
|
373
|
+
z4.object({
|
|
374
|
+
type: z4.literal("string"),
|
|
358
375
|
...settingsBaseFields,
|
|
359
|
-
secret:
|
|
360
|
-
experimental_multiline:
|
|
376
|
+
secret: z4.literal(true).optional(),
|
|
377
|
+
experimental_multiline: z4.boolean().optional(),
|
|
361
378
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
362
|
-
default:
|
|
379
|
+
default: z4.string().optional()
|
|
363
380
|
}).strict().refine(
|
|
364
381
|
(descriptor) => !(descriptor.secret === true && descriptor.experimental_multiline === true),
|
|
365
382
|
{
|
|
@@ -367,30 +384,30 @@ var settingDescriptorSchema = z3.discriminatedUnion("type", [
|
|
|
367
384
|
path: ["experimental_multiline"]
|
|
368
385
|
}
|
|
369
386
|
),
|
|
370
|
-
|
|
371
|
-
type:
|
|
387
|
+
z4.object({
|
|
388
|
+
type: z4.literal("boolean"),
|
|
372
389
|
...settingsBaseFields,
|
|
373
390
|
experimental_schema: booleanSettingSchemaSchema.optional(),
|
|
374
|
-
default:
|
|
391
|
+
default: z4.boolean().optional()
|
|
375
392
|
}).strict(),
|
|
376
|
-
|
|
377
|
-
type:
|
|
393
|
+
z4.object({
|
|
394
|
+
type: z4.literal("number"),
|
|
378
395
|
...settingsBaseFields,
|
|
379
396
|
experimental_schema: numberSettingSchemaSchema.optional(),
|
|
380
|
-
default:
|
|
397
|
+
default: z4.number().finite().optional()
|
|
381
398
|
}).strict(),
|
|
382
|
-
|
|
383
|
-
type:
|
|
399
|
+
z4.object({
|
|
400
|
+
type: z4.literal("select"),
|
|
384
401
|
...settingsBaseFields,
|
|
385
|
-
options:
|
|
402
|
+
options: z4.array(z4.string().min(1)).min(1),
|
|
386
403
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
387
|
-
default:
|
|
404
|
+
default: z4.string().optional()
|
|
388
405
|
}).strict(),
|
|
389
|
-
|
|
390
|
-
type:
|
|
406
|
+
z4.object({
|
|
407
|
+
type: z4.literal("project"),
|
|
391
408
|
...settingsBaseFields,
|
|
392
409
|
experimental_schema: stringSettingSchemaSchema.optional(),
|
|
393
|
-
default:
|
|
410
|
+
default: z4.string().optional()
|
|
394
411
|
}).strict()
|
|
395
412
|
]);
|
|
396
413
|
function registerSettingDescriptors(target, added) {
|
|
@@ -1410,11 +1427,21 @@ function readRpcMethodContract(method, value) {
|
|
|
1410
1427
|
function isZodSchemaLike(value) {
|
|
1411
1428
|
return typeof value === "object" && value !== null && typeof value.safeParse === "function";
|
|
1412
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
|
+
}
|
|
1413
1440
|
function zodSchemaToJsonSchema(schema) {
|
|
1414
1441
|
if (typeof schema.toJSONSchema === "function") {
|
|
1415
1442
|
return schema.toJSONSchema({ io: "input" });
|
|
1416
1443
|
}
|
|
1417
|
-
return
|
|
1444
|
+
return z4.toJSONSchema(schema, { io: "input" });
|
|
1418
1445
|
}
|
|
1419
1446
|
var SINGLE_SCHEMA_KEYWORDS = [
|
|
1420
1447
|
"additionalItems",
|
|
@@ -1740,6 +1767,130 @@ function storePluginHook(records, hook, handler) {
|
|
|
1740
1767
|
function pluginHookAlreadyRegisteredMessage(hook) {
|
|
1741
1768
|
return `a "${hook}" hook handler is already registered by this plugin`;
|
|
1742
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();
|
|
1743
1894
|
|
|
1744
1895
|
// src/testing/fake-sdk.ts
|
|
1745
1896
|
function withSpawnAttribution(pluginId, args) {
|
|
@@ -2778,11 +2929,14 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
2778
2929
|
"interaction.pending": [],
|
|
2779
2930
|
"message.queued": [],
|
|
2780
2931
|
"message.dispatched": [],
|
|
2781
|
-
"turn.failed": []
|
|
2932
|
+
"turn.failed": [],
|
|
2933
|
+
"message.cancelled": [],
|
|
2934
|
+
"thread.unarchived": []
|
|
2782
2935
|
};
|
|
2783
2936
|
const hooks = {
|
|
2784
2937
|
"message.dispatch": null
|
|
2785
2938
|
};
|
|
2939
|
+
const environmentProviders = /* @__PURE__ */ new Map();
|
|
2786
2940
|
const disposeHooks = [];
|
|
2787
2941
|
const serviceControllers = [];
|
|
2788
2942
|
let nextInteractionId = 1;
|
|
@@ -3049,6 +3203,20 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3049
3203
|
requestedDrains += 1;
|
|
3050
3204
|
}
|
|
3051
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
|
+
};
|
|
3052
3220
|
const bb = {
|
|
3053
3221
|
pluginId,
|
|
3054
3222
|
log,
|
|
@@ -3064,6 +3232,7 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3064
3232
|
ui,
|
|
3065
3233
|
events,
|
|
3066
3234
|
experimental_hooks,
|
|
3235
|
+
experimental_environments,
|
|
3067
3236
|
status,
|
|
3068
3237
|
server,
|
|
3069
3238
|
hosts,
|
|
@@ -3160,12 +3329,17 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3160
3329
|
"interaction.pending": threadEventHandlers["interaction.pending"].length,
|
|
3161
3330
|
"message.queued": threadEventHandlers["message.queued"].length,
|
|
3162
3331
|
"message.dispatched": threadEventHandlers["message.dispatched"].length,
|
|
3163
|
-
"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
|
|
3164
3335
|
};
|
|
3165
3336
|
},
|
|
3166
3337
|
get hooks() {
|
|
3167
3338
|
return { ...hooks };
|
|
3168
3339
|
},
|
|
3340
|
+
get environmentProviders() {
|
|
3341
|
+
return new Map(environmentProviders);
|
|
3342
|
+
},
|
|
3169
3343
|
mentionProviders,
|
|
3170
3344
|
providerRegistrations,
|
|
3171
3345
|
providerEnvResolvers,
|
|
@@ -3634,8 +3808,8 @@ function makePluginAgentConfigurationContext(overrides = {}) {
|
|
|
3634
3808
|
id: "environment-test",
|
|
3635
3809
|
name: null,
|
|
3636
3810
|
path: "/tmp/test",
|
|
3637
|
-
|
|
3638
|
-
|
|
3811
|
+
branchName: null,
|
|
3812
|
+
workspaceProvisionType: null
|
|
3639
3813
|
},
|
|
3640
3814
|
host: { id: "host-test", name: "Test host" },
|
|
3641
3815
|
provider: {
|
|
@@ -3694,7 +3868,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3694
3868
|
origin: null,
|
|
3695
3869
|
originPluginId: null,
|
|
3696
3870
|
startedOnBehalfOf: null,
|
|
3697
|
-
parentThreadId: null
|
|
3871
|
+
parentThreadId: null,
|
|
3872
|
+
environmentIntent: null
|
|
3698
3873
|
};
|
|
3699
3874
|
const environmentDefaults = {
|
|
3700
3875
|
id: "environment-1",
|
|
@@ -3702,14 +3877,18 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3702
3877
|
projectId: "project-1",
|
|
3703
3878
|
hostId: "host-1",
|
|
3704
3879
|
path: "/tmp/test",
|
|
3705
|
-
managed: true,
|
|
3706
3880
|
isGitRepo: true,
|
|
3707
3881
|
isWorktree: false,
|
|
3708
|
-
workspaceProvisionType: "unmanaged",
|
|
3709
3882
|
branchName: "main",
|
|
3710
3883
|
baseBranch: null,
|
|
3711
3884
|
defaultBranch: "main",
|
|
3712
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,
|
|
3713
3892
|
status: "ready",
|
|
3714
3893
|
createdAt: 0,
|
|
3715
3894
|
updatedAt: 0
|
|
@@ -3717,8 +3896,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3717
3896
|
const hostDefaults = {
|
|
3718
3897
|
id: "host-1",
|
|
3719
3898
|
name: "Test host",
|
|
3720
|
-
type: "persistent",
|
|
3721
3899
|
status: "connected",
|
|
3900
|
+
type: "persistent",
|
|
3722
3901
|
maxPermissionMode: "full",
|
|
3723
3902
|
lastSeenAt: null,
|
|
3724
3903
|
lastRejectedProtocolVersion: null,
|
|
@@ -3764,6 +3943,8 @@ function makeMessageDispatchHookContext(overrides = {}) {
|
|
|
3764
3943
|
function makeQueueEntry(overrides = {}) {
|
|
3765
3944
|
return {
|
|
3766
3945
|
id: "queued_1",
|
|
3946
|
+
initiator: "user",
|
|
3947
|
+
senderThreadId: null,
|
|
3767
3948
|
threadId: "thread-1",
|
|
3768
3949
|
content: [{ type: "text", text: "Queued turn", mentions: [] }],
|
|
3769
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",
|