From 0eb0cc564aa7ee5fe6e7804f42a18f535380a09f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 14:13:43 +0000 Subject: [PATCH 1/2] chore(deps): update dependency stacklok/toolhive to v0.42.0 --- utils/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/constants.ts b/utils/constants.ts index 10c086924..da3f712cb 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -3,4 +3,4 @@ * This is managed by Renovate and updated automatically when new versions are released. * renovate: datasource=github-releases depName=stacklok/toolhive versioning=semver */ -export const TOOLHIVE_VERSION = process.env.THV_VERSION ?? 'v0.41.0' +export const TOOLHIVE_VERSION = process.env.THV_VERSION ?? 'v0.42.0' From 7ce7fb8a414d27492bbd15f3de4fa90ce3437834 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 14:14:46 +0000 Subject: [PATCH 2/2] chore: regenerate artifacts after dependency update --- .../generated/@tanstack/react-query.gen.ts | 482 ++++++ common/api/generated/index.ts | 94 ++ common/api/generated/sdk.gen.ts | 301 ++++ common/api/generated/types.gen.ts | 984 ++++++++++- common/api/openapi.json | 1493 ++++++++++++++++- 5 files changed, 3268 insertions(+), 86 deletions(-) diff --git a/common/api/generated/@tanstack/react-query.gen.ts b/common/api/generated/@tanstack/react-query.gen.ts index c0173124d..aa48e9f51 100644 --- a/common/api/generated/@tanstack/react-query.gen.ts +++ b/common/api/generated/@tanstack/react-query.gen.ts @@ -13,6 +13,8 @@ import { deleteApiV1BetaClientsByName, deleteApiV1BetaClientsByNameGroupsByGroup, deleteApiV1BetaGroupsByName, + deleteApiV1BetaPluginsBuildsByTag, + deleteApiV1BetaPluginsByName, deleteApiV1BetaRegistryByName, deleteApiV1BetaSecretsDefaultKeysByKey, deleteApiV1BetaSkillsBuildsByTag, @@ -23,6 +25,10 @@ import { getApiV1BetaDiscoveryClients, getApiV1BetaGroups, getApiV1BetaGroupsByName, + getApiV1BetaPlugins, + getApiV1BetaPluginsBuilds, + getApiV1BetaPluginsByName, + getApiV1BetaPluginsContent, getApiV1BetaRegistry, getApiV1BetaRegistryByName, getApiV1BetaRegistryByNameServers, @@ -45,6 +51,8 @@ import { getHealth, getRegistryByRegistryNameV01Servers, getRegistryByRegistryNameV01ServersByServerNameVersionsLatest, + getRegistryByRegistryNameV01xDevToolhivePlugins, + getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginName, getRegistryByRegistryNameV01xDevToolhiveSkills, getRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillName, type Options, @@ -52,6 +60,10 @@ import { postApiV1BetaClientsRegister, postApiV1BetaClientsUnregister, postApiV1BetaGroups, + postApiV1BetaPlugins, + postApiV1BetaPluginsBuild, + postApiV1BetaPluginsPush, + postApiV1BetaPluginsValidate, postApiV1BetaRegistry, postApiV1BetaRegistryAuthLogin, postApiV1BetaRegistryAuthLogout, @@ -85,6 +97,12 @@ import type { DeleteApiV1BetaGroupsByNameData, DeleteApiV1BetaGroupsByNameError, DeleteApiV1BetaGroupsByNameResponse, + DeleteApiV1BetaPluginsBuildsByTagData, + DeleteApiV1BetaPluginsBuildsByTagError, + DeleteApiV1BetaPluginsBuildsByTagResponse, + DeleteApiV1BetaPluginsByNameData, + DeleteApiV1BetaPluginsByNameError, + DeleteApiV1BetaPluginsByNameResponse, DeleteApiV1BetaRegistryByNameData, DeleteApiV1BetaRegistryByNameError, DeleteApiV1BetaRegistryByNameResponse, @@ -112,6 +130,18 @@ import type { GetApiV1BetaGroupsData, GetApiV1BetaGroupsError, GetApiV1BetaGroupsResponse, + GetApiV1BetaPluginsBuildsData, + GetApiV1BetaPluginsBuildsError, + GetApiV1BetaPluginsBuildsResponse, + GetApiV1BetaPluginsByNameData, + GetApiV1BetaPluginsByNameError, + GetApiV1BetaPluginsByNameResponse, + GetApiV1BetaPluginsContentData, + GetApiV1BetaPluginsContentError, + GetApiV1BetaPluginsContentResponse, + GetApiV1BetaPluginsData, + GetApiV1BetaPluginsError, + GetApiV1BetaPluginsResponse, GetApiV1BetaRegistryByNameData, GetApiV1BetaRegistryByNameError, GetApiV1BetaRegistryByNameResponse, @@ -175,6 +205,12 @@ import type { GetRegistryByRegistryNameV01ServersData, GetRegistryByRegistryNameV01ServersError, GetRegistryByRegistryNameV01ServersResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameData, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameError, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsData, + GetRegistryByRegistryNameV01xDevToolhivePluginsError, + GetRegistryByRegistryNameV01xDevToolhivePluginsResponse, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameData, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameError, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameResponse, @@ -193,6 +229,18 @@ import type { PostApiV1BetaGroupsData, PostApiV1BetaGroupsError, PostApiV1BetaGroupsResponse, + PostApiV1BetaPluginsBuildData, + PostApiV1BetaPluginsBuildError, + PostApiV1BetaPluginsBuildResponse, + PostApiV1BetaPluginsData, + PostApiV1BetaPluginsError, + PostApiV1BetaPluginsPushData, + PostApiV1BetaPluginsPushError, + PostApiV1BetaPluginsPushResponse, + PostApiV1BetaPluginsResponse, + PostApiV1BetaPluginsValidateData, + PostApiV1BetaPluginsValidateError, + PostApiV1BetaPluginsValidateResponse, PostApiV1BetaRegistryAuthLoginData, PostApiV1BetaRegistryAuthLoginError, PostApiV1BetaRegistryAuthLoginResponse, @@ -654,6 +702,301 @@ export const getApiV1BetaGroupsByNameOptions = ( queryKey: getApiV1BetaGroupsByNameQueryKey(options), }) +export const getApiV1BetaPluginsQueryKey = ( + options?: Options +) => createQueryKey('getApiV1BetaPlugins', options) + +/** + * List all installed plugins + * + * Get a list of all installed plugins + */ +export const getApiV1BetaPluginsOptions = ( + options?: Options +) => + queryOptions< + GetApiV1BetaPluginsResponse, + GetApiV1BetaPluginsError, + GetApiV1BetaPluginsResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getApiV1BetaPlugins({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }) + return data + }, + queryKey: getApiV1BetaPluginsQueryKey(options), + }) + +/** + * Install a plugin + * + * Install a plugin from a remote source + */ +export const postApiV1BetaPluginsMutation = ( + options?: Partial> +): UseMutationOptions< + PostApiV1BetaPluginsResponse, + PostApiV1BetaPluginsError, + Options +> => { + const mutationOptions: UseMutationOptions< + PostApiV1BetaPluginsResponse, + PostApiV1BetaPluginsError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await postApiV1BetaPlugins({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +/** + * Build a plugin + * + * Build a plugin from a local directory + */ +export const postApiV1BetaPluginsBuildMutation = ( + options?: Partial> +): UseMutationOptions< + PostApiV1BetaPluginsBuildResponse, + PostApiV1BetaPluginsBuildError, + Options +> => { + const mutationOptions: UseMutationOptions< + PostApiV1BetaPluginsBuildResponse, + PostApiV1BetaPluginsBuildError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await postApiV1BetaPluginsBuild({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +export const getApiV1BetaPluginsBuildsQueryKey = ( + options?: Options +) => createQueryKey('getApiV1BetaPluginsBuilds', options) + +/** + * List locally-built plugin artifacts + * + * Get a list of all locally-built OCI plugin artifacts in the local store + */ +export const getApiV1BetaPluginsBuildsOptions = ( + options?: Options +) => + queryOptions< + GetApiV1BetaPluginsBuildsResponse, + GetApiV1BetaPluginsBuildsError, + GetApiV1BetaPluginsBuildsResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getApiV1BetaPluginsBuilds({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }) + return data + }, + queryKey: getApiV1BetaPluginsBuildsQueryKey(options), + }) + +/** + * Delete a locally-built plugin artifact + * + * Remove a locally-built OCI plugin artifact and its blobs from the local store + */ +export const deleteApiV1BetaPluginsBuildsByTagMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteApiV1BetaPluginsBuildsByTagResponse, + DeleteApiV1BetaPluginsBuildsByTagError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteApiV1BetaPluginsBuildsByTagResponse, + DeleteApiV1BetaPluginsBuildsByTagError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await deleteApiV1BetaPluginsBuildsByTag({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +export const getApiV1BetaPluginsContentQueryKey = ( + options: Options +) => createQueryKey('getApiV1BetaPluginsContent', options) + +/** + * Get plugin content + * + * Retrieve the plugin.json body and file listing from an artifact + * without installing it. Accepts OCI refs, git refs, or local tags. + */ +export const getApiV1BetaPluginsContentOptions = ( + options: Options +) => + queryOptions< + GetApiV1BetaPluginsContentResponse, + GetApiV1BetaPluginsContentError, + GetApiV1BetaPluginsContentResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getApiV1BetaPluginsContent({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }) + return data + }, + queryKey: getApiV1BetaPluginsContentQueryKey(options), + }) + +/** + * Push a plugin + * + * Push a built plugin artifact to a remote registry + */ +export const postApiV1BetaPluginsPushMutation = ( + options?: Partial> +): UseMutationOptions< + PostApiV1BetaPluginsPushResponse, + PostApiV1BetaPluginsPushError, + Options +> => { + const mutationOptions: UseMutationOptions< + PostApiV1BetaPluginsPushResponse, + PostApiV1BetaPluginsPushError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await postApiV1BetaPluginsPush({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +/** + * Validate a plugin + * + * Validate a plugin definition + */ +export const postApiV1BetaPluginsValidateMutation = ( + options?: Partial> +): UseMutationOptions< + PostApiV1BetaPluginsValidateResponse, + PostApiV1BetaPluginsValidateError, + Options +> => { + const mutationOptions: UseMutationOptions< + PostApiV1BetaPluginsValidateResponse, + PostApiV1BetaPluginsValidateError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await postApiV1BetaPluginsValidate({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +/** + * Uninstall a plugin + * + * Remove an installed plugin + */ +export const deleteApiV1BetaPluginsByNameMutation = ( + options?: Partial> +): UseMutationOptions< + DeleteApiV1BetaPluginsByNameResponse, + DeleteApiV1BetaPluginsByNameError, + Options +> => { + const mutationOptions: UseMutationOptions< + DeleteApiV1BetaPluginsByNameResponse, + DeleteApiV1BetaPluginsByNameError, + Options + > = { + mutationFn: async (fnOptions) => { + const { data } = await deleteApiV1BetaPluginsByName({ + ...options, + ...fnOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + +export const getApiV1BetaPluginsByNameQueryKey = ( + options: Options +) => createQueryKey('getApiV1BetaPluginsByName', options) + +/** + * Get plugin details + * + * Get detailed information about a specific plugin + */ +export const getApiV1BetaPluginsByNameOptions = ( + options: Options +) => + queryOptions< + GetApiV1BetaPluginsByNameResponse, + GetApiV1BetaPluginsByNameError, + GetApiV1BetaPluginsByNameResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getApiV1BetaPluginsByName({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }) + return data + }, + queryKey: getApiV1BetaPluginsByNameQueryKey(options), + }) + export const getApiV1BetaRegistryQueryKey = ( options?: Options ) => createQueryKey('getApiV1BetaRegistry', options) @@ -2207,6 +2550,145 @@ export const getRegistryByRegistryNameV01ServersByServerNameVersionsLatestOption ), }) +export const getRegistryByRegistryNameV01xDevToolhivePluginsQueryKey = ( + options: Options +) => createQueryKey('getRegistryByRegistryNameV01XDevToolhivePlugins', options) + +/** + * List available registry plugins + * + * Get a paginated list of plugins from the registry. Supports optional full-text search and pagination. + */ +export const getRegistryByRegistryNameV01xDevToolhivePluginsOptions = ( + options: Options +) => + queryOptions< + GetRegistryByRegistryNameV01xDevToolhivePluginsResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsError, + GetRegistryByRegistryNameV01xDevToolhivePluginsResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRegistryByRegistryNameV01xDevToolhivePlugins({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }) + return data + }, + queryKey: getRegistryByRegistryNameV01xDevToolhivePluginsQueryKey(options), + }) + +export const getRegistryByRegistryNameV01xDevToolhivePluginsInfiniteQueryKey = ( + options: Options +): QueryKey> => + createQueryKey( + 'getRegistryByRegistryNameV01XDevToolhivePlugins', + options, + true + ) + +/** + * List available registry plugins + * + * Get a paginated list of plugins from the registry. Supports optional full-text search and pagination. + */ +export const getRegistryByRegistryNameV01xDevToolhivePluginsInfiniteOptions = ( + options: Options +) => { + const opts = infiniteQueryOptions< + GetRegistryByRegistryNameV01xDevToolhivePluginsResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsError, + InfiniteData, + QueryKey>, + | number + | Pick< + QueryKey< + Options + >[0], + 'body' | 'headers' | 'path' | 'query' + > + >( + // @ts-ignore + { + queryFn: async ({ pageParam, queryKey, signal }) => { + // @ts-ignore + const page: Pick< + QueryKey< + Options + >[0], + 'body' | 'headers' | 'path' | 'query' + > = + typeof pageParam === 'object' + ? pageParam + : { + query: { + page: pageParam, + }, + } + const params = createInfiniteParams(queryKey, page) + const { data } = await getRegistryByRegistryNameV01xDevToolhivePlugins({ + ...options, + ...params, + signal, + throwOnError: true, + }) + return data + }, + queryKey: + getRegistryByRegistryNameV01xDevToolhivePluginsInfiniteQueryKey( + options + ), + } + ) + return opts as Omit +} + +export const getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameQueryKey = + ( + options: Options + ) => + createQueryKey( + 'getRegistryByRegistryNameV01XDevToolhivePluginsByNamespaceByPluginName', + options + ) + +/** + * Get a registry plugin + * + * Retrieve a single plugin by its namespace and name from the registry. + */ +export const getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameOptions = + ( + options: Options + ) => + queryOptions< + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameError, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponse, + ReturnType< + typeof getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameQueryKey + > + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = + await getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginName( + { + ...options, + ...queryKey[0], + signal, + throwOnError: true, + } + ) + return data + }, + queryKey: + getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameQueryKey( + options + ), + }) + export const getRegistryByRegistryNameV01xDevToolhiveSkillsQueryKey = ( options: Options ) => createQueryKey('getRegistryByRegistryNameV01XDevToolhiveSkills', options) diff --git a/common/api/generated/index.ts b/common/api/generated/index.ts index 2a634c691..970bfc590 100644 --- a/common/api/generated/index.ts +++ b/common/api/generated/index.ts @@ -4,6 +4,8 @@ export { deleteApiV1BetaClientsByName, deleteApiV1BetaClientsByNameGroupsByGroup, deleteApiV1BetaGroupsByName, + deleteApiV1BetaPluginsBuildsByTag, + deleteApiV1BetaPluginsByName, deleteApiV1BetaRegistryByName, deleteApiV1BetaSecretsDefaultKeysByKey, deleteApiV1BetaSkillsBuildsByTag, @@ -14,6 +16,10 @@ export { getApiV1BetaDiscoveryClients, getApiV1BetaGroups, getApiV1BetaGroupsByName, + getApiV1BetaPlugins, + getApiV1BetaPluginsBuilds, + getApiV1BetaPluginsByName, + getApiV1BetaPluginsContent, getApiV1BetaRegistry, getApiV1BetaRegistryByName, getApiV1BetaRegistryByNameServers, @@ -36,6 +42,8 @@ export { getHealth, getRegistryByRegistryNameV01Servers, getRegistryByRegistryNameV01ServersByServerNameVersionsLatest, + getRegistryByRegistryNameV01xDevToolhivePlugins, + getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginName, getRegistryByRegistryNameV01xDevToolhiveSkills, getRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillName, type Options, @@ -43,6 +51,10 @@ export { postApiV1BetaClientsRegister, postApiV1BetaClientsUnregister, postApiV1BetaGroups, + postApiV1BetaPlugins, + postApiV1BetaPluginsBuild, + postApiV1BetaPluginsPush, + postApiV1BetaPluginsValidate, postApiV1BetaRegistry, postApiV1BetaRegistryAuthLogin, postApiV1BetaRegistryAuthLogout, @@ -85,6 +97,16 @@ export type { DeleteApiV1BetaGroupsByNameErrors, DeleteApiV1BetaGroupsByNameResponse, DeleteApiV1BetaGroupsByNameResponses, + DeleteApiV1BetaPluginsBuildsByTagData, + DeleteApiV1BetaPluginsBuildsByTagError, + DeleteApiV1BetaPluginsBuildsByTagErrors, + DeleteApiV1BetaPluginsBuildsByTagResponse, + DeleteApiV1BetaPluginsBuildsByTagResponses, + DeleteApiV1BetaPluginsByNameData, + DeleteApiV1BetaPluginsByNameError, + DeleteApiV1BetaPluginsByNameErrors, + DeleteApiV1BetaPluginsByNameResponse, + DeleteApiV1BetaPluginsByNameResponses, DeleteApiV1BetaRegistryByNameData, DeleteApiV1BetaRegistryByNameError, DeleteApiV1BetaRegistryByNameErrors, @@ -129,6 +151,26 @@ export type { GetApiV1BetaGroupsErrors, GetApiV1BetaGroupsResponse, GetApiV1BetaGroupsResponses, + GetApiV1BetaPluginsBuildsData, + GetApiV1BetaPluginsBuildsError, + GetApiV1BetaPluginsBuildsErrors, + GetApiV1BetaPluginsBuildsResponse, + GetApiV1BetaPluginsBuildsResponses, + GetApiV1BetaPluginsByNameData, + GetApiV1BetaPluginsByNameError, + GetApiV1BetaPluginsByNameErrors, + GetApiV1BetaPluginsByNameResponse, + GetApiV1BetaPluginsByNameResponses, + GetApiV1BetaPluginsContentData, + GetApiV1BetaPluginsContentError, + GetApiV1BetaPluginsContentErrors, + GetApiV1BetaPluginsContentResponse, + GetApiV1BetaPluginsContentResponses, + GetApiV1BetaPluginsData, + GetApiV1BetaPluginsError, + GetApiV1BetaPluginsErrors, + GetApiV1BetaPluginsResponse, + GetApiV1BetaPluginsResponses, GetApiV1BetaRegistryByNameData, GetApiV1BetaRegistryByNameError, GetApiV1BetaRegistryByNameErrors, @@ -233,6 +275,16 @@ export type { GetRegistryByRegistryNameV01ServersErrors, GetRegistryByRegistryNameV01ServersResponse, GetRegistryByRegistryNameV01ServersResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameData, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameError, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsData, + GetRegistryByRegistryNameV01xDevToolhivePluginsError, + GetRegistryByRegistryNameV01xDevToolhivePluginsErrors, + GetRegistryByRegistryNameV01xDevToolhivePluginsResponse, + GetRegistryByRegistryNameV01xDevToolhivePluginsResponses, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameData, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameError, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameErrors, @@ -266,6 +318,19 @@ export type { GithubComStacklokToolhivePkgClientClientAppStatus, GithubComStacklokToolhivePkgClientRegisteredClient, GithubComStacklokToolhivePkgGroupsGroup, + GithubComStacklokToolhivePkgPluginsBuildResult, + GithubComStacklokToolhivePkgPluginsComponentInventory, + GithubComStacklokToolhivePkgPluginsComponentType, + GithubComStacklokToolhivePkgPluginsDependency, + GithubComStacklokToolhivePkgPluginsInstalledPlugin, + GithubComStacklokToolhivePkgPluginsInstallStatus, + GithubComStacklokToolhivePkgPluginsLocalBuild, + GithubComStacklokToolhivePkgPluginsPluginContent, + GithubComStacklokToolhivePkgPluginsPluginFileEntry, + GithubComStacklokToolhivePkgPluginsPluginInfo, + GithubComStacklokToolhivePkgPluginsPluginMetadata, + GithubComStacklokToolhivePkgPluginsScope, + GithubComStacklokToolhivePkgPluginsValidationResult, GithubComStacklokToolhivePkgRatelimitTypesRateLimitBucket, GithubComStacklokToolhivePkgRatelimitTypesToolRateLimitConfig, GithubComStacklokToolhivePkgRegistryOAuthPublicConfig, @@ -315,6 +380,7 @@ export type { PermissionsOutboundNetworkPermissions, PermissionsProfile, PkgApiV1BuildListResponse, + PkgApiV1BuildPluginRequest, PkgApiV1BuildSkillRequest, PkgApiV1BulkClientRequest, PkgApiV1BulkOperationRequest, @@ -332,13 +398,19 @@ export type { PkgApiV1GetServerResponse, PkgApiV1GroupListResponse, PkgApiV1HeaderForwardConfig, + PkgApiV1InstallPluginRequest, + PkgApiV1InstallPluginResponse, PkgApiV1InstallSkillRequest, PkgApiV1InstallSkillResponse, PkgApiV1ListSecretsResponse, PkgApiV1ListServersResponse, PkgApiV1OidcOptions, PkgApiV1PaginationV01Metadata, + PkgApiV1PluginBuildListResponse, + PkgApiV1PluginListResponse, + PkgApiV1PluginsV01Response, PkgApiV1ProviderCapabilitiesResponse, + PkgApiV1PushPluginRequest, PkgApiV1PushSkillRequest, PkgApiV1RegistryErrorResponse, PkgApiV1RegistryInfo, @@ -363,6 +435,7 @@ export type { PkgApiV1UpgradeCheckResponse, PkgApiV1UpgradeRequest, PkgApiV1UpgradeSkillsRequest, + PkgApiV1ValidatePluginRequest, PkgApiV1ValidateSkillRequest, PkgApiV1VersionResponse, PkgApiV1WorkloadListResponse, @@ -387,6 +460,26 @@ export type { PostApiV1BetaGroupsErrors, PostApiV1BetaGroupsResponse, PostApiV1BetaGroupsResponses, + PostApiV1BetaPluginsBuildData, + PostApiV1BetaPluginsBuildError, + PostApiV1BetaPluginsBuildErrors, + PostApiV1BetaPluginsBuildResponse, + PostApiV1BetaPluginsBuildResponses, + PostApiV1BetaPluginsData, + PostApiV1BetaPluginsError, + PostApiV1BetaPluginsErrors, + PostApiV1BetaPluginsPushData, + PostApiV1BetaPluginsPushError, + PostApiV1BetaPluginsPushErrors, + PostApiV1BetaPluginsPushResponse, + PostApiV1BetaPluginsPushResponses, + PostApiV1BetaPluginsResponse, + PostApiV1BetaPluginsResponses, + PostApiV1BetaPluginsValidateData, + PostApiV1BetaPluginsValidateError, + PostApiV1BetaPluginsValidateErrors, + PostApiV1BetaPluginsValidateResponse, + PostApiV1BetaPluginsValidateResponses, PostApiV1BetaRegistryAuthLoginData, PostApiV1BetaRegistryAuthLoginError, PostApiV1BetaRegistryAuthLoginErrors, @@ -502,6 +595,7 @@ export type { RegistryKubernetesMetadata, RegistryMetadata, RegistryOAuthConfig, + RegistryPlugin, RegistryProvenance, RegistryRegistry, RegistryRemoteServerMetadata, diff --git a/common/api/generated/sdk.gen.ts b/common/api/generated/sdk.gen.ts index 17d30ac47..fac8437e1 100644 --- a/common/api/generated/sdk.gen.ts +++ b/common/api/generated/sdk.gen.ts @@ -18,6 +18,12 @@ import type { DeleteApiV1BetaGroupsByNameData, DeleteApiV1BetaGroupsByNameErrors, DeleteApiV1BetaGroupsByNameResponses, + DeleteApiV1BetaPluginsBuildsByTagData, + DeleteApiV1BetaPluginsBuildsByTagErrors, + DeleteApiV1BetaPluginsBuildsByTagResponses, + DeleteApiV1BetaPluginsByNameData, + DeleteApiV1BetaPluginsByNameErrors, + DeleteApiV1BetaPluginsByNameResponses, DeleteApiV1BetaRegistryByNameData, DeleteApiV1BetaRegistryByNameErrors, DeleteApiV1BetaRegistryByNameResponses, @@ -45,6 +51,18 @@ import type { GetApiV1BetaGroupsData, GetApiV1BetaGroupsErrors, GetApiV1BetaGroupsResponses, + GetApiV1BetaPluginsBuildsData, + GetApiV1BetaPluginsBuildsErrors, + GetApiV1BetaPluginsBuildsResponses, + GetApiV1BetaPluginsByNameData, + GetApiV1BetaPluginsByNameErrors, + GetApiV1BetaPluginsByNameResponses, + GetApiV1BetaPluginsContentData, + GetApiV1BetaPluginsContentErrors, + GetApiV1BetaPluginsContentResponses, + GetApiV1BetaPluginsData, + GetApiV1BetaPluginsErrors, + GetApiV1BetaPluginsResponses, GetApiV1BetaRegistryByNameData, GetApiV1BetaRegistryByNameErrors, GetApiV1BetaRegistryByNameResponses, @@ -108,6 +126,12 @@ import type { GetRegistryByRegistryNameV01ServersData, GetRegistryByRegistryNameV01ServersErrors, GetRegistryByRegistryNameV01ServersResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameData, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsData, + GetRegistryByRegistryNameV01xDevToolhivePluginsErrors, + GetRegistryByRegistryNameV01xDevToolhivePluginsResponses, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameData, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameErrors, GetRegistryByRegistryNameV01xDevToolhiveSkillsByNamespaceBySkillNameResponses, @@ -126,6 +150,18 @@ import type { PostApiV1BetaGroupsData, PostApiV1BetaGroupsErrors, PostApiV1BetaGroupsResponses, + PostApiV1BetaPluginsBuildData, + PostApiV1BetaPluginsBuildErrors, + PostApiV1BetaPluginsBuildResponses, + PostApiV1BetaPluginsData, + PostApiV1BetaPluginsErrors, + PostApiV1BetaPluginsPushData, + PostApiV1BetaPluginsPushErrors, + PostApiV1BetaPluginsPushResponses, + PostApiV1BetaPluginsResponses, + PostApiV1BetaPluginsValidateData, + PostApiV1BetaPluginsValidateErrors, + PostApiV1BetaPluginsValidateResponses, PostApiV1BetaRegistryAuthLoginData, PostApiV1BetaRegistryAuthLoginErrors, PostApiV1BetaRegistryAuthLoginResponses, @@ -460,6 +496,223 @@ export const getApiV1BetaGroupsByName = ( ThrowOnError >({ url: '/api/v1beta/groups/{name}', ...options }) +/** + * List all installed plugins + * + * Get a list of all installed plugins + */ +export const getApiV1BetaPlugins = ( + options?: Options +): RequestResult< + GetApiV1BetaPluginsResponses, + GetApiV1BetaPluginsErrors, + ThrowOnError +> => + (options?.client ?? client).get< + GetApiV1BetaPluginsResponses, + GetApiV1BetaPluginsErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins', ...options }) + +/** + * Install a plugin + * + * Install a plugin from a remote source + */ +export const postApiV1BetaPlugins = ( + options: Options +): RequestResult< + PostApiV1BetaPluginsResponses, + PostApiV1BetaPluginsErrors, + ThrowOnError +> => + (options.client ?? client).post< + PostApiV1BetaPluginsResponses, + PostApiV1BetaPluginsErrors, + ThrowOnError + >({ + url: '/api/v1beta/plugins', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }) + +/** + * Build a plugin + * + * Build a plugin from a local directory + */ +export const postApiV1BetaPluginsBuild = ( + options: Options +): RequestResult< + PostApiV1BetaPluginsBuildResponses, + PostApiV1BetaPluginsBuildErrors, + ThrowOnError +> => + (options.client ?? client).post< + PostApiV1BetaPluginsBuildResponses, + PostApiV1BetaPluginsBuildErrors, + ThrowOnError + >({ + url: '/api/v1beta/plugins/build', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }) + +/** + * List locally-built plugin artifacts + * + * Get a list of all locally-built OCI plugin artifacts in the local store + */ +export const getApiV1BetaPluginsBuilds = ( + options?: Options +): RequestResult< + GetApiV1BetaPluginsBuildsResponses, + GetApiV1BetaPluginsBuildsErrors, + ThrowOnError +> => + (options?.client ?? client).get< + GetApiV1BetaPluginsBuildsResponses, + GetApiV1BetaPluginsBuildsErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins/builds', ...options }) + +/** + * Delete a locally-built plugin artifact + * + * Remove a locally-built OCI plugin artifact and its blobs from the local store + */ +export const deleteApiV1BetaPluginsBuildsByTag = < + ThrowOnError extends boolean = false, +>( + options: Options +): RequestResult< + DeleteApiV1BetaPluginsBuildsByTagResponses, + DeleteApiV1BetaPluginsBuildsByTagErrors, + ThrowOnError +> => + (options.client ?? client).delete< + DeleteApiV1BetaPluginsBuildsByTagResponses, + DeleteApiV1BetaPluginsBuildsByTagErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins/builds/{tag}', ...options }) + +/** + * Get plugin content + * + * Retrieve the plugin.json body and file listing from an artifact + * without installing it. Accepts OCI refs, git refs, or local tags. + */ +export const getApiV1BetaPluginsContent = < + ThrowOnError extends boolean = false, +>( + options: Options +): RequestResult< + GetApiV1BetaPluginsContentResponses, + GetApiV1BetaPluginsContentErrors, + ThrowOnError +> => + (options.client ?? client).get< + GetApiV1BetaPluginsContentResponses, + GetApiV1BetaPluginsContentErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins/content', ...options }) + +/** + * Push a plugin + * + * Push a built plugin artifact to a remote registry + */ +export const postApiV1BetaPluginsPush = ( + options: Options +): RequestResult< + PostApiV1BetaPluginsPushResponses, + PostApiV1BetaPluginsPushErrors, + ThrowOnError +> => + (options.client ?? client).post< + PostApiV1BetaPluginsPushResponses, + PostApiV1BetaPluginsPushErrors, + ThrowOnError + >({ + url: '/api/v1beta/plugins/push', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }) + +/** + * Validate a plugin + * + * Validate a plugin definition + */ +export const postApiV1BetaPluginsValidate = < + ThrowOnError extends boolean = false, +>( + options: Options +): RequestResult< + PostApiV1BetaPluginsValidateResponses, + PostApiV1BetaPluginsValidateErrors, + ThrowOnError +> => + (options.client ?? client).post< + PostApiV1BetaPluginsValidateResponses, + PostApiV1BetaPluginsValidateErrors, + ThrowOnError + >({ + url: '/api/v1beta/plugins/validate', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }) + +/** + * Uninstall a plugin + * + * Remove an installed plugin + */ +export const deleteApiV1BetaPluginsByName = < + ThrowOnError extends boolean = false, +>( + options: Options +): RequestResult< + DeleteApiV1BetaPluginsByNameResponses, + DeleteApiV1BetaPluginsByNameErrors, + ThrowOnError +> => + (options.client ?? client).delete< + DeleteApiV1BetaPluginsByNameResponses, + DeleteApiV1BetaPluginsByNameErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins/{name}', ...options }) + +/** + * Get plugin details + * + * Get detailed information about a specific plugin + */ +export const getApiV1BetaPluginsByName = ( + options: Options +): RequestResult< + GetApiV1BetaPluginsByNameResponses, + GetApiV1BetaPluginsByNameErrors, + ThrowOnError +> => + (options.client ?? client).get< + GetApiV1BetaPluginsByNameResponses, + GetApiV1BetaPluginsByNameErrors, + ThrowOnError + >({ url: '/api/v1beta/plugins/{name}', ...options }) + /** * List registries * @@ -1534,6 +1787,54 @@ export const getRegistryByRegistryNameV01ServersByServerNameVersionsLatest = < ...options, }) +/** + * List available registry plugins + * + * Get a paginated list of plugins from the registry. Supports optional full-text search and pagination. + */ +export const getRegistryByRegistryNameV01xDevToolhivePlugins = < + ThrowOnError extends boolean = false, +>( + options: Options< + GetRegistryByRegistryNameV01xDevToolhivePluginsData, + ThrowOnError + > +): RequestResult< + GetRegistryByRegistryNameV01xDevToolhivePluginsResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsErrors, + ThrowOnError +> => + (options.client ?? client).get< + GetRegistryByRegistryNameV01xDevToolhivePluginsResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsErrors, + ThrowOnError + >({ url: '/registry/{registryName}/v0.1/x/dev.toolhive/plugins', ...options }) + +/** + * Get a registry plugin + * + * Retrieve a single plugin by its namespace and name from the registry. + */ +export const getRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginName = + ( + options: Options< + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameData, + ThrowOnError + > + ): RequestResult< + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors, + ThrowOnError + > => + (options.client ?? client).get< + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses, + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors, + ThrowOnError + >({ + url: '/registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{pluginName}', + ...options, + }) + /** * List available registry skills * diff --git a/common/api/generated/types.gen.ts b/common/api/generated/types.gen.ts index 8117197e6..e494a44ed 100644 --- a/common/api/generated/types.gen.ts +++ b/common/api/generated/types.gen.ts @@ -874,6 +874,222 @@ export type GithubComStacklokToolhivePkgGroupsGroup = { skills?: Array } +export type GithubComStacklokToolhivePkgPluginsBuildResult = { + /** + * Reference is the OCI reference of the built skill artifact. + */ + reference?: string +} + +/** + * Components is the inventory of component types declared by the plugin + * (e.g. {"commands": 3, "skills": 2}). Extracted from the OCI artifact. + */ +export type GithubComStacklokToolhivePkgPluginsComponentInventory = { + [key: string]: number +} + +export type GithubComStacklokToolhivePkgPluginsComponentType = + 'commands' | 'agents' | 'skills' | 'hooks' | 'mcpServers' | 'lspServers' + +export type GithubComStacklokToolhivePkgPluginsDependency = { + /** + * Digest is the OCI digest for upgrade detection. + */ + digest?: string + /** + * Name is the dependency name. + */ + name?: string + /** + * Reference is the OCI reference for the dependency. + */ + reference?: string +} + +/** + * Status is the current installation status. + */ +export type GithubComStacklokToolhivePkgPluginsInstallStatus = + 'installed' | 'pending' | 'failed' + +/** + * InstalledPlugin contains the full installation record. + */ +export type GithubComStacklokToolhivePkgPluginsInstalledPlugin = { + /** + * Clients is the list of client identifiers the plugin is installed for. + */ + clients?: Array + components?: GithubComStacklokToolhivePkgPluginsComponentInventory + /** + * Dependencies is the list of external plugin dependencies. + */ + dependencies?: Array + /** + * Digest is the OCI digest (sha256:...) for upgrade detection. + */ + digest?: string + /** + * InstalledAt is the timestamp when the plugin was installed. + */ + installed_at?: string + metadata?: GithubComStacklokToolhivePkgPluginsPluginMetadata + /** + * ProjectRoot is the project root path for project-scoped plugins. Empty for user-scoped. + */ + project_root?: string + /** + * Reference is the full OCI reference (e.g. ghcr.io/org/plugin:v1). + */ + reference?: string + scope?: GithubComStacklokToolhivePkgPluginsScope + /** + * Signature is the optional signing signature for the plugin artifact. + */ + signature?: string + status?: GithubComStacklokToolhivePkgPluginsInstallStatus + /** + * Tag is the OCI tag (e.g. v1.0.0). + */ + tag?: string +} + +export type GithubComStacklokToolhivePkgPluginsLocalBuild = { + /** + * Description is the skill description extracted from the artifact metadata, if available. + */ + description?: string + /** + * Digest is the OCI digest of the artifact (sha256:...). + */ + digest?: string + /** + * Name is the skill name extracted from the artifact metadata, if available. + */ + name?: string + /** + * Tag is the OCI tag or name used to reference the artifact. + */ + tag?: string + /** + * Version is the skill version extracted from the artifact metadata, if available. + */ + version?: string +} + +export type GithubComStacklokToolhivePkgPluginsPluginContent = { + /** + * Description is the plugin description from the OCI config labels. + */ + description?: string + /** + * Files is the list of all files in the artifact with their sizes. + */ + files?: Array + /** + * License is the SPDX license identifier from the OCI config labels. + */ + license?: string + /** + * Manifest is the raw .claude-plugin/plugin.json body. + */ + manifest?: string + /** + * Name is the plugin name from the OCI config labels. + */ + name?: string + /** + * Version is the plugin version from the OCI config labels. + */ + version?: string +} + +export type GithubComStacklokToolhivePkgPluginsPluginFileEntry = { + /** + * Path is the file path within the artifact. + */ + path?: string + /** + * Size is the uncompressed file size in bytes. + */ + size?: number +} + +export type GithubComStacklokToolhivePkgPluginsPluginInfo = { + installed_plugin?: GithubComStacklokToolhivePkgPluginsInstalledPlugin + metadata?: GithubComStacklokToolhivePkgPluginsPluginMetadata + /** + * ProjectScopeDegradedClients lists the client types for which a + * project-scoped install degraded (the adapter could only materialize at + * user scope — e.g. Codex always writes to the user-scoped config.toml). + * Populated by Info; empty for user-scoped installs. Recomputed at read + * time from the stored scope + each adapter's capability, mirroring the + * UnmaterializedComponents pattern (no persistence needed — the degradation + * is deterministic from scope + client type). + */ + project_scope_degraded_clients?: Array + /** + * UnmaterializedComponents lists, per client type, the component types the + * plugin declares that the installed client adapter does NOT load. Populated + * by Info by diffing InstalledPlugin.Components against each installed + * client adapter's SupportedComponents. + */ + unmaterialized_components?: { + [key: string]: Array + } +} + +/** + * Metadata contains the plugin's metadata. + */ +export type GithubComStacklokToolhivePkgPluginsPluginMetadata = { + /** + * Author is the plugin author or maintainer. + */ + author?: string + /** + * Description is a human-readable description of the plugin. + */ + description?: string + /** + * Keywords is a list of keywords for categorization/search. + */ + keywords?: Array + /** + * License is the SPDX license identifier for the plugin. + */ + license?: string + /** + * Name is the unique name of the plugin (kebab-case). + */ + name?: string + /** + * Version is the semantic version of the plugin. + */ + version?: string +} + +/** + * Scope for the installation + */ +export type GithubComStacklokToolhivePkgPluginsScope = 'user' | 'project' + +export type GithubComStacklokToolhivePkgPluginsValidationResult = { + /** + * Errors is a list of validation errors, if any. + */ + errors?: Array + /** + * Valid indicates whether the skill definition is valid. + */ + valid?: boolean + /** + * Warnings is a list of non-blocking validation warnings, if any. + */ + warnings?: Array +} + /** * PerUser token bucket configuration for this tool. * +optional @@ -1275,6 +1491,9 @@ export type GithubComStacklokToolhivePkgSkillsFailureReason = | 'digest-missing' | 'validation-rejected' | 'lock-write-failed' + | 'signature-invalid' + | 'signer-mismatch' + | 'unsigned-rejected' | 'unknown' /** @@ -1495,6 +1714,11 @@ export type GithubComStacklokToolhivePkgSkillsUpgradeOutcome = { * NewResolvedReference is the new resolvedReference when it changed. */ new_resolved_reference?: string + /** + * NewSignerIdentity is the candidate's signer identity when it differs + * from the recorded one (empty when the candidate is unsigned). + */ + new_signer_identity?: string /** * OldDigest is the digest pinned in the lock file before this operation. */ @@ -1514,7 +1738,12 @@ export type GithubComStacklokToolhivePkgSkillsUpgradeResult = { * Status is the outcome of the upgrade attempt. */ export type GithubComStacklokToolhivePkgSkillsUpgradeStatus = - 'upgraded' | 'up-to-date' | 'not-upgradable' | 'ref-change-blocked' | 'failed' + | 'upgraded' + | 'up-to-date' + | 'not-upgradable' + | 'ref-change-blocked' + | 'signer-change-blocked' + | 'failed' export type GithubComStacklokToolhivePkgSkillsValidationResult = { /** @@ -1955,6 +2184,20 @@ export type PkgApiV1BuildListResponse = { builds?: Array } +/** + * Request to build a plugin from a local directory + */ +export type PkgApiV1BuildPluginRequest = { + /** + * Path to the plugin definition directory + */ + path?: string + /** + * OCI tag for the built artifact + */ + tag?: string +} + /** * Request to build a skill from a local directory */ @@ -2273,10 +2516,56 @@ export type PkgApiV1HeaderForwardConfig = { } } +/** + * Request to install a plugin + */ +export type PkgApiV1InstallPluginRequest = { + /** + * Clients lists target client identifiers (e.g., "claude-code"), + * or ["all"] to target every plugin-supporting client. + * Omitting this field installs to all available clients. + */ + clients?: Array + /** + * Force allows overwriting unmanaged plugin directories + */ + force?: boolean + /** + * Group is the group name to add the plugin to after installation + */ + group?: string + /** + * Name or OCI reference of the plugin to install + */ + name?: string + /** + * ProjectRoot is the project root path for project-scoped installs + */ + project_root?: string + scope?: GithubComStacklokToolhivePkgPluginsScope + /** + * Version to install (empty means latest) + */ + version?: string +} + +/** + * Response after successfully installing a plugin + */ +export type PkgApiV1InstallPluginResponse = { + plugin?: GithubComStacklokToolhivePkgPluginsInstalledPlugin +} + /** * Request to install a skill */ export type PkgApiV1InstallSkillRequest = { + /** + * AllowUnsigned permits installing a project-scoped skill without a + * verified signature; the exception is recorded in the project's lock + * file. + */ + allow_unsigned?: boolean /** * Clients lists target client identifiers (e.g., "claude-code"), * or ["all"] to target every skill-supporting client. @@ -2389,6 +2678,37 @@ export type PkgApiV1PaginationV01Metadata = { total?: number } +/** + * Response containing a list of locally-built OCI plugin artifacts + */ +export type PkgApiV1PluginBuildListResponse = { + /** + * List of locally-built OCI plugin artifacts + */ + builds?: Array +} + +/** + * Response containing a list of installed plugins + */ +export type PkgApiV1PluginListResponse = { + /** + * List of installed plugins + */ + plugins?: Array +} + +/** + * Paginated list of plugins from the registry + */ +export type PkgApiV1PluginsV01Response = { + metadata?: PkgApiV1PaginationV01Metadata + /** + * Plugins is the list of plugins on the current page + */ + plugins?: Array +} + /** * Capabilities of the secrets provider */ @@ -2415,6 +2735,16 @@ export type PkgApiV1ProviderCapabilitiesResponse = { can_write?: boolean } +/** + * Request to push a built plugin artifact + */ +export type PkgApiV1PushPluginRequest = { + /** + * OCI reference to push + */ + reference?: string +} + /** * Request to push a built skill artifact */ @@ -2622,6 +2952,11 @@ export type PkgApiV1SyncSkillsRequest = { * Adopt writes lock entries for existing unmanaged project-scope installs */ adopt?: boolean + /** + * AllowUnsigned permits adopting skills whose signature state cannot be + * established, recording them as unsigned + */ + allow_unsigned?: boolean /** * Check verifies on-disk content against the lock file without installing or writing anything */ @@ -2821,6 +3156,11 @@ export type PkgApiV1UpgradeSkillsRequest = { * AllowRefChange permits resolvedReference changes during upgrade */ allow_ref_change?: boolean + /** + * AllowSignerChange permits upgrading to an artifact signed by a + * different identity than the recorded one + */ + allow_signer_change?: boolean /** * Clients lists target client identifiers. Empty means every * skill-supporting client detected on this host. @@ -2844,6 +3184,16 @@ export type PkgApiV1UpgradeSkillsRequest = { project_root?: string } +/** + * Request to validate a plugin definition + */ +export type PkgApiV1ValidatePluginRequest = { + /** + * Path to the plugin definition directory + */ + path?: string +} + /** * Request to validate a skill definition */ @@ -3161,22 +3511,81 @@ export type RegistryOAuthConfig = { use_pkce?: boolean } -/** - * Provenance contains verification and signing metadata - */ -export type RegistryProvenance = { - attestation?: RegistryVerifiedAttestation - cert_issuer?: string - repository_ref?: string - repository_uri?: string - runner_environment?: string - signer_identity?: string - sigstore_url?: string -} - -/** - * Full registry data - */ +export type RegistryPlugin = { + /** + * Meta is an opaque payload with extended meta data details of the plugin. + */ + _meta?: { + [key: string]: unknown + } + /** + * Description is the description of the plugin. + */ + description?: string + /** + * Icons is the list of icons for the plugin. + */ + icons?: Array + /** + * License is the SPDX license identifier of the plugin. + */ + license?: string + /** + * Metadata is the official metadata of the plugin as reported in the + * plugin manifest file. + */ + metadata?: { + [key: string]: unknown + } + /** + * Name is the name of the plugin. + * The format is that of identifiers, e.g. "my-plugin". + */ + name?: string + /** + * Namespace is the namespace of the plugin. + * The format is reverse-DNS, e.g. "io.github.user". + */ + namespace?: string + /** + * Packages is the list of packages for the plugin. + */ + packages?: Array + repository?: RegistrySkillRepository + /** + * Status is the status of the plugin. + * Can be one of "active", "deprecated", or "archived". + */ + status?: string + /** + * Title is the title of the plugin. + * This is for human consumption, not an identifier. + */ + title?: string + /** + * Version is the version of the plugin. + * Any non-empty string is valid, but ideally it should be either a + * semantic version or a commit hash. + */ + version?: string +} + +/** + * Provenance contains verification and signing metadata + */ +export type RegistryProvenance = { + attestation?: RegistryVerifiedAttestation + cert_issuer?: string + repository_ref?: string + repository_uri?: string + runner_environment?: string + signer_identity?: string + sigstore_url?: string +} + +/** + * Full registry data + */ export type RegistryRegistry = { /** * Groups is a slice of group definitions containing related MCP servers @@ -4229,6 +4638,447 @@ export type GetApiV1BetaGroupsByNameResponses = { export type GetApiV1BetaGroupsByNameResponse = GetApiV1BetaGroupsByNameResponses[keyof GetApiV1BetaGroupsByNameResponses] +export type GetApiV1BetaPluginsData = { + body?: never + path?: never + query?: { + /** + * Filter by scope (user or project) + */ + scope?: 'user' | 'project' + /** + * Filter by client app + */ + client?: string + /** + * Filter by project root path + */ + project_root?: string + /** + * Filter by group name + */ + group?: string + } + url: '/api/v1beta/plugins' +} + +export type GetApiV1BetaPluginsErrors = { + /** + * Internal Server Error + */ + 500: string +} + +export type GetApiV1BetaPluginsError = + GetApiV1BetaPluginsErrors[keyof GetApiV1BetaPluginsErrors] + +export type GetApiV1BetaPluginsResponses = { + /** + * OK + */ + 200: PkgApiV1PluginListResponse +} + +export type GetApiV1BetaPluginsResponse = + GetApiV1BetaPluginsResponses[keyof GetApiV1BetaPluginsResponses] + +export type PostApiV1BetaPluginsData = { + /** + * Install request + */ + body: + | { + [key: string]: unknown + } + | PkgApiV1InstallPluginRequest + path?: never + query?: never + url: '/api/v1beta/plugins' +} + +export type PostApiV1BetaPluginsErrors = { + /** + * Bad Request + */ + 400: string + /** + * Unauthorized (registry refused credentials) + */ + 401: string + /** + * Not Found (artifact not present in registry) + */ + 404: string + /** + * Conflict + */ + 409: string + /** + * Too Many Requests (registry rate limit) + */ + 429: string + /** + * Internal Server Error + */ + 500: string + /** + * Bad Gateway (upstream registry failure) + */ + 502: string + /** + * Gateway Timeout (upstream pull timed out) + */ + 504: string +} + +export type PostApiV1BetaPluginsError = + PostApiV1BetaPluginsErrors[keyof PostApiV1BetaPluginsErrors] + +export type PostApiV1BetaPluginsResponses = { + /** + * Created + */ + 201: PkgApiV1InstallPluginResponse +} + +export type PostApiV1BetaPluginsResponse = + PostApiV1BetaPluginsResponses[keyof PostApiV1BetaPluginsResponses] + +export type PostApiV1BetaPluginsBuildData = { + /** + * Build request + */ + body: + | { + [key: string]: unknown + } + | PkgApiV1BuildPluginRequest + path?: never + query?: never + url: '/api/v1beta/plugins/build' +} + +export type PostApiV1BetaPluginsBuildErrors = { + /** + * Bad Request + */ + 400: string + /** + * Internal Server Error + */ + 500: string +} + +export type PostApiV1BetaPluginsBuildError = + PostApiV1BetaPluginsBuildErrors[keyof PostApiV1BetaPluginsBuildErrors] + +export type PostApiV1BetaPluginsBuildResponses = { + /** + * OK + */ + 200: GithubComStacklokToolhivePkgPluginsBuildResult +} + +export type PostApiV1BetaPluginsBuildResponse = + PostApiV1BetaPluginsBuildResponses[keyof PostApiV1BetaPluginsBuildResponses] + +export type GetApiV1BetaPluginsBuildsData = { + body?: never + path?: never + query?: never + url: '/api/v1beta/plugins/builds' +} + +export type GetApiV1BetaPluginsBuildsErrors = { + /** + * Internal Server Error + */ + 500: string +} + +export type GetApiV1BetaPluginsBuildsError = + GetApiV1BetaPluginsBuildsErrors[keyof GetApiV1BetaPluginsBuildsErrors] + +export type GetApiV1BetaPluginsBuildsResponses = { + /** + * OK + */ + 200: PkgApiV1PluginBuildListResponse +} + +export type GetApiV1BetaPluginsBuildsResponse = + GetApiV1BetaPluginsBuildsResponses[keyof GetApiV1BetaPluginsBuildsResponses] + +export type DeleteApiV1BetaPluginsBuildsByTagData = { + body?: never + path: { + /** + * Artifact tag + */ + tag: string + } + query?: never + url: '/api/v1beta/plugins/builds/{tag}' +} + +export type DeleteApiV1BetaPluginsBuildsByTagErrors = { + /** + * Not Found + */ + 404: string + /** + * Internal Server Error + */ + 500: string +} + +export type DeleteApiV1BetaPluginsBuildsByTagError = + DeleteApiV1BetaPluginsBuildsByTagErrors[keyof DeleteApiV1BetaPluginsBuildsByTagErrors] + +export type DeleteApiV1BetaPluginsBuildsByTagResponses = { + /** + * No Content + */ + 204: string +} + +export type DeleteApiV1BetaPluginsBuildsByTagResponse = + DeleteApiV1BetaPluginsBuildsByTagResponses[keyof DeleteApiV1BetaPluginsBuildsByTagResponses] + +export type GetApiV1BetaPluginsContentData = { + body?: never + path?: never + query: { + /** + * OCI reference or local build tag + */ + ref: string + } + url: '/api/v1beta/plugins/content' +} + +export type GetApiV1BetaPluginsContentErrors = { + /** + * Bad Request + */ + 400: string + /** + * Unauthorized (registry refused credentials) + */ + 401: string + /** + * Not Found (artifact not present in registry) + */ + 404: string + /** + * Too Many Requests (registry rate limit) + */ + 429: string + /** + * Internal Server Error + */ + 500: string + /** + * Bad Gateway (upstream registry or git resolver failure) + */ + 502: string + /** + * Gateway Timeout (upstream pull timed out) + */ + 504: string +} + +export type GetApiV1BetaPluginsContentError = + GetApiV1BetaPluginsContentErrors[keyof GetApiV1BetaPluginsContentErrors] + +export type GetApiV1BetaPluginsContentResponses = { + /** + * OK + */ + 200: GithubComStacklokToolhivePkgPluginsPluginContent +} + +export type GetApiV1BetaPluginsContentResponse = + GetApiV1BetaPluginsContentResponses[keyof GetApiV1BetaPluginsContentResponses] + +export type PostApiV1BetaPluginsPushData = { + /** + * Push request + */ + body: + | { + [key: string]: unknown + } + | PkgApiV1PushPluginRequest + path?: never + query?: never + url: '/api/v1beta/plugins/push' +} + +export type PostApiV1BetaPluginsPushErrors = { + /** + * Bad Request + */ + 400: string + /** + * Not Found + */ + 404: string + /** + * Internal Server Error + */ + 500: string +} + +export type PostApiV1BetaPluginsPushError = + PostApiV1BetaPluginsPushErrors[keyof PostApiV1BetaPluginsPushErrors] + +export type PostApiV1BetaPluginsPushResponses = { + /** + * No Content + */ + 204: string +} + +export type PostApiV1BetaPluginsPushResponse = + PostApiV1BetaPluginsPushResponses[keyof PostApiV1BetaPluginsPushResponses] + +export type PostApiV1BetaPluginsValidateData = { + /** + * Validate request + */ + body: + | { + [key: string]: unknown + } + | PkgApiV1ValidatePluginRequest + path?: never + query?: never + url: '/api/v1beta/plugins/validate' +} + +export type PostApiV1BetaPluginsValidateErrors = { + /** + * Bad Request + */ + 400: string + /** + * Internal Server Error + */ + 500: string +} + +export type PostApiV1BetaPluginsValidateError = + PostApiV1BetaPluginsValidateErrors[keyof PostApiV1BetaPluginsValidateErrors] + +export type PostApiV1BetaPluginsValidateResponses = { + /** + * OK + */ + 200: GithubComStacklokToolhivePkgPluginsValidationResult +} + +export type PostApiV1BetaPluginsValidateResponse = + PostApiV1BetaPluginsValidateResponses[keyof PostApiV1BetaPluginsValidateResponses] + +export type DeleteApiV1BetaPluginsByNameData = { + body?: never + path: { + /** + * Plugin name + */ + name: string + } + query?: { + /** + * Scope to uninstall from (user or project) + */ + scope?: 'user' | 'project' + /** + * Project root path for project-scoped plugins + */ + project_root?: string + } + url: '/api/v1beta/plugins/{name}' +} + +export type DeleteApiV1BetaPluginsByNameErrors = { + /** + * Bad Request + */ + 400: string + /** + * Not Found + */ + 404: string + /** + * Internal Server Error + */ + 500: string +} + +export type DeleteApiV1BetaPluginsByNameError = + DeleteApiV1BetaPluginsByNameErrors[keyof DeleteApiV1BetaPluginsByNameErrors] + +export type DeleteApiV1BetaPluginsByNameResponses = { + /** + * No Content + */ + 204: string +} + +export type DeleteApiV1BetaPluginsByNameResponse = + DeleteApiV1BetaPluginsByNameResponses[keyof DeleteApiV1BetaPluginsByNameResponses] + +export type GetApiV1BetaPluginsByNameData = { + body?: never + path: { + /** + * Plugin name + */ + name: string + } + query?: { + /** + * Filter by scope (user or project) + */ + scope?: 'user' | 'project' + /** + * Project root path for project-scoped plugins + */ + project_root?: string + } + url: '/api/v1beta/plugins/{name}' +} + +export type GetApiV1BetaPluginsByNameErrors = { + /** + * Bad Request + */ + 400: string + /** + * Not Found + */ + 404: string + /** + * Internal Server Error + */ + 500: string +} + +export type GetApiV1BetaPluginsByNameError = + GetApiV1BetaPluginsByNameErrors[keyof GetApiV1BetaPluginsByNameErrors] + +export type GetApiV1BetaPluginsByNameResponses = { + /** + * OK + */ + 200: GithubComStacklokToolhivePkgPluginsPluginInfo +} + +export type GetApiV1BetaPluginsByNameResponse = + GetApiV1BetaPluginsByNameResponses[keyof GetApiV1BetaPluginsByNameResponses] + export type GetApiV1BetaRegistryData = { body?: never path?: never @@ -6101,6 +6951,106 @@ export type GetRegistryByRegistryNameV01ServersByServerNameVersionsLatestRespons export type GetRegistryByRegistryNameV01ServersByServerNameVersionsLatestResponse = GetRegistryByRegistryNameV01ServersByServerNameVersionsLatestResponses[keyof GetRegistryByRegistryNameV01ServersByServerNameVersionsLatestResponses] +export type GetRegistryByRegistryNameV01xDevToolhivePluginsData = { + body?: never + path: { + /** + * Registry name (currently ignored, uses the default provider) + */ + registryName: string + } + query?: { + /** + * Search filter — matches against plugin name, namespace, and description + */ + q?: string + /** + * Page number, 1-based (default: 1) + */ + page?: number + /** + * Items per page, max 200 (default: 50) + */ + limit?: number + } + url: '/registry/{registryName}/v0.1/x/dev.toolhive/plugins' +} + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsErrors = { + /** + * Internal server error + */ + 500: PkgApiV1RegistryErrorResponse + /** + * Registry authentication required or upstream registry unavailable + */ + 503: PkgApiV1RegistryErrorResponse +} + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsError = + GetRegistryByRegistryNameV01xDevToolhivePluginsErrors[keyof GetRegistryByRegistryNameV01xDevToolhivePluginsErrors] + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsResponses = { + /** + * OK + */ + 200: PkgApiV1PluginsV01Response +} + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsResponse = + GetRegistryByRegistryNameV01xDevToolhivePluginsResponses[keyof GetRegistryByRegistryNameV01xDevToolhivePluginsResponses] + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameData = + { + body?: never + path: { + /** + * Registry name (currently ignored, uses the default provider) + */ + registryName: string + /** + * Plugin namespace in reverse-DNS format (e.g. io.github.stacklok) + */ + namespace: string + /** + * Plugin name + */ + pluginName: string + } + query?: never + url: '/registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{pluginName}' + } + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors = + { + /** + * Plugin not found + */ + 404: PkgApiV1RegistryErrorResponse + /** + * Internal server error + */ + 500: PkgApiV1RegistryErrorResponse + /** + * Registry authentication required or upstream registry unavailable + */ + 503: PkgApiV1RegistryErrorResponse + } + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameError = + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors[keyof GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameErrors] + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses = + { + /** + * OK + */ + 200: RegistryPlugin + } + +export type GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponse = + GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses[keyof GetRegistryByRegistryNameV01xDevToolhivePluginsByNamespaceByPluginNameResponses] + export type GetRegistryByRegistryNameV01xDevToolhiveSkillsData = { body?: never path: { diff --git a/common/api/openapi.json b/common/api/openapi.json index a91c3ff1d..b7bfaa4e8 100644 --- a/common/api/openapi.json +++ b/common/api/openapi.json @@ -846,6 +846,291 @@ }, "type": "object" }, + "github_com_stacklok_toolhive_pkg_plugins.BuildResult": { + "properties": { + "reference": { + "description": "Reference is the OCI reference of the built skill artifact.", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.ComponentInventory": { + "additionalProperties": { + "type": "integer" + }, + "description": "Components is the inventory of component types declared by the plugin\n(e.g. {\"commands\": 3, \"skills\": 2}). Extracted from the OCI artifact.", + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.ComponentType": { + "enum": [ + "commands", + "agents", + "skills", + "hooks", + "mcpServers", + "lspServers" + ], + "type": "string", + "x-enum-varnames": [ + "ComponentCommands", + "ComponentAgents", + "ComponentSkills", + "ComponentHooks", + "ComponentMCP", + "ComponentLSP" + ] + }, + "github_com_stacklok_toolhive_pkg_plugins.Dependency": { + "properties": { + "digest": { + "description": "Digest is the OCI digest for upgrade detection.", + "type": "string" + }, + "name": { + "description": "Name is the dependency name.", + "type": "string" + }, + "reference": { + "description": "Reference is the OCI reference for the dependency.", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.InstallStatus": { + "description": "Status is the current installation status.", + "enum": ["installed", "pending", "failed"], + "type": "string", + "x-enum-varnames": [ + "InstallStatusInstalled", + "InstallStatusPending", + "InstallStatusFailed" + ] + }, + "github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin": { + "description": "InstalledPlugin contains the full installation record.", + "properties": { + "clients": { + "description": "Clients is the list of client identifiers the plugin is installed for.", + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "components": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ComponentInventory" + }, + "dependencies": { + "description": "Dependencies is the list of external plugin dependencies.", + "items": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Dependency" + }, + "type": "array", + "uniqueItems": false + }, + "digest": { + "description": "Digest is the OCI digest (sha256:...) for upgrade detection.", + "type": "string" + }, + "installed_at": { + "description": "InstalledAt is the timestamp when the plugin was installed.", + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginMetadata" + }, + "project_root": { + "description": "ProjectRoot is the project root path for project-scoped plugins. Empty for user-scoped.", + "type": "string" + }, + "reference": { + "description": "Reference is the full OCI reference (e.g. ghcr.io/org/plugin:v1).", + "type": "string" + }, + "scope": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Scope" + }, + "signature": { + "description": "Signature is the optional signing signature for the plugin artifact.", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstallStatus" + }, + "tag": { + "description": "Tag is the OCI tag (e.g. v1.0.0).", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.LocalBuild": { + "properties": { + "description": { + "description": "Description is the skill description extracted from the artifact metadata, if available.", + "type": "string" + }, + "digest": { + "description": "Digest is the OCI digest of the artifact (sha256:...).", + "type": "string" + }, + "name": { + "description": "Name is the skill name extracted from the artifact metadata, if available.", + "type": "string" + }, + "tag": { + "description": "Tag is the OCI tag or name used to reference the artifact.", + "type": "string" + }, + "version": { + "description": "Version is the skill version extracted from the artifact metadata, if available.", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.PluginContent": { + "properties": { + "description": { + "description": "Description is the plugin description from the OCI config labels.", + "type": "string" + }, + "files": { + "description": "Files is the list of all files in the artifact with their sizes.", + "items": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginFileEntry" + }, + "type": "array", + "uniqueItems": false + }, + "license": { + "description": "License is the SPDX license identifier from the OCI config labels.", + "type": "string" + }, + "manifest": { + "description": "Manifest is the raw .claude-plugin/plugin.json body.", + "type": "string" + }, + "name": { + "description": "Name is the plugin name from the OCI config labels.", + "type": "string" + }, + "version": { + "description": "Version is the plugin version from the OCI config labels.", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.PluginFileEntry": { + "properties": { + "path": { + "description": "Path is the file path within the artifact.", + "type": "string" + }, + "size": { + "description": "Size is the uncompressed file size in bytes.", + "type": "integer" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.PluginInfo": { + "properties": { + "installed_plugin": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin" + }, + "metadata": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginMetadata" + }, + "project_scope_degraded_clients": { + "description": "ProjectScopeDegradedClients lists the client types for which a\nproject-scoped install degraded (the adapter could only materialize at\nuser scope — e.g. Codex always writes to the user-scoped config.toml).\nPopulated by Info; empty for user-scoped installs. Recomputed at read\ntime from the stored scope + each adapter's capability, mirroring the\nUnmaterializedComponents pattern (no persistence needed — the degradation\nis deterministic from scope + client type).", + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "unmaterialized_components": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ComponentType" + }, + "type": "array" + }, + "description": "UnmaterializedComponents lists, per client type, the component types the\nplugin declares that the installed client adapter does NOT load. Populated\nby Info by diffing InstalledPlugin.Components against each installed\nclient adapter's SupportedComponents.", + "type": "object" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.PluginMetadata": { + "description": "Metadata contains the plugin's metadata.", + "properties": { + "author": { + "description": "Author is the plugin author or maintainer.", + "type": "string" + }, + "description": { + "description": "Description is a human-readable description of the plugin.", + "type": "string" + }, + "keywords": { + "description": "Keywords is a list of keywords for categorization/search.", + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "license": { + "description": "License is the SPDX license identifier for the plugin.", + "type": "string" + }, + "name": { + "description": "Name is the unique name of the plugin (kebab-case).", + "type": "string" + }, + "version": { + "description": "Version is the semantic version of the plugin.", + "type": "string" + } + }, + "type": "object" + }, + "github_com_stacklok_toolhive_pkg_plugins.Scope": { + "description": "Scope for the installation", + "enum": ["user", "project"], + "type": "string", + "x-enum-varnames": ["ScopeUser", "ScopeProject"] + }, + "github_com_stacklok_toolhive_pkg_plugins.ValidationResult": { + "properties": { + "errors": { + "description": "Errors is a list of validation errors, if any.", + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "valid": { + "description": "Valid indicates whether the skill definition is valid.", + "type": "boolean" + }, + "warnings": { + "description": "Warnings is a list of non-blocking validation warnings, if any.", + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, "github_com_stacklok_toolhive_pkg_ratelimit_types.RateLimitBucket": { "description": "PerUser token bucket configuration for this tool.\n+optional", "properties": { @@ -1276,6 +1561,9 @@ "digest-missing", "validation-rejected", "lock-write-failed", + "signature-invalid", + "signer-mismatch", + "unsigned-rejected", "unknown" ], "type": "string", @@ -1284,6 +1572,9 @@ "FailureReasonDigestMissing", "FailureReasonValidationRejected", "FailureReasonLockWriteFailed", + "FailureReasonSignatureInvalid", + "FailureReasonSignerMismatch", + "FailureReasonUnsignedRejected", "FailureReasonUnknown" ] }, @@ -1573,6 +1864,10 @@ "description": "NewResolvedReference is the new resolvedReference when it changed.", "type": "string" }, + "new_signer_identity": { + "description": "NewSignerIdentity is the candidate's signer identity when it differs\nfrom the recorded one (empty when the candidate is unsigned).", + "type": "string" + }, "old_digest": { "description": "OldDigest is the digest pinned in the lock file before this operation.", "type": "string" @@ -1606,6 +1901,7 @@ "up-to-date", "not-upgradable", "ref-change-blocked", + "signer-change-blocked", "failed" ], "type": "string", @@ -1614,6 +1910,7 @@ "UpgradeStatusUpToDate", "UpgradeStatusNotUpgradable", "UpgradeStatusRefChangeBlocked", + "UpgradeStatusSignerChangeBlocked", "UpgradeStatusFailed" ] }, @@ -2297,6 +2594,20 @@ }, "type": "object" }, + "pkg_api_v1.buildPluginRequest": { + "description": "Request to build a plugin from a local directory", + "properties": { + "path": { + "description": "Path to the plugin definition directory", + "type": "string" + }, + "tag": { + "description": "OCI tag for the built artifact", + "type": "string" + } + }, + "type": "object" + }, "pkg_api_v1.buildSkillRequest": { "description": "Request to build a skill from a local directory", "properties": { @@ -2696,11 +3007,11 @@ }, "type": "object" }, - "pkg_api_v1.installSkillRequest": { - "description": "Request to install a skill", + "pkg_api_v1.installPluginRequest": { + "description": "Request to install a plugin", "properties": { "clients": { - "description": "Clients lists target client identifiers (e.g., \"claude-code\"),\nor [\"all\"] to target every skill-supporting client.\nOmitting this field installs to all available clients.", + "description": "Clients lists target client identifiers (e.g., \"claude-code\"),\nor [\"all\"] to target every plugin-supporting client.\nOmitting this field installs to all available clients.", "items": { "type": "string" }, @@ -2708,15 +3019,15 @@ "uniqueItems": false }, "force": { - "description": "Force allows overwriting unmanaged skill directories", + "description": "Force allows overwriting unmanaged plugin directories", "type": "boolean" }, "group": { - "description": "Group is the group name to add the skill to after installation", + "description": "Group is the group name to add the plugin to after installation", "type": "string" }, "name": { - "description": "Name or OCI reference of the skill to install", + "description": "Name or OCI reference of the plugin to install", "type": "string" }, "project_root": { @@ -2724,7 +3035,7 @@ "type": "string" }, "scope": { - "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_skills.Scope" + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.Scope" }, "version": { "description": "Version to install (empty means latest)", @@ -2733,27 +3044,77 @@ }, "type": "object" }, - "pkg_api_v1.installSkillResponse": { - "description": "Response after successfully installing a skill", + "pkg_api_v1.installPluginResponse": { + "description": "Response after successfully installing a plugin", "properties": { - "skill": { - "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_skills.InstalledSkill" + "plugin": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin" } }, "type": "object" }, - "pkg_api_v1.listSecretsResponse": { - "description": "Response containing a list of secret keys", + "pkg_api_v1.installSkillRequest": { + "description": "Request to install a skill", "properties": { - "keys": { - "description": "List of secret keys", + "allow_unsigned": { + "description": "AllowUnsigned permits installing a project-scoped skill without a\nverified signature; the exception is recorded in the project's lock\nfile.", + "type": "boolean" + }, + "clients": { + "description": "Clients lists target client identifiers (e.g., \"claude-code\"),\nor [\"all\"] to target every skill-supporting client.\nOmitting this field installs to all available clients.", "items": { - "$ref": "#/components/schemas/pkg_api_v1.secretKeyResponse" + "type": "string" }, "type": "array", "uniqueItems": false - } - }, + }, + "force": { + "description": "Force allows overwriting unmanaged skill directories", + "type": "boolean" + }, + "group": { + "description": "Group is the group name to add the skill to after installation", + "type": "string" + }, + "name": { + "description": "Name or OCI reference of the skill to install", + "type": "string" + }, + "project_root": { + "description": "ProjectRoot is the project root path for project-scoped installs", + "type": "string" + }, + "scope": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_skills.Scope" + }, + "version": { + "description": "Version to install (empty means latest)", + "type": "string" + } + }, + "type": "object" + }, + "pkg_api_v1.installSkillResponse": { + "description": "Response after successfully installing a skill", + "properties": { + "skill": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_skills.InstalledSkill" + } + }, + "type": "object" + }, + "pkg_api_v1.listSecretsResponse": { + "description": "Response containing a list of secret keys", + "properties": { + "keys": { + "description": "List of secret keys", + "items": { + "$ref": "#/components/schemas/pkg_api_v1.secretKeyResponse" + }, + "type": "array", + "uniqueItems": false + } + }, "type": "object" }, "pkg_api_v1.listServersResponse": { @@ -2834,6 +3195,51 @@ }, "type": "object" }, + "pkg_api_v1.pluginBuildListResponse": { + "description": "Response containing a list of locally-built OCI plugin artifacts", + "properties": { + "builds": { + "description": "List of locally-built OCI plugin artifacts", + "items": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.LocalBuild" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "pkg_api_v1.pluginListResponse": { + "description": "Response containing a list of installed plugins", + "properties": { + "plugins": { + "description": "List of installed plugins", + "items": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.InstalledPlugin" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "pkg_api_v1.pluginsV01Response": { + "description": "Paginated list of plugins from the registry", + "properties": { + "metadata": { + "$ref": "#/components/schemas/pkg_api_v1.paginationV01Metadata" + }, + "plugins": { + "description": "Plugins is the list of plugins on the current page", + "items": { + "$ref": "#/components/schemas/registry.Plugin" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, "pkg_api_v1.providerCapabilitiesResponse": { "description": "Capabilities of the secrets provider", "properties": { @@ -2860,6 +3266,16 @@ }, "type": "object" }, + "pkg_api_v1.pushPluginRequest": { + "description": "Request to push a built plugin artifact", + "properties": { + "reference": { + "description": "OCI reference to push", + "type": "string" + } + }, + "type": "object" + }, "pkg_api_v1.pushSkillRequest": { "description": "Request to push a built skill artifact", "properties": { @@ -3094,6 +3510,10 @@ "description": "Adopt writes lock entries for existing unmanaged project-scope installs", "type": "boolean" }, + "allow_unsigned": { + "description": "AllowUnsigned permits adopting skills whose signature state cannot be\nestablished, recording them as unsigned", + "type": "boolean" + }, "check": { "description": "Check verifies on-disk content against the lock file without installing or writing anything", "type": "boolean" @@ -3328,6 +3748,10 @@ "description": "AllowRefChange permits resolvedReference changes during upgrade", "type": "boolean" }, + "allow_signer_change": { + "description": "AllowSignerChange permits upgrading to an artifact signed by a\ndifferent identity than the recorded one", + "type": "boolean" + }, "clients": { "description": "Clients lists target client identifiers. Empty means every\nskill-supporting client detected on this host.", "items": { @@ -3359,6 +3783,16 @@ }, "type": "object" }, + "pkg_api_v1.validatePluginRequest": { + "description": "Request to validate a plugin definition", + "properties": { + "path": { + "description": "Path to the plugin definition directory", + "type": "string" + } + }, + "type": "object" + }, "pkg_api_v1.validateSkillRequest": { "description": "Request to validate a skill definition", "properties": { @@ -3703,6 +4137,68 @@ }, "type": "object" }, + "registry.Plugin": { + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "Meta is an opaque payload with extended meta data details of the plugin.", + "type": "object" + }, + "description": { + "description": "Description is the description of the plugin.", + "type": "string" + }, + "icons": { + "description": "Icons is the list of icons for the plugin.", + "items": { + "$ref": "#/components/schemas/registry.SkillIcon" + }, + "type": "array", + "uniqueItems": false + }, + "license": { + "description": "License is the SPDX license identifier of the plugin.", + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "description": "Metadata is the official metadata of the plugin as reported in the\nplugin manifest file.", + "type": "object" + }, + "name": { + "description": "Name is the name of the plugin.\nThe format is that of identifiers, e.g. \"my-plugin\".", + "type": "string" + }, + "namespace": { + "description": "Namespace is the namespace of the plugin.\nThe format is reverse-DNS, e.g. \"io.github.user\".", + "type": "string" + }, + "packages": { + "description": "Packages is the list of packages for the plugin.", + "items": { + "$ref": "#/components/schemas/registry.SkillPackage" + }, + "type": "array", + "uniqueItems": false + }, + "repository": { + "$ref": "#/components/schemas/registry.SkillRepository" + }, + "status": { + "description": "Status is the status of the plugin.\nCan be one of \"active\", \"deprecated\", or \"archived\".", + "type": "string" + }, + "title": { + "description": "Title is the title of the plugin.\nThis is for human consumption, not an identifier.", + "type": "string" + }, + "version": { + "description": "Version is the version of the plugin.\nAny non-empty string is valid, but ideally it should be either a\nsemantic version or a commit hash.", + "type": "string" + } + }, + "type": "object" + }, "registry.Provenance": { "description": "Provenance contains verification and signing metadata", "properties": { @@ -4764,30 +5260,699 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pkg_api_v1.clientStatusResponse" + "$ref": "#/components/schemas/pkg_api_v1.clientStatusResponse" + } + } + }, + "description": "OK" + } + }, + "summary": "List all clients status", + "tags": ["discovery"] + } + }, + "/api/v1beta/groups": { + "get": { + "description": "Get a list of all groups", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.groupListResponse" + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "List all groups", + "tags": ["groups"] + }, + "post": { + "description": "Create a new group with the specified name", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object" + }, + { + "$ref": "#/components/schemas/pkg_api_v1.createGroupRequest", + "summary": "group", + "description": "Group creation request" + } + ] + } + } + }, + "description": "Group creation request", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.createGroupResponse" + } + } + }, + "description": "Created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, + "409": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Conflict" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Create a new group", + "tags": ["groups"] + } + }, + "/api/v1beta/groups/{name}": { + "delete": { + "description": "Delete a group by name.", + "parameters": [ + { + "description": "Group name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Delete all workloads in the group (default: false, moves workloads to default group)", + "in": "query", + "name": "with-workloads", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "204": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "No Content" + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Not Found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Delete a group", + "tags": ["groups"] + }, + "get": { + "description": "Get details of a specific group", + "parameters": [ + { + "description": "Group name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_groups.Group" + } + } + }, + "description": "OK" + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Not Found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Get group details", + "tags": ["groups"] + } + }, + "/api/v1beta/plugins": { + "get": { + "description": "Get a list of all installed plugins", + "parameters": [ + { + "description": "Filter by scope (user or project)", + "in": "query", + "name": "scope", + "schema": { + "enum": ["user", "project"], + "type": "string" + } + }, + { + "description": "Filter by client app", + "in": "query", + "name": "client", + "schema": { + "type": "string" + } + }, + { + "description": "Filter by project root path", + "in": "query", + "name": "project_root", + "schema": { + "type": "string" + } + }, + { + "description": "Filter by group name", + "in": "query", + "name": "group", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.pluginListResponse" + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "List all installed plugins", + "tags": ["plugins"] + }, + "post": { + "description": "Install a plugin from a remote source", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object" + }, + { + "$ref": "#/components/schemas/pkg_api_v1.installPluginRequest", + "summary": "request", + "description": "Install request" + } + ] + } + } + }, + "description": "Install request", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.installPluginResponse" + } + } + }, + "description": "Created", + "headers": { + "Location": { + "description": "URI of the installed plugin resource", + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized (registry refused credentials)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Not Found (artifact not present in registry)" + }, + "409": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Conflict" + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Too Many Requests (registry rate limit)" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + }, + "502": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Gateway (upstream registry failure)" + }, + "504": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Gateway Timeout (upstream pull timed out)" + } + }, + "summary": "Install a plugin", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/build": { + "post": { + "description": "Build a plugin from a local directory", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object" + }, + { + "$ref": "#/components/schemas/pkg_api_v1.buildPluginRequest", + "summary": "request", + "description": "Build request" + } + ] + } + } + }, + "description": "Build request", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.BuildResult" + } + } + }, + "description": "OK" + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Build a plugin", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/builds": { + "get": { + "description": "Get a list of all locally-built OCI plugin artifacts in the local store", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.pluginBuildListResponse" + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "List locally-built plugin artifacts", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/builds/{tag}": { + "delete": { + "description": "Remove a locally-built OCI plugin artifact and its blobs from the local store", + "parameters": [ + { + "description": "Artifact tag", + "in": "path", + "name": "tag", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "No Content" + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Not Found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Delete a locally-built plugin artifact", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/content": { + "get": { + "description": "Retrieve the plugin.json body and file listing from an artifact\nwithout installing it. Accepts OCI refs, git refs, or local tags.", + "parameters": [ + { + "description": "OCI reference or local build tag", + "in": "query", + "name": "ref", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginContent" + } + } + }, + "description": "OK" + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized (registry refused credentials)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Not Found (artifact not present in registry)" + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Too Many Requests (registry rate limit)" + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal Server Error" + }, + "502": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Gateway (upstream registry or git resolver failure)" + }, + "504": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Gateway Timeout (upstream pull timed out)" + } + }, + "summary": "Get plugin content", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/push": { + "post": { + "description": "Push a built plugin artifact to a remote registry", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object" + }, + { + "$ref": "#/components/schemas/pkg_api_v1.pushPluginRequest", + "summary": "request", + "description": "Push request" + } + ] + } + } + }, + "description": "Push request", + "required": true + }, + "responses": { + "204": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "No Content" + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" } } }, - "description": "OK" - } - }, - "summary": "List all clients status", - "tags": ["discovery"] - } - }, - "/api/v1beta/groups": { - "get": { - "description": "Get a list of all groups", - "responses": { - "200": { + "description": "Bad Request" + }, + "404": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pkg_api_v1.groupListResponse" + "type": "string" } } }, - "description": "OK" + "description": "Not Found" }, "500": { "content": { @@ -4800,11 +5965,13 @@ "description": "Internal Server Error" } }, - "summary": "List all groups", - "tags": ["groups"] - }, + "summary": "Push a plugin", + "tags": ["plugins"] + } + }, + "/api/v1beta/plugins/validate": { "post": { - "description": "Create a new group with the specified name", + "description": "Validate a plugin definition", "requestBody": { "content": { "application/json": { @@ -4814,27 +5981,27 @@ "type": "object" }, { - "$ref": "#/components/schemas/pkg_api_v1.createGroupRequest", - "summary": "group", - "description": "Group creation request" + "$ref": "#/components/schemas/pkg_api_v1.validatePluginRequest", + "summary": "request", + "description": "Validate request" } ] } } }, - "description": "Group creation request", + "description": "Validate request", "required": true }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pkg_api_v1.createGroupResponse" + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.ValidationResult" } } }, - "description": "Created" + "description": "OK" }, "400": { "content": { @@ -4846,16 +6013,6 @@ }, "description": "Bad Request" }, - "409": { - "content": { - "application/json": { - "schema": { - "type": "string" - } - } - }, - "description": "Conflict" - }, "500": { "content": { "application/json": { @@ -4867,16 +6024,16 @@ "description": "Internal Server Error" } }, - "summary": "Create a new group", - "tags": ["groups"] + "summary": "Validate a plugin", + "tags": ["plugins"] } }, - "/api/v1beta/groups/{name}": { + "/api/v1beta/plugins/{name}": { "delete": { - "description": "Delete a group by name.", + "description": "Remove an installed plugin", "parameters": [ { - "description": "Group name", + "description": "Plugin name", "in": "path", "name": "name", "required": true, @@ -4885,11 +6042,20 @@ } }, { - "description": "Delete all workloads in the group (default: false, moves workloads to default group)", + "description": "Scope to uninstall from (user or project)", "in": "query", - "name": "with-workloads", + "name": "scope", "schema": { - "type": "boolean" + "enum": ["user", "project"], + "type": "string" + } + }, + { + "description": "Project root path for project-scoped plugins", + "in": "query", + "name": "project_root", + "schema": { + "type": "string" } } ], @@ -4904,6 +6070,16 @@ }, "description": "No Content" }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, "404": { "content": { "application/json": { @@ -4925,20 +6101,37 @@ "description": "Internal Server Error" } }, - "summary": "Delete a group", - "tags": ["groups"] + "summary": "Uninstall a plugin", + "tags": ["plugins"] }, "get": { - "description": "Get details of a specific group", + "description": "Get detailed information about a specific plugin", "parameters": [ { - "description": "Group name", + "description": "Plugin name", "in": "path", "name": "name", "required": true, "schema": { "type": "string" } + }, + { + "description": "Filter by scope (user or project)", + "in": "query", + "name": "scope", + "schema": { + "enum": ["user", "project"], + "type": "string" + } + }, + { + "description": "Project root path for project-scoped plugins", + "in": "query", + "name": "project_root", + "schema": { + "type": "string" + } } ], "responses": { @@ -4946,12 +6139,22 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_groups.Group" + "$ref": "#/components/schemas/github_com_stacklok_toolhive_pkg_plugins.PluginInfo" } } }, "description": "OK" }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Bad Request" + }, "404": { "content": { "application/json": { @@ -4973,8 +6176,8 @@ "description": "Internal Server Error" } }, - "summary": "Get group details", - "tags": ["groups"] + "summary": "Get plugin details", + "tags": ["plugins"] } }, "/api/v1beta/registry": { @@ -7777,6 +8980,158 @@ "tags": ["registry-servers"] } }, + "/registry/{registryName}/v0.1/x/dev.toolhive/plugins": { + "get": { + "description": "Get a paginated list of plugins from the registry. Supports optional full-text search and pagination.", + "parameters": [ + { + "description": "Registry name (currently ignored, uses the default provider)", + "in": "path", + "name": "registryName", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Search filter — matches against plugin name, namespace, and description", + "in": "query", + "name": "q", + "schema": { + "type": "string" + } + }, + { + "description": "Page number, 1-based (default: 1)", + "in": "query", + "name": "page", + "schema": { + "type": "integer" + } + }, + { + "description": "Items per page, max 200 (default: 50)", + "in": "query", + "name": "limit", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.pluginsV01Response" + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.registryErrorResponse" + } + } + }, + "description": "Internal server error" + }, + "503": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.registryErrorResponse" + } + } + }, + "description": "Registry authentication required or upstream registry unavailable" + } + }, + "summary": "List available registry plugins", + "tags": ["registry-plugins"] + } + }, + "/registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{pluginName}": { + "get": { + "description": "Retrieve a single plugin by its namespace and name from the registry.", + "parameters": [ + { + "description": "Registry name (currently ignored, uses the default provider)", + "in": "path", + "name": "registryName", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Plugin namespace in reverse-DNS format (e.g. io.github.stacklok)", + "in": "path", + "name": "namespace", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Plugin name", + "in": "path", + "name": "pluginName", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/registry.Plugin" + } + } + }, + "description": "OK" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.registryErrorResponse" + } + } + }, + "description": "Plugin not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.registryErrorResponse" + } + } + }, + "description": "Internal server error" + }, + "503": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pkg_api_v1.registryErrorResponse" + } + } + }, + "description": "Registry authentication required or upstream registry unavailable" + } + }, + "summary": "Get a registry plugin", + "tags": ["registry-plugins"] + } + }, "/registry/{registryName}/v0.1/x/dev.toolhive/skills": { "get": { "description": "Get a paginated list of skills from the registry. Supports optional full-text search and pagination.",