diff --git a/packages/shared/src/types/company-portability.ts b/packages/shared/src/types/company-portability.ts index 982a3f25564..28a6da75e8a 100644 --- a/packages/shared/src/types/company-portability.ts +++ b/packages/shared/src/types/company-portability.ts @@ -138,8 +138,8 @@ export interface CompanyPortabilityAgentManifestEntry { icon: string | null; capabilities: string | null; reportsToSlug: string | null; - reportsToExistingAgentId: string | null; - reportsToExistingAgentSlug: string | null; + reportsToExistingAgentId?: string | null; + reportsToExistingAgentSlug?: string | null; adapterType: string; adapterConfig: Record; runtimeConfig: Record; diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index f048a1cdf19..db0b68f2439 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -89,6 +89,7 @@ export type { CatalogTeamSourceRef, CatalogTeamFile, CatalogTeam, + CatalogManifest, CatalogTeamListQuery, CatalogTeamFileDetail, CatalogTeamSourcePolicy, diff --git a/packages/shared/src/types/teams-catalog.ts b/packages/shared/src/types/teams-catalog.ts index 76f662ae337..a088b07eb0b 100644 --- a/packages/shared/src/types/teams-catalog.ts +++ b/packages/shared/src/types/teams-catalog.ts @@ -110,6 +110,14 @@ export interface CatalogTeam { packageVersion?: string; } +export interface CatalogManifest { + schemaVersion: 1; + packageName: "@paperclipai/teams-catalog"; + packageVersion: string; + generatedAt: string; + teams: CatalogTeam[]; +} + export interface CatalogTeamListQuery { kind?: CatalogTeamKind; category?: string; diff --git a/server/src/__tests__/openapi-routes.test.ts b/server/src/__tests__/openapi-routes.test.ts index 4c4e8efb023..36d0bafbb3d 100644 --- a/server/src/__tests__/openapi-routes.test.ts +++ b/server/src/__tests__/openapi-routes.test.ts @@ -42,6 +42,7 @@ const apiPrefixes: Record = { "secrets.ts": "/api", "sidebar-badges.ts": "/api", "sidebar-preferences.ts": "/api", + "teams-catalog.ts": "/api", "user-profiles.ts": "/api", }; diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index e0aab890c3b..d7860ceaf21 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -124,6 +124,10 @@ import { secretProviderConfigDiscoveryPreviewSchema, remoteSecretImportPreviewSchema, remoteSecretImportSchema, + // Team catalog + catalogTeamInstallSchema, + catalogTeamListQuerySchema, + catalogTeamPreviewSchema, } from "@paperclipai/shared"; type JsonSchema = Record; @@ -871,6 +875,79 @@ registry.registerPath({ responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized }, }); +// ─── Team Catalog ──────────────────────────────────────────────────────────── + +registry.registerPath({ + method: "get", + path: "/api/teams/catalog", + tags: ["team-catalog"], + summary: "List catalog teams", + request: { query: catalogTeamListQuerySchema }, + responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized }, +}); + +registry.registerPath({ + method: "get", + path: "/api/teams/catalog/{catalogId}/files", + tags: ["team-catalog"], + summary: "Read a catalog team file", + request: { + params: z.object({ catalogId: z.string() }), + query: z.object({ + ref: z.string().optional(), + path: z.string().optional(), + }), + }, + responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registry.registerPath({ + method: "get", + path: "/api/teams/catalog/{catalogId}", + tags: ["team-catalog"], + summary: "Get a catalog team", + request: { + params: z.object({ catalogId: z.string() }), + query: z.object({ ref: z.string().optional() }), + }, + responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized, 404: r.notFound }, +}); + +registry.registerPath({ + method: "get", + path: "/api/companies/{companyId}/teams/catalog/installed", + tags: ["team-catalog"], + summary: "List installed catalog teams for a company", + request: { params: z.object({ companyId: z.string() }) }, + responses: { 200: r.ok(), 401: r.unauthorized, 403: r.forbidden }, +}); + +registry.registerPath({ + method: "post", + path: "/api/companies/{companyId}/teams/catalog/{catalogId}/preview", + tags: ["team-catalog"], + summary: "Preview catalog team installation", + request: { + params: z.object({ companyId: z.string(), catalogId: z.string() }), + query: z.object({ ref: z.string().optional() }), + body: jsonBody(catalogTeamPreviewSchema), + }, + responses: { 200: r.ok(), 400: r.badRequest, 401: r.unauthorized, 403: r.forbidden, 404: r.notFound }, +}); + +registry.registerPath({ + method: "post", + path: "/api/companies/{companyId}/teams/catalog/{catalogId}/install", + tags: ["team-catalog"], + summary: "Install a catalog team", + request: { + params: z.object({ companyId: z.string(), catalogId: z.string() }), + query: z.object({ ref: z.string().optional() }), + body: jsonBody(catalogTeamInstallSchema), + }, + responses: { 201: r.ok(), 400: r.badRequest, 401: r.unauthorized, 403: r.forbidden, 404: r.notFound }, +}); + // ─── Agents ────────────────────────────────────────────────────────────────── registry.registerPath({