elsabro 2.3.0 → 3.7.0

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.
Files changed (67) hide show
  1. package/README.md +668 -20
  2. package/bin/install.js +0 -0
  3. package/flows/development-flow.json +452 -0
  4. package/flows/quick-flow.json +118 -0
  5. package/package.json +3 -2
  6. package/references/SYSTEM_INDEX.md +379 -5
  7. package/references/agent-marketplace.md +2274 -0
  8. package/references/agent-protocol.md +1126 -0
  9. package/references/ai-code-suggestions.md +2413 -0
  10. package/references/checkpointing.md +595 -0
  11. package/references/collaboration-patterns.md +851 -0
  12. package/references/collaborative-sessions.md +1081 -0
  13. package/references/configuration-management.md +1810 -0
  14. package/references/cost-tracking.md +1095 -0
  15. package/references/enterprise-sso.md +2001 -0
  16. package/references/error-contracts-v2.md +968 -0
  17. package/references/event-driven.md +1031 -0
  18. package/references/flow-orchestration.md +940 -0
  19. package/references/flow-visualization.md +1557 -0
  20. package/references/ide-integrations.md +3513 -0
  21. package/references/interrupt-system.md +681 -0
  22. package/references/kubernetes-deployment.md +3099 -0
  23. package/references/memory-system.md +683 -0
  24. package/references/mobile-companion.md +3236 -0
  25. package/references/multi-llm-providers.md +2494 -0
  26. package/references/multi-project-memory.md +1182 -0
  27. package/references/observability.md +793 -0
  28. package/references/output-schemas.md +858 -0
  29. package/references/performance-profiler.md +955 -0
  30. package/references/plugin-system.md +1526 -0
  31. package/references/prompt-management.md +292 -0
  32. package/references/sandbox-execution.md +303 -0
  33. package/references/security-system.md +1253 -0
  34. package/references/streaming.md +696 -0
  35. package/references/testing-framework.md +1151 -0
  36. package/references/time-travel.md +802 -0
  37. package/references/tool-registry.md +886 -0
  38. package/references/voice-commands.md +3296 -0
  39. package/templates/agent-marketplace-config.json +220 -0
  40. package/templates/agent-protocol-config.json +136 -0
  41. package/templates/ai-suggestions-config.json +100 -0
  42. package/templates/checkpoint-state.json +61 -0
  43. package/templates/collaboration-config.json +157 -0
  44. package/templates/collaborative-sessions-config.json +153 -0
  45. package/templates/configuration-config.json +245 -0
  46. package/templates/cost-tracking-config.json +148 -0
  47. package/templates/enterprise-sso-config.json +438 -0
  48. package/templates/events-config.json +148 -0
  49. package/templates/flow-visualization-config.json +196 -0
  50. package/templates/ide-integrations-config.json +442 -0
  51. package/templates/kubernetes-config.json +764 -0
  52. package/templates/memory-state.json +84 -0
  53. package/templates/mobile-companion-config.json +600 -0
  54. package/templates/multi-llm-config.json +544 -0
  55. package/templates/multi-project-memory-config.json +145 -0
  56. package/templates/observability-config.json +109 -0
  57. package/templates/performance-profiler-config.json +125 -0
  58. package/templates/plugin-config.json +170 -0
  59. package/templates/prompt-management-config.json +86 -0
  60. package/templates/sandbox-config.json +185 -0
  61. package/templates/schemas-config.json +65 -0
  62. package/templates/security-config.json +120 -0
  63. package/templates/streaming-config.json +72 -0
  64. package/templates/testing-config.json +81 -0
  65. package/templates/timetravel-config.json +62 -0
  66. package/templates/tool-registry-config.json +109 -0
  67. package/templates/voice-commands-config.json +658 -0
@@ -0,0 +1,858 @@
1
+ ---
2
+ name: output-schemas
3
+ description: Sistema de validación de outputs con schemas JSON/Zod
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # ELSABRO Output Schemas System
8
+
9
+ ## Vision General
10
+
11
+ El sistema de Output Schemas garantiza que los outputs de agentes cumplan con estructuras definidas, proporcionando type-safety y comunicación predecible entre componentes.
12
+
13
+ ```
14
+ ┌──────────────────────────────────────────────────────────────────────────┐
15
+ │ OUTPUT VALIDATION FLOW │
16
+ ├──────────────────────────────────────────────────────────────────────────┤
17
+ │ │
18
+ │ AGENT OUTPUT │
19
+ │ │ │
20
+ │ ▼ │
21
+ │ ┌──────────────┐ │
22
+ │ │ PARSE │ ──── Extract structured data from response │
23
+ │ └──────┬───────┘ │
24
+ │ │ │
25
+ │ ▼ │
26
+ │ ┌──────────────┐ INVALID ┌──────────────┐ │
27
+ │ │ VALIDATE │ ─────────────► │ RETRY │ │
28
+ │ │ (vs Schema) │ │ (with hints) │ │
29
+ │ └──────┬───────┘ └──────────────┘ │
30
+ │ │ VALID │
31
+ │ ▼ │
32
+ │ ┌──────────────┐ │
33
+ │ │ TRANSFORM │ ──── Apply defaults, coerce types │
34
+ │ └──────┬───────┘ │
35
+ │ │ │
36
+ │ ▼ │
37
+ │ TYPED OUTPUT │
38
+ │ │
39
+ └──────────────────────────────────────────────────────────────────────────┘
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Definición de Schemas
45
+
46
+ ### JSON Schema Format
47
+
48
+ ```json
49
+ {
50
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
51
+ "$id": "elsabro://schemas/analysis-result",
52
+ "title": "AnalysisResult",
53
+ "description": "Output schema for analysis agent",
54
+ "type": "object",
55
+ "required": ["summary", "files", "recommendations"],
56
+ "properties": {
57
+ "summary": {
58
+ "type": "string",
59
+ "description": "Brief summary of the analysis",
60
+ "minLength": 10,
61
+ "maxLength": 500
62
+ },
63
+ "files": {
64
+ "type": "array",
65
+ "description": "Files analyzed",
66
+ "items": {
67
+ "type": "object",
68
+ "required": ["path", "purpose"],
69
+ "properties": {
70
+ "path": { "type": "string" },
71
+ "purpose": { "type": "string" },
72
+ "complexity": {
73
+ "type": "string",
74
+ "enum": ["low", "medium", "high"]
75
+ },
76
+ "linesOfCode": { "type": "integer", "minimum": 0 }
77
+ }
78
+ }
79
+ },
80
+ "recommendations": {
81
+ "type": "array",
82
+ "description": "List of recommendations",
83
+ "items": {
84
+ "type": "object",
85
+ "required": ["action", "priority"],
86
+ "properties": {
87
+ "action": { "type": "string" },
88
+ "priority": {
89
+ "type": "string",
90
+ "enum": ["low", "medium", "high", "critical"]
91
+ },
92
+ "reason": { "type": "string" }
93
+ }
94
+ }
95
+ },
96
+ "techDebt": {
97
+ "type": "object",
98
+ "properties": {
99
+ "score": { "type": "number", "minimum": 0, "maximum": 10 },
100
+ "issues": { "type": "array", "items": { "type": "string" } }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### TypeScript/Zod Format
108
+
109
+ ```typescript
110
+ import { z } from 'zod';
111
+
112
+ // Schema para resultado de análisis
113
+ export const AnalysisResultSchema = z.object({
114
+ summary: z.string().min(10).max(500).describe('Brief summary of the analysis'),
115
+
116
+ files: z.array(z.object({
117
+ path: z.string(),
118
+ purpose: z.string(),
119
+ complexity: z.enum(['low', 'medium', 'high']).optional(),
120
+ linesOfCode: z.number().int().nonnegative().optional()
121
+ })).describe('Files analyzed'),
122
+
123
+ recommendations: z.array(z.object({
124
+ action: z.string(),
125
+ priority: z.enum(['low', 'medium', 'high', 'critical']),
126
+ reason: z.string().optional()
127
+ })).describe('List of recommendations'),
128
+
129
+ techDebt: z.object({
130
+ score: z.number().min(0).max(10),
131
+ issues: z.array(z.string())
132
+ }).optional()
133
+ });
134
+
135
+ export type AnalysisResult = z.infer<typeof AnalysisResultSchema>;
136
+
137
+ // Schema para resultado de implementación
138
+ export const ImplementationResultSchema = z.object({
139
+ success: z.boolean(),
140
+
141
+ filesCreated: z.array(z.object({
142
+ path: z.string(),
143
+ purpose: z.string(),
144
+ linesAdded: z.number().int().nonnegative()
145
+ })).default([]),
146
+
147
+ filesModified: z.array(z.object({
148
+ path: z.string(),
149
+ changes: z.string(),
150
+ linesAdded: z.number().int().nonnegative(),
151
+ linesRemoved: z.number().int().nonnegative()
152
+ })).default([]),
153
+
154
+ testsCreated: z.array(z.object({
155
+ path: z.string(),
156
+ testCount: z.number().int().positive(),
157
+ coverage: z.number().min(0).max(100).optional()
158
+ })).default([]),
159
+
160
+ decisions: z.array(z.object({
161
+ question: z.string(),
162
+ decision: z.string(),
163
+ reasoning: z.string(),
164
+ alternatives: z.array(z.string()).optional()
165
+ })).default([]),
166
+
167
+ errors: z.array(z.object({
168
+ type: z.string(),
169
+ message: z.string(),
170
+ file: z.string().optional(),
171
+ line: z.number().optional()
172
+ })).default([])
173
+ });
174
+
175
+ export type ImplementationResult = z.infer<typeof ImplementationResultSchema>;
176
+
177
+ // Schema para resultado de review
178
+ export const ReviewResultSchema = z.object({
179
+ approved: z.boolean(),
180
+
181
+ issues: z.array(z.object({
182
+ severity: z.enum(['critical', 'high', 'medium', 'low', 'info']),
183
+ type: z.enum(['bug', 'security', 'performance', 'style', 'maintainability']),
184
+ file: z.string(),
185
+ line: z.number().optional(),
186
+ message: z.string(),
187
+ suggestion: z.string().optional(),
188
+ autoFixable: z.boolean().default(false)
189
+ })).default([]),
190
+
191
+ summary: z.object({
192
+ critical: z.number().int().nonnegative(),
193
+ high: z.number().int().nonnegative(),
194
+ medium: z.number().int().nonnegative(),
195
+ low: z.number().int().nonnegative(),
196
+ info: z.number().int().nonnegative()
197
+ }),
198
+
199
+ recommendation: z.enum(['approve', 'request_changes', 'needs_discussion'])
200
+ });
201
+
202
+ export type ReviewResult = z.infer<typeof ReviewResultSchema>;
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Schemas Predefinidos
208
+
209
+ ### 1. AnalysisResult
210
+
211
+ Para agentes de análisis (elsabro-analyst, Explore, Plan).
212
+
213
+ ```javascript
214
+ {
215
+ summary: string,
216
+ files: Array<{ path, purpose, complexity?, linesOfCode? }>,
217
+ recommendations: Array<{ action, priority, reason? }>,
218
+ techDebt?: { score, issues }
219
+ }
220
+ ```
221
+
222
+ ### 2. ImplementationResult
223
+
224
+ Para agentes de implementación (elsabro-executor, elsabro-quick-dev).
225
+
226
+ ```javascript
227
+ {
228
+ success: boolean,
229
+ filesCreated: Array<{ path, purpose, linesAdded }>,
230
+ filesModified: Array<{ path, changes, linesAdded, linesRemoved }>,
231
+ testsCreated: Array<{ path, testCount, coverage? }>,
232
+ decisions: Array<{ question, decision, reasoning, alternatives? }>,
233
+ errors: Array<{ type, message, file?, line? }>
234
+ }
235
+ ```
236
+
237
+ ### 3. ReviewResult
238
+
239
+ Para agentes de review (code-reviewer, silent-failure-hunter).
240
+
241
+ ```javascript
242
+ {
243
+ approved: boolean,
244
+ issues: Array<{ severity, type, file, line?, message, suggestion?, autoFixable }>,
245
+ summary: { critical, high, medium, low, info },
246
+ recommendation: 'approve' | 'request_changes' | 'needs_discussion'
247
+ }
248
+ ```
249
+
250
+ ### 4. VerificationResult
251
+
252
+ Para agentes de verificación (elsabro-verifier, elsabro-qa).
253
+
254
+ ```javascript
255
+ {
256
+ passed: boolean,
257
+ tests: {
258
+ total: number,
259
+ passed: number,
260
+ failed: number,
261
+ skipped: number
262
+ },
263
+ typescript: {
264
+ passed: boolean,
265
+ errors: Array<{ file, line, message }>
266
+ },
267
+ lint: {
268
+ passed: boolean,
269
+ warnings: number,
270
+ errors: number
271
+ },
272
+ coverage?: {
273
+ statements: number,
274
+ branches: number,
275
+ functions: number,
276
+ lines: number
277
+ }
278
+ }
279
+ ```
280
+
281
+ ### 5. PlanResult
282
+
283
+ Para agentes de planificación (elsabro-planner).
284
+
285
+ ```javascript
286
+ {
287
+ phases: Array<{
288
+ id: string,
289
+ name: string,
290
+ description: string,
291
+ tasks: Array<{ id, description, agent?, dependencies? }>,
292
+ estimatedComplexity: 'low' | 'medium' | 'high'
293
+ }>,
294
+ dependencies: Array<{ from, to }>,
295
+ risks: Array<{ description, severity, mitigation }>,
296
+ prerequisites: Array<string>
297
+ }
298
+ ```
299
+
300
+ ---
301
+
302
+ ## API de Validación
303
+
304
+ ### SchemaValidator
305
+
306
+ ```javascript
307
+ /**
308
+ * SchemaValidator
309
+ * Valida outputs de agentes contra schemas definidos
310
+ */
311
+ class SchemaValidator {
312
+ constructor() {
313
+ this.schemas = new Map();
314
+ this.validationCache = new Map();
315
+
316
+ // Registrar schemas predefinidos
317
+ this.registerPredefinedSchemas();
318
+ }
319
+
320
+ /**
321
+ * Registra un schema
322
+ */
323
+ registerSchema(name, schema) {
324
+ this.schemas.set(name, {
325
+ name,
326
+ schema,
327
+ validator: this.compileValidator(schema)
328
+ });
329
+ }
330
+
331
+ /**
332
+ * Compila un validator desde JSON Schema o Zod
333
+ */
334
+ compileValidator(schema) {
335
+ // Si es Zod schema
336
+ if (schema._def) {
337
+ return (data) => {
338
+ const result = schema.safeParse(data);
339
+ return {
340
+ valid: result.success,
341
+ data: result.success ? result.data : null,
342
+ errors: result.success ? [] : result.error.errors.map(e => ({
343
+ path: e.path.join('.'),
344
+ message: e.message,
345
+ code: e.code
346
+ }))
347
+ };
348
+ };
349
+ }
350
+
351
+ // Si es JSON Schema
352
+ return (data) => this.validateJsonSchema(data, schema);
353
+ }
354
+
355
+ /**
356
+ * Valida JSON Schema manualmente
357
+ */
358
+ validateJsonSchema(data, schema) {
359
+ const errors = [];
360
+
361
+ // Validar tipo
362
+ if (schema.type && typeof data !== schema.type) {
363
+ if (!(schema.type === 'array' && Array.isArray(data))) {
364
+ errors.push({
365
+ path: '',
366
+ message: `Expected ${schema.type}, got ${typeof data}`,
367
+ code: 'invalid_type'
368
+ });
369
+ return { valid: false, data: null, errors };
370
+ }
371
+ }
372
+
373
+ // Validar required
374
+ if (schema.required && schema.type === 'object') {
375
+ for (const key of schema.required) {
376
+ if (!(key in data)) {
377
+ errors.push({
378
+ path: key,
379
+ message: `Missing required field: ${key}`,
380
+ code: 'missing_required'
381
+ });
382
+ }
383
+ }
384
+ }
385
+
386
+ // Validar propiedades
387
+ if (schema.properties && schema.type === 'object') {
388
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
389
+ if (key in data) {
390
+ const result = this.validateJsonSchema(data[key], propSchema);
391
+ if (!result.valid) {
392
+ errors.push(...result.errors.map(e => ({
393
+ ...e,
394
+ path: e.path ? `${key}.${e.path}` : key
395
+ })));
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ // Validar array items
402
+ if (schema.items && Array.isArray(data)) {
403
+ data.forEach((item, index) => {
404
+ const result = this.validateJsonSchema(item, schema.items);
405
+ if (!result.valid) {
406
+ errors.push(...result.errors.map(e => ({
407
+ ...e,
408
+ path: `[${index}]${e.path ? '.' + e.path : ''}`
409
+ })));
410
+ }
411
+ });
412
+ }
413
+
414
+ // Validar enum
415
+ if (schema.enum && !schema.enum.includes(data)) {
416
+ errors.push({
417
+ path: '',
418
+ message: `Value must be one of: ${schema.enum.join(', ')}`,
419
+ code: 'invalid_enum'
420
+ });
421
+ }
422
+
423
+ // Validar string constraints
424
+ if (schema.type === 'string') {
425
+ if (schema.minLength && data.length < schema.minLength) {
426
+ errors.push({
427
+ path: '',
428
+ message: `String must be at least ${schema.minLength} characters`,
429
+ code: 'too_short'
430
+ });
431
+ }
432
+ if (schema.maxLength && data.length > schema.maxLength) {
433
+ errors.push({
434
+ path: '',
435
+ message: `String must be at most ${schema.maxLength} characters`,
436
+ code: 'too_long'
437
+ });
438
+ }
439
+ }
440
+
441
+ // Validar number constraints
442
+ if (schema.type === 'number' || schema.type === 'integer') {
443
+ if (schema.minimum !== undefined && data < schema.minimum) {
444
+ errors.push({
445
+ path: '',
446
+ message: `Number must be >= ${schema.minimum}`,
447
+ code: 'too_small'
448
+ });
449
+ }
450
+ if (schema.maximum !== undefined && data > schema.maximum) {
451
+ errors.push({
452
+ path: '',
453
+ message: `Number must be <= ${schema.maximum}`,
454
+ code: 'too_big'
455
+ });
456
+ }
457
+ }
458
+
459
+ return {
460
+ valid: errors.length === 0,
461
+ data: errors.length === 0 ? data : null,
462
+ errors
463
+ };
464
+ }
465
+
466
+ /**
467
+ * Valida output contra un schema
468
+ */
469
+ validate(schemaName, data) {
470
+ const schemaEntry = this.schemas.get(schemaName);
471
+
472
+ if (!schemaEntry) {
473
+ return {
474
+ valid: false,
475
+ data: null,
476
+ errors: [{ path: '', message: `Schema not found: ${schemaName}`, code: 'schema_not_found' }]
477
+ };
478
+ }
479
+
480
+ return schemaEntry.validator(data);
481
+ }
482
+
483
+ /**
484
+ * Valida y transforma (aplica defaults, coerción)
485
+ */
486
+ validateAndTransform(schemaName, data, options = {}) {
487
+ const result = this.validate(schemaName, data);
488
+
489
+ if (!result.valid && options.coerce) {
490
+ // Intentar coerción de tipos
491
+ const coerced = this.coerceTypes(data, this.schemas.get(schemaName).schema);
492
+ const retryResult = this.validate(schemaName, coerced);
493
+
494
+ if (retryResult.valid) {
495
+ return { ...retryResult, coerced: true };
496
+ }
497
+ }
498
+
499
+ if (result.valid && options.applyDefaults) {
500
+ result.data = this.applyDefaults(result.data, this.schemas.get(schemaName).schema);
501
+ }
502
+
503
+ return result;
504
+ }
505
+
506
+ /**
507
+ * Intenta coercer tipos
508
+ */
509
+ coerceTypes(data, schema) {
510
+ if (schema.type === 'string' && typeof data !== 'string') {
511
+ return String(data);
512
+ }
513
+ if (schema.type === 'number' && typeof data === 'string') {
514
+ const num = parseFloat(data);
515
+ if (!isNaN(num)) return num;
516
+ }
517
+ if (schema.type === 'integer' && typeof data === 'string') {
518
+ const num = parseInt(data, 10);
519
+ if (!isNaN(num)) return num;
520
+ }
521
+ if (schema.type === 'boolean') {
522
+ if (data === 'true') return true;
523
+ if (data === 'false') return false;
524
+ }
525
+ if (schema.type === 'array' && !Array.isArray(data)) {
526
+ return [data];
527
+ }
528
+
529
+ if (schema.type === 'object' && schema.properties) {
530
+ const result = { ...data };
531
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
532
+ if (key in result) {
533
+ result[key] = this.coerceTypes(result[key], propSchema);
534
+ }
535
+ }
536
+ return result;
537
+ }
538
+
539
+ return data;
540
+ }
541
+
542
+ /**
543
+ * Aplica valores por defecto
544
+ */
545
+ applyDefaults(data, schema) {
546
+ if (schema.type !== 'object' || !schema.properties) {
547
+ return data;
548
+ }
549
+
550
+ const result = { ...data };
551
+
552
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
553
+ if (!(key in result) && propSchema.default !== undefined) {
554
+ result[key] = propSchema.default;
555
+ } else if (key in result && propSchema.type === 'object') {
556
+ result[key] = this.applyDefaults(result[key], propSchema);
557
+ }
558
+ }
559
+
560
+ return result;
561
+ }
562
+
563
+ /**
564
+ * Genera hints para corregir errores
565
+ */
566
+ generateHints(errors, schema) {
567
+ return errors.map(error => {
568
+ let hint = `Fix ${error.path || 'root'}: ${error.message}`;
569
+
570
+ if (error.code === 'missing_required') {
571
+ hint += `. Add the missing field.`;
572
+ } else if (error.code === 'invalid_type') {
573
+ hint += `. Check the data type.`;
574
+ } else if (error.code === 'invalid_enum') {
575
+ hint += `. Use one of the allowed values.`;
576
+ }
577
+
578
+ return { ...error, hint };
579
+ });
580
+ }
581
+
582
+ /**
583
+ * Registra schemas predefinidos
584
+ */
585
+ registerPredefinedSchemas() {
586
+ // AnalysisResult
587
+ this.registerSchema('analysis', {
588
+ type: 'object',
589
+ required: ['summary', 'files', 'recommendations'],
590
+ properties: {
591
+ summary: { type: 'string', minLength: 10, maxLength: 500 },
592
+ files: {
593
+ type: 'array',
594
+ items: {
595
+ type: 'object',
596
+ required: ['path', 'purpose'],
597
+ properties: {
598
+ path: { type: 'string' },
599
+ purpose: { type: 'string' },
600
+ complexity: { type: 'string', enum: ['low', 'medium', 'high'] },
601
+ linesOfCode: { type: 'integer', minimum: 0 }
602
+ }
603
+ }
604
+ },
605
+ recommendations: {
606
+ type: 'array',
607
+ items: {
608
+ type: 'object',
609
+ required: ['action', 'priority'],
610
+ properties: {
611
+ action: { type: 'string' },
612
+ priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
613
+ reason: { type: 'string' }
614
+ }
615
+ }
616
+ },
617
+ techDebt: {
618
+ type: 'object',
619
+ properties: {
620
+ score: { type: 'number', minimum: 0, maximum: 10 },
621
+ issues: { type: 'array', items: { type: 'string' } }
622
+ }
623
+ }
624
+ }
625
+ });
626
+
627
+ // ImplementationResult
628
+ this.registerSchema('implementation', {
629
+ type: 'object',
630
+ required: ['success'],
631
+ properties: {
632
+ success: { type: 'boolean' },
633
+ filesCreated: { type: 'array', default: [] },
634
+ filesModified: { type: 'array', default: [] },
635
+ testsCreated: { type: 'array', default: [] },
636
+ decisions: { type: 'array', default: [] },
637
+ errors: { type: 'array', default: [] }
638
+ }
639
+ });
640
+
641
+ // ReviewResult
642
+ this.registerSchema('review', {
643
+ type: 'object',
644
+ required: ['approved', 'issues', 'summary', 'recommendation'],
645
+ properties: {
646
+ approved: { type: 'boolean' },
647
+ issues: { type: 'array' },
648
+ summary: {
649
+ type: 'object',
650
+ required: ['critical', 'high', 'medium', 'low', 'info'],
651
+ properties: {
652
+ critical: { type: 'integer', minimum: 0 },
653
+ high: { type: 'integer', minimum: 0 },
654
+ medium: { type: 'integer', minimum: 0 },
655
+ low: { type: 'integer', minimum: 0 },
656
+ info: { type: 'integer', minimum: 0 }
657
+ }
658
+ },
659
+ recommendation: { type: 'string', enum: ['approve', 'request_changes', 'needs_discussion'] }
660
+ }
661
+ });
662
+
663
+ // VerificationResult
664
+ this.registerSchema('verification', {
665
+ type: 'object',
666
+ required: ['passed', 'tests', 'typescript', 'lint'],
667
+ properties: {
668
+ passed: { type: 'boolean' },
669
+ tests: {
670
+ type: 'object',
671
+ required: ['total', 'passed', 'failed', 'skipped'],
672
+ properties: {
673
+ total: { type: 'integer', minimum: 0 },
674
+ passed: { type: 'integer', minimum: 0 },
675
+ failed: { type: 'integer', minimum: 0 },
676
+ skipped: { type: 'integer', minimum: 0 }
677
+ }
678
+ },
679
+ typescript: {
680
+ type: 'object',
681
+ required: ['passed'],
682
+ properties: {
683
+ passed: { type: 'boolean' },
684
+ errors: { type: 'array' }
685
+ }
686
+ },
687
+ lint: {
688
+ type: 'object',
689
+ required: ['passed'],
690
+ properties: {
691
+ passed: { type: 'boolean' },
692
+ warnings: { type: 'integer', minimum: 0 },
693
+ errors: { type: 'integer', minimum: 0 }
694
+ }
695
+ },
696
+ coverage: {
697
+ type: 'object',
698
+ properties: {
699
+ statements: { type: 'number', minimum: 0, maximum: 100 },
700
+ branches: { type: 'number', minimum: 0, maximum: 100 },
701
+ functions: { type: 'number', minimum: 0, maximum: 100 },
702
+ lines: { type: 'number', minimum: 0, maximum: 100 }
703
+ }
704
+ }
705
+ }
706
+ });
707
+
708
+ // PlanResult
709
+ this.registerSchema('plan', {
710
+ type: 'object',
711
+ required: ['phases'],
712
+ properties: {
713
+ phases: {
714
+ type: 'array',
715
+ items: {
716
+ type: 'object',
717
+ required: ['id', 'name', 'tasks'],
718
+ properties: {
719
+ id: { type: 'string' },
720
+ name: { type: 'string' },
721
+ description: { type: 'string' },
722
+ tasks: { type: 'array' },
723
+ estimatedComplexity: { type: 'string', enum: ['low', 'medium', 'high'] }
724
+ }
725
+ }
726
+ },
727
+ dependencies: { type: 'array' },
728
+ risks: { type: 'array' },
729
+ prerequisites: { type: 'array', items: { type: 'string' } }
730
+ }
731
+ });
732
+ }
733
+ }
734
+
735
+ // Singleton instance
736
+ let validatorInstance = null;
737
+
738
+ function getValidator() {
739
+ if (!validatorInstance) {
740
+ validatorInstance = new SchemaValidator();
741
+ }
742
+ return validatorInstance;
743
+ }
744
+
745
+ module.exports = { SchemaValidator, getValidator };
746
+ ```
747
+
748
+ ---
749
+
750
+ ## Integración con Agentes
751
+
752
+ ### Validación de Output en Agent Execution
753
+
754
+ ```javascript
755
+ async function executeAgentWithSchema(agent, inputs, expectedSchema) {
756
+ const validator = getValidator();
757
+ const telemetry = getTelemetry();
758
+
759
+ // Ejecutar agente
760
+ const rawOutput = await executeAgent(agent, inputs);
761
+
762
+ // Parsear output estructurado
763
+ const parsed = parseAgentOutput(rawOutput);
764
+
765
+ // Validar contra schema
766
+ const validation = validator.validateAndTransform(expectedSchema, parsed, {
767
+ coerce: true,
768
+ applyDefaults: true
769
+ });
770
+
771
+ if (!validation.valid) {
772
+ telemetry.logger.warn(`Agent output validation failed: ${agent.id}`, {
773
+ errors: validation.errors,
774
+ schema: expectedSchema
775
+ });
776
+
777
+ // Retry con hints
778
+ if (agent.config.retryOnSchemaError) {
779
+ const hints = validator.generateHints(validation.errors, expectedSchema);
780
+ const retryOutput = await executeAgent(agent, {
781
+ ...inputs,
782
+ _schemaHints: hints,
783
+ _expectedFormat: `Please return output matching this structure: ${JSON.stringify(expectedSchema)}`
784
+ });
785
+
786
+ const retryValidation = validator.validate(expectedSchema, parseAgentOutput(retryOutput));
787
+ if (retryValidation.valid) {
788
+ return retryValidation.data;
789
+ }
790
+ }
791
+
792
+ throw new SchemaValidationError(validation.errors, expectedSchema);
793
+ }
794
+
795
+ return validation.data;
796
+ }
797
+ ```
798
+
799
+ ### Declaración de Schema en Flow
800
+
801
+ ```json
802
+ {
803
+ "id": "analyze",
804
+ "type": "agent",
805
+ "agent": "elsabro-analyst",
806
+ "outputSchema": "analysis",
807
+ "config": {
808
+ "retryOnSchemaError": true,
809
+ "maxSchemaRetries": 2
810
+ }
811
+ }
812
+ ```
813
+
814
+ ---
815
+
816
+ ## Comandos de Usuario
817
+
818
+ ### /elsabro:schema
819
+
820
+ ```bash
821
+ /elsabro:schema list # Listar schemas disponibles
822
+ /elsabro:schema show <name> # Mostrar schema específico
823
+ /elsabro:schema validate <file> # Validar archivo contra schema
824
+ /elsabro:schema create # Crear nuevo schema (interactivo)
825
+ ```
826
+
827
+ ---
828
+
829
+ ## Configuración
830
+
831
+ ### .planning/schemas-config.json
832
+
833
+ ```json
834
+ {
835
+ "schemas": {
836
+ "validation": {
837
+ "strict": true,
838
+ "coerceTypes": true,
839
+ "applyDefaults": true,
840
+ "retryOnError": true,
841
+ "maxRetries": 2
842
+ },
843
+ "customSchemas": {
844
+ "directory": ".planning/schemas/",
845
+ "autoLoad": true
846
+ },
847
+ "agentDefaults": {
848
+ "elsabro-analyst": "analysis",
849
+ "elsabro-executor": "implementation",
850
+ "elsabro-verifier": "verification",
851
+ "elsabro-planner": "plan",
852
+ "code-reviewer": "review",
853
+ "pr-review-toolkit:code-reviewer": "review",
854
+ "pr-review-toolkit:silent-failure-hunter": "review"
855
+ }
856
+ }
857
+ }
858
+ ```