@get-bb/plugin-sdk 0.4.56 → 0.4.87

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.
@@ -1,4 +1,5 @@
1
1
  // src/internal/host-policy.ts
2
+ import { createHash } from "node:crypto";
2
3
  import { z as z4 } from "zod";
3
4
 
4
5
  // ../domain/src/plugin-icon.ts
@@ -44,6 +45,10 @@ var RESERVED_BB_CLI_COMMANDS = [
44
45
  "voice"
45
46
  ];
46
47
 
48
+ // ../domain/src/plugin-interaction-limits.ts
49
+ var PLUGIN_INTERACTION_MAX_TITLE_LENGTH = 160;
50
+ var PLUGIN_INTERACTION_MAX_PAYLOAD_BYTES = 64 * 1024;
51
+
47
52
  // ../domain/src/provider-fork.ts
48
53
  import { z } from "zod";
49
54
  var PROVIDER_FORK_VALUES = ["none", "tip", "checkpoint"];
@@ -306,8 +311,7 @@ var pluginProviderEnvEntrySchema = z4.object({
306
311
  z4.string(),
307
312
  z4.object({ serverPath: z4.string().startsWith("/") }).strict()
308
313
  ]),
309
- reason: z4.string(),
310
- secret: z4.boolean()
314
+ reason: z4.string()
311
315
  }).strict();
