import { z } from 'zod'; // ── Site Context ── export const siteContextSchema = z.object({ businessName: z.string(), tagline: z.string().optional(), tone: z.string().default('professional and friendly'), style: z.string().optional(), promptContext: z.string().optional(), primaryColor: z.string().optional(), contactEmail: z.string().email().optional(), contactPhone: z.string().optional(), address: z.string().optional(), }); export type SiteContext = z.infer; // ── Section File (union of section types) ── const baseSectionFields = { id: z.string(), order: z.number().int().default(0), visible: z.boolean().default(true), image: z.string().optional(), }; export const heroSectionSchema = z.object({ ...baseSectionFields, type: z.literal('hero'), headline: z.string(), subheading: z.string().optional(), ctaText: z.string().optional(), ctaLink: z.string().optional(), }); export const aboutSectionSchema = z.object({ ...baseSectionFields, type: z.literal('about'), title: z.string().default('About Us'), content: z.string(), }); export const featureItemSchema = z.object({ title: z.string(), description: z.string(), icon: z.string().optional(), }); export const featuresSectionSchema = z.object({ ...baseSectionFields, type: z.literal('features'), title: z.string().default('What We Offer'), items: z.array(featureItemSchema).min(1), }); export const testimonialItemSchema = z.object({ quote: z.string(), author: z.string(), role: z.string().optional(), }); export const testimonialsSectionSchema = z.object({ ...baseSectionFields, type: z.literal('testimonials'), title: z.string().default('What Our Clients Say'), items: z.array(testimonialItemSchema).min(1), }); export const textSectionSchema = z.object({ ...baseSectionFields, type: z.literal('text'), heading: z.string().optional(), content: z.string(), }); export const sectionFileSchema = z.discriminatedUnion('type', [ heroSectionSchema, aboutSectionSchema, featuresSectionSchema, testimonialsSectionSchema, textSectionSchema, ]); export type SectionFile = z.infer; // ── Events ── export const eventItemSchema = z.object({ id: z.string(), title: z.string(), description: z.string().optional(), date: z.string(), time: z.string().optional(), location: z.string().optional(), }); export const eventsFileSchema = z.object({ events: z.array(eventItemSchema), }); export type EventsFile = z.infer; // ── SMS Sites Config ── export const smsSiteEntrySchema = z.object({ siteId: z.string(), phoneNumber: z.string(), allowedSenders: z.array(z.string()), repoRoot: z.string().optional(), }); export const smsSitesConfigSchema = z.object({ sites: z.array(smsSiteEntrySchema), }); export type SmsSitesConfig = z.infer; // ── Edit Request ── export const editRequestSchema = z.object({ message: z.string().min(1), repo_relative_path: z.string().optional(), proposal_id: z.string().optional(), confirm: z.enum(['yes', 'no']).optional(), }); export type EditRequest = z.infer; export const editJobPayloadSchema = z.discriminatedUnion('kind', [ z.object({ kind: z.literal('propose'), id: z.string(), message: z.string(), repo_relative_path: z.string().optional(), source: z.enum(['sms', 'http', 'editor']).default('http'), smsReplyMeta: z.object({ from: z.string(), to: z.string(), }).optional(), }), z.object({ kind: z.literal('apply'), id: z.string(), proposal_id: z.string(), source: z.enum(['sms', 'http', 'editor']).default('http'), smsReplyMeta: z.object({ from: z.string(), to: z.string(), }).optional(), }), ]); export type EditJobPayload = z.infer; // ── Classification output (first LLM call) ── export const classificationSchema = z.object({ intent: z.enum(['edit', 'info', 'help']), reason: z.string(), }); export type ClassificationOutput = z.infer; // ── Routing output (LLM structured output) ── export const routingOutputSchema = z.object({ repo_relative_path: z.string(), needs_clarification: z.boolean().default(false), reason: z.string(), clarification_message: z.string().optional(), }); export type RoutingOutput = z.infer;