ponch-mcp-server 1.0.21 → 1.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brandBrief.d.ts","sourceRoot":"","sources":["../../../src/schemas/marketing/brandBrief.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,sBAAsB;;;;;;;;;gCAGnB,CAAC;AAEjB,eAAO,MAAM,wBAAwB;;;;;;;;;gCAGrB,CAAC;AAEjB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAKd,CAAC;AAEjB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;gCAOf,CAAC;AAEjB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;gCAIf,CAAC;AAEjB,eAAO,MAAM,cAAc;;;;;;;;;;;;gCAIX,CAAC;AAEjB,eAAO,MAAM,uBAAuB;;;;;;;;;gCAGpB,CAAC;AAEjB,eAAO,MAAM,eAAe;;;;;;;;;;;;gCAIZ,CAAC;AAMjB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA+Cb,CAAC;AAEjB,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM1D,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEN;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAiB7E;AAmBD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkE/B,CAAC"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * mcp-server/src/schemas/marketing/brandBrief.ts
3
+ *
4
+ * Schemas Zod del Brand Brief — perfil profundo del negocio.
5
+ *
6
+ * Vive en marketing_config.brands[brandId].brandBrief
7
+ * Generado por Cowork via save_brand_brief, validado en este schema.
8
+ *
9
+ * DEUDA 2 expandida (sesion 176B): brand brief completo migrado.
10
+ */
11
+ import { z } from 'zod';
12
+ // ═══════════════════════════════════════════════════════════
13
+ // PRIMITIVOS
14
+ // ═══════════════════════════════════════════════════════════
15
+ const SegmentoEnum = z.enum(['accesible', 'medio', 'premium', 'lujo']);
16
+ // ═══════════════════════════════════════════════════════════
17
+ // SUB-SCHEMAS REUTILIZABLES
18
+ // ═══════════════════════════════════════════════════════════
19
+ export const ProductoEstrellaSchema = z.object({
20
+ nombre: z.string().min(1),
21
+ porQue: z.string().optional(),
22
+ }).passthrough();
23
+ export const RangoPrecioBracketSchema = z.object({
24
+ min: z.number().nullable().optional(),
25
+ max: z.number().nullable().optional(),
26
+ }).passthrough();
27
+ export const RangoPrecioSchema = z.object({
28
+ entrada: RangoPrecioBracketSchema.optional(),
29
+ medio: RangoPrecioBracketSchema.optional(),
30
+ premium: RangoPrecioBracketSchema.optional(),
31
+ moneda: z.string().optional(),
32
+ }).passthrough();
33
+ export const BuyerPersonaSchema = z.object({
34
+ id: z.string().optional(),
35
+ nombre: z.string().min(1),
36
+ descripcion: z.string().optional(),
37
+ motivacion: z.string().optional(),
38
+ objeciones: z.array(z.string()).optional(),
39
+ canalDescubrimiento: z.array(z.string()).optional(),
40
+ }).passthrough();
41
+ export const ZonaServicioSchema = z.object({
42
+ entrega: z.string().optional(),
43
+ compradores: z.string().optional(),
44
+ tiendaFisica: z.string().optional(),
45
+ }).passthrough();
46
+ export const HorariosSchema = z.object({
47
+ lv: z.string().optional(),
48
+ sabado: z.string().optional(),
49
+ domingo: z.string().optional(),
50
+ }).passthrough();
51
+ export const CompetidorDirectoSchema = z.object({
52
+ dominio: z.string().min(1),
53
+ notas: z.string().nullable().optional(),
54
+ }).passthrough();
55
+ export const ObjetivosSchema = z.object({
56
+ corto: z.string().optional(),
57
+ mediano: z.string().optional(),
58
+ largo: z.string().optional(),
59
+ }).passthrough();
60
+ // ═══════════════════════════════════════════════════════════
61
+ // SCHEMA RAIZ DEL BRAND BRIEF
62
+ // ═══════════════════════════════════════════════════════════
63
+ export const BrandBriefSchema = z.object({
64
+ // Campos minimos obligatorios
65
+ descripcionCorta: z.string().min(1, 'descripcionCorta es obligatorio'),
66
+ segmento: SegmentoEnum,
67
+ // Identidad
68
+ categoriaIndustria: z.string().optional(),
69
+ propuestaDeValor: z.string().optional(),
70
+ // Productos y precios
71
+ productosEstrella: z.array(ProductoEstrellaSchema).optional(),
72
+ rangoPrecio: RangoPrecioSchema.optional(),
73
+ // Negativos
74
+ keywordsNegativas: z.array(z.string()).optional(),
75
+ noHacemos: z.array(z.string()).optional(),
76
+ // Audiencia
77
+ buyerPersonas: z.array(BuyerPersonaSchema).optional(),
78
+ // Zona y servicio
79
+ zonaServicio: ZonaServicioSchema.optional(),
80
+ horarios: HorariosSchema.optional(),
81
+ // Marca y tono
82
+ personalidadMarca: z.array(z.string()).optional(),
83
+ valores: z.array(z.string()).optional(),
84
+ tonoContenido: z.string().optional(),
85
+ mensajesClave: z.array(z.string()).optional(),
86
+ // Competencia
87
+ competidoresDirectos: z.array(CompetidorDirectoSchema).optional(),
88
+ competidoresIndirectos: z.array(z.string()).optional(),
89
+ queMejorHacen: z.string().optional(),
90
+ queEvitar: z.string().optional(),
91
+ // Objetivos
92
+ objetivos: ObjetivosSchema.optional(),
93
+ enfoque: z.string().optional(),
94
+ ocasionesEvergreen: z.array(z.string()).optional(),
95
+ // Meta (gestionado por save_brand_brief, no por Cowork directamente)
96
+ generadoAt: z.union([z.string(), z.date(), z.object({ seconds: z.number() }).passthrough()]).optional(),
97
+ generadoPor: z.string().optional(),
98
+ validadoPor: z.string().nullable().optional(),
99
+ validadoAt: z.union([z.string(), z.date(), z.object({ seconds: z.number() }).passthrough()]).nullable().optional(),
100
+ _validatedFields: z.record(z.boolean()).optional(),
101
+ }).passthrough();
102
+ /**
103
+ * Valida un brand brief completo. Si falla, retorna error estructurado
104
+ * con los 4 campos para que Cowork pueda auto-corregir.
105
+ */
106
+ export function validateBrandBrief(value) {
107
+ const result = BrandBriefSchema.safeParse(value);
108
+ if (result.success) {
109
+ return { ok: true, parsed: result.data };
110
+ }
111
+ const firstError = result.error.errors[0];
112
+ const path = ['brandBrief', ...firstError.path].join('.');
113
+ const received = getValueAtPath(value, firstError.path);
114
+ return {
115
+ ok: false,
116
+ error: firstError.message,
117
+ path,
118
+ received,
119
+ example: BRAND_BRIEF_EXAMPLE,
120
+ };
121
+ }
122
+ function getValueAtPath(obj, path) {
123
+ let current = obj;
124
+ for (const key of path) {
125
+ if (current == null)
126
+ return current;
127
+ if (typeof current === 'object') {
128
+ current = current[key];
129
+ }
130
+ else {
131
+ return undefined;
132
+ }
133
+ }
134
+ return current;
135
+ }
136
+ // ═══════════════════════════════════════════════════════════
137
+ // EJEMPLO HUMAN-READABLE (para system prompt y errores)
138
+ // ═══════════════════════════════════════════════════════════
139
+ export const BRAND_BRIEF_EXAMPLE = {
140
+ descripcionCorta: 'Florería premium en CDMX con entrega el mismo día',
141
+ categoriaIndustria: 'Florería / Regalos premium',
142
+ segmento: 'premium',
143
+ propuestaDeValor: 'Diseño floral curado por colecciones + entrega same-day + presentación que impacta',
144
+ productosEstrella: [
145
+ { nombre: 'Ramillete 50 rosas', porQue: 'Bestseller, alto ticket' },
146
+ { nombre: 'Domos', porQue: 'Piezas statement de lujo' },
147
+ ],
148
+ rangoPrecio: {
149
+ entrada: { min: 600, max: 1200 },
150
+ medio: { min: 1500, max: 3500 },
151
+ premium: { min: 4000, max: 12000 },
152
+ moneda: 'MXN',
153
+ },
154
+ keywordsNegativas: ['coronas fúnebres', 'flores artificiales', 'mayoreo', 'peonías'],
155
+ noHacemos: ['Envíos fuera de CDMX', 'Venta mayorista'],
156
+ buyerPersonas: [
157
+ {
158
+ id: 'comprador-individual',
159
+ nombre: 'Comprador Individual',
160
+ descripcion: 'H/M 25-55, NSE medio-alto/alto, CDMX o internacional',
161
+ motivacion: 'Expresar emociones con diseños que impacten',
162
+ objeciones: ['¿Llegará como en la foto?', '¿Llega hoy?'],
163
+ canalDescubrimiento: ['Google Search', 'Instagram', 'Referidos'],
164
+ },
165
+ ],
166
+ zonaServicio: {
167
+ entrega: 'CDMX',
168
+ compradores: 'CDMX, México, Internacional',
169
+ tiendaFisica: 'Roma Sur, CDMX',
170
+ },
171
+ horarios: {
172
+ lv: '8:00am - 9:00pm',
173
+ sabado: '8:00am - 8:00pm',
174
+ domingo: 'Cerrado',
175
+ },
176
+ personalidadMarca: ['Sofisticada', 'Confiable', 'Editorial'],
177
+ valores: ['Calidad', 'Puntualidad', 'Diseño'],
178
+ tonoContenido: 'Profesional y cercano, nunca casual. Editorial pero cálido.',
179
+ mensajesClave: [
180
+ 'Entrega el mismo día',
181
+ 'Diseños impactantes',
182
+ 'Envío gratis desde $700',
183
+ 'Más de una década de experiencia',
184
+ ],
185
+ competidoresDirectos: [
186
+ { dominio: 'azapflores.com', notas: 'Constancia, UGC' },
187
+ { dominio: 'guapaconflores.com', notas: null },
188
+ ],
189
+ competidoresIndirectos: ['Floristerías físicas locales'],
190
+ queMejorHacen: 'Constancia, disponibilidad en temporadas, UGC',
191
+ queEvitar: 'Sobre-promoción, stock genérico, feeds desordenados',
192
+ objetivos: {
193
+ corto: 'Pipeline de UGC + primeros backlinks editoriales',
194
+ mediano: 'Autoridad SEO + frente B2B + menciones en medios CDMX',
195
+ largo: 'Top-of-mind florería premium CDMX, local e internacional',
196
+ },
197
+ enfoque: 'Florería de ocasión todo el año — NO centrar en San Valentín/Día de las Madres',
198
+ ocasionesEvergreen: [
199
+ 'Cumpleaños',
200
+ 'Aniversarios',
201
+ 'Agradecimiento',
202
+ 'Corporativo',
203
+ 'Sorpresas',
204
+ ],
205
+ };
206
+ //# sourceMappingURL=brandBrief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brandBrief.js","sourceRoot":"","sources":["../../../src/schemas/marketing/brandBrief.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * mcp-server/src/schemas/marketing/collectionSuggestions.ts
3
+ *
4
+ * Schemas Zod para sugerencias SEO de colecciones de Shopify.
5
+ *
6
+ * Vive en marketing_config.brands[brandId].collectionSuggestions.{collectionId}
7
+ * Generado por Cowork via save_collection_suggestions.
8
+ *
9
+ * DEUDA 2 expandida (sesion 176B): collection suggestions migradas con
10
+ * reglas de negocio (max chars de meta title/description, etc).
11
+ */
12
+ import { z } from 'zod';
13
+ /**
14
+ * Una sola sugerencia de colección. Strict en max lengths
15
+ * (Google las trunca y la UI los marca como overflow).
16
+ *
17
+ * SEO best practices 2026:
18
+ * - meta title 50-60 chars (max 600px width)
19
+ * - meta description 120-158 chars (mobile 120, desktop 158)
20
+ * - image alt < 125 chars (Google Images limit)
21
+ */
22
+ export declare const CollectionSuggestionInputSchema: z.ZodObject<{
23
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
24
+ suggestedTitle: z.ZodOptional<z.ZodString>;
25
+ suggestedDescription: z.ZodOptional<z.ZodString>;
26
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
27
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
28
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
30
+ keyword: z.ZodOptional<z.ZodString>;
31
+ notas: z.ZodOptional<z.ZodString>;
32
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
33
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
34
+ suggestedTitle: z.ZodOptional<z.ZodString>;
35
+ suggestedDescription: z.ZodOptional<z.ZodString>;
36
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
37
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
38
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
39
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
40
+ keyword: z.ZodOptional<z.ZodString>;
41
+ notas: z.ZodOptional<z.ZodString>;
42
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
43
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
44
+ suggestedTitle: z.ZodOptional<z.ZodString>;
45
+ suggestedDescription: z.ZodOptional<z.ZodString>;
46
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
47
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
48
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
49
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
50
+ keyword: z.ZodOptional<z.ZodString>;
51
+ notas: z.ZodOptional<z.ZodString>;
52
+ }, z.ZodTypeAny, "passthrough">>;
53
+ export type CollectionSuggestionInput = z.infer<typeof CollectionSuggestionInputSchema>;
54
+ /**
55
+ * Array de sugerencias (lo que viene en el parametro `suggestions`).
56
+ */
57
+ export declare const CollectionSuggestionsInputArraySchema: z.ZodArray<z.ZodObject<{
58
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
59
+ suggestedTitle: z.ZodOptional<z.ZodString>;
60
+ suggestedDescription: z.ZodOptional<z.ZodString>;
61
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
62
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
63
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
64
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
65
+ keyword: z.ZodOptional<z.ZodString>;
66
+ notas: z.ZodOptional<z.ZodString>;
67
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
68
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
69
+ suggestedTitle: z.ZodOptional<z.ZodString>;
70
+ suggestedDescription: z.ZodOptional<z.ZodString>;
71
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
72
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
73
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
74
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
75
+ keyword: z.ZodOptional<z.ZodString>;
76
+ notas: z.ZodOptional<z.ZodString>;
77
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
78
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
79
+ suggestedTitle: z.ZodOptional<z.ZodString>;
80
+ suggestedDescription: z.ZodOptional<z.ZodString>;
81
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
82
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
83
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
84
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
85
+ keyword: z.ZodOptional<z.ZodString>;
86
+ notas: z.ZodOptional<z.ZodString>;
87
+ }, z.ZodTypeAny, "passthrough">>, "many">;
88
+ export type CollectionSuggestionsInputArray = z.infer<typeof CollectionSuggestionsInputArraySchema>;
89
+ /**
90
+ * Una sugerencia tal como queda guardada en Firestore.
91
+ * Tiene campos extra que el tool agrega: estado, generadoAt, generadoPor, appliedFields.
92
+ * Útil si en el futuro queremos validar lecturas del doc.
93
+ */
94
+ export declare const CollectionSuggestionStoredSchema: z.ZodObject<{
95
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
96
+ suggestedTitle: z.ZodOptional<z.ZodString>;
97
+ suggestedDescription: z.ZodOptional<z.ZodString>;
98
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
99
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
100
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
101
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
102
+ keyword: z.ZodOptional<z.ZodString>;
103
+ notas: z.ZodOptional<z.ZodString>;
104
+ } & {
105
+ estado: z.ZodEnum<["pendiente", "rechazado", "aplicado_parcial", "aplicado_total"]>;
106
+ generadoAt: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
107
+ seconds: z.ZodNumber;
108
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
109
+ seconds: z.ZodNumber;
110
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
111
+ seconds: z.ZodNumber;
112
+ }, z.ZodTypeAny, "passthrough">>]>>;
113
+ generadoPor: z.ZodOptional<z.ZodString>;
114
+ appliedFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
115
+ before: z.ZodUnknown;
116
+ after: z.ZodUnknown;
117
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
118
+ seconds: z.ZodNumber;
119
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
120
+ seconds: z.ZodNumber;
121
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
122
+ seconds: z.ZodNumber;
123
+ }, z.ZodTypeAny, "passthrough">>]>;
124
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
125
+ before: z.ZodUnknown;
126
+ after: z.ZodUnknown;
127
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
128
+ seconds: z.ZodNumber;
129
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
130
+ seconds: z.ZodNumber;
131
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
132
+ seconds: z.ZodNumber;
133
+ }, z.ZodTypeAny, "passthrough">>]>;
134
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
135
+ before: z.ZodUnknown;
136
+ after: z.ZodUnknown;
137
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
138
+ seconds: z.ZodNumber;
139
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
140
+ seconds: z.ZodNumber;
141
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
142
+ seconds: z.ZodNumber;
143
+ }, z.ZodTypeAny, "passthrough">>]>;
144
+ }, z.ZodTypeAny, "passthrough">>>>;
145
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
146
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
147
+ suggestedTitle: z.ZodOptional<z.ZodString>;
148
+ suggestedDescription: z.ZodOptional<z.ZodString>;
149
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
150
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
151
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
152
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
153
+ keyword: z.ZodOptional<z.ZodString>;
154
+ notas: z.ZodOptional<z.ZodString>;
155
+ } & {
156
+ estado: z.ZodEnum<["pendiente", "rechazado", "aplicado_parcial", "aplicado_total"]>;
157
+ generadoAt: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
158
+ seconds: z.ZodNumber;
159
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
160
+ seconds: z.ZodNumber;
161
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
162
+ seconds: z.ZodNumber;
163
+ }, z.ZodTypeAny, "passthrough">>]>>;
164
+ generadoPor: z.ZodOptional<z.ZodString>;
165
+ appliedFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
166
+ before: z.ZodUnknown;
167
+ after: z.ZodUnknown;
168
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
169
+ seconds: z.ZodNumber;
170
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
171
+ seconds: z.ZodNumber;
172
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
173
+ seconds: z.ZodNumber;
174
+ }, z.ZodTypeAny, "passthrough">>]>;
175
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
176
+ before: z.ZodUnknown;
177
+ after: z.ZodUnknown;
178
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
179
+ seconds: z.ZodNumber;
180
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
181
+ seconds: z.ZodNumber;
182
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
183
+ seconds: z.ZodNumber;
184
+ }, z.ZodTypeAny, "passthrough">>]>;
185
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
186
+ before: z.ZodUnknown;
187
+ after: z.ZodUnknown;
188
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
189
+ seconds: z.ZodNumber;
190
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
191
+ seconds: z.ZodNumber;
192
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
193
+ seconds: z.ZodNumber;
194
+ }, z.ZodTypeAny, "passthrough">>]>;
195
+ }, z.ZodTypeAny, "passthrough">>>>;
196
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
197
+ collectionId: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
198
+ suggestedTitle: z.ZodOptional<z.ZodString>;
199
+ suggestedDescription: z.ZodOptional<z.ZodString>;
200
+ suggestedMetaTitle: z.ZodOptional<z.ZodString>;
201
+ suggestedMetaDescription: z.ZodOptional<z.ZodString>;
202
+ suggestedHandle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
203
+ suggestedImageAlt: z.ZodOptional<z.ZodString>;
204
+ keyword: z.ZodOptional<z.ZodString>;
205
+ notas: z.ZodOptional<z.ZodString>;
206
+ } & {
207
+ estado: z.ZodEnum<["pendiente", "rechazado", "aplicado_parcial", "aplicado_total"]>;
208
+ generadoAt: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
209
+ seconds: z.ZodNumber;
210
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
211
+ seconds: z.ZodNumber;
212
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
213
+ seconds: z.ZodNumber;
214
+ }, z.ZodTypeAny, "passthrough">>]>>;
215
+ generadoPor: z.ZodOptional<z.ZodString>;
216
+ appliedFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
217
+ before: z.ZodUnknown;
218
+ after: z.ZodUnknown;
219
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
220
+ seconds: z.ZodNumber;
221
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
222
+ seconds: z.ZodNumber;
223
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
224
+ seconds: z.ZodNumber;
225
+ }, z.ZodTypeAny, "passthrough">>]>;
226
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
227
+ before: z.ZodUnknown;
228
+ after: z.ZodUnknown;
229
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
230
+ seconds: z.ZodNumber;
231
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
232
+ seconds: z.ZodNumber;
233
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
234
+ seconds: z.ZodNumber;
235
+ }, z.ZodTypeAny, "passthrough">>]>;
236
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
237
+ before: z.ZodUnknown;
238
+ after: z.ZodUnknown;
239
+ appliedAt: z.ZodUnion<[z.ZodString, z.ZodDate, z.ZodObject<{
240
+ seconds: z.ZodNumber;
241
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
242
+ seconds: z.ZodNumber;
243
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
244
+ seconds: z.ZodNumber;
245
+ }, z.ZodTypeAny, "passthrough">>]>;
246
+ }, z.ZodTypeAny, "passthrough">>>>;
247
+ }, z.ZodTypeAny, "passthrough">>;
248
+ export type CollectionSuggestionStored = z.infer<typeof CollectionSuggestionStoredSchema>;
249
+ export type CollectionSuggestionsValidationResult = {
250
+ ok: true;
251
+ parsed: CollectionSuggestionsInputArray;
252
+ } | {
253
+ ok: false;
254
+ error: string;
255
+ path: string;
256
+ received: unknown;
257
+ example: unknown;
258
+ };
259
+ /**
260
+ * Valida un array de collection suggestions con reglas de negocio.
261
+ */
262
+ export declare function validateCollectionSuggestions(value: unknown): CollectionSuggestionsValidationResult;
263
+ export declare const COLLECTION_SUGGESTION_EXAMPLE: {
264
+ collectionId: number;
265
+ suggestedTitle: string;
266
+ suggestedDescription: string;
267
+ suggestedMetaTitle: string;
268
+ suggestedMetaDescription: string;
269
+ suggestedHandle: null;
270
+ suggestedImageAlt: string;
271
+ keyword: string;
272
+ notas: string;
273
+ }[];
274
+ //# sourceMappingURL=collectionSuggestions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionSuggestions.d.ts","sourceRoot":"","sources":["../../../src/schemas/marketing/collectionSuggestions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA4B5B,CAAC;AAEjB,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF;;GAEG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAAuF,CAAC;AAC1I,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AAMpG;;;;GAIG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAiB7B,CAAC;AACjB,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAM1F,MAAM,MAAM,qCAAqC,GAC7C;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,+BAA+B,CAAA;CAAE,GACrD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEN;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,GACb,qCAAqC,CAiBvC;AAmBD,eAAO,MAAM,6BAA6B;;;;;;;;;;GAYzC,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * mcp-server/src/schemas/marketing/collectionSuggestions.ts
3
+ *
4
+ * Schemas Zod para sugerencias SEO de colecciones de Shopify.
5
+ *
6
+ * Vive en marketing_config.brands[brandId].collectionSuggestions.{collectionId}
7
+ * Generado por Cowork via save_collection_suggestions.
8
+ *
9
+ * DEUDA 2 expandida (sesion 176B): collection suggestions migradas con
10
+ * reglas de negocio (max chars de meta title/description, etc).
11
+ */
12
+ import { z } from 'zod';
13
+ // ═══════════════════════════════════════════════════════════
14
+ // SCHEMA INPUT (lo que Cowork manda a save_collection_suggestions)
15
+ // ═══════════════════════════════════════════════════════════
16
+ /**
17
+ * Una sola sugerencia de colección. Strict en max lengths
18
+ * (Google las trunca y la UI los marca como overflow).
19
+ *
20
+ * SEO best practices 2026:
21
+ * - meta title 50-60 chars (max 600px width)
22
+ * - meta description 120-158 chars (mobile 120, desktop 158)
23
+ * - image alt < 125 chars (Google Images limit)
24
+ */
25
+ export const CollectionSuggestionInputSchema = z.object({
26
+ collectionId: z.union([z.string(), z.number()], {
27
+ errorMap: () => ({ message: 'collectionId debe ser string o number (ID de Shopify, no GID)' }),
28
+ }),
29
+ suggestedTitle: z.string().min(1).max(120).optional()
30
+ .describe('H1 de la página. Keyword al inicio.'),
31
+ suggestedDescription: z.string().min(1).optional()
32
+ .describe('HTML 200-400 palabras. Incluir links internos.'),
33
+ suggestedMetaTitle: z.string().min(1).max(60, 'meta title NO debe exceder 60 chars (Google trunca)').optional()
34
+ .describe('50-60 chars. Keyword al inicio. Formato: {Keyword} | {Brand}'),
35
+ suggestedMetaDescription: z.string().min(1).max(158, 'meta description NO debe exceder 158 chars (Google trunca)').optional()
36
+ .describe('120-158 chars. Keyword + CTA + value prop'),
37
+ suggestedHandle: z.string().nullable().optional()
38
+ .describe('Solo cambiar si el handle actual es malo. null = no cambiar (preserva URL indexado)'),
39
+ suggestedImageAlt: z.string().min(1).max(125, 'image alt NO debe exceder 125 chars (Google Images)').optional()
40
+ .describe('Descriptivo con keyword. Accesibilidad + Google Images + AEO'),
41
+ keyword: z.string().min(1).optional()
42
+ .describe('Keyword target de esta colección (del plan de marketing)'),
43
+ notas: z.string().optional()
44
+ .describe('Explicación breve de qué cambiaste y por qué'),
45
+ }).passthrough();
46
+ /**
47
+ * Array de sugerencias (lo que viene en el parametro `suggestions`).
48
+ */
49
+ export const CollectionSuggestionsInputArraySchema = z.array(CollectionSuggestionInputSchema).min(1, 'Debe enviar al menos 1 sugerencia');
50
+ // ═══════════════════════════════════════════════════════════
51
+ // SCHEMA STORED (como queda en Firestore con meta agregada)
52
+ // ═══════════════════════════════════════════════════════════
53
+ /**
54
+ * Una sugerencia tal como queda guardada en Firestore.
55
+ * Tiene campos extra que el tool agrega: estado, generadoAt, generadoPor, appliedFields.
56
+ * Útil si en el futuro queremos validar lecturas del doc.
57
+ */
58
+ export const CollectionSuggestionStoredSchema = CollectionSuggestionInputSchema.extend({
59
+ estado: z.enum(['pendiente', 'rechazado', 'aplicado_parcial', 'aplicado_total']),
60
+ generadoAt: z.union([
61
+ z.string(),
62
+ z.date(),
63
+ z.object({ seconds: z.number() }).passthrough(),
64
+ ]).optional(),
65
+ generadoPor: z.string().optional(),
66
+ appliedFields: z.record(z.object({
67
+ before: z.unknown(),
68
+ after: z.unknown(),
69
+ appliedAt: z.union([
70
+ z.string(),
71
+ z.date(),
72
+ z.object({ seconds: z.number() }).passthrough(),
73
+ ]),
74
+ }).passthrough()).optional(),
75
+ }).passthrough();
76
+ /**
77
+ * Valida un array de collection suggestions con reglas de negocio.
78
+ */
79
+ export function validateCollectionSuggestions(value) {
80
+ const result = CollectionSuggestionsInputArraySchema.safeParse(value);
81
+ if (result.success) {
82
+ return { ok: true, parsed: result.data };
83
+ }
84
+ const firstError = result.error.errors[0];
85
+ const path = ['suggestions', ...firstError.path].join('.');
86
+ const received = getValueAtPath(value, firstError.path);
87
+ return {
88
+ ok: false,
89
+ error: firstError.message,
90
+ path,
91
+ received,
92
+ example: COLLECTION_SUGGESTION_EXAMPLE,
93
+ };
94
+ }
95
+ function getValueAtPath(obj, path) {
96
+ let current = obj;
97
+ for (const key of path) {
98
+ if (current == null)
99
+ return current;
100
+ if (typeof current === 'object') {
101
+ current = current[key];
102
+ }
103
+ else {
104
+ return undefined;
105
+ }
106
+ }
107
+ return current;
108
+ }
109
+ // ═══════════════════════════════════════════════════════════
110
+ // EJEMPLO HUMAN-READABLE
111
+ // ═══════════════════════════════════════════════════════════
112
+ export const COLLECTION_SUGGESTION_EXAMPLE = [
113
+ {
114
+ collectionId: 471581688126,
115
+ suggestedTitle: 'Flores Moradas | Envío CDMX',
116
+ suggestedDescription: '<p>Descubre nuestra colección de flores moradas con rosas, tulipanes y lirios...</p>',
117
+ suggestedMetaTitle: 'Flores Moradas CDMX | Envío Mismo Día',
118
+ suggestedMetaDescription: 'Envía flores moradas a domicilio en CDMX. Arreglos frescos con rosas, tulipanes y lirios. Entrega el mismo día.',
119
+ suggestedHandle: null,
120
+ suggestedImageAlt: 'Ramo de flores moradas con rosas y tulipanes - Ponch florería CDMX',
121
+ keyword: 'flores moradas cdmx',
122
+ notas: 'Meta title con keyword local. Description con long-tail. Handle preservado.',
123
+ },
124
+ ];
125
+ //# sourceMappingURL=collectionSuggestions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionSuggestions.js","sourceRoot":"","sources":["../../../src/schemas/marketing/collectionSuggestions.ts"],"names":[],"mappings":"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"}