From 051ce5e786532c44c51890313d00c7dec9d7bda2 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Wed, 27 May 2026 19:23:20 -0300 Subject: [PATCH] feat(agent-skills): add foundation types + Zod schemas --- src/lib/agentSkills/schemas.ts | 41 +++++++++++++++ src/lib/agentSkills/types.ts | 96 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/lib/agentSkills/schemas.ts create mode 100644 src/lib/agentSkills/types.ts diff --git a/src/lib/agentSkills/schemas.ts b/src/lib/agentSkills/schemas.ts new file mode 100644 index 0000000000..f6538a1f90 --- /dev/null +++ b/src/lib/agentSkills/schemas.ts @@ -0,0 +1,41 @@ +import { z } from "zod"; + +export const SkillCategorySchema = z.enum(["api", "cli"]); + +export const AgentSkillSchema = z.object({ + id: z.string().regex(/^[a-z][a-z0-9-]*$/), + name: z.string().min(1).max(100), + description: z.string().min(1).max(2000), + category: SkillCategorySchema, + area: z.string().min(1).max(50), + endpoints: z.array(z.string()).optional(), + cliCommands: z.array(z.string()).optional(), + icon: z.string().optional(), + isEntry: z.boolean().optional(), + isNew: z.boolean().optional(), + rawUrl: z.string().url(), + githubUrl: z.string().url(), +}); + +export const SkillCoverageSchema = z.object({ + api: z.object({ have: z.number().int().nonnegative(), total: z.literal(22) }), + cli: z.object({ have: z.number().int().nonnegative(), total: z.literal(20) }), + totalSkills: z.number().int().nonnegative(), + generatedAt: z.string().datetime(), +}); + +export const ListQuerySchema = z.object({ + category: SkillCategorySchema.optional(), + area: z.string().optional(), +}); + +export const GenerateBodySchema = z.object({ + dryRun: z.boolean().default(true), + prune: z.boolean().default(false), + onlyIds: z.array(z.string()).optional(), +}); + +export type AgentSkillT = z.infer; +export type SkillCoverageT = z.infer; +export type ListQueryT = z.infer; +export type GenerateBodyT = z.infer; diff --git a/src/lib/agentSkills/types.ts b/src/lib/agentSkills/types.ts new file mode 100644 index 0000000000..d187ff1566 --- /dev/null +++ b/src/lib/agentSkills/types.ts @@ -0,0 +1,96 @@ +export type SkillCategory = "api" | "cli"; + +export type SkillArea = + // API areas (22) + | "auth" + | "providers" + | "models" + | "combos-routing" + | "api-keys" + | "usage-logs" + | "budget" + | "settings" + | "proxies" + | "cache" + | "compression" + | "context-rtk" + | "resilience" + | "cli-tools" + | "tunnels" + | "sync-cloud" + | "db-backups" + | "webhooks" + | "mcp" + | "agents-a2a" + | "version-manager" + | "inference" + // CLI families (20) + | "cli-serve" + | "cli-health" + | "cli-providers" + | "cli-keys" + | "cli-models" + | "cli-chat" + | "cli-routing" + | "cli-resilience" + | "cli-compression" + | "cli-contexts" + | "cli-cost-usage" + | "cli-mcp" + | "cli-a2a" + | "cli-tunnel" + | "cli-backup-sync" + | "cli-policy-audit" + | "cli-batches" + | "cli-eval" + | "cli-plugins-skills" + | "cli-setup"; + +export interface AgentSkill { + id: string; // canonical id (e.g. "omni-providers", "cli-serve") + name: string; // human-readable + description: string; // 1-paragraph + category: SkillCategory; + area: SkillArea; + endpoints?: string[]; // e.g. ["POST /api/providers", "GET /api/providers/:id"] (api only) + cliCommands?: string[]; // e.g. ["providers list", "providers test", "providers rotate"] (cli only) + icon?: string; // Material symbol name + isEntry?: boolean; // "start here" tag + isNew?: boolean; // "new" tag + rawUrl: string; // GitHub raw URL of SKILL.md + githubUrl: string; // GitHub blob URL +} + +export interface SkillCoverage { + api: { have: number; total: 22 }; + cli: { have: number; total: 20 }; + totalSkills: number; // sum + generatedAt: string; // ISO datetime +} + +export interface SkillCatalogEntry extends AgentSkill { + // No additional fields; alias for AgentSkill at catalog-level. +} + +export interface SkillMarkdown { + id: string; + frontmatter: { name: string; description: string }; + body: string; // raw markdown after frontmatter + source: "filesystem" | "github" | "generated"; + fetchedAt: string; // ISO +} + +export interface GeneratorOptions { + dryRun: boolean; // default true + prune: boolean; // default false + outputDir?: string; // default "skills/" + onlyIds?: string[]; // regenerate only these +} + +export interface GeneratorReport { + generated: string[]; // ids that got new/updated SKILL.md + unchanged: string[]; // ids that already match + pruned: string[]; // ids whose folder was deleted (prune mode) + orphansDetected: string[]; // ids in repo that aren't in catalog (prune dry-run shows these) + errors: Array<{ id: string; error: string }>; +}