@get-bb/plugin-sdk 0.4.84 → 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"];
@@ -514,6 +519,22 @@ function validateSettingsUpdate(descriptors, values) {
514
519
  }
515
520
  return errors;
516
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
+ }
517
538
  var PLUGIN_MENTION_TRIGGER_VALUES = [
518
539
  "@",
519
540
  "#",
@@ -1792,71 +1813,47 @@ var environmentCompositionSchema = z4.object({
1792
1813
  machineProviderId: z4.string().regex(ENVIRONMENT_PROVIDER_ID_PATTERN),
1793
1814
  environmentProviderId: z4.string().regex(ENVIRONMENT_PROVIDER_ID_PATTERN)
1794
1815
  }).strict();
1795
- function validatePluginEnvironmentProviderDeclaration(declaration) {
1816
+ function requireProviderIdAndDisplayName(noun, declaration) {
1796
1817
  if (typeof declaration !== "object" || declaration === null) {
1797
- throw new Error("environment provider declaration must be an object");
1818
+ throw new Error(`${noun} declaration must be an object`);
1798
1819
  }
1799
1820
  const id = declaration.id;
1800
1821
  if (typeof id !== "string" || !ENVIRONMENT_PROVIDER_ID_PATTERN.test(id)) {
1801
1822
  throw new Error(
1802
- `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`
1803
1824
  );
1804
1825
  }
1805
1826
  const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
1806
1827
  if (displayName.length === 0 || displayName.length > ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS) {
1807
1828
  throw new Error(
1808
- `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`
1809
1830
  );
1810
1831
  }
1811
- const description = z4.string().trim().min(1).max(ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS).optional().transform((value) => value ?? null).parse(declaration.description);
1812
- const icon = z4.string().trim().min(1).optional().transform((value) => value ?? null).parse(declaration.icon);
1813
- if (icon !== null && isPluginOwnedIconPath(icon)) {
1832
+ return { id, displayName };
1833
+ }
1834
+ function assertProviderIconShape(noun, id, icon) {
1835
+ if (isPluginOwnedIconPath(icon)) {
1814
1836
  validateProviderRelativePath(icon, `"${id}" icon`);
1815
- } else if (icon !== null && !isNamespacedGlyph(icon) && /[/\\]/u.test(icon)) {
1816
- throw new Error(
1817
- `environment provider "${id}" icon must be a glyph, declared icon, or plugin-relative path`
1818
- );
1819
- }
1820
- const requires = normalizeEnvironmentProviderRequirements(id, declaration);
1821
- const inputs = normalizeEnvironmentProviderInputs(id, declaration);
1822
- if (typeof declaration.create !== "function" || typeof declaration.remove !== "function") {
1823
- throw new Error(
1824
- `environment provider "${id}" must declare create and remove functions`
1825
- );
1826
- }
1827
- if (declaration.validate !== void 0 && typeof declaration.validate !== "function") {
1837
+ } else if (!isNamespacedGlyph(icon) && /[/\\]/u.test(icon)) {
1828
1838
  throw new Error(
1829
- `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`
1830
1840
  );
1831
1841
  }
1832
- 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") {
1833
1845
  throw new Error(
1834
- `environment provider "${id}" declares availability that is not a function`
1846
+ `${noun} "${id}" declares ${phrase} that is not a function`
1835
1847
  );
1836
1848
  }
1837
- return {
1838
- id,
1839
- displayName,
1840
- description,
1841
- icon,
1842
- requires,
1843
- inputs: inputs === null ? null : inputs.schema,
1844
- inputsJsonSchema: inputs === null ? null : inputs.jsonSchema,
1845
- availability: declaration.availability ?? null,
1846
- validate: declaration.validate ?? null,
1847
- create: declaration.create,
1848
- remove: declaration.remove,
1849
- policy: environmentProviderPolicySchema.parse(declaration.policy ?? {})
1850
- };
1851
1849
  }
1852
- function normalizeEnvironmentProviderInputs(id, declaration) {
1853
- const inputs = declaration.inputs;
1850
+ function normalizeProviderInputs(noun, id, inputs) {
1854
1851
  if (inputs === void 0) {
1855
1852
  return null;
1856
1853
  }
1857
1854
  if (!isStandardSchema(inputs)) {
1858
1855
  throw new Error(
1859
- `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`
1860
1857
  );
1861
1858
  }
1862
1859
  let converted;
@@ -1864,17 +1861,65 @@ function normalizeEnvironmentProviderInputs(id, declaration) {
1864
1861
  converted = JSON.parse(JSON.stringify(standardSchemaToJsonSchema(inputs)));
1865
1862
  } catch (error) {
1866
1863
  throw new Error(
1867
- `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()`
1868
1865
  );
1869
1866
  }
1870
1867
  const jsonSchema = jsonValueSchema.safeParse(converted);
1871
1868
  if (!jsonSchema.success) {
1872
1869
  throw new Error(
1873
- `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`
1874
1871
  );
1875
1872
  }
1876
1873
  return { schema: inputs, jsonSchema: jsonSchema.data };
1877
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
+ }
1878
1923
  function normalizeEnvironmentProviderRequirements(id, declaration) {
1879
1924
  const requires = declaration.requires ?? {};
1880
1925
  if (typeof requires !== "object" || requires === null || Array.isArray(requires)) {
@@ -1908,32 +1953,19 @@ var environmentProviderPolicySchema = z4.object({
1908
1953
  }).strict();
1909
1954
  var MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS = 200;
1910
1955
  function validatePluginMachineProviderDeclaration(declaration) {
1911
- if (typeof declaration !== "object" || declaration === null) {
1912
- throw new Error("machine provider declaration must be an object");
1913
- }
1914
- const id = declaration.id;
1915
- if (typeof id !== "string" || !ENVIRONMENT_PROVIDER_ID_PATTERN.test(id)) {
1916
- throw new Error(
1917
- `invalid machine provider id ${JSON.stringify(id)} \u2014 use 2-64 lowercase letters, digits, or "-", starting with a letter or digit`
1918
- );
1919
- }
1920
- const displayName = typeof declaration.displayName === "string" ? declaration.displayName.trim() : "";
1921
- if (displayName.length === 0 || displayName.length > ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS) {
1922
- throw new Error(
1923
- `machine provider "${id}" needs a displayName of 1-${ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS} characters`
1924
- );
1925
- }
1956
+ const { id, displayName } = requireProviderIdAndDisplayName(
1957
+ "machine provider",
1958
+ declaration
1959
+ );
1926
1960
  const description = z4.string().trim().min(1).max(MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS).parse(declaration.description);
1927
1961
  const icon = z4.string().trim().min(1).parse(declaration.icon);
1928
- if (isPluginOwnedIconPath(icon)) {
1929
- validateProviderRelativePath(icon, `"${id}" icon`);
1930
- } else if (!isNamespacedGlyph(icon) && /[/\\]/u.test(icon)) {
1931
- throw new Error(
1932
- `machine provider "${id}" icon must be a glyph, declared icon, or plugin-relative path`
1933
- );
1934
- }
1962
+ assertProviderIconShape("machine provider", id, icon);
1935
1963
  const ephemeral = z4.boolean().default(false).parse(declaration.ephemeral);
1936
- const inputs = normalizeMachineProviderInputs(id, declaration);
1964
+ const inputs = normalizeProviderInputs(
1965
+ "machine provider",
1966
+ id,
1967
+ declaration.inputs
1968
+ );
1937
1969
  if (typeof declaration.create !== "function" || typeof declaration.reconcileCleanup !== "function" || typeof declaration.remove !== "function") {
1938
1970
  throw new Error(
1939
1971
  `machine provider "${id}" must declare create, reconcileCleanup and remove functions`
@@ -1946,16 +1978,18 @@ function validatePluginMachineProviderDeclaration(declaration) {
1946
1978
  `machine provider "${id}" must declare suspend and resume together`
1947
1979
  );
1948
1980
  }
1949
- if (declaration.validate !== void 0 && typeof declaration.validate !== "function") {
1950
- throw new Error(
1951
- `machine provider "${id}" declares a validate that is not a function`
1952
- );
1953
- }
1954
- if (declaration.availability !== void 0 && typeof declaration.availability !== "function") {
1955
- throw new Error(
1956
- `machine provider "${id}" declares availability that is not a function`
1957
- );
1958
- }
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
+ );
1959
1993
  return {
1960
1994
  id,
1961
1995
  displayName,
@@ -1973,56 +2007,691 @@ function validatePluginMachineProviderDeclaration(declaration) {
1973
2007
  remove: declaration.remove
1974
2008
  };
1975
2009
  }
1976
- function normalizeMachineProviderInputs(id, declaration) {
1977
- const inputs = declaration.inputs;
1978
- if (inputs === void 0) return null;
1979
- if (!isStandardSchema(inputs)) {
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)) {
1980
2069
  throw new Error(
1981
- `machine provider "${id}" declares an inputs that is not a Standard Schema v1 validator`
2070
+ `invalid http method "${String(method)}" \u2014 use one of: ${[...PLUGIN_HTTP_METHODS].join(", ")}`
1982
2071
  );
1983
2072
  }
1984
- let converted;
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;
1985
2166
  try {
1986
- converted = JSON.parse(JSON.stringify(standardSchemaToJsonSchema(inputs)));
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));
1987
2205
  } catch (error) {
1988
2206
  throw new Error(
1989
- `machine 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()`
2207
+ `invalid cron ${JSON.stringify(cron)} for schedule "${name}": ${error instanceof Error ? error.message : String(error)}`
1990
2208
  );
1991
2209
  }
1992
- const jsonSchema = jsonValueSchema.safeParse(converted);
1993
- if (!jsonSchema.success) {
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)) {
1994
2221
  throw new Error(
1995
- `machine provider "${id}" declares an inputs schema whose JSON Schema is not JSON-serializable`
2222
+ `invalid cli command name ${JSON.stringify(name)} \u2014 use lowercase letters, digits, and "-"`
1996
2223
  );
1997
2224
  }
1998
- return { schema: inputs, jsonSchema: jsonSchema.data };
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
+ };
1999
2255
  }
2000
- function validateServerAccessProviderDeclaration(declaration) {
2001
- if (typeof declaration !== "object" || declaration === null)
2002
- throw new Error("Invalid server access provider declaration");
2003
- if (typeof declaration.id !== "string" || !/^[a-z][a-z0-9-]*$/u.test(declaration.id) || declaration.id === "direct")
2004
- throw new Error("Invalid or reserved server access provider id");
2005
- 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")
2006
- throw new Error("Invalid server access provider declaration");
2007
- return declaration;
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");
2008
2686
  }
2009
2687
  export {
2010
- AGENT_TOOL_NAME_PATTERN,
2011
- BACKGROUND_NAME_PATTERN,
2012
- CLI_COMMAND_NAME_PATTERN,
2013
2688
  ENVIRONMENT_PROVIDER_DESCRIPTION_MAX_CHARS,
2014
2689
  ENVIRONMENT_PROVIDER_DISPLAY_NAME_MAX_CHARS,
2015
2690
  ENVIRONMENT_PROVIDER_ID_PATTERN,
2016
2691
  ENVIRONMENT_PROVIDER_REQUIREMENT_NAMES,
2017
2692
  KV_VALUE_MAX_BYTES,
2018
2693
  MACHINE_PROVIDER_DESCRIPTION_MAX_CHARS,
2019
- MENTION_PROVIDER_ID_PATTERN,
2020
- PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS,
2021
- PLUGIN_AGENT_SELECTION_MAX_IDS,
2022
- PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS,
2023
2694
  PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS,
2024
- PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES,
2025
- PLUGIN_HTTP_METHODS,
2026
2695
  PLUGIN_MENTION_TRIGGER_VALUES,
2027
2696
  PLUGIN_PROVIDER_BRIDGE_OPTIONS_MAX_BYTES,
2028
2697
  PLUGIN_PROVIDER_COMPOSER_ACTION_VALUES,
@@ -2034,40 +2703,47 @@ export {
2034
2703
  PROVIDER_ID_PATTERN,
2035
2704
  RESERVED_AGENT_TOOL_NAMES,
2036
2705
  RESERVED_BB_CLI_COMMANDS,
2037
- RPC_METHOD_PATTERN,
2038
2706
  SERVER_DIRECT_AI_SERVICE_IDS,
2039
2707
  SETTING_KEY_PATTERN,
2040
2708
  adoptHttpRouteResponse,
2041
- agentToolIconRefusalMessage,
2042
2709
  aiServiceAlreadyRegisteredMessage,
2043
2710
  assertAiServiceRegistrable,
2044
- assertNoRecursiveJsonSchemaReferences,
2711
+ coerceStoredPluginSettingValue,
2045
2712
  deriveValidatedProviderOptions,
2046
2713
  enforcePluginCliOutputLimit,
2047
2714
  environmentCompositionSchema,
2048
2715
  isPluginMentionTrigger,
2049
2716
  isStandardSchema,
2050
- isZodSchemaLike,
2051
- normalizeMentionProviderTriggers,
2717
+ normalizeAgentToolRegistration,
2718
+ normalizeCliRegistration,
2719
+ normalizeHttpRouteRegistration,
2720
+ normalizeInteractionRequest,
2721
+ normalizeMentionProviderRegistration,
2722
+ normalizePluginAgentConfiguration,
2723
+ normalizeRealtimePayload,
2724
+ normalizeRpcJsonResult,
2725
+ normalizeRpcRegistration,
2726
+ normalizeWebSocketRouteRegistration,
2052
2727
  parsePluginAgentToolPresentation,
2053
2728
  pluginCliCollisionWarning,
2054
2729
  pluginHookAlreadyRegisteredMessage,
2055
2730
  providerAlreadyRegisteredMessage,
2056
2731
  providerIconRefusalMessage,
2057
2732
  providerWithoutBridgeMessage,
2058
- readRpcMethodContract,
2059
2733
  registerSettingDescriptors,
2060
- rejectStaleAgentToolFields,
2734
+ runPluginStorageMigrations,
2061
2735
  storePluginHook,
2062
- summarizeParseIssues,
2063
2736
  summarizeStandardIssues,
2064
2737
  undeclaredIconProblem,
2738
+ validateBackgroundServiceRegistration,
2065
2739
  validatePluginAiServiceDeclaration,
2066
2740
  validatePluginEnvironmentProviderDeclaration,
2067
2741
  validatePluginMachineProviderDeclaration,
2068
2742
  validatePluginProviderDeclaration,
2069
2743
  validatePluginProviderEnvEntries,
2744
+ validateProviderEnvContribution,
2745
+ validateRpcValue,
2746
+ validateScheduleRegistration,
2070
2747
  validateServerAccessProviderDeclaration,
2071
- validateSettingsUpdate,
2072
- zodSchemaToJsonSchema
2748
+ validateSettingsUpdate
2073
2749
  };