312
316
  var pluginProviderEnvEntriesSchema = z4.array(pluginProviderEnvEntrySchema).max(PLUGIN_PROVIDER_ENV_MAX_ENTRIES).superRefine((entries, context) => {
313
317
  const names = /* @__PURE__ */ new Set();
@@ -515,6 +519,22 @@ function validateSettingsUpdate(descriptors, values) {
515
519
  }
516
520
  return errors;
517
521
  }
522
+ function coerceStoredPluginSettingValue(descriptor, value) {
523
+ let coerced = value;
524
+ if (descriptor.type === "number" && typeof coerced === "string") {
525
+ const legacyNumber = Number(coerced.trim());
526
+ coerced = coerced.trim().length > 0 && Number.isFinite(legacyNumber) ? legacyNumber : void 0;
527
+ }
528
+ if (descriptor.type === "number" && typeof coerced === "number" && !Number.isFinite(coerced)) {
529
+ coerced = void 0;
530
+ }
531
+ const expected = descriptor.type === "boolean" ? "boolean" : descriptor.type === "number" ? "number" : "string";
532
+ if (typeof coerced !== expected) coerced = void 0;
533
+ if (descriptor.type === "select" && typeof coerced === "string" && !descriptor.options.includes(coerced)) {
534
+ coerced = void 0;
535
+ }
536
+ return coerced ?? descriptor.default;
537
+ }
518
538
  var PLUGIN_MENTION_TRIGGER_VALUES = [
519
539
  "@",
520
540
  "#",
@@ -1776,79 +1796,64 @@ function pluginHookAlreadyRegisteredMessage(hook) {
1776
1796
  }
1777
1797
  var ENVIRONMENT_PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
1778
1798
  var ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS = 80;
1799
+ var ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS = 200;
1779
1800
  var ENVIRONMENT_PROVIDER_REQUIREMENT_NAMES = [
1780
1801
  "projectCheckout",
1781
1802
  "gitCheckout",
1782
1803
  "gitRemote",
1783
1804
  "projectless"
1784
1805
  ];
1785
- function validatePluginEnvironmentProviderDeclaration(declaration) {
1806
+ var environmentCompositionSchema = z4.object({
1807
+ id: z4.string().regex(ENVIRONMENT_PROVIDER_ID_PATTERN),
1808
+ displayName: z4.string().trim().min(1).max(ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS),
1809
+ description: z4.string().trim().min(1).max(ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS).optional().transform((value) => value ?? null),
1810
+ icon: z4.string().trim().min(1).transform(
1811
+ (icon) => isPluginOwnedIconPath(icon) ? validateProviderRelativePath(icon, "Composition icon") : icon
1812
+ ).optional().transform((value) => value ?? null),
1813
+ machineProviderId: z4.string().regex(ENVIRONMENT_PROVIDER_ID_PATTERN),
1814
+ environmentProviderId: z4.string().regex(ENVIRONMENT_PROVIDER_ID_PATTERN)
1815
+ }).strict();
1816
+ function requireProviderIdAndDisplayName(noun, declaration) {
1786
1817
  if (typeof declaration !== "object" || declaration === null) {
1787
- throw new Error("environment provider declaration must be an object");
1818
+ throw new Error(`${noun} declaration must be an object`);
1788
1819
  }
1789
1820
  const id = declaration.id;
1790
1821
  if (typeof id !== "string" || !ENVIRONMENT_PROVIDER_ID_PATTERN.test(id)) {
1791
1822
  throw new Error(
1792
- `invalid environment provider id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, or "-", starting with a letter or digit`
1823
+ `invalid ${noun} id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, or "-", starting with a letter or digit`
1793
1824
  );
1794
1825
  }
1795
1826
  const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
1796
1827
  if (displayName.length === 0 || displayName.length > ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS) {
1797
1828
  throw new Error(
1798
- `environment provider "${id}" needs a displayName of 1-${ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS} characters`
1829
+ `${noun} "${id}" needs a displayName of 1-${ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS} characters`
1799
1830
  );
1800
1831
  }
1801
- const icon = declaration.icon === void 0 ? null : z4.string().min(1).parse(declaration.icon).trim();
1802
- if (icon !== null) {
1803
- if (isPluginOwnedIconPath(icon))
1804
- validateProviderRelativePath(icon, `"${id}" icon`);
1805
- else if (!isNamespacedGlyph(icon) && /[/\\]/u.test(icon))
1806
- throw new Error(
1807
- `environment provider "${id}" icon must be a glyph, declared icon, or plugin-relative path`
1808
- );
1809
- }
1810
- if (icon !== null && icon.length === 0) {
1811
- throw new Error(`environment provider "${id}" declares an empty icon`);
1812
- }
1813
- const requires = normalizeEnvironmentProviderRequirements(id, declaration);
1814
- const inputs = normalizeEnvironmentProviderInputs(id, declaration);
1815
- if (typeof declaration.create !== "function" || typeof declaration.remove !== "function") {
1816
- throw new Error(
1817
- `environment provider "${id}" must declare create and remove functions`
1818
- );
1819
- }
1820
- if (declaration.validate !== void 0 && typeof declaration.validate !== "function") {
1832
+ return { id, displayName };
1833
+ }
1834
+ function assertProviderIconShape(noun, id, icon) {
1835
+ if (isPluginOwnedIconPath(icon)) {
1836
+ validateProviderRelativePath(icon, `"${id}" icon`);
1837
+ } else if (!isNamespacedGlyph(icon) && /[/\\]/u.test(icon)) {
1821
1838
  throw new Error(
1822
- `environment provider "${id}" declares a validate that is not a function`
1839
+ `${noun} "${id}" icon must be a glyph, declared icon, or plugin-relative path`
1823
1840
  );
1824
1841
  }
1825
- if (declaration.availability !== void 0 && typeof declaration.availability !== "function") {
1842
+ }
1843
+ function assertOptionalFunction(noun, id, value, phrase) {
1844
+ if (value !== void 0 && typeof value !== "function") {
1826
1845
  throw new Error(
1827
- `environment provider "${id}" declares availability that is not a function`
1846
+ `${noun} "${id}" declares ${phrase} that is not a function`
1828
1847
  );
1829
1848
  }
1830
- return {
1831
- id,
1832
- displayName,
1833
- icon,
1834
- requires,
1835
- inputs: inputs === null ? null : inputs.schema,
1836
- inputsJsonSchema: inputs === null ? null : inputs.jsonSchema,
1837
- availability: declaration.availability ?? null,
1838
- validate: declaration.validate ?? null,
1839
- create: declaration.create,
1840
- remove: declaration.remove,
1841
- policy: environmentProviderPolicySchema.parse(declaration.policy ?? {})
1842
- };
1843
1849
  }
1844
- function normalizeEnvironmentProviderInputs(id, declaration) {
1845
- const inputs = declaration.inputs;
1850
+ function normalizeProviderInputs(noun, id, inputs) {
1846
1851
  if (inputs === void 0) {
1847
1852
  return null;
1848
1853
  }
1849
1854
  if (!isStandardSchema(inputs)) {
1850
1855
  throw new Error(
1851
- `environment provider "${id}" declares an inputs that is not a Standard Schema v1 validator`
1856
+ `${noun} "${id}" declares an inputs that is not a Standard Schema v1 validator`
1852
1857
  );
1853
1858
  }
1854
1859
  let converted;
@@ -1856,17 +1861,65 @@ function normalizeEnvironmentProviderInputs(id, declaration) {
1856
1861
  converted = JSON.parse(JSON.stringify(standardSchemaToJsonSchema(inputs)));
1857
1862
  } catch (error) {
1858
1863
  throw new Error(
1859
- `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()`
1864
+ `${noun} "${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()`
1860
1865
  );
1861
1866
  }
1862
1867
  const jsonSchema = jsonValueSchema.safeParse(converted);
1863
1868
  if (!jsonSchema.success) {
1864
1869
  throw new Error(
1865
- `environment provider "${id}" declares an inputs schema whose JSON Schema is not JSON-serializable`
1870
+ `${noun} "${id}" declares an inputs schema whose JSON Schema is not JSON-serializable`
1866
1871
  );
1867
1872
  }
1868
1873
  return { schema: inputs, jsonSchema: jsonSchema.data };
1869
1874
  }
1875
+ function validatePluginEnvironmentProviderDeclaration(declaration) {
1876
+ const { id, displayName } = requireProviderIdAndDisplayName(
1877
+ "environment provider",
1878
+ declaration
1879
+ );
1880
+ const description = z4.string().trim().min(1).max(ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS).optional().transform((value) => value ?? null).parse(declaration.description);
1881
+ const icon = z4.string().trim().min(1).optional().transform((value) => value ?? null).parse(declaration.icon);
1882
+ if (icon !== null) {
1883
+ assertProviderIconShape("environment provider", id, icon);
1884
+ }
1885
+ const requires = normalizeEnvironmentProviderRequirements(id, declaration);
1886
+ const inputs = normalizeProviderInputs(
1887
+ "environment provider",
1888
+ id,
1889
+ declaration.inputs
1890
+ );
1891
+ if (typeof declaration.create !== "function" || typeof declaration.remove !== "function") {
1892
+ throw new Error(
1893
+ `environment provider "${id}" must declare create and remove functions`
1894
+ );
1895
+ }
1896
+ assertOptionalFunction(
1897
+ "environment provider",
1898
+ id,
1899
+ declaration.validate,
1900
+ "a validate"
1901
+ );
1902
+ assertOptionalFunction(
1903
+ "environment provider",
1904
+ id,
1905
+ declaration.availability,
1906
+ "availability"
1907
+ );
1908
+ return {
1909
+ id,
1910
+ displayName,
1911
+ description,
1912
+ icon,
1913
+ requires,
1914
+ inputs: inputs === null ? null : inputs.schema,
1915
+ inputsJsonSchema: inputs === null ? null : inputs.jsonSchema,
1916
+ availability: declaration.availability ?? null,
1917
+ validate: declaration.validate ?? null,
1918
+ create: declaration.create,
1919
+ remove: declaration.remove,
1920
+ policy: environmentProviderPolicySchema.parse(declaration.policy ?? {})
1921
+ };
1922
+ }
1870
1923
  function normalizeEnvironmentProviderRequirements(id, declaration) {
1871
1924
  const requires = declaration.requires ?? {};
1872
1925
  if (typeof requires !== "object" || requires === null || Array.isArray(requires)) {
@@ -1898,23 +1951,747 @@ var environmentProviderPolicySchema = z4.object({
1898
1951
  retireGraceMs: z4.number().int().nonnegative().nullable().default(3e5),
1899
1952
  pathKeys: z4.enum(["per-thread", "per-attempt"]).default("per-thread")
1900
1953
  }).strict();
1901
- var MACHINE_PROVIDER_REQUIREMENT_NAMES = ["gitRemote"];
1954
+ var MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS = 200;
1955
+ function validatePluginMachineProviderDeclaration(declaration) {
1956
+ const { id, displayName } = requireProviderIdAndDisplayName(
1957
+ "machine provider",
1958
+ declaration
1959
+ );
1960
+ const description = z4.string().trim().min(1).max(MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS).parse(declaration.description);
1961
+ const icon = z4.string().trim().min(1).parse(declaration.icon);
1962
+ assertProviderIconShape("machine provider", id, icon);
1963
+ const ephemeral = z4.boolean().default(false).parse(declaration.ephemeral);
1964
+ const inputs = normalizeProviderInputs(
1965
+ "machine provider",
1966
+ id,
1967
+ declaration.inputs
1968
+ );
1969
+ if (typeof declaration.create !== "function" || typeof declaration.reconcileCleanup !== "function" || typeof declaration.remove !== "function") {
1970
+ throw new Error(
1971
+ `machine provider "${id}" must declare create, reconcileCleanup and remove functions`
1972
+ );
1973
+ }
1974
+ const hasSuspend = typeof declaration.suspend === "function";
1975
+ const hasResume = typeof declaration.resume === "function";
1976
+ if (hasSuspend !== hasResume) {
1977
+ throw new Error(
1978
+ `machine provider "${id}" must declare suspend and resume together`
1979
+ );
1980
+ }
1981
+ assertOptionalFunction(
1982
+ "machine provider",
1983
+ id,
1984
+ declaration.validate,
1985
+ "a validate"
1986
+ );
1987
+ assertOptionalFunction(
1988
+ "machine provider",
1989
+ id,
1990
+ declaration.availability,
1991
+ "availability"
1992
+ );
1993
+ return {
1994
+ id,
1995
+ displayName,
1996
+ description,
1997
+ icon,
1998
+ ephemeral,
1999
+ inputs: inputs === null ? null : inputs.schema,
2000
+ inputsJsonSchema: inputs === null ? null : inputs.jsonSchema,
2001
+ availability: declaration.availability ?? null,
2002
+ validate: declaration.validate ?? null,
2003
+ reconcileCleanup: declaration.reconcileCleanup,
2004
+ create: declaration.create,
2005
+ suspend: declaration.suspend ?? null,
2006
+ resume: declaration.resume ?? null,
2007
+ remove: declaration.remove
2008
+ };
2009
+ }
2010
+ function validateServerAccessProviderDeclaration(declaration) {
2011
+ if (typeof declaration !== "object" || declaration === null)
2012
+ throw new Error("Invalid server access provider declaration");
2013
+ if (typeof declaration.id !== "string" || !/^[a-z][a-z0-9-]*$/u.test(declaration.id) || declaration.id === "direct")
2014
+ throw new Error("Invalid or reserved server access provider id");
2015
+ if (typeof declaration.displayName !== "string" || !declaration.displayName.trim() || typeof declaration.description !== "string" || !declaration.description.trim() || typeof declaration.availability !== "function" || typeof declaration.acquire !== "function" || typeof declaration.release !== "function")
2016
+ throw new Error("Invalid server access provider declaration");
2017
+ return declaration;
2018
+ }
2019
+ var LEGACY_UNKNOWN_MIGRATION_HASH = "legacy-unknown";
2020
+ function migrationStatementHash(statement) {
2021
+ return createHash("sha256").update(statement).digest("hex");
2022
+ }
2023
+ function runPluginStorageMigrations(database, statements) {
2024
+ database.exec(
2025
+ "CREATE TABLE IF NOT EXISTS _bb_migrations (id INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL, statement_hash TEXT)"
2026
+ );
2027
+ const migrationColumns = database.prepare("PRAGMA table_info(_bb_migrations)").all();
2028
+ if (!migrationColumns.some((column) => column.name === "statement_hash")) {
2029
+ database.exec("ALTER TABLE _bb_migrations ADD COLUMN statement_hash TEXT");
2030
+ }
2031
+ const rows = database.prepare(
2032
+ "SELECT id, statement_hash FROM _bb_migrations ORDER BY id"
2033
+ ).all();
2034
+ const applied = /* @__PURE__ */ new Map();
2035
+ for (const row of rows) applied.set(row.id, row.statement_hash);
2036
+ const statementHashes = statements.map(migrationStatementHash);
2037
+ statementHashes.forEach((statementHash, index) => {
2038
+ const recordedHash = applied.get(index);
2039
+ if (recordedHash !== void 0 && recordedHash !== null && recordedHash !== statementHash) {
2040
+ throw new Error(
2041
+ `migration ${index} does not match the recorded statement; append a new migration instead of changing or reusing an index`
2042
+ );
2043
+ }
2044
+ });
2045
+ const adopt = database.prepare(
2046
+ "UPDATE _bb_migrations SET statement_hash = ? WHERE id = ? AND statement_hash IS NULL"
2047
+ );
2048
+ const record = database.prepare(
2049
+ "INSERT INTO _bb_migrations (id, applied_at, statement_hash) VALUES (?, ?, ?)"
2050
+ );
2051
+ database.transaction(() => {
2052
+ for (const row of rows) {
2053
+ if (row.statement_hash !== null) continue;
2054
+ adopt.run(
2055
+ statementHashes[row.id] ?? LEGACY_UNKNOWN_MIGRATION_HASH,
2056
+ row.id
2057
+ );
2058
+ }
2059
+ statements.forEach((statement, index) => {
2060
+ if (applied.has(index)) return;
2061
+ database.exec(statement);
2062
+ record.run(index, Date.now(), statementHashes[index]);
2063
+ });
2064
+ })();
2065
+ }
2066
+ function normalizeHttpRouteRegistration(method, path, handler, opts, existingRoutes) {
2067
+ const normalizedMethod = String(method).toUpperCase();
2068
+ if (!PLUGIN_HTTP_METHODS.has(normalizedMethod)) {
2069
+ throw new Error(
2070
+ `invalid http method "${String(method)}" \u2014 use one of: ${[...PLUGIN_HTTP_METHODS].join(", ")}`
2071
+ );
2072
+ }
2073
+ if (typeof path !== "string" || !path.startsWith("/")) {
2074
+ throw new Error(
2075
+ `http route path must be a string starting with "/", got ${JSON.stringify(path)}`
2076
+ );
2077
+ }
2078
+ if (typeof handler !== "function") {
2079
+ throw new Error(
2080
+ `http route handler for ${normalizedMethod} ${path} must be a function`
2081
+ );
2082
+ }
2083
+ const auth = opts?.auth ?? "local";
2084
+ if (auth !== "local" && auth !== "token" && auth !== "none") {
2085
+ throw new Error(
2086
+ `invalid auth mode "${String(auth)}" for ${normalizedMethod} ${path} \u2014 use "local", "token", or "none"`
2087
+ );
2088
+ }
2089
+ if (existingRoutes.some(
2090
+ (route) => route.method === normalizedMethod && route.path === path
2091
+ )) {
2092
+ throw new Error(
2093
+ `http route ${normalizedMethod} ${path} is already registered`
2094
+ );
2095
+ }
2096
+ return { method: normalizedMethod, path, auth };
2097
+ }
2098
+ function normalizeWebSocketRouteRegistration(path, handler, opts, existingRoutes) {
2099
+ if (typeof path !== "string" || !path.startsWith("/")) {
2100
+ throw new Error(
2101
+ `websocket route path must be a string starting with "/", got ${JSON.stringify(path)}`
2102
+ );
2103
+ }
2104
+ if (typeof handler !== "function") {
2105
+ throw new Error(`websocket route handler for ${path} must be a function`);
2106
+ }
2107
+ const auth = opts?.auth ?? "local";
2108
+ if (auth !== "local" && auth !== "token" && auth !== "none") {
2109
+ throw new Error(
2110
+ `invalid auth mode "${String(auth)}" for websocket ${path} \u2014 use "local", "token", or "none"`
2111
+ );
2112
+ }
2113
+ if (existingRoutes.some((route) => route.path === path)) {
2114
+ throw new Error(`websocket route ${path} is already registered`);
2115
+ }
2116
+ return { path, auth };
2117
+ }
2118
+ function normalizeRpcRegistration(contract, handlers, registered) {
2119
+ if (typeof contract !== "object" || contract === null || Array.isArray(contract)) {
2120
+ throw new Error("rpc.register contract must be an object");
2121
+ }
2122
+ if (typeof handlers !== "object" || handlers === null || Array.isArray(handlers)) {
2123
+ throw new Error("rpc.register handlers must be an object");
2124
+ }
2125
+ const pending = [];
2126
+ const contractEntries = Object.entries(contract);
2127
+ const contractNames = new Set(contractEntries.map(([name]) => name));
2128
+ for (const extraName of Object.keys(handlers)) {
2129
+ if (!contractNames.has(extraName)) {
2130
+ throw new Error(
2131
+ `rpc handler "${extraName}" has no matching contract method`
2132
+ );
2133
+ }
2134
+ }
2135
+ for (const [name, methodContractValue] of contractEntries) {
2136
+ if (!RPC_METHOD_PATTERN.test(name)) {
2137
+ throw new Error(
2138
+ `invalid rpc method name "${name}" \u2014 use dot-separated segments with letters, digits, "-" and "_"`
2139
+ );
2140
+ }
2141
+ const methodContract = readRpcMethodContract(name, methodContractValue);
2142
+ const handler = Reflect.get(handlers, name);
2143
+ if (typeof handler !== "function") {
2144
+ throw new Error(`rpc method "${name}" must provide a handler function`);
2145
+ }
2146
+ if (registered.has(name)) {
2147
+ throw new Error(`rpc method "${name}" is already registered`);
2148
+ }
2149
+ pending.push([
2150
+ name,
2151
+ {
2152
+ inputSchema: methodContract.input,
2153
+ outputSchema: methodContract.output,
2154
+ handler
2155
+ }
2156
+ ]);
2157
+ }
2158
+ return pending;
2159
+ }
2160
+ function normalizeRealtimePayload(channel, payload) {
2161
+ if (typeof channel !== "string" || channel.length === 0) {
2162
+ throw new Error("realtime channel must be a non-empty string");
2163
+ }
2164
+ if (payload === void 0) return null;
2165
+ let json;
2166
+ try {
2167
+ json = JSON.stringify(payload);
2168
+ } catch {
2169
+ json = void 0;
2170
+ }
2171
+ if (json === void 0) {
2172
+ throw new Error(
2173
+ `realtime payload for channel "${channel}" is not JSON-serializable`
2174
+ );
2175
+ }
2176
+ return JSON.parse(json);
2177
+ }
2178
+ function validateBackgroundServiceRegistration(name, service, existing) {
2179
+ if (typeof name !== "string" || !BACKGROUND_NAME_PATTERN.test(name)) {
2180
+ throw new Error(
2181
+ `invalid service name ${JSON.stringify(name)} \u2014 use letters, digits, "-" and "_"`
2182
+ );
2183
+ }
2184
+ if (existing.some((record) => record.name === name)) {
2185
+ throw new Error(`background service "${name}" is already registered`);
2186
+ }
2187
+ if (typeof service?.start !== "function") {
2188
+ throw new Error(
2189
+ `background service "${name}" must provide a start(signal) function`
2190
+ );
2191
+ }
2192
+ return { name, start: service.start.bind(service) };
2193
+ }
2194
+ function validateScheduleRegistration(name, cron, fn, existing, parseCron) {
2195
+ if (typeof name !== "string" || !BACKGROUND_NAME_PATTERN.test(name)) {
2196
+ throw new Error(
2197
+ `invalid schedule name ${JSON.stringify(name)} \u2014 use letters, digits, "-" and "_"`
2198
+ );
2199
+ }
2200
+ if (existing.some((record) => record.name === name)) {
2201
+ throw new Error(`schedule "${name}" is already registered`);
2202
+ }
2203
+ try {
2204
+ parseCron(String(cron));
2205
+ } catch (error) {
2206
+ throw new Error(
2207
+ `invalid cron ${JSON.stringify(cron)} for schedule "${name}": ${error instanceof Error ? error.message : String(error)}`
2208
+ );
2209
+ }
2210
+ if (typeof fn !== "function") {
2211
+ throw new Error(`schedule "${name}" must provide a function`);
2212
+ }
2213
+ return { name, cron: String(cron), fn };
2214
+ }
2215
+ function normalizeCliRegistration(registration, alreadyRegistered) {
2216
+ if (alreadyRegistered) {
2217
+ throw new Error("cli command is already registered");
2218
+ }
2219
+ const name = registration?.name;
2220
+ if (typeof name !== "string" || !CLI_COMMAND_NAME_PATTERN.test(name)) {
2221
+ throw new Error(
2222
+ `invalid cli command name ${JSON.stringify(name)} \u2014 use lowercase letters, digits, and "-"`
2223
+ );
2224
+ }
2225
+ if (typeof registration.summary !== "string" || registration.summary.trim().length === 0) {
2226
+ throw new Error(`cli command "${name}" must provide a summary`);
2227
+ }
2228
+ const commands = registration.commands ?? [];
2229
+ if (!Array.isArray(commands)) {
2230
+ throw new Error(`cli command "${name}" commands must be an array`);
2231
+ }
2232
+ const validatedCommands = commands.map((command, index) => {
2233
+ if (typeof command?.name !== "string" || !CLI_COMMAND_NAME_PATTERN.test(command.name) || typeof command.summary !== "string" || typeof command.usage !== "string") {
2234
+ throw new Error(
2235
+ `cli command "${name}" commands[${index}] must be { name: [a-z0-9-]+, summary, usage }`
2236
+ );
2237
+ }
2238
+ return {
2239
+ name: command.name,
2240
+ summary: command.summary,
2241
+ usage: command.usage
2242
+ };
2243
+ });
2244
+ if (typeof registration.run !== "function") {
2245
+ throw new Error(
2246
+ `cli command "${name}" must provide a run(argv, ctx) function`
2247
+ );
2248
+ }
2249
+ return {
2250
+ name,
2251
+ summary: registration.summary,
2252
+ commands: validatedCommands,
2253
+ run: registration.run.bind(registration)
2254
+ };
2255
+ }
2256
+ function normalizeAgentToolRegistration(args) {
2257
+ const { pluginId, declaredIconNames, tool } = args;
2258
+ const name = tool?.name;
2259
+ if (typeof name !== "string" || !AGENT_TOOL_NAME_PATTERN.test(name)) {
2260
+ throw new Error(
2261
+ `invalid tool name ${JSON.stringify(name)} \u2014 use letters, digits, "-" and "_"`
2262
+ );
2263
+ }
2264
+ if (RESERVED_AGENT_TOOL_NAMES.includes(name)) {
2265
+ throw new Error(
2266
+ `tool name "${name}" is a built-in bb tool \u2014 pick another name`
2267
+ );
2268
+ }
2269
+ rejectStaleAgentToolFields(name, tool);
2270
+ if (typeof tool.description !== "string" || tool.description.trim().length === 0) {
2271
+ throw new Error(`tool "${name}" must provide a description`);
2272
+ }
2273
+ if (tool.instructions !== void 0 && typeof tool.instructions !== "string") {
2274
+ throw new Error(`tool "${name}" instructions must be a string`);
2275
+ }
2276
+ if (typeof tool.instructions === "string" && tool.instructions.length > PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS) {
2277
+ throw new Error(
2278
+ `tool "${name}" instructions exceed the ${PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS}-character limit`
2279
+ );
2280
+ }
2281
+ const presentation = parsePluginAgentToolPresentation(
2282
+ name,
2283
+ tool.presentation
2284
+ );
2285
+ if (presentation?.icon !== void 0) {
2286
+ const problem = undeclaredIconProblem(
2287
+ pluginId,
2288
+ declaredIconNames,
2289
+ presentation.icon.glyph
2290
+ );
2291
+ if (problem !== null) {
2292
+ throw new Error(agentToolIconRefusalMessage(name, problem));
2293
+ }
2294
+ }
2295
+ if (typeof tool.execute !== "function") {
2296
+ throw new Error(
2297
+ `tool "${name}" must provide an execute(params, ctx) function`
2298
+ );
2299
+ }
2300
+ const parameters = tool.parameters;
2301
+ let inputSchema;
2302
+ let parse;
2303
+ if (isZodSchemaLike(parameters)) {
2304
+ try {
2305
+ inputSchema = zodSchemaToJsonSchema(parameters);
2306
+ } catch (error) {
2307
+ throw new Error(
2308
+ `tool "${name}" parameters look like a zod schema but could not be converted to JSON Schema (${error instanceof Error ? error.message : String(error)}) \u2014 use zod 4, or pass a plain JSON-schema object`
2309
+ );
2310
+ }
2311
+ parse = (input) => {
2312
+ const result = parameters.safeParse(input);
2313
+ if (result.success) return { ok: true, value: result.data };
2314
+ return { ok: false, error: summarizeParseIssues(result.error) };
2315
+ };
2316
+ } else if (typeof parameters === "object" && parameters !== null && !Array.isArray(parameters)) {
2317
+ try {
2318
+ inputSchema = JSON.parse(JSON.stringify(parameters));
2319
+ } catch {
2320
+ throw new Error(
2321
+ `tool "${name}" parameters JSON schema is not JSON-serializable`
2322
+ );
2323
+ }
2324
+ parse = (input) => ({ ok: true, value: input });
2325
+ } else {
2326
+ throw new Error(
2327
+ `tool "${name}" parameters must be a zod schema or a JSON-schema object`
2328
+ );
2329
+ }
2330
+ assertNoRecursiveJsonSchemaReferences(
2331
+ inputSchema,
2332
+ `tool "${name}" parameters`
2333
+ );
2334
+ return {
2335
+ name,
2336
+ description: tool.description,
2337
+ presentation,
2338
+ instructions: tool.instructions !== void 0 && tool.instructions.trim().length > 0 ? tool.instructions : null,
2339
+ inputSchema,
2340
+ parse,
2341
+ execute: tool.execute.bind(tool)
2342
+ };
2343
+ }
2344
+ function normalizeMentionProviderRegistration(provider, existing) {
2345
+ const id = provider?.id;
2346
+ if (typeof id !== "string" || !MENTION_PROVIDER_ID_PATTERN.test(id)) {
2347
+ throw new Error(
2348
+ `invalid mention provider id ${JSON.stringify(id)} \u2014 use letters, digits, "-" and "_"`
2349
+ );
2350
+ }
2351
+ if (existing.some((record) => record.id === id)) {
2352
+ throw new Error(`mention provider "${id}" is already registered`);
2353
+ }
2354
+ if (typeof provider.label !== "string" || provider.label.trim().length === 0) {
2355
+ throw new Error(`mention provider "${id}" must provide a label`);
2356
+ }
2357
+ if (typeof provider.search !== "function") {
2358
+ throw new Error(
2359
+ `mention provider "${id}" must provide a search({ query, projectId, threadId }) function`
2360
+ );
2361
+ }
2362
+ if (typeof provider.resolve !== "function") {
2363
+ throw new Error(
2364
+ `mention provider "${id}" must provide a resolve(itemId) function`
2365
+ );
2366
+ }
2367
+ return {
2368
+ id,
2369
+ label: provider.label.trim(),
2370
+ triggers: normalizeMentionProviderTriggers(id, provider.triggers),
2371
+ search: provider.search.bind(provider),
2372
+ resolve: provider.resolve.bind(provider)
2373
+ };
2374
+ }
2375
+ function normalizeInteractionRequest(request) {
2376
+ if (!request || typeof request !== "object") {
2377
+ throw new Error("ui.requestInput requires an options object");
2378
+ }
2379
+ if (typeof request.threadId !== "string" || request.threadId.length === 0) {
2380
+ throw new Error("ui.requestInput threadId must be a non-empty string");
2381
+ }
2382
+ if (typeof request.rendererId !== "string" || !/^[a-zA-Z0-9_-]+$/.test(request.rendererId)) {
2383
+ throw new Error(
2384
+ "ui.requestInput rendererId must use letters, digits, '-' or '_'"
2385
+ );
2386
+ }
2387
+ if (typeof request.title !== "string" || request.title.trim().length === 0 || request.title.trim().length > PLUGIN_INTERACTION_MAX_TITLE_LENGTH) {
2388
+ throw new Error(
2389
+ `ui.requestInput title must be 1-${PLUGIN_INTERACTION_MAX_TITLE_LENGTH} characters`
2390
+ );
2391
+ }
2392
+ let payload;
2393
+ try {
2394
+ const json = JSON.stringify(request.payload);
2395
+ if (json === void 0) throw new Error();
2396
+ if (Buffer.byteLength(json, "utf8") > PLUGIN_INTERACTION_MAX_PAYLOAD_BYTES) {
2397
+ throw new Error("ui.requestInput payload exceeds 64 KiB");
2398
+ }
2399
+ payload = JSON.parse(json);
2400
+ } catch (error) {
2401
+ if (error instanceof Error && error.message.includes("64 KiB")) {
2402
+ throw error;
2403
+ }
2404
+ throw new Error("ui.requestInput payload must be JSON-serializable");
2405
+ }
2406
+ const timeoutMs = request.timeoutMs ?? 10 * 60 * 1e3;
2407
+ if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 60 * 60 * 1e3) {
2408
+ throw new Error("ui.requestInput timeoutMs must be between 1 and 3600000");
2409
+ }
2410
+ return {
2411
+ threadId: request.threadId,
2412
+ rendererId: request.rendererId,
2413
+ title: request.title.trim(),
2414
+ payload,
2415
+ timeoutMs
2416
+ };
2417
+ }
2418
+ function validateProviderEnvContribution(label, providerId, resolve, registered) {
2419
+ if (typeof providerId !== "string" || providerId.trim().length === 0) {
2420
+ throw new Error(`${label} requires a provider id`);
2421
+ }
2422
+ if (registered.has(providerId)) {
2423
+ throw new Error(`${label} for "${providerId}" is already registered`);
2424
+ }
2425
+ if (typeof resolve !== "function") {
2426
+ throw new Error(`${label} requires a resolver function`);
2427
+ }
2428
+ }
2429
+ function normalizePluginAgentToolParameters(args) {
2430
+ const { index, value } = args;
2431
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
2432
+ throw new Error(
2433
+ `configure() output.tools[${index}].parameters must be a JSON-schema object`
2434
+ );
2435
+ }
2436
+ let serialized;
2437
+ try {
2438
+ serialized = JSON.stringify(value);
2439
+ } catch {
2440
+ throw new Error(
2441
+ `configure() output.tools[${index}].parameters is not JSON-serializable`
2442
+ );
2443
+ }
2444
+ if (serialized === void 0) {
2445
+ throw new Error(
2446
+ `configure() output.tools[${index}].parameters is not JSON-serializable`
2447
+ );
2448
+ }
2449
+ if (Buffer.byteLength(serialized, "utf8") > PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES) {
2450
+ throw new Error(
2451
+ `configure() output.tools[${index}].parameters exceeds the ${PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES}-byte limit`
2452
+ );
2453
+ }
2454
+ const parameters = JSON.parse(serialized);
2455
+ if (parameters.type !== "object") {
2456
+ throw new Error(
2457
+ `configure() output.tools[${index}].parameters must have root type "object"`
2458
+ );
2459
+ }
2460
+ assertNoRecursiveJsonSchemaReferences(
2461
+ parameters,
2462
+ `configure() output.tools[${index}].parameters`
2463
+ );
2464
+ return parameters;
2465
+ }
2466
+ function normalizePluginAgentToolSelections(args) {
2467
+ if (!Array.isArray(args.value)) {
2468
+ throw new Error("configure() output.tools must be an array");
2469
+ }
2470
+ if (args.value.length > PLUGIN_AGENT_SELECTION_MAX_IDS) {
2471
+ throw new Error(
2472
+ `configure() output.tools exceeds the ${PLUGIN_AGENT_SELECTION_MAX_IDS}-id limit`
2473
+ );
2474
+ }
2475
+ const toolIds = [];
2476
+ const parameterOverrides = /* @__PURE__ */ new Map();
2477
+ const seen = /* @__PURE__ */ new Set();
2478
+ for (let index = 0; index < args.value.length; index += 1) {
2479
+ const entry = args.value[index];
2480
+ let name;
2481
+ let parameters = null;
2482
+ if (typeof entry === "string") {
2483
+ name = entry;
2484
+ } else if (typeof entry === "object" && entry !== null && !Array.isArray(entry)) {
2485
+ const typed = entry;
2486
+ const unknownKeys = Object.keys(typed).filter((key) => !["name", "parameters"].includes(key)).sort();
2487
+ if (unknownKeys.length > 0) {
2488
+ throw new Error(
2489
+ `configure() output.tools[${index}] contains unknown field${unknownKeys.length === 1 ? "" : "s"}: ${unknownKeys.join(", ")}`
2490
+ );
2491
+ }
2492
+ name = typed.name;
2493
+ parameters = normalizePluginAgentToolParameters({
2494
+ index,
2495
+ value: typed.parameters
2496
+ });
2497
+ } else {
2498
+ throw new Error(
2499
+ `configure() output.tools[${index}] must be a tool name or { name, parameters }`
2500
+ );
2501
+ }
2502
+ if (typeof name !== "string" || name.length === 0) {
2503
+ throw new Error(
2504
+ `configure() output.tools[${index}] must ${typeof entry === "string" ? "be" : "name"} a non-empty string`
2505
+ );
2506
+ }
2507
+ if (seen.has(name)) {
2508
+ throw new Error(
2509
+ `configure() output.tools contains duplicate id ${JSON.stringify(name)}`
2510
+ );
2511
+ }
2512
+ if (!args.knownIds.has(name)) {
2513
+ throw new Error(
2514
+ `configure() selected unknown tool id ${JSON.stringify(name)} owned by plugin ${JSON.stringify(args.pluginId)}`
2515
+ );
2516
+ }
2517
+ seen.add(name);
2518
+ toolIds.push(name);
2519
+ if (parameters !== null) parameterOverrides.set(name, parameters);
2520
+ }
2521
+ return { toolIds, parameterOverrides };
2522
+ }
2523
+ function normalizePluginAgentSelectionIds(args) {
2524
+ if (!Array.isArray(args.value)) {
2525
+ throw new Error("configure() output.skills must be an array");
2526
+ }
2527
+ if (args.value.length > PLUGIN_AGENT_SELECTION_MAX_IDS) {
2528
+ throw new Error(
2529
+ `configure() output.skills exceeds the ${PLUGIN_AGENT_SELECTION_MAX_IDS}-id limit`
2530
+ );
2531
+ }
2532
+ const selected = [];
2533
+ const seen = /* @__PURE__ */ new Set();
2534
+ for (let index = 0; index < args.value.length; index += 1) {
2535
+ const id = args.value[index];
2536
+ if (typeof id !== "string" || id.length === 0) {
2537
+ throw new Error(
2538
+ `configure() output.skills[${index}] must be a non-empty string`
2539
+ );
2540
+ }
2541
+ if (seen.has(id)) {
2542
+ throw new Error(
2543
+ `configure() output.skills contains duplicate id ${JSON.stringify(id)}`
2544
+ );
2545
+ }
2546
+ if (!args.knownIds.has(id)) {
2547
+ throw new Error(
2548
+ `configure() selected unknown skill id ${JSON.stringify(id)} owned by plugin ${JSON.stringify(args.pluginId)}`
2549
+ );
2550
+ }
2551
+ seen.add(id);
2552
+ selected.push(id);
2553
+ }
2554
+ return selected;
2555
+ }
2556
+ function normalizePluginAgentConfiguration(args) {
2557
+ if (typeof args.value !== "object" || args.value === null || Array.isArray(args.value)) {
2558
+ throw new Error(
2559
+ "configure() must return { tools: string[], skills: string[], instructions?: string }"
2560
+ );
2561
+ }
2562
+ const output = args.value;
2563
+ const unknownKeys = Object.keys(output).filter((key) => !["tools", "skills", "instructions"].includes(key)).sort();
2564
+ if (unknownKeys.length > 0) {
2565
+ throw new Error(
2566
+ `configure() output contains unknown field${unknownKeys.length === 1 ? "" : "s"}: ${unknownKeys.join(", ")}`
2567
+ );
2568
+ }
2569
+ if (output.instructions !== void 0 && typeof output.instructions !== "string") {
2570
+ throw new Error("configure() output.instructions must be a string");
2571
+ }
2572
+ const instructions = typeof output.instructions === "string" && output.instructions.trim().length > 0 ? output.instructions.slice(
2573
+ 0,
2574
+ PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS
2575
+ ) : null;
2576
+ const toolSelections = normalizePluginAgentToolSelections({
2577
+ knownIds: args.knownToolIds,
2578
+ pluginId: args.pluginId,
2579
+ value: output.tools
2580
+ });
2581
+ return {
2582
+ toolIds: toolSelections.toolIds,
2583
+ toolParameterOverrides: toolSelections.parameterOverrides,
2584
+ skillIds: normalizePluginAgentSelectionIds({
2585
+ knownIds: args.knownSkillIds,
2586
+ pluginId: args.pluginId,
2587
+ value: output.skills
2588
+ }),
2589
+ instructions
2590
+ };
2591
+ }
2592
+ function normalizeRpcIssuePath(path) {
2593
+ if (path === void 0) return void 0;
2594
+ const segments = Array.isArray(path) ? path : [path];
2595
+ const normalized = segments.map((segment) => {
2596
+ const key = typeof segment === "object" && segment !== null ? Reflect.get(segment, "key") : segment;
2597
+ return typeof key === "number" ? key : String(key);
2598
+ });
2599
+ return normalized.length > 0 ? normalized : void 0;
2600
+ }
2601
+ function normalizeRpcIssues(issues) {
2602
+ return issues.map((issue) => {
2603
+ const path = normalizeRpcIssuePath(issue.path);
2604
+ return {
2605
+ message: issue.message,
2606
+ ...path !== void 0 ? { path } : {}
2607
+ };
2608
+ });
2609
+ }
2610
+ async function validateRpcValue(schema, value, phase, fail) {
2611
+ let result;
2612
+ try {
2613
+ result = await schema["~standard"].validate(value);
2614
+ } catch (error) {
2615
+ const detail = error instanceof Error ? error.message : String(error);
2616
+ return fail({
2617
+ code: phase === "input" ? "invalid_input" : "invalid_output",
2618
+ message: `rpc ${phase} validator failed: ${detail}`,
2619
+ issues: [{ message: detail }]
2620
+ });
2621
+ }
2622
+ if (result.issues !== void 0) {
2623
+ return fail({
2624
+ code: phase === "input" ? "invalid_input" : "invalid_output",
2625
+ message: `rpc ${phase} validation failed`,
2626
+ issues: normalizeRpcIssues(result.issues)
2627
+ });
2628
+ }
2629
+ return result.value;
2630
+ }
2631
+ function normalizeRpcJsonResult(value, fail) {
2632
+ const ancestors = /* @__PURE__ */ new Set();
2633
+ function visit(current, path) {
2634
+ if (current === null || typeof current === "string" || typeof current === "boolean") {
2635
+ return current;
2636
+ }
2637
+ if (typeof current === "number") {
2638
+ if (!Number.isFinite(current)) {
2639
+ return fail({
2640
+ code: "non_json_result",
2641
+ message: `rpc result at ${path} contains a non-finite number`
2642
+ });
2643
+ }
2644
+ return current;
2645
+ }
2646
+ if (typeof current !== "object") {
2647
+ return fail({
2648
+ code: "non_json_result",
2649
+ message: `rpc result at ${path} is not a JSON value (${typeof current})`
2650
+ });
2651
+ }
2652
+ if (ancestors.has(current)) {
2653
+ return fail({
2654
+ code: "non_json_result",
2655
+ message: `rpc result at ${path} is cyclic`
2656
+ });
2657
+ }
2658
+ ancestors.add(current);
2659
+ try {
2660
+ if (Array.isArray(current)) {
2661
+ return current.map((item, index) => visit(item, `${path}[${index}]`));
2662
+ }
2663
+ const prototype = Object.getPrototypeOf(current);
2664
+ if (prototype !== Object.prototype && prototype !== null) {
2665
+ return fail({
2666
+ code: "non_json_result",
2667
+ message: `rpc result at ${path} must be a plain JSON object`
2668
+ });
2669
+ }
2670
+ if (Reflect.ownKeys(current).some((key) => typeof key === "symbol")) {
2671
+ return fail({
2672
+ code: "non_json_result",
2673
+ message: `rpc result at ${path} contains a symbol key`
2674
+ });
2675
+ }
2676
+ const normalized = {};
2677
+ for (const [key, child] of Object.entries(current)) {
2678
+ normalized[key] = visit(child, `${path}.${key}`);
2679
+ }
2680
+ return normalized;
2681
+ } finally {
2682
+ ancestors.delete(current);
2683
+ }
2684
+ }
2685
+ return visit(value, "$result");
2686
+ }
1902
2687
  export {
1903
- AGENT_TOOL_NAME_PATTERN,
1904
- BACKGROUND_NAME_PATTERN,
1905
- CLI_COMMAND_NAME_PATTERN,
2688
+ ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS,
1906
2689
  ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS,
1907
2690
  ENVIRONMENT_PROVIDER_ID_PATTERN,
1908
2691
  ENVIRONMENT_PROVIDER_REQUIREMENT_NAMES,
1909
2692
  KV_VALUE_MAX_BYTES,
1910
- MACHINE_PROVIDER_REQUIREMENT_NAMES,
1911
- MENTION_PROVIDER_ID_PATTERN,
1912
- PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS,
1913
- PLUGIN_AGENT_SELECTION_MAX_IDS,
1914
- PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS,
2693
+ MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS,
1915
2694
  PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS,
1916
- PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES,
1917
- PLUGIN_HTTP_METHODS,
1918
2695
  PLUGIN_MENTION_TRIGGER_VALUES,
1919
2696
  PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES,
1920
2697
  PLUGIN_PROVIDER_COMPOSER_ACTION_VALUES,
@@ -1926,37 +2703,47 @@ export {
1926
2703
  PROVIDER_ID_PATTERN,
1927
2704
  RESERVED_AGENT_TOOL_NAMES,
1928
2705
  RESERVED_BB_CLI_COMMANDS,
1929
- RPC_METHOD_PATTERN,
1930
2706
  SERVER_DIRECT_AI_SERVICE_IDS,
1931
2707
  SETTING_KEY_PATTERN,
1932
2708
  adoptHttpRouteResponse,
1933
- agentToolIconRefusalMessage,
1934
2709
  aiServiceAlreadyRegisteredMessage,
1935
2710
  assertAiServiceRegistrable,
1936
- assertNoRecursiveJsonSchemaReferences,
2711
+ coerceStoredPluginSettingValue,
1937
2712
  deriveValidatedProviderOptions,
1938
2713
  enforcePluginCliOutputLimit,
2714
+ environmentCompositionSchema,
1939
2715
  isPluginMentionTrigger,
1940
2716
  isStandardSchema,
1941
- isZodSchemaLike,
1942
- normalizeMentionProviderTriggers,
2717
+ normalizeAgentToolRegistration,
2718
+ normalizeCliRegistration,
2719
+ normalizeHttpRouteRegistration,
2720
+ normalizeInteractionRequest,
2721
+ normalizeMentionProviderRegistration,
2722
+ normalizePluginAgentConfiguration,
2723
+ normalizeRealtimePayload,
2724
+ normalizeRpcJsonResult,
2725
+ normalizeRpcRegistration,
2726
+ normalizeWebSocketRouteRegistration,
1943
2727
  parsePluginAgentToolPresentation,
1944
2728
  pluginCliCollisionWarning,
1945
2729
  pluginHookAlreadyRegisteredMessage,
1946
2730
  providerAlreadyRegisteredMessage,
1947
2731
  providerIconRefusalMessage,
1948
2732
  providerWithoutBridgeMessage,
1949
- readRpcMethodContract,
1950
2733
  registerSettingDescriptors,
1951
- rejectStaleAgentToolFields,
2734
+ runPluginStorageMigrations,
1952
2735
  storePluginHook,
1953
- summarizeParseIssues,
1954
2736
  summarizeStandardIssues,
1955
2737
  undeclaredIconProblem,
2738
+ validateBackgroundServiceRegistration,
1956
2739
  validatePluginAiServiceDeclaration,
1957
2740
  validatePluginEnvironmentProviderDeclaration,
2741
+ validatePluginMachineProviderDeclaration,
1958
2742
  validatePluginProviderDeclaration,
1959
2743
  validatePluginProviderEnvEntries,
1960
- validateSettingsUpdate,
1961
- zodSchemaToJsonSchema
2744
+ validateProviderEnvContribution,
2745
+ validateRpcValue,
2746
+ validateScheduleRegistration,
2747
+ validateServerAccessProviderDeclaration,
2748
+ validateSettingsUpdate
1962
2749
  };