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,2274 @@
1
+ # ELSABRO Agent Marketplace
2
+
3
+ > Sistema de marketplace para publicar, descubrir e instalar agentes de la comunidad con verificacion, reviews y sandboxing.
4
+
5
+ ## Arquitectura General
6
+
7
+ ```
8
+ +-----------------------------------------------------------------------------+
9
+ | Agent Marketplace System |
10
+ +-----------------------------------------------------------------------------+
11
+ | +-------------------+ +-------------------+ +-------------------+ |
12
+ | | MarketplaceRegistry| | AgentPackager | |PublishingPipeline| |
13
+ | | ----------------- | | --------------- | | --------------- | |
14
+ | | * Agent catalog | | * Package agents | | * Submit flow | |
15
+ | | * Search/filter | | * Validate code | | * Auto review | |
16
+ | | * Versioning | | * Sign packages | | * Approval | |
17
+ | +-------------------+ +-------------------+ +-------------------+ |
18
+ | | |
19
+ | +---------------------------+-------------------------------+ |
20
+ | | ReviewSystem | |
21
+ | | * Ratings (1-5) * Text reviews * Usage metrics | |
22
+ | +------------------------------------------------------------+ |
23
+ | | |
24
+ | +---------------------------+-------------------------------+ |
25
+ | | InstallationManager | |
26
+ | | * Install/Update * Dependencies * Sandboxed execution | |
27
+ | +------------------------------------------------------------+ |
28
+ +-----------------------------------------------------------------------------+
29
+ ```
30
+
31
+ ---
32
+
33
+ ## 1. MarketplaceRegistry
34
+
35
+ ### Proposito
36
+
37
+ Registro central de agentes publicados con busqueda, filtrado y versionado semantico.
38
+
39
+ ### Interfaces
40
+
41
+ ```typescript
42
+ interface MarketplaceRegistry {
43
+ // Catalog operations
44
+ list(options?: ListOptions): Promise<AgentListing[]>;
45
+ get(name: string, version?: string): Promise<AgentDetails | null>;
46
+ search(query: SearchQuery): Promise<SearchResult>;
47
+
48
+ // Categories
49
+ getCategories(): Promise<Category[]>;
50
+ getByCategory(categoryId: AgentCategory): Promise<AgentListing[]>;
51
+
52
+ // Versions
53
+ getVersions(name: string): Promise<VersionInfo[]>;
54
+ getLatestVersion(name: string): Promise<string>;
55
+ checkCompatibility(name: string, version: string): Promise<CompatibilityResult>;
56
+
57
+ // Statistics
58
+ getStats(name: string): Promise<AgentStats>;
59
+ getTrending(period: TrendingPeriod): Promise<AgentListing[]>;
60
+
61
+ // Events
62
+ onUpdate(callback: (agent: AgentListing) => void): Disposable;
63
+ }
64
+
65
+ type AgentCategory =
66
+ | 'exploration'
67
+ | 'implementation'
68
+ | 'review'
69
+ | 'testing'
70
+ | 'specialized';
71
+
72
+ interface AgentListing {
73
+ // Identity
74
+ name: string;
75
+ displayName: string;
76
+ description: string;
77
+ version: string;
78
+ author: AuthorInfo;
79
+
80
+ // Classification
81
+ category: AgentCategory;
82
+ tags: string[];
83
+
84
+ // Stats
85
+ downloads: number;
86
+ rating: number;
87
+ reviewCount: number;
88
+
89
+ // Metadata
90
+ createdAt: Date;
91
+ updatedAt: Date;
92
+ verified: boolean;
93
+ featured: boolean;
94
+
95
+ // Links
96
+ repository?: string;
97
+ homepage?: string;
98
+ documentation?: string;
99
+ }
100
+
101
+ interface AuthorInfo {
102
+ name: string;
103
+ email?: string;
104
+ url?: string;
105
+ verified: boolean;
106
+ publisherSince: Date;
107
+ }
108
+
109
+ interface SearchQuery {
110
+ text?: string;
111
+ category?: AgentCategory;
112
+ tags?: string[];
113
+ minRating?: number;
114
+ minDownloads?: number;
115
+ verified?: boolean;
116
+ compatible?: string; // ELSABRO version
117
+ sortBy?: 'relevance' | 'downloads' | 'rating' | 'updated' | 'name';
118
+ sortOrder?: 'asc' | 'desc';
119
+ page?: number;
120
+ limit?: number;
121
+ }
122
+
123
+ interface SearchResult {
124
+ items: AgentListing[];
125
+ total: number;
126
+ page: number;
127
+ totalPages: number;
128
+ facets: {
129
+ categories: Record<AgentCategory, number>;
130
+ tags: Record<string, number>;
131
+ ratings: Record<number, number>;
132
+ };
133
+ }
134
+
135
+ interface VersionInfo {
136
+ version: string;
137
+ publishedAt: Date;
138
+ downloads: number;
139
+ changelog?: string;
140
+ compatibility: {
141
+ elsabro: string;
142
+ node?: string;
143
+ };
144
+ deprecated?: boolean;
145
+ deprecationMessage?: string;
146
+ }
147
+
148
+ interface CompatibilityResult {
149
+ compatible: boolean;
150
+ currentVersion: string;
151
+ requiredVersion: string;
152
+ issues: CompatibilityIssue[];
153
+ }
154
+
155
+ interface CompatibilityIssue {
156
+ type: 'version' | 'dependency' | 'permission' | 'platform';
157
+ severity: 'error' | 'warning';
158
+ message: string;
159
+ }
160
+ ```
161
+
162
+ ### Implementacion
163
+
164
+ ```typescript
165
+ class MarketplaceRegistryImpl implements MarketplaceRegistry {
166
+ private cache: Map<string, CachedEntry> = new Map();
167
+ private updateCallbacks: Set<Function> = new Set();
168
+
169
+ constructor(
170
+ private config: MarketplaceConfig,
171
+ private httpClient: HttpClient,
172
+ private cacheManager: CacheManager
173
+ ) {}
174
+
175
+ async list(options: ListOptions = {}): Promise<AgentListing[]> {
176
+ const cacheKey = `list:${JSON.stringify(options)}`;
177
+ const cached = await this.cacheManager.get<AgentListing[]>(cacheKey);
178
+
179
+ if (cached && !options.forceRefresh) {
180
+ return cached;
181
+ }
182
+
183
+ const response = await this.httpClient.get<ApiResponse<AgentListing[]>>(
184
+ `${this.config.registry.url}/agents`,
185
+ { params: this.buildListParams(options) }
186
+ );
187
+
188
+ await this.cacheManager.set(cacheKey, response.data, this.config.registry.cacheTTL);
189
+ return response.data;
190
+ }
191
+
192
+ async get(name: string, version?: string): Promise<AgentDetails | null> {
193
+ const cacheKey = `agent:${name}:${version || 'latest'}`;
194
+ const cached = await this.cacheManager.get<AgentDetails>(cacheKey);
195
+
196
+ if (cached) return cached;
197
+
198
+ try {
199
+ const url = version
200
+ ? `${this.config.registry.url}/agents/${name}/versions/${version}`
201
+ : `${this.config.registry.url}/agents/${name}`;
202
+
203
+ const response = await this.httpClient.get<ApiResponse<AgentDetails>>(url);
204
+ await this.cacheManager.set(cacheKey, response.data, this.config.registry.cacheTTL);
205
+ return response.data;
206
+ } catch (error) {
207
+ if (error.status === 404) return null;
208
+ throw error;
209
+ }
210
+ }
211
+
212
+ async search(query: SearchQuery): Promise<SearchResult> {
213
+ const response = await this.httpClient.post<ApiResponse<SearchResult>>(
214
+ `${this.config.registry.url}/search`,
215
+ { body: query }
216
+ );
217
+
218
+ return response.data;
219
+ }
220
+
221
+ async getCategories(): Promise<Category[]> {
222
+ return this.config.categories.map(cat => ({
223
+ id: cat.id,
224
+ name: cat.name,
225
+ description: cat.description,
226
+ icon: cat.icon,
227
+ agentCount: 0 // Populated from API
228
+ }));
229
+ }
230
+
231
+ async getByCategory(categoryId: AgentCategory): Promise<AgentListing[]> {
232
+ return this.search({ category: categoryId, limit: 100 }).then(r => r.items);
233
+ }
234
+
235
+ async getVersions(name: string): Promise<VersionInfo[]> {
236
+ const response = await this.httpClient.get<ApiResponse<VersionInfo[]>>(
237
+ `${this.config.registry.url}/agents/${name}/versions`
238
+ );
239
+ return response.data;
240
+ }
241
+
242
+ async getLatestVersion(name: string): Promise<string> {
243
+ const agent = await this.get(name);
244
+ if (!agent) throw new Error(`Agent not found: ${name}`);
245
+ return agent.version;
246
+ }
247
+
248
+ async checkCompatibility(name: string, version: string): Promise<CompatibilityResult> {
249
+ const agent = await this.get(name, version);
250
+ if (!agent) {
251
+ return {
252
+ compatible: false,
253
+ currentVersion: this.config.elsabroVersion,
254
+ requiredVersion: 'unknown',
255
+ issues: [{ type: 'version', severity: 'error', message: 'Agent not found' }]
256
+ };
257
+ }
258
+
259
+ const issues: CompatibilityIssue[] = [];
260
+ const requiredVersion = agent.manifest.engines?.elsabro || '*';
261
+
262
+ if (!semver.satisfies(this.config.elsabroVersion, requiredVersion)) {
263
+ issues.push({
264
+ type: 'version',
265
+ severity: 'error',
266
+ message: `Requires ELSABRO ${requiredVersion}, current: ${this.config.elsabroVersion}`
267
+ });
268
+ }
269
+
270
+ // Check dependencies
271
+ for (const [dep, ver] of Object.entries(agent.manifest.dependencies || {})) {
272
+ const installed = await this.checkInstalledAgent(dep);
273
+ if (!installed) {
274
+ issues.push({
275
+ type: 'dependency',
276
+ severity: 'error',
277
+ message: `Missing dependency: ${dep}@${ver}`
278
+ });
279
+ } else if (!semver.satisfies(installed.version, ver)) {
280
+ issues.push({
281
+ type: 'dependency',
282
+ severity: 'warning',
283
+ message: `Dependency version mismatch: ${dep} requires ${ver}, installed: ${installed.version}`
284
+ });
285
+ }
286
+ }
287
+
288
+ return {
289
+ compatible: issues.filter(i => i.severity === 'error').length === 0,
290
+ currentVersion: this.config.elsabroVersion,
291
+ requiredVersion,
292
+ issues
293
+ };
294
+ }
295
+
296
+ async getStats(name: string): Promise<AgentStats> {
297
+ const response = await this.httpClient.get<ApiResponse<AgentStats>>(
298
+ `${this.config.registry.url}/agents/${name}/stats`
299
+ );
300
+ return response.data;
301
+ }
302
+
303
+ async getTrending(period: TrendingPeriod = 'week'): Promise<AgentListing[]> {
304
+ const response = await this.httpClient.get<ApiResponse<AgentListing[]>>(
305
+ `${this.config.registry.url}/trending`,
306
+ { params: { period } }
307
+ );
308
+ return response.data;
309
+ }
310
+
311
+ onUpdate(callback: (agent: AgentListing) => void): Disposable {
312
+ this.updateCallbacks.add(callback);
313
+ return { dispose: () => this.updateCallbacks.delete(callback) };
314
+ }
315
+
316
+ private buildListParams(options: ListOptions): Record<string, string> {
317
+ const params: Record<string, string> = {};
318
+ if (options.page) params.page = String(options.page);
319
+ if (options.limit) params.limit = String(options.limit);
320
+ if (options.sortBy) params.sort = options.sortBy;
321
+ if (options.category) params.category = options.category;
322
+ return params;
323
+ }
324
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 2. AgentPackager
330
+
331
+ ### Proposito
332
+
333
+ Empaquetado de agentes para distribucion con validacion, manifest y firma digital.
334
+
335
+ ### Interfaces
336
+
337
+ ```typescript
338
+ interface AgentPackager {
339
+ // Packaging
340
+ pack(sourcePath: string, options?: PackOptions): Promise<PackageResult>;
341
+ validate(sourcePath: string): Promise<ValidationResult>;
342
+
343
+ // Manifest
344
+ generateManifest(sourcePath: string): Promise<AgentManifest>;
345
+ validateManifest(manifest: AgentManifest): ValidationResult;
346
+
347
+ // Signing
348
+ sign(packagePath: string, privateKey: string): Promise<SignedPackage>;
349
+ verify(packagePath: string): Promise<VerificationResult>;
350
+
351
+ // Unpacking
352
+ unpack(packagePath: string, destPath: string): Promise<UnpackResult>;
353
+ inspect(packagePath: string): Promise<PackageInfo>;
354
+ }
355
+
356
+ interface AgentManifest {
357
+ // Required fields
358
+ name: string;
359
+ version: string;
360
+ displayName: string;
361
+ description: string;
362
+ author: string | AuthorInfo;
363
+ main: string;
364
+
365
+ // Classification
366
+ category: AgentCategory;
367
+ tags?: string[];
368
+ keywords?: string[];
369
+
370
+ // Compatibility
371
+ engines: {
372
+ elsabro: string;
373
+ node?: string;
374
+ };
375
+
376
+ // Dependencies
377
+ dependencies?: Record<string, string>;
378
+ peerDependencies?: Record<string, string>;
379
+
380
+ // Permissions
381
+ permissions?: AgentPermission[];
382
+
383
+ // Contributions
384
+ contributes?: {
385
+ tools?: ToolContribution[];
386
+ commands?: CommandContribution[];
387
+ hooks?: HookContribution[];
388
+ config?: ConfigContribution;
389
+ };
390
+
391
+ // Metadata
392
+ license?: string;
393
+ repository?: string;
394
+ homepage?: string;
395
+ bugs?: string;
396
+ changelog?: string;
397
+
398
+ // Files
399
+ files?: string[];
400
+ exclude?: string[];
401
+ }
402
+
403
+ type AgentPermission =
404
+ | 'filesystem:read'
405
+ | 'filesystem:write'
406
+ | 'network'
407
+ | 'network:external'
408
+ | 'shell'
409
+ | 'shell:restricted'
410
+ | 'env'
411
+ | 'secrets'
412
+ | 'config:read'
413
+ | 'config:write'
414
+ | 'agents:spawn'
415
+ | 'tools:register';
416
+
417
+ interface PackOptions {
418
+ outputPath?: string;
419
+ sign?: boolean;
420
+ privateKeyPath?: string;
421
+ includeSourceMaps?: boolean;
422
+ minify?: boolean;
423
+ compressionLevel?: number;
424
+ }
425
+
426
+ interface PackageResult {
427
+ success: boolean;
428
+ packagePath: string;
429
+ size: number;
430
+ checksum: string;
431
+ manifest: AgentManifest;
432
+ files: PackagedFile[];
433
+ warnings: string[];
434
+ }
435
+
436
+ interface PackagedFile {
437
+ path: string;
438
+ size: number;
439
+ checksum: string;
440
+ }
441
+
442
+ interface SignedPackage {
443
+ packagePath: string;
444
+ signature: string;
445
+ signedAt: Date;
446
+ publicKey: string;
447
+ algorithm: string;
448
+ }
449
+
450
+ interface VerificationResult {
451
+ valid: boolean;
452
+ signed: boolean;
453
+ signature?: {
454
+ algorithm: string;
455
+ publicKey: string;
456
+ signedAt: Date;
457
+ publisher?: string;
458
+ verified: boolean;
459
+ };
460
+ checksum: {
461
+ expected: string;
462
+ actual: string;
463
+ valid: boolean;
464
+ };
465
+ issues: string[];
466
+ }
467
+ ```
468
+
469
+ ### Implementacion
470
+
471
+ ```typescript
472
+ class AgentPackagerImpl implements AgentPackager {
473
+ constructor(
474
+ private config: MarketplaceConfig,
475
+ private crypto: CryptoService,
476
+ private validator: ManifestValidator
477
+ ) {}
478
+
479
+ async pack(sourcePath: string, options: PackOptions = {}): Promise<PackageResult> {
480
+ // Validate first
481
+ const validation = await this.validate(sourcePath);
482
+ if (!validation.valid) {
483
+ throw new PackagingError('Validation failed', validation.errors);
484
+ }
485
+
486
+ // Read manifest
487
+ const manifestPath = path.join(sourcePath, this.config.packaging.manifestFile);
488
+ const manifest = await this.readManifest(manifestPath);
489
+
490
+ // Determine files to include
491
+ const files = await this.collectFiles(sourcePath, manifest);
492
+
493
+ // Create package
494
+ const outputPath = options.outputPath ||
495
+ path.join(sourcePath, `${manifest.name}-${manifest.version}.elsabro`);
496
+
497
+ const archive = archiver('zip', {
498
+ zlib: { level: options.compressionLevel ?? this.config.packaging.compressionLevel }
499
+ });
500
+
501
+ const output = fs.createWriteStream(outputPath);
502
+ archive.pipe(output);
503
+
504
+ // Add manifest
505
+ archive.append(JSON.stringify(manifest, null, 2), { name: 'agent.manifest.json' });
506
+
507
+ // Add files
508
+ const packagedFiles: PackagedFile[] = [];
509
+ for (const file of files) {
510
+ const content = await fs.readFile(path.join(sourcePath, file));
511
+ const checksum = this.crypto.hash(content, 'sha256');
512
+
513
+ archive.append(content, { name: file });
514
+ packagedFiles.push({
515
+ path: file,
516
+ size: content.length,
517
+ checksum
518
+ });
519
+ }
520
+
521
+ await archive.finalize();
522
+
523
+ // Calculate package checksum
524
+ const packageContent = await fs.readFile(outputPath);
525
+ const checksum = this.crypto.hash(packageContent, 'sha256');
526
+
527
+ // Sign if requested
528
+ if (options.sign && options.privateKeyPath) {
529
+ const privateKey = await fs.readFile(options.privateKeyPath, 'utf-8');
530
+ await this.sign(outputPath, privateKey);
531
+ }
532
+
533
+ return {
534
+ success: true,
535
+ packagePath: outputPath,
536
+ size: packageContent.length,
537
+ checksum,
538
+ manifest,
539
+ files: packagedFiles,
540
+ warnings: validation.warnings
541
+ };
542
+ }
543
+
544
+ async validate(sourcePath: string): Promise<ValidationResult> {
545
+ const errors: string[] = [];
546
+ const warnings: string[] = [];
547
+
548
+ // Check manifest exists
549
+ const manifestPath = path.join(sourcePath, this.config.packaging.manifestFile);
550
+ if (!await this.fileExists(manifestPath)) {
551
+ errors.push(`Missing manifest file: ${this.config.packaging.manifestFile}`);
552
+ return { valid: false, errors, warnings };
553
+ }
554
+
555
+ // Validate manifest
556
+ const manifest = await this.readManifest(manifestPath);
557
+ const manifestValidation = this.validateManifest(manifest);
558
+ errors.push(...manifestValidation.errors);
559
+ warnings.push(...manifestValidation.warnings);
560
+
561
+ // Check main entry exists
562
+ if (manifest.main) {
563
+ const mainPath = path.join(sourcePath, manifest.main);
564
+ if (!await this.fileExists(mainPath)) {
565
+ errors.push(`Main entry file not found: ${manifest.main}`);
566
+ }
567
+ }
568
+
569
+ // Check package size
570
+ const totalSize = await this.calculateDirectorySize(sourcePath);
571
+ if (totalSize > this.config.packaging.maxPackageSize) {
572
+ errors.push(`Package exceeds maximum size: ${totalSize} > ${this.config.packaging.maxPackageSize}`);
573
+ }
574
+
575
+ // Validate code structure
576
+ const codeValidation = await this.validateCode(sourcePath, manifest);
577
+ errors.push(...codeValidation.errors);
578
+ warnings.push(...codeValidation.warnings);
579
+
580
+ return {
581
+ valid: errors.length === 0,
582
+ errors,
583
+ warnings
584
+ };
585
+ }
586
+
587
+ validateManifest(manifest: AgentManifest): ValidationResult {
588
+ const errors: string[] = [];
589
+ const warnings: string[] = [];
590
+
591
+ // Required fields
592
+ for (const field of this.config.packaging.requiredFields) {
593
+ if (!manifest[field]) {
594
+ errors.push(`Missing required field: ${field}`);
595
+ }
596
+ }
597
+
598
+ // Version format
599
+ if (manifest.version && !semver.valid(manifest.version)) {
600
+ errors.push(`Invalid version format: ${manifest.version}`);
601
+ }
602
+
603
+ // Name format
604
+ if (manifest.name && !/^[a-z0-9-]+$/.test(manifest.name)) {
605
+ errors.push(`Invalid name format: ${manifest.name}. Use lowercase letters, numbers, and hyphens only.`);
606
+ }
607
+
608
+ // Category validation
609
+ const validCategories = ['exploration', 'implementation', 'review', 'testing', 'specialized'];
610
+ if (manifest.category && !validCategories.includes(manifest.category)) {
611
+ errors.push(`Invalid category: ${manifest.category}`);
612
+ }
613
+
614
+ // Engine compatibility
615
+ if (!manifest.engines?.elsabro) {
616
+ warnings.push('No ELSABRO engine version specified');
617
+ }
618
+
619
+ // Permission validation
620
+ const validPermissions = [
621
+ 'filesystem:read', 'filesystem:write', 'network', 'network:external',
622
+ 'shell', 'shell:restricted', 'env', 'secrets', 'config:read',
623
+ 'config:write', 'agents:spawn', 'tools:register'
624
+ ];
625
+
626
+ for (const perm of manifest.permissions || []) {
627
+ if (!validPermissions.includes(perm)) {
628
+ warnings.push(`Unknown permission: ${perm}`);
629
+ }
630
+ }
631
+
632
+ // High-risk permissions warning
633
+ const highRiskPerms = ['shell', 'secrets', 'filesystem:write'];
634
+ const hasHighRisk = (manifest.permissions || []).some(p => highRiskPerms.includes(p));
635
+ if (hasHighRisk) {
636
+ warnings.push('Agent requests high-risk permissions. Manual review may be required.');
637
+ }
638
+
639
+ return { valid: errors.length === 0, errors, warnings };
640
+ }
641
+
642
+ async sign(packagePath: string, privateKey: string): Promise<SignedPackage> {
643
+ const content = await fs.readFile(packagePath);
644
+ const signature = this.crypto.sign(content, privateKey, this.config.signing.algorithm);
645
+ const publicKey = this.crypto.derivePublicKey(privateKey);
646
+
647
+ // Append signature to package
648
+ const signatureData = {
649
+ signature,
650
+ algorithm: this.config.signing.algorithm,
651
+ publicKey,
652
+ signedAt: new Date().toISOString()
653
+ };
654
+
655
+ const signaturePath = packagePath + '.sig';
656
+ await fs.writeFile(signaturePath, JSON.stringify(signatureData, null, 2));
657
+
658
+ return {
659
+ packagePath,
660
+ signature,
661
+ signedAt: new Date(),
662
+ publicKey,
663
+ algorithm: this.config.signing.algorithm
664
+ };
665
+ }
666
+
667
+ async verify(packagePath: string): Promise<VerificationResult> {
668
+ const issues: string[] = [];
669
+ const content = await fs.readFile(packagePath);
670
+
671
+ // Check checksum
672
+ const actualChecksum = this.crypto.hash(content, 'sha256');
673
+ const info = await this.inspect(packagePath);
674
+ const expectedChecksum = info.checksum;
675
+ const checksumValid = actualChecksum === expectedChecksum;
676
+
677
+ if (!checksumValid) {
678
+ issues.push('Checksum mismatch - package may be corrupted or tampered');
679
+ }
680
+
681
+ // Check signature
682
+ const signaturePath = packagePath + '.sig';
683
+ let signatureInfo = undefined;
684
+ let signed = false;
685
+
686
+ if (await this.fileExists(signaturePath)) {
687
+ signed = true;
688
+ const sigData = JSON.parse(await fs.readFile(signaturePath, 'utf-8'));
689
+ const verified = this.crypto.verify(content, sigData.signature, sigData.publicKey, sigData.algorithm);
690
+
691
+ signatureInfo = {
692
+ algorithm: sigData.algorithm,
693
+ publicKey: sigData.publicKey,
694
+ signedAt: new Date(sigData.signedAt),
695
+ verified
696
+ };
697
+
698
+ if (!verified) {
699
+ issues.push('Signature verification failed');
700
+ }
701
+ } else if (this.config.signing.required) {
702
+ issues.push('Package is not signed but signing is required');
703
+ }
704
+
705
+ return {
706
+ valid: issues.length === 0,
707
+ signed,
708
+ signature: signatureInfo,
709
+ checksum: {
710
+ expected: expectedChecksum,
711
+ actual: actualChecksum,
712
+ valid: checksumValid
713
+ },
714
+ issues
715
+ };
716
+ }
717
+
718
+ async unpack(packagePath: string, destPath: string): Promise<UnpackResult> {
719
+ // Verify before unpacking
720
+ const verification = await this.verify(packagePath);
721
+ if (!verification.valid && !this.config.signing.allowUnsigned) {
722
+ throw new PackagingError('Package verification failed', verification.issues);
723
+ }
724
+
725
+ await fs.mkdir(destPath, { recursive: true });
726
+
727
+ const zip = new AdmZip(packagePath);
728
+ zip.extractAllTo(destPath, true);
729
+
730
+ const manifest = await this.readManifest(path.join(destPath, 'agent.manifest.json'));
731
+
732
+ return {
733
+ success: true,
734
+ destPath,
735
+ manifest,
736
+ verification
737
+ };
738
+ }
739
+
740
+ async inspect(packagePath: string): Promise<PackageInfo> {
741
+ const zip = new AdmZip(packagePath);
742
+ const manifestEntry = zip.getEntry('agent.manifest.json');
743
+
744
+ if (!manifestEntry) {
745
+ throw new PackagingError('Invalid package: missing manifest');
746
+ }
747
+
748
+ const manifest = JSON.parse(manifestEntry.getData().toString('utf-8'));
749
+ const entries = zip.getEntries();
750
+
751
+ const content = await fs.readFile(packagePath);
752
+
753
+ return {
754
+ manifest,
755
+ size: content.length,
756
+ checksum: this.crypto.hash(content, 'sha256'),
757
+ files: entries.map(e => ({
758
+ path: e.entryName,
759
+ size: e.header.size,
760
+ compressed: e.header.compressedSize
761
+ })),
762
+ createdAt: new Date(entries[0]?.header.time || Date.now())
763
+ };
764
+ }
765
+
766
+ private async collectFiles(sourcePath: string, manifest: AgentManifest): Promise<string[]> {
767
+ const includePatterns = manifest.files || ['**/*'];
768
+ const excludePatterns = [
769
+ ...this.config.packaging.excludePatterns,
770
+ ...(manifest.exclude || [])
771
+ ];
772
+
773
+ const files = await glob(includePatterns, {
774
+ cwd: sourcePath,
775
+ ignore: excludePatterns,
776
+ nodir: true
777
+ });
778
+
779
+ // Filter by allowed file types
780
+ return files.filter(f => {
781
+ const ext = path.extname(f);
782
+ return this.config.packaging.allowedFileTypes.includes(ext) || ext === '';
783
+ });
784
+ }
785
+
786
+ private async validateCode(sourcePath: string, manifest: AgentManifest): Promise<ValidationResult> {
787
+ const errors: string[] = [];
788
+ const warnings: string[] = [];
789
+
790
+ // Check for potentially dangerous patterns
791
+ const mainPath = path.join(sourcePath, manifest.main);
792
+ if (await this.fileExists(mainPath)) {
793
+ const content = await fs.readFile(mainPath, 'utf-8');
794
+
795
+ // Check for dynamic code execution patterns (security validation)
796
+ if (/\bFunction\s*\(/.test(content)) {
797
+ warnings.push('Code contains Function constructor which may pose security risks');
798
+ }
799
+
800
+ // Check for dynamic requires without permissions
801
+ if (/require\s*\([^'"]+\)/.test(content) && !manifest.permissions?.includes('shell')) {
802
+ warnings.push('Code contains dynamic requires');
803
+ }
804
+ }
805
+
806
+ return { valid: errors.length === 0, errors, warnings };
807
+ }
808
+
809
+ private async fileExists(filePath: string): Promise<boolean> {
810
+ try {
811
+ await fs.access(filePath);
812
+ return true;
813
+ } catch {
814
+ return false;
815
+ }
816
+ }
817
+
818
+ private async readManifest(manifestPath: string): Promise<AgentManifest> {
819
+ const content = await fs.readFile(manifestPath, 'utf-8');
820
+ return JSON.parse(content);
821
+ }
822
+
823
+ private async calculateDirectorySize(dirPath: string): Promise<number> {
824
+ let size = 0;
825
+ const files = await glob('**/*', { cwd: dirPath, nodir: true });
826
+
827
+ for (const file of files) {
828
+ const stat = await fs.stat(path.join(dirPath, file));
829
+ size += stat.size;
830
+ }
831
+
832
+ return size;
833
+ }
834
+ }
835
+ ```
836
+
837
+ ---
838
+
839
+ ## 3. PublishingPipeline
840
+
841
+ ### Proposito
842
+
843
+ Flujo de publicacion con validacion automatica, review y rollback.
844
+
845
+ ### Interfaces
846
+
847
+ ```typescript
848
+ interface PublishingPipeline {
849
+ // Submission
850
+ submit(packagePath: string, options?: SubmitOptions): Promise<Submission>;
851
+ getSubmission(id: string): Promise<Submission | null>;
852
+ cancelSubmission(id: string): Promise<void>;
853
+
854
+ // Review process
855
+ startReview(submissionId: string): Promise<ReviewProcess>;
856
+ getReviewStatus(submissionId: string): Promise<ReviewStatus>;
857
+
858
+ // Publishing
859
+ approve(submissionId: string, reviewerId: string): Promise<void>;
860
+ reject(submissionId: string, reason: string, reviewerId: string): Promise<void>;
861
+ publish(submissionId: string): Promise<PublishResult>;
862
+
863
+ // Rollback
864
+ unpublish(name: string, version: string, reason: string): Promise<void>;
865
+ rollback(name: string, toVersion: string): Promise<RollbackResult>;
866
+
867
+ // Webhooks
868
+ onStageChange(callback: (submission: Submission, stage: PublishStage) => void): Disposable;
869
+ }
870
+
871
+ type PublishStage = 'submit' | 'validate' | 'review' | 'approve' | 'publish' | 'rejected';
872
+
873
+ interface Submission {
874
+ id: string;
875
+ packagePath: string;
876
+ manifest: AgentManifest;
877
+ submittedBy: string;
878
+ submittedAt: Date;
879
+ stage: PublishStage;
880
+ stageHistory: StageHistoryEntry[];
881
+ validation?: ValidationResult;
882
+ review?: ReviewProcess;
883
+ publishedAt?: Date;
884
+ rejectionReason?: string;
885
+ }
886
+
887
+ interface StageHistoryEntry {
888
+ stage: PublishStage;
889
+ timestamp: Date;
890
+ actor?: string;
891
+ notes?: string;
892
+ }
893
+
894
+ interface SubmitOptions {
895
+ releaseNotes?: string;
896
+ prerelease?: boolean;
897
+ tags?: string[];
898
+ }
899
+
900
+ interface ReviewProcess {
901
+ id: string;
902
+ submissionId: string;
903
+ startedAt: Date;
904
+ completedAt?: Date;
905
+ status: 'pending' | 'in_progress' | 'passed' | 'failed';
906
+
907
+ // Automated checks
908
+ automatedChecks: AutomatedCheck[];
909
+ automatedScore: number;
910
+
911
+ // Manual review (if needed)
912
+ requiresManualReview: boolean;
913
+ manualReviewer?: string;
914
+ manualReviewNotes?: string;
915
+ }
916
+
917
+ interface AutomatedCheck {
918
+ name: string;
919
+ description: string;
920
+ status: 'pending' | 'running' | 'passed' | 'failed' | 'skipped';
921
+ result?: {
922
+ passed: boolean;
923
+ score: number;
924
+ details: string;
925
+ duration: number;
926
+ };
927
+ }
928
+
929
+ interface ReviewStatus {
930
+ stage: PublishStage;
931
+ automatedChecks: {
932
+ total: number;
933
+ passed: number;
934
+ failed: number;
935
+ pending: number;
936
+ };
937
+ score: number;
938
+ requiresManualReview: boolean;
939
+ estimatedCompletion?: Date;
940
+ }
941
+
942
+ interface PublishResult {
943
+ success: boolean;
944
+ name: string;
945
+ version: string;
946
+ publishedAt: Date;
947
+ url: string;
948
+ }
949
+
950
+ interface RollbackResult {
951
+ success: boolean;
952
+ previousVersion: string;
953
+ newVersion: string;
954
+ affectedInstalls: number;
955
+ }
956
+ ```
957
+
958
+ ### Implementacion
959
+
960
+ ```typescript
961
+ class PublishingPipelineImpl implements PublishingPipeline {
962
+ private submissions: Map<string, Submission> = new Map();
963
+ private stageCallbacks: Set<Function> = new Set();
964
+
965
+ constructor(
966
+ private config: MarketplaceConfig,
967
+ private packager: AgentPackager,
968
+ private registry: MarketplaceRegistry,
969
+ private testRunner: TestRunner,
970
+ private notifier: NotificationService
971
+ ) {}
972
+
973
+ async submit(packagePath: string, options: SubmitOptions = {}): Promise<Submission> {
974
+ // Inspect package
975
+ const info = await this.packager.inspect(packagePath);
976
+
977
+ // Check if version already exists
978
+ const existing = await this.registry.get(info.manifest.name, info.manifest.version);
979
+ if (existing) {
980
+ throw new PublishError(`Version ${info.manifest.version} already exists for ${info.manifest.name}`);
981
+ }
982
+
983
+ const submission: Submission = {
984
+ id: this.generateId(),
985
+ packagePath,
986
+ manifest: info.manifest,
987
+ submittedBy: this.getCurrentUser(),
988
+ submittedAt: new Date(),
989
+ stage: 'submit',
990
+ stageHistory: [{
991
+ stage: 'submit',
992
+ timestamp: new Date()
993
+ }]
994
+ };
995
+
996
+ this.submissions.set(submission.id, submission);
997
+
998
+ // Start validation automatically
999
+ this.processSubmission(submission);
1000
+
1001
+ return submission;
1002
+ }
1003
+
1004
+ private async processSubmission(submission: Submission): Promise<void> {
1005
+ try {
1006
+ // Stage: Validate
1007
+ await this.transitionStage(submission, 'validate');
1008
+ submission.validation = await this.packager.validate(
1009
+ path.dirname(submission.packagePath)
1010
+ );
1011
+
1012
+ if (!submission.validation.valid) {
1013
+ await this.transitionStage(submission, 'rejected', {
1014
+ notes: `Validation failed: ${submission.validation.errors.join(', ')}`
1015
+ });
1016
+ return;
1017
+ }
1018
+
1019
+ // Stage: Review
1020
+ await this.transitionStage(submission, 'review');
1021
+ const review = await this.startReview(submission.id);
1022
+
1023
+ // Wait for automated checks
1024
+ await this.waitForAutomatedChecks(review);
1025
+
1026
+ // Check if manual review is needed
1027
+ if (review.requiresManualReview) {
1028
+ this.notifier.notifyReviewers(submission);
1029
+ return; // Wait for manual approval
1030
+ }
1031
+
1032
+ // Auto-approve if score is high enough
1033
+ if (review.automatedScore >= this.config.publishing.manualReviewThreshold) {
1034
+ await this.approve(submission.id, 'system');
1035
+ }
1036
+
1037
+ } catch (error) {
1038
+ await this.transitionStage(submission, 'rejected', {
1039
+ notes: `Processing error: ${error.message}`
1040
+ });
1041
+ }
1042
+ }
1043
+
1044
+ async startReview(submissionId: string): Promise<ReviewProcess> {
1045
+ const submission = this.submissions.get(submissionId);
1046
+ if (!submission) throw new Error('Submission not found');
1047
+
1048
+ const review: ReviewProcess = {
1049
+ id: this.generateId(),
1050
+ submissionId,
1051
+ startedAt: new Date(),
1052
+ status: 'in_progress',
1053
+ automatedChecks: this.createAutomatedChecks(),
1054
+ automatedScore: 0,
1055
+ requiresManualReview: false
1056
+ };
1057
+
1058
+ submission.review = review;
1059
+
1060
+ // Run automated checks
1061
+ await this.runAutomatedChecks(submission, review);
1062
+
1063
+ return review;
1064
+ }
1065
+
1066
+ private createAutomatedChecks(): AutomatedCheck[] {
1067
+ return [
1068
+ { name: 'manifest_validation', description: 'Validate manifest structure', status: 'pending' },
1069
+ { name: 'code_security', description: 'Security analysis of code', status: 'pending' },
1070
+ { name: 'dependency_check', description: 'Check dependencies for vulnerabilities', status: 'pending' },
1071
+ { name: 'unit_tests', description: 'Run unit tests', status: 'pending' },
1072
+ { name: 'integration_tests', description: 'Run integration tests', status: 'pending' },
1073
+ { name: 'compatibility_tests', description: 'Test ELSABRO version compatibility', status: 'pending' },
1074
+ { name: 'performance_check', description: 'Basic performance benchmarks', status: 'pending' },
1075
+ { name: 'documentation_check', description: 'Verify documentation exists', status: 'pending' }
1076
+ ];
1077
+ }
1078
+
1079
+ private async runAutomatedChecks(submission: Submission, review: ReviewProcess): Promise<void> {
1080
+ let totalScore = 0;
1081
+ let checkCount = 0;
1082
+
1083
+ for (const check of review.automatedChecks) {
1084
+ check.status = 'running';
1085
+ const startTime = Date.now();
1086
+
1087
+ try {
1088
+ const result = await this.runCheck(check.name, submission);
1089
+ check.status = result.passed ? 'passed' : 'failed';
1090
+ check.result = {
1091
+ ...result,
1092
+ duration: Date.now() - startTime
1093
+ };
1094
+
1095
+ totalScore += result.score;
1096
+ checkCount++;
1097
+
1098
+ // If critical check fails, require manual review
1099
+ if (!result.passed && ['code_security', 'dependency_check'].includes(check.name)) {
1100
+ review.requiresManualReview = true;
1101
+ }
1102
+
1103
+ } catch (error) {
1104
+ check.status = 'failed';
1105
+ check.result = {
1106
+ passed: false,
1107
+ score: 0,
1108
+ details: error.message,
1109
+ duration: Date.now() - startTime
1110
+ };
1111
+ }
1112
+ }
1113
+
1114
+ review.automatedScore = checkCount > 0 ? totalScore / checkCount : 0;
1115
+ review.status = review.automatedChecks.every(c => c.status === 'passed') ? 'passed' : 'failed';
1116
+
1117
+ // High-risk permissions always require manual review
1118
+ const highRiskPerms = ['shell', 'secrets'];
1119
+ if (submission.manifest.permissions?.some(p => highRiskPerms.includes(p))) {
1120
+ review.requiresManualReview = true;
1121
+ }
1122
+ }
1123
+
1124
+ private async runCheck(checkName: string, submission: Submission): Promise<{passed: boolean; score: number; details: string}> {
1125
+ switch (checkName) {
1126
+ case 'manifest_validation':
1127
+ const validation = this.packager.validateManifest(submission.manifest);
1128
+ return {
1129
+ passed: validation.valid,
1130
+ score: validation.valid ? 1 : 0,
1131
+ details: validation.errors.join('; ') || 'Manifest is valid'
1132
+ };
1133
+
1134
+ case 'unit_tests':
1135
+ const testResult = await this.testRunner.runTests(submission.packagePath, 'unit');
1136
+ return {
1137
+ passed: testResult.passed && testResult.coverage >= this.config.testing.minCoverage,
1138
+ score: testResult.coverage / 100,
1139
+ details: `${testResult.passed}/${testResult.total} tests passed, ${testResult.coverage}% coverage`
1140
+ };
1141
+
1142
+ case 'code_security':
1143
+ const securityResult = await this.runSecurityScan(submission.packagePath);
1144
+ return {
1145
+ passed: securityResult.vulnerabilities.high === 0,
1146
+ score: securityResult.score,
1147
+ details: `Found ${securityResult.vulnerabilities.total} vulnerabilities`
1148
+ };
1149
+
1150
+ default:
1151
+ return { passed: true, score: 1, details: 'Check passed' };
1152
+ }
1153
+ }
1154
+
1155
+ async approve(submissionId: string, reviewerId: string): Promise<void> {
1156
+ const submission = this.submissions.get(submissionId);
1157
+ if (!submission) throw new Error('Submission not found');
1158
+
1159
+ if (submission.stage !== 'review') {
1160
+ throw new Error(`Cannot approve submission in stage: ${submission.stage}`);
1161
+ }
1162
+
1163
+ await this.transitionStage(submission, 'approve', { actor: reviewerId });
1164
+
1165
+ // Auto-publish after approval
1166
+ await this.publish(submissionId);
1167
+ }
1168
+
1169
+ async reject(submissionId: string, reason: string, reviewerId: string): Promise<void> {
1170
+ const submission = this.submissions.get(submissionId);
1171
+ if (!submission) throw new Error('Submission not found');
1172
+
1173
+ submission.rejectionReason = reason;
1174
+ await this.transitionStage(submission, 'rejected', {
1175
+ actor: reviewerId,
1176
+ notes: reason
1177
+ });
1178
+
1179
+ // Notify submitter
1180
+ this.notifier.notifyRejection(submission, reason);
1181
+ }
1182
+
1183
+ async publish(submissionId: string): Promise<PublishResult> {
1184
+ const submission = this.submissions.get(submissionId);
1185
+ if (!submission) throw new Error('Submission not found');
1186
+
1187
+ if (submission.stage !== 'approve') {
1188
+ throw new Error(`Cannot publish submission in stage: ${submission.stage}`);
1189
+ }
1190
+
1191
+ try {
1192
+ // Upload to registry
1193
+ const result = await this.uploadToRegistry(submission);
1194
+
1195
+ submission.publishedAt = new Date();
1196
+ await this.transitionStage(submission, 'publish');
1197
+
1198
+ // Trigger webhooks
1199
+ await this.triggerWebhook('onPublish', submission);
1200
+
1201
+ return result;
1202
+
1203
+ } catch (error) {
1204
+ // Automatic rollback on failure
1205
+ await this.transitionStage(submission, 'rejected', {
1206
+ notes: `Publish failed: ${error.message}`
1207
+ });
1208
+ throw error;
1209
+ }
1210
+ }
1211
+
1212
+ async unpublish(name: string, version: string, reason: string): Promise<void> {
1213
+ await this.registry.removeVersion(name, version);
1214
+ this.notifier.notifyUnpublish(name, version, reason);
1215
+ }
1216
+
1217
+ async rollback(name: string, toVersion: string): Promise<RollbackResult> {
1218
+ const versions = await this.registry.getVersions(name);
1219
+ const currentVersion = versions[0]?.version;
1220
+
1221
+ if (!currentVersion) {
1222
+ throw new Error('No published versions found');
1223
+ }
1224
+
1225
+ // Mark newer versions as deprecated
1226
+ for (const ver of versions) {
1227
+ if (semver.gt(ver.version, toVersion)) {
1228
+ await this.registry.deprecateVersion(name, ver.version, `Rolled back to ${toVersion}`);
1229
+ }
1230
+ }
1231
+
1232
+ return {
1233
+ success: true,
1234
+ previousVersion: currentVersion,
1235
+ newVersion: toVersion,
1236
+ affectedInstalls: await this.countAffectedInstalls(name, currentVersion)
1237
+ };
1238
+ }
1239
+
1240
+ private async transitionStage(
1241
+ submission: Submission,
1242
+ stage: PublishStage,
1243
+ options: { actor?: string; notes?: string } = {}
1244
+ ): Promise<void> {
1245
+ submission.stage = stage;
1246
+ submission.stageHistory.push({
1247
+ stage,
1248
+ timestamp: new Date(),
1249
+ actor: options.actor,
1250
+ notes: options.notes
1251
+ });
1252
+
1253
+ this.stageCallbacks.forEach(cb => cb(submission, stage));
1254
+ }
1255
+
1256
+ onStageChange(callback: (submission: Submission, stage: PublishStage) => void): Disposable {
1257
+ this.stageCallbacks.add(callback);
1258
+ return { dispose: () => this.stageCallbacks.delete(callback) };
1259
+ }
1260
+
1261
+ private generateId(): string {
1262
+ return `sub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1263
+ }
1264
+ }
1265
+ ```
1266
+
1267
+ ---
1268
+
1269
+ ## 4. ReviewSystem
1270
+
1271
+ ### Proposito
1272
+
1273
+ Sistema de ratings, reviews de texto y metricas de uso.
1274
+
1275
+ ### Interfaces
1276
+
1277
+ ```typescript
1278
+ interface ReviewSystem {
1279
+ // Reviews
1280
+ submitReview(agentName: string, review: ReviewInput): Promise<Review>;
1281
+ updateReview(reviewId: string, updates: Partial<ReviewInput>): Promise<Review>;
1282
+ deleteReview(reviewId: string): Promise<void>;
1283
+ getReviews(agentName: string, options?: ReviewQueryOptions): Promise<ReviewResult>;
1284
+
1285
+ // Ratings
1286
+ getRating(agentName: string): Promise<RatingSummary>;
1287
+ getUserRating(agentName: string, userId: string): Promise<number | null>;
1288
+
1289
+ // Metrics
1290
+ getMetrics(agentName: string): Promise<AgentMetrics>;
1291
+ trackUsage(agentName: string, event: UsageEvent): Promise<void>;
1292
+
1293
+ // Reporting
1294
+ reportIssue(agentName: string, report: IssueReport): Promise<ReportResult>;
1295
+ getReports(agentName: string): Promise<IssueReport[]>;
1296
+ }
1297
+
1298
+ interface ReviewInput {
1299
+ rating: number; // 1-5
1300
+ title?: string;
1301
+ body?: string;
1302
+ pros?: string[];
1303
+ cons?: string[];
1304
+ version: string;
1305
+ }
1306
+
1307
+ interface Review {
1308
+ id: string;
1309
+ agentName: string;
1310
+ userId: string;
1311
+ userName: string;
1312
+ rating: number;
1313
+ title?: string;
1314
+ body?: string;
1315
+ pros?: string[];
1316
+ cons?: string[];
1317
+ version: string;
1318
+ createdAt: Date;
1319
+ updatedAt?: Date;
1320
+ helpful: number;
1321
+ verified: boolean; // User actually installed the agent
1322
+
1323
+ // Publisher response
1324
+ response?: {
1325
+ body: string;
1326
+ respondedAt: Date;
1327
+ };
1328
+ }
1329
+
1330
+ interface ReviewQueryOptions {
1331
+ sortBy?: 'recent' | 'helpful' | 'rating_high' | 'rating_low';
1332
+ filterRating?: number;
1333
+ filterVersion?: string;
1334
+ verified?: boolean;
1335
+ page?: number;
1336
+ limit?: number;
1337
+ }
1338
+
1339
+ interface ReviewResult {
1340
+ items: Review[];
1341
+ total: number;
1342
+ page: number;
1343
+ summary: RatingSummary;
1344
+ }
1345
+
1346
+ interface RatingSummary {
1347
+ average: number;
1348
+ total: number;
1349
+ distribution: {
1350
+ 1: number;
1351
+ 2: number;
1352
+ 3: number;
1353
+ 4: number;
1354
+ 5: number;
1355
+ };
1356
+ trend: 'up' | 'down' | 'stable';
1357
+ trendValue: number;
1358
+ }
1359
+
1360
+ interface AgentMetrics {
1361
+ // Downloads
1362
+ downloads: {
1363
+ total: number;
1364
+ lastWeek: number;
1365
+ lastMonth: number;
1366
+ trend: number; // percentage change
1367
+ };
1368
+
1369
+ // Active users
1370
+ activeUsers: {
1371
+ daily: number;
1372
+ weekly: number;
1373
+ monthly: number;
1374
+ };
1375
+
1376
+ // Success rate
1377
+ successRate: {
1378
+ overall: number;
1379
+ lastWeek: number;
1380
+ byVersion: Record<string, number>;
1381
+ };
1382
+
1383
+ // Performance
1384
+ performance: {
1385
+ avgExecutionTime: number;
1386
+ p95ExecutionTime: number;
1387
+ errorRate: number;
1388
+ };
1389
+
1390
+ // Retention
1391
+ retention: {
1392
+ day1: number;
1393
+ day7: number;
1394
+ day30: number;
1395
+ };
1396
+ }
1397
+
1398
+ interface UsageEvent {
1399
+ type: 'install' | 'uninstall' | 'update' | 'execute' | 'error';
1400
+ version: string;
1401
+ duration?: number;
1402
+ success?: boolean;
1403
+ errorCode?: string;
1404
+ metadata?: Record<string, unknown>;
1405
+ }
1406
+
1407
+ interface IssueReport {
1408
+ id: string;
1409
+ agentName: string;
1410
+ type: 'bug' | 'security' | 'inappropriate' | 'license';
1411
+ title: string;
1412
+ description: string;
1413
+ reportedBy: string;
1414
+ reportedAt: Date;
1415
+ status: 'open' | 'investigating' | 'resolved' | 'dismissed';
1416
+ severity: 'low' | 'medium' | 'high' | 'critical';
1417
+ version?: string;
1418
+ evidence?: string[];
1419
+ }
1420
+ ```
1421
+
1422
+ ### Implementacion
1423
+
1424
+ ```typescript
1425
+ class ReviewSystemImpl implements ReviewSystem {
1426
+ constructor(
1427
+ private config: MarketplaceConfig,
1428
+ private db: Database,
1429
+ private installationManager: InstallationManager,
1430
+ private moderator: ContentModerator
1431
+ ) {}
1432
+
1433
+ async submitReview(agentName: string, input: ReviewInput): Promise<Review> {
1434
+ const userId = this.getCurrentUserId();
1435
+
1436
+ // Validate rating
1437
+ if (input.rating < 1 || input.rating > 5) {
1438
+ throw new ValidationError('Rating must be between 1 and 5');
1439
+ }
1440
+
1441
+ // Check if user has installed the agent
1442
+ const hasInstalled = await this.installationManager.hasInstalled(agentName, userId);
1443
+
1444
+ // Check for existing review
1445
+ const existing = await this.db.reviews.findOne({ agentName, userId });
1446
+ if (existing) {
1447
+ throw new ValidationError('You have already reviewed this agent. Use updateReview instead.');
1448
+ }
1449
+
1450
+ // Moderate content if enabled
1451
+ if (this.config.reviews.moderationEnabled && input.body) {
1452
+ const moderation = await this.moderator.check(input.body);
1453
+ if (!moderation.approved) {
1454
+ throw new ModerationError('Review content violates community guidelines');
1455
+ }
1456
+ }
1457
+
1458
+ const review: Review = {
1459
+ id: this.generateId(),
1460
+ agentName,
1461
+ userId,
1462
+ userName: await this.getUserName(userId),
1463
+ rating: input.rating,
1464
+ title: input.title,
1465
+ body: input.body,
1466
+ pros: input.pros,
1467
+ cons: input.cons,
1468
+ version: input.version,
1469
+ createdAt: new Date(),
1470
+ helpful: 0,
1471
+ verified: hasInstalled
1472
+ };
1473
+
1474
+ await this.db.reviews.insert(review);
1475
+ await this.updateRatingCache(agentName);
1476
+
1477
+ return review;
1478
+ }
1479
+
1480
+ async getRating(agentName: string): Promise<RatingSummary> {
1481
+ const reviews = await this.db.reviews.find({ agentName });
1482
+
1483
+ if (reviews.length === 0) {
1484
+ return {
1485
+ average: 0,
1486
+ total: 0,
1487
+ distribution: { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 },
1488
+ trend: 'stable',
1489
+ trendValue: 0
1490
+ };
1491
+ }
1492
+
1493
+ const distribution = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
1494
+ let sum = 0;
1495
+
1496
+ for (const review of reviews) {
1497
+ distribution[review.rating as 1|2|3|4|5]++;
1498
+ sum += review.rating;
1499
+ }
1500
+
1501
+ const average = sum / reviews.length;
1502
+
1503
+ // Calculate trend (last 30 days vs previous 30 days)
1504
+ const now = new Date();
1505
+ const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
1506
+ const sixtyDaysAgo = new Date(now.getTime() - 60 * 24 * 60 * 60 * 1000);
1507
+
1508
+ const recentReviews = reviews.filter(r => r.createdAt > thirtyDaysAgo);
1509
+ const previousReviews = reviews.filter(r => r.createdAt > sixtyDaysAgo && r.createdAt <= thirtyDaysAgo);
1510
+
1511
+ const recentAvg = recentReviews.length > 0
1512
+ ? recentReviews.reduce((s, r) => s + r.rating, 0) / recentReviews.length
1513
+ : average;
1514
+ const previousAvg = previousReviews.length > 0
1515
+ ? previousReviews.reduce((s, r) => s + r.rating, 0) / previousReviews.length
1516
+ : average;
1517
+
1518
+ const trendValue = recentAvg - previousAvg;
1519
+ const trend = trendValue > 0.1 ? 'up' : trendValue < -0.1 ? 'down' : 'stable';
1520
+
1521
+ return {
1522
+ average: Math.round(average * 10) / 10,
1523
+ total: reviews.length,
1524
+ distribution,
1525
+ trend,
1526
+ trendValue: Math.round(trendValue * 100) / 100
1527
+ };
1528
+ }
1529
+
1530
+ async getMetrics(agentName: string): Promise<AgentMetrics> {
1531
+ const now = new Date();
1532
+ const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
1533
+ const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
1534
+
1535
+ // Get usage events
1536
+ const events = await this.db.usageEvents.find({ agentName });
1537
+
1538
+ // Calculate downloads
1539
+ const installs = events.filter(e => e.type === 'install');
1540
+ const lastWeekInstalls = installs.filter(e => e.timestamp > weekAgo);
1541
+ const lastMonthInstalls = installs.filter(e => e.timestamp > monthAgo);
1542
+
1543
+ // Calculate success rate
1544
+ const executions = events.filter(e => e.type === 'execute');
1545
+ const successfulExecs = executions.filter(e => e.success);
1546
+
1547
+ // Calculate performance
1548
+ const durations = executions.filter(e => e.duration).map(e => e.duration!);
1549
+ durations.sort((a, b) => a - b);
1550
+
1551
+ const errors = events.filter(e => e.type === 'error');
1552
+
1553
+ return {
1554
+ downloads: {
1555
+ total: installs.length,
1556
+ lastWeek: lastWeekInstalls.length,
1557
+ lastMonth: lastMonthInstalls.length,
1558
+ trend: 0
1559
+ },
1560
+ activeUsers: {
1561
+ daily: await this.countActiveUsers(agentName, 1),
1562
+ weekly: await this.countActiveUsers(agentName, 7),
1563
+ monthly: await this.countActiveUsers(agentName, 30)
1564
+ },
1565
+ successRate: {
1566
+ overall: executions.length > 0 ? (successfulExecs.length / executions.length) * 100 : 100,
1567
+ lastWeek: this.calculateSuccessRate(executions.filter(e => e.timestamp > weekAgo)),
1568
+ byVersion: this.calculateSuccessRateByVersion(executions)
1569
+ },
1570
+ performance: {
1571
+ avgExecutionTime: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
1572
+ p95ExecutionTime: durations.length > 0 ? durations[Math.floor(durations.length * 0.95)] : 0,
1573
+ errorRate: executions.length > 0 ? (errors.length / executions.length) * 100 : 0
1574
+ },
1575
+ retention: await this.calculateRetention(agentName)
1576
+ };
1577
+ }
1578
+
1579
+ async trackUsage(agentName: string, event: UsageEvent): Promise<void> {
1580
+ await this.db.usageEvents.insert({
1581
+ agentName,
1582
+ userId: this.getCurrentUserId(),
1583
+ timestamp: new Date(),
1584
+ ...event
1585
+ });
1586
+ }
1587
+
1588
+ async reportIssue(agentName: string, report: Omit<IssueReport, 'id' | 'reportedBy' | 'reportedAt' | 'status'>): Promise<ReportResult> {
1589
+ // Validate description length
1590
+ if (report.description.length < this.config.reporting.minDescriptionLength) {
1591
+ throw new ValidationError(`Description must be at least ${this.config.reporting.minDescriptionLength} characters`);
1592
+ }
1593
+
1594
+ const issueReport: IssueReport = {
1595
+ id: this.generateId(),
1596
+ agentName,
1597
+ ...report,
1598
+ reportedBy: this.getCurrentUserId(),
1599
+ reportedAt: new Date(),
1600
+ status: 'open'
1601
+ };
1602
+
1603
+ await this.db.reports.insert(issueReport);
1604
+
1605
+ // Notify publisher if configured
1606
+ if (this.config.reporting.notifyPublisher) {
1607
+ await this.notifyPublisher(agentName, issueReport);
1608
+ }
1609
+
1610
+ // Auto-escalate security issues
1611
+ if (report.type === 'security' && report.severity === 'critical') {
1612
+ await this.escalateToSecurityTeam(issueReport);
1613
+ }
1614
+
1615
+ return {
1616
+ id: issueReport.id,
1617
+ status: 'submitted',
1618
+ message: 'Your report has been submitted and will be reviewed.'
1619
+ };
1620
+ }
1621
+
1622
+ private generateId(): string {
1623
+ return `rev_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1624
+ }
1625
+ }
1626
+ ```
1627
+
1628
+ ---
1629
+
1630
+ ## 5. InstallationManager
1631
+
1632
+ ### Proposito
1633
+
1634
+ Gestion de instalacion, actualizacion y ejecucion sandboxed de agentes.
1635
+
1636
+ ### Interfaces
1637
+
1638
+ ```typescript
1639
+ interface InstallationManager {
1640
+ // Installation
1641
+ install(name: string, version?: string, options?: InstallOptions): Promise<InstalledAgent>;
1642
+ installFromPath(packagePath: string, options?: InstallOptions): Promise<InstalledAgent>;
1643
+ uninstall(name: string): Promise<void>;
1644
+
1645
+ // Updates
1646
+ update(name: string, version?: string): Promise<InstalledAgent>;
1647
+ checkUpdates(): Promise<UpdateInfo[]>;
1648
+ updateAll(): Promise<UpdateResult[]>;
1649
+
1650
+ // Queries
1651
+ list(): Promise<InstalledAgent[]>;
1652
+ get(name: string): Promise<InstalledAgent | null>;
1653
+ isInstalled(name: string): Promise<boolean>;
1654
+
1655
+ // Dependencies
1656
+ resolveDependencies(name: string, version: string): Promise<DependencyTree>;
1657
+
1658
+ // Execution
1659
+ load(name: string): Promise<LoadedAgent>;
1660
+ execute(name: string, input: AgentInput): Promise<AgentOutput>;
1661
+
1662
+ // Sandbox
1663
+ createSandbox(agent: InstalledAgent): AgentSandbox;
1664
+ }
1665
+
1666
+ interface InstalledAgent {
1667
+ name: string;
1668
+ version: string;
1669
+ displayName: string;
1670
+ description: string;
1671
+ category: AgentCategory;
1672
+
1673
+ // Paths
1674
+ installPath: string;
1675
+ mainPath: string;
1676
+
1677
+ // Metadata
1678
+ installedAt: Date;
1679
+ updatedAt?: Date;
1680
+ installedBy: string;
1681
+
1682
+ // State
1683
+ enabled: boolean;
1684
+ loaded: boolean;
1685
+
1686
+ // Manifest
1687
+ manifest: AgentManifest;
1688
+
1689
+ // Dependencies
1690
+ dependencies: InstalledDependency[];
1691
+ }
1692
+
1693
+ interface InstalledDependency {
1694
+ name: string;
1695
+ version: string;
1696
+ required: string;
1697
+ satisfied: boolean;
1698
+ }
1699
+
1700
+ interface InstallOptions {
1701
+ global?: boolean;
1702
+ force?: boolean;
1703
+ skipDependencies?: boolean;
1704
+ skipVerification?: boolean;
1705
+ }
1706
+
1707
+ interface UpdateInfo {
1708
+ name: string;
1709
+ currentVersion: string;
1710
+ latestVersion: string;
1711
+ updateType: 'major' | 'minor' | 'patch';
1712
+ breaking: boolean;
1713
+ changelog?: string;
1714
+ }
1715
+
1716
+ interface DependencyTree {
1717
+ name: string;
1718
+ version: string;
1719
+ dependencies: DependencyTree[];
1720
+ conflicts: DependencyConflict[];
1721
+ }
1722
+
1723
+ interface DependencyConflict {
1724
+ package: string;
1725
+ required: string[];
1726
+ installed?: string;
1727
+ resolution: 'upgrade' | 'downgrade' | 'unresolvable';
1728
+ }
1729
+
1730
+ interface AgentSandbox {
1731
+ // Permissions
1732
+ permissions: Set<AgentPermission>;
1733
+
1734
+ // Resource limits
1735
+ limits: {
1736
+ memory: number;
1737
+ cpu: number;
1738
+ timeout: number;
1739
+ };
1740
+
1741
+ // Execution
1742
+ execute<T>(fn: () => Promise<T>): Promise<T>;
1743
+
1744
+ // Cleanup
1745
+ dispose(): void;
1746
+ }
1747
+ ```
1748
+
1749
+ ### Implementacion
1750
+
1751
+ ```typescript
1752
+ class InstallationManagerImpl implements InstallationManager {
1753
+ private installed: Map<string, InstalledAgent> = new Map();
1754
+ private loaded: Map<string, LoadedAgent> = new Map();
1755
+ private lockfile: Lockfile;
1756
+
1757
+ constructor(
1758
+ private config: MarketplaceConfig,
1759
+ private registry: MarketplaceRegistry,
1760
+ private packager: AgentPackager,
1761
+ private reviewSystem: ReviewSystem
1762
+ ) {
1763
+ this.lockfile = new Lockfile(this.config.installation.lockFile);
1764
+ }
1765
+
1766
+ async install(name: string, version?: string, options: InstallOptions = {}): Promise<InstalledAgent> {
1767
+ // Get agent info from registry
1768
+ const targetVersion = version || await this.registry.getLatestVersion(name);
1769
+ const agentInfo = await this.registry.get(name, targetVersion);
1770
+
1771
+ if (!agentInfo) {
1772
+ throw new InstallError(`Agent not found: ${name}@${targetVersion}`);
1773
+ }
1774
+
1775
+ // Check compatibility
1776
+ const compatibility = await this.registry.checkCompatibility(name, targetVersion);
1777
+ if (!compatibility.compatible && !options.force) {
1778
+ throw new InstallError(`Incompatible agent: ${compatibility.issues.map(i => i.message).join(', ')}`);
1779
+ }
1780
+
1781
+ // Resolve dependencies
1782
+ if (!options.skipDependencies) {
1783
+ const depTree = await this.resolveDependencies(name, targetVersion);
1784
+
1785
+ if (depTree.conflicts.some(c => c.resolution === 'unresolvable')) {
1786
+ throw new DependencyError('Unresolvable dependency conflicts', depTree.conflicts);
1787
+ }
1788
+
1789
+ // Install dependencies first
1790
+ await this.installDependencies(depTree);
1791
+ }
1792
+
1793
+ // Download package
1794
+ const packagePath = await this.downloadPackage(name, targetVersion);
1795
+
1796
+ // Verify package
1797
+ if (!options.skipVerification) {
1798
+ const verification = await this.packager.verify(packagePath);
1799
+ if (!verification.valid) {
1800
+ throw new VerificationError('Package verification failed', verification.issues);
1801
+ }
1802
+
1803
+ if (!verification.signed && this.config.signing.warnUnsigned) {
1804
+ console.warn(`Warning: Installing unsigned package ${name}@${targetVersion}`);
1805
+ }
1806
+ }
1807
+
1808
+ // Determine install path
1809
+ const installPath = options.global
1810
+ ? path.join(this.config.installation.globalPath, name)
1811
+ : path.join(this.config.installation.defaultPath, name);
1812
+
1813
+ // Backup existing if updating
1814
+ const existing = await this.get(name);
1815
+ if (existing && this.config.installation.backupBeforeUpdate) {
1816
+ await this.backupAgent(existing);
1817
+ }
1818
+
1819
+ // Unpack
1820
+ const unpackResult = await this.packager.unpack(packagePath, installPath);
1821
+
1822
+ // Create installed agent record
1823
+ const installedAgent: InstalledAgent = {
1824
+ name,
1825
+ version: targetVersion,
1826
+ displayName: unpackResult.manifest.displayName,
1827
+ description: unpackResult.manifest.description,
1828
+ category: unpackResult.manifest.category,
1829
+ installPath,
1830
+ mainPath: path.join(installPath, unpackResult.manifest.main),
1831
+ installedAt: new Date(),
1832
+ installedBy: this.getCurrentUserId(),
1833
+ enabled: true,
1834
+ loaded: false,
1835
+ manifest: unpackResult.manifest,
1836
+ dependencies: await this.getInstalledDependencies(unpackResult.manifest)
1837
+ };
1838
+
1839
+ // Save to lockfile
1840
+ this.installed.set(name, installedAgent);
1841
+ await this.lockfile.add(installedAgent);
1842
+
1843
+ // Track installation
1844
+ await this.reviewSystem.trackUsage(name, {
1845
+ type: 'install',
1846
+ version: targetVersion
1847
+ });
1848
+
1849
+ return installedAgent;
1850
+ }
1851
+
1852
+ async uninstall(name: string): Promise<void> {
1853
+ const agent = await this.get(name);
1854
+ if (!agent) {
1855
+ throw new Error(`Agent not installed: ${name}`);
1856
+ }
1857
+
1858
+ // Check if other agents depend on this one
1859
+ const dependents = await this.findDependents(name);
1860
+ if (dependents.length > 0) {
1861
+ throw new DependencyError(
1862
+ `Cannot uninstall: other agents depend on ${name}`,
1863
+ dependents.map(d => ({ name: d.name, required: d.manifest.dependencies?.[name] || '*' }))
1864
+ );
1865
+ }
1866
+
1867
+ // Unload if loaded
1868
+ if (this.loaded.has(name)) {
1869
+ await this.unload(name);
1870
+ }
1871
+
1872
+ // Remove files
1873
+ await fs.rm(agent.installPath, { recursive: true, force: true });
1874
+
1875
+ // Update records
1876
+ this.installed.delete(name);
1877
+ await this.lockfile.remove(name);
1878
+
1879
+ // Track uninstall
1880
+ await this.reviewSystem.trackUsage(name, {
1881
+ type: 'uninstall',
1882
+ version: agent.version
1883
+ });
1884
+ }
1885
+
1886
+ async checkUpdates(): Promise<UpdateInfo[]> {
1887
+ const updates: UpdateInfo[] = [];
1888
+
1889
+ for (const [name, agent] of this.installed) {
1890
+ try {
1891
+ const latestVersion = await this.registry.getLatestVersion(name);
1892
+
1893
+ if (semver.gt(latestVersion, agent.version)) {
1894
+ const diff = semver.diff(agent.version, latestVersion);
1895
+ const agentInfo = await this.registry.get(name, latestVersion);
1896
+
1897
+ updates.push({
1898
+ name,
1899
+ currentVersion: agent.version,
1900
+ latestVersion,
1901
+ updateType: diff as 'major' | 'minor' | 'patch',
1902
+ breaking: diff === 'major',
1903
+ changelog: agentInfo?.changelog
1904
+ });
1905
+ }
1906
+ } catch (error) {
1907
+ // Skip agents that can't be checked
1908
+ }
1909
+ }
1910
+
1911
+ return updates;
1912
+ }
1913
+
1914
+ createSandbox(agent: InstalledAgent): AgentSandbox {
1915
+ const permissions = new Set<AgentPermission>(agent.manifest.permissions || []);
1916
+
1917
+ return new AgentSandboxImpl({
1918
+ permissions,
1919
+ limits: {
1920
+ memory: this.config.sandbox.resourceLimits.memory,
1921
+ cpu: this.config.sandbox.resourceLimits.cpu,
1922
+ timeout: this.config.sandbox.resourceLimits.timeout
1923
+ },
1924
+ allowedHosts: this.config.sandbox.allowedHosts,
1925
+ blockedHosts: this.config.sandbox.blockedHosts,
1926
+ isolationLevel: this.config.sandbox.isolationLevel
1927
+ });
1928
+ }
1929
+
1930
+ async list(): Promise<InstalledAgent[]> {
1931
+ return Array.from(this.installed.values());
1932
+ }
1933
+
1934
+ async get(name: string): Promise<InstalledAgent | null> {
1935
+ return this.installed.get(name) || null;
1936
+ }
1937
+
1938
+ async isInstalled(name: string): Promise<boolean> {
1939
+ return this.installed.has(name);
1940
+ }
1941
+ }
1942
+ ```
1943
+
1944
+ ---
1945
+
1946
+ ## 6. CLI Commands
1947
+
1948
+ ### Comandos Disponibles
1949
+
1950
+ ```
1951
+ /elsabro:marketplace list [options]
1952
+ Lista agentes del marketplace
1953
+
1954
+ Opciones:
1955
+ --category <cat> Filtrar por categoria
1956
+ --sort <field> Ordenar por: downloads, rating, updated, name
1957
+ --limit <n> Numero maximo de resultados
1958
+ --installed Mostrar solo agentes instalados
1959
+ --updates Mostrar agentes con actualizaciones disponibles
1960
+
1961
+ Ejemplos:
1962
+ /elsabro:marketplace list
1963
+ /elsabro:marketplace list --category testing --sort rating
1964
+ /elsabro:marketplace list --installed --updates
1965
+ ```
1966
+
1967
+ ```
1968
+ /elsabro:marketplace search <query> [options]
1969
+ Busca agentes en el marketplace
1970
+
1971
+ Opciones:
1972
+ --category <cat> Filtrar por categoria
1973
+ --tags <t1,t2> Filtrar por tags
1974
+ --min-rating <n> Rating minimo (1-5)
1975
+ --verified Solo agentes verificados
1976
+
1977
+ Ejemplos:
1978
+ /elsabro:marketplace search "code review"
1979
+ /elsabro:marketplace search testing --category testing --min-rating 4
1980
+ ```
1981
+
1982
+ ```
1983
+ /elsabro:marketplace install <name>[@version] [options]
1984
+ Instala un agente del marketplace
1985
+
1986
+ Opciones:
1987
+ --global Instalar globalmente
1988
+ --force Forzar instalacion
1989
+ --skip-deps No instalar dependencias
1990
+
1991
+ Ejemplos:
1992
+ /elsabro:marketplace install elsabro-reviewer
1993
+ /elsabro:marketplace install elsabro-tester@2.1.0 --global
1994
+ ```
1995
+
1996
+ ```
1997
+ /elsabro:marketplace publish <path> [options]
1998
+ Publica un agente al marketplace
1999
+
2000
+ Opciones:
2001
+ --prerelease Marcar como prerelease
2002
+ --notes <text> Notas de release
2003
+ --sign <keyfile> Firmar con clave privada
2004
+
2005
+ Ejemplos:
2006
+ /elsabro:marketplace publish ./my-agent
2007
+ /elsabro:marketplace publish ./my-agent --sign ~/.keys/private.pem
2008
+ ```
2009
+
2010
+ ```
2011
+ /elsabro:marketplace info <name>
2012
+ Muestra informacion detallada de un agente
2013
+
2014
+ Ejemplos:
2015
+ /elsabro:marketplace info elsabro-reviewer
2016
+ ```
2017
+
2018
+ ```
2019
+ /elsabro:marketplace update [name]
2020
+ Actualiza agentes instalados
2021
+
2022
+ Opciones:
2023
+ --all Actualizar todos los agentes
2024
+ --check Solo verificar actualizaciones
2025
+
2026
+ Ejemplos:
2027
+ /elsabro:marketplace update elsabro-reviewer
2028
+ /elsabro:marketplace update --all
2029
+ /elsabro:marketplace update --check
2030
+ ```
2031
+
2032
+ ```
2033
+ /elsabro:marketplace uninstall <name>
2034
+ Desinstala un agente
2035
+
2036
+ Ejemplos:
2037
+ /elsabro:marketplace uninstall elsabro-reviewer
2038
+ ```
2039
+
2040
+ ```
2041
+ /elsabro:marketplace review <name>
2042
+ Escribe una review para un agente
2043
+
2044
+ Opciones:
2045
+ --rating <1-5> Rating (requerido)
2046
+ --title <text> Titulo de la review
2047
+ --body <text> Cuerpo de la review
2048
+
2049
+ Ejemplos:
2050
+ /elsabro:marketplace review elsabro-reviewer --rating 5 --title "Excelente"
2051
+ ```
2052
+
2053
+ ---
2054
+
2055
+ ## 7. Marketplace Dashboard
2056
+
2057
+ ```
2058
+ +-----------------------------------------------------------------------------+
2059
+ | ELSABRO Agent Marketplace |
2060
+ +-----------------------------------------------------------------------------+
2061
+ | Catalog: 1,247 agents | Installed: 12 | Updates: 3 |
2062
+ | Categories: exploration(342) implementation(456) review(189) |
2063
+ | testing(198) specialized(62) |
2064
+ +-----------------------------------------------------------------------------+
2065
+
2066
+ TRENDING THIS WEEK
2067
+ +------------------------+--------+--------+----------+-----------------------+
2068
+ | Agent | Rating | DLs/wk | Category | Description |
2069
+ +------------------------+--------+--------+----------+-----------------------+
2070
+ | elsabro-code-reviewer | 4.8 | 2,341 | review | AI-powered code review|
2071
+ | elsabro-test-generator | 4.6 | 1,892 | testing | Auto test generation |
2072
+ | elsabro-doc-writer | 4.7 | 1,654 | impl | Documentation gen |
2073
+ | elsabro-security-scan | 4.9 | 1,423 | review | Security analysis |
2074
+ | elsabro-refactorer | 4.5 | 1,201 | impl | Code refactoring |
2075
+ +------------------------+--------+--------+----------+-----------------------+
2076
+
2077
+ INSTALLED AGENTS
2078
+ +------------------------+---------+--------+------------+---------------------+
2079
+ | Agent | Version | Status | Updated | Updates |
2080
+ +------------------------+---------+--------+------------+---------------------+
2081
+ | elsabro-code-reviewer | 2.3.1 | Active | 2024-01-15 | 2.4.0 available |
2082
+ | elsabro-test-generator | 1.8.0 | Active | 2024-01-10 | Up to date |
2083
+ | elsabro-linter | 3.1.2 | Active | 2024-01-08 | 3.2.0 available |
2084
+ | elsabro-formatter | 1.2.0 | Idle | 2024-01-05 | Up to date |
2085
+ | my-custom-agent | 0.1.0 | Dev | 2024-01-18 | Local |
2086
+ +------------------------+---------+--------+------------+---------------------+
2087
+
2088
+ RECENT ACTIVITY
2089
+ +-----------------------------------------------------------------------------+
2090
+ | [15:32] Installed elsabro-doc-writer@2.1.0 |
2091
+ | [14:15] Updated elsabro-test-generator 1.7.0 -> 1.8.0 |
2092
+ | [12:45] Published my-custom-agent@0.1.0 to marketplace |
2093
+ | [11:20] Review submitted for elsabro-code-reviewer (5 stars) |
2094
+ +-----------------------------------------------------------------------------+
2095
+
2096
+ Commands: list | search | install | publish | update | info | review
2097
+ ```
2098
+
2099
+ ---
2100
+
2101
+ ## 8. Agent Package Structure
2102
+
2103
+ ```
2104
+ my-agent/
2105
+ +-- agent.manifest.json # Manifest del agente
2106
+ +-- src/
2107
+ | +-- index.ts # Entry point principal
2108
+ | +-- agent.ts # Implementacion del agente
2109
+ | +-- tools/ # Herramientas custom
2110
+ | | +-- my-tool.ts
2111
+ | +-- prompts/ # System prompts
2112
+ | +-- main.md
2113
+ +-- tests/
2114
+ | +-- agent.test.ts # Tests unitarios
2115
+ | +-- integration.test.ts # Tests de integracion
2116
+ +-- docs/
2117
+ | +-- README.md # Documentacion
2118
+ | +-- CHANGELOG.md # Historial de cambios
2119
+ +-- LICENSE
2120
+ +-- package.json # Dependencias npm
2121
+ ```
2122
+
2123
+ ### Manifest de Ejemplo
2124
+
2125
+ ```json
2126
+ {
2127
+ "name": "elsabro-code-reviewer",
2128
+ "version": "2.4.0",
2129
+ "displayName": "Code Reviewer",
2130
+ "description": "AI-powered code review with best practices analysis",
2131
+ "author": {
2132
+ "name": "ELSABRO Team",
2133
+ "email": "team@elsabro.dev",
2134
+ "url": "https://elsabro.dev"
2135
+ },
2136
+ "main": "dist/index.js",
2137
+ "category": "review",
2138
+ "tags": ["code-review", "best-practices", "quality"],
2139
+ "keywords": ["review", "lint", "quality", "analysis"],
2140
+
2141
+ "engines": {
2142
+ "elsabro": ">=3.4.0",
2143
+ "node": ">=18.0.0"
2144
+ },
2145
+
2146
+ "dependencies": {
2147
+ "elsabro-linter": "^3.0.0"
2148
+ },
2149
+
2150
+ "permissions": [
2151
+ "filesystem:read",
2152
+ "config:read"
2153
+ ],
2154
+
2155
+ "contributes": {
2156
+ "tools": [
2157
+ {
2158
+ "name": "analyze-code",
2159
+ "displayName": "Analyze Code",
2160
+ "description": "Perform deep code analysis",
2161
+ "inputSchema": {
2162
+ "type": "object",
2163
+ "properties": {
2164
+ "path": { "type": "string" },
2165
+ "depth": { "type": "string", "enum": ["shallow", "deep"] }
2166
+ },
2167
+ "required": ["path"]
2168
+ }
2169
+ }
2170
+ ],
2171
+ "commands": [
2172
+ {
2173
+ "command": "review.start",
2174
+ "title": "Start Code Review",
2175
+ "category": "Review"
2176
+ }
2177
+ ]
2178
+ },
2179
+
2180
+ "license": "MIT",
2181
+ "repository": "https://github.com/elsabro/code-reviewer",
2182
+ "homepage": "https://elsabro.dev/agents/code-reviewer",
2183
+ "bugs": "https://github.com/elsabro/code-reviewer/issues"
2184
+ }
2185
+ ```
2186
+
2187
+ ---
2188
+
2189
+ ## 9. Security Model
2190
+
2191
+ ### Niveles de Aislamiento
2192
+
2193
+ ```
2194
+ +-----------------------------------------------------------------------------+
2195
+ | Sandbox Isolation Levels |
2196
+ +-----------------------------------------------------------------------------+
2197
+
2198
+ STRICT (Default para agentes de terceros)
2199
+ +----------------------------------+
2200
+ | * VM aislada |
2201
+ | * Sin acceso a filesystem |
2202
+ | * Network solo whitelist |
2203
+ | * Sin shell |
2204
+ | * Memory/CPU limitados |
2205
+ +----------------------------------+
2206
+
2207
+ MODERATE (Agentes verificados)
2208
+ +----------------------------------+
2209
+ | * Proceso separado |
2210
+ | * Filesystem read-only |
2211
+ | * Network con restricciones |
2212
+ | * Shell denegado |
2213
+ | * Limits menos estrictos |
2214
+ +----------------------------------+
2215
+
2216
+ TRUSTED (Agentes oficiales)
2217
+ +----------------------------------+
2218
+ | * Mismo proceso |
2219
+ | * Filesystem segun permisos |
2220
+ | * Network permitido |
2221
+ | * Shell con restricciones |
2222
+ | * Sin limits de recursos |
2223
+ +----------------------------------+
2224
+ ```
2225
+
2226
+ ### Permission Flow
2227
+
2228
+ ```
2229
+ +-------------------+
2230
+ | Agent requests |
2231
+ | permission |
2232
+ +---------+---------+
2233
+ |
2234
+ +---------v---------+
2235
+ | Check manifest |
2236
+ | declarations |
2237
+ +---------+---------+
2238
+ |
2239
+ +---------------+---------------+
2240
+ | |
2241
+ +---------v---------+ +---------v---------+
2242
+ | Declared in | | Not declared |
2243
+ | manifest | | |
2244
+ +---------+---------+ +---------+---------+
2245
+ | |
2246
+ +---------v---------+ |
2247
+ | User approved? | |
2248
+ +---------+---------+ |
2249
+ | |
2250
+ +-------+-------+ |
2251
+ | | |
2252
+ +-----v-----+ +-----v-----+ +-----v-----+
2253
+ | GRANTED | | DENIED | | DENIED |
2254
+ +-----------+ +-----------+ +-----------+
2255
+ ```
2256
+
2257
+ ---
2258
+
2259
+ ## Referencias
2260
+
2261
+ - **REF-024**: Plugin System (base architecture)
2262
+ - **REF-022**: Security System (sandbox implementation)
2263
+ - **REF-023**: Configuration Management
2264
+ - **REF-025**: Esta referencia (Agent Marketplace)
2265
+
2266
+ ## Changelog
2267
+
2268
+ ### v3.6.0
2269
+ - Initial marketplace implementation
2270
+ - Registry with search and filtering
2271
+ - Package signing and verification
2272
+ - Publishing pipeline with automated review
2273
+ - Rating and review system
2274
+ - Sandboxed execution for third-party agents