@sparkleideas/plugins 3.0.0-alpha.8

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 (80) hide show
  1. package/README.md +401 -0
  2. package/__tests__/collection-manager.test.ts +332 -0
  3. package/__tests__/dependency-graph.test.ts +434 -0
  4. package/__tests__/enhanced-plugin-registry.test.ts +488 -0
  5. package/__tests__/plugin-registry.test.ts +368 -0
  6. package/__tests__/ruvector-bridge.test.ts +2429 -0
  7. package/__tests__/ruvector-integration.test.ts +1602 -0
  8. package/__tests__/ruvector-migrations.test.ts +1099 -0
  9. package/__tests__/ruvector-quantization.test.ts +846 -0
  10. package/__tests__/ruvector-streaming.test.ts +1088 -0
  11. package/__tests__/sdk.test.ts +325 -0
  12. package/__tests__/security.test.ts +348 -0
  13. package/__tests__/utils/ruvector-test-utils.ts +860 -0
  14. package/examples/plugin-creator/index.ts +636 -0
  15. package/examples/plugin-creator/plugin-creator.test.ts +312 -0
  16. package/examples/ruvector/README.md +288 -0
  17. package/examples/ruvector/attention-patterns.ts +394 -0
  18. package/examples/ruvector/basic-usage.ts +288 -0
  19. package/examples/ruvector/docker-compose.yml +75 -0
  20. package/examples/ruvector/gnn-analysis.ts +501 -0
  21. package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
  22. package/examples/ruvector/init-db.sql +119 -0
  23. package/examples/ruvector/quantization.ts +680 -0
  24. package/examples/ruvector/self-learning.ts +447 -0
  25. package/examples/ruvector/semantic-search.ts +576 -0
  26. package/examples/ruvector/streaming-large-data.ts +507 -0
  27. package/examples/ruvector/transactions.ts +594 -0
  28. package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
  29. package/examples/ruvector-plugins/index.ts +79 -0
  30. package/examples/ruvector-plugins/intent-router.ts +354 -0
  31. package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
  32. package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
  33. package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
  34. package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
  35. package/examples/ruvector-plugins/shared/index.ts +20 -0
  36. package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
  37. package/examples/ruvector-plugins/sona-learning.ts +445 -0
  38. package/package.json +97 -0
  39. package/src/collections/collection-manager.ts +661 -0
  40. package/src/collections/index.ts +56 -0
  41. package/src/collections/official/index.ts +1040 -0
  42. package/src/core/base-plugin.ts +416 -0
  43. package/src/core/plugin-interface.ts +215 -0
  44. package/src/hooks/index.ts +685 -0
  45. package/src/index.ts +378 -0
  46. package/src/integrations/agentic-flow.ts +743 -0
  47. package/src/integrations/index.ts +88 -0
  48. package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
  49. package/src/integrations/ruvector/attention-advanced.ts +1040 -0
  50. package/src/integrations/ruvector/attention-executor.ts +782 -0
  51. package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
  52. package/src/integrations/ruvector/attention.ts +1063 -0
  53. package/src/integrations/ruvector/gnn.ts +3050 -0
  54. package/src/integrations/ruvector/hyperbolic.ts +1948 -0
  55. package/src/integrations/ruvector/index.ts +394 -0
  56. package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
  57. package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
  58. package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
  59. package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
  60. package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
  61. package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
  62. package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
  63. package/src/integrations/ruvector/migrations/index.ts +35 -0
  64. package/src/integrations/ruvector/migrations/migrations.ts +647 -0
  65. package/src/integrations/ruvector/quantization.ts +2036 -0
  66. package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
  67. package/src/integrations/ruvector/self-learning.ts +2376 -0
  68. package/src/integrations/ruvector/streaming.ts +1737 -0
  69. package/src/integrations/ruvector/types.ts +1945 -0
  70. package/src/providers/index.ts +643 -0
  71. package/src/registry/dependency-graph.ts +568 -0
  72. package/src/registry/enhanced-plugin-registry.ts +994 -0
  73. package/src/registry/plugin-registry.ts +604 -0
  74. package/src/sdk/index.ts +563 -0
  75. package/src/security/index.ts +594 -0
  76. package/src/types/index.ts +446 -0
  77. package/src/workers/index.ts +700 -0
  78. package/tmp.json +0 -0
  79. package/tsconfig.json +25 -0
  80. package/vitest.config.ts +23 -0
@@ -0,0 +1,661 @@
1
+ /**
2
+ * Plugin Collection Manager
3
+ *
4
+ * Manages collections of plugins with activation/deactivation,
5
+ * category filtering, and state persistence.
6
+ */
7
+
8
+ import type { IPlugin, PluginFactory } from '../core/plugin-interface.js';
9
+ import type { PluginConfig } from '../types/index.js';
10
+ import type { PluginRegistry } from '../registry/plugin-registry.js';
11
+
12
+ // ============================================================================
13
+ // Types
14
+ // ============================================================================
15
+
16
+ export type PluginCategory =
17
+ | 'agent' // Agent types and definitions
18
+ | 'task' // Task types and handlers
19
+ | 'tool' // MCP tools
20
+ | 'memory' // Memory backends
21
+ | 'provider' // LLM providers
22
+ | 'hook' // Lifecycle hooks
23
+ | 'worker' // Background workers
24
+ | 'integration' // External integrations
25
+ | 'database' // Database backends and integrations
26
+ | 'utility'; // General utilities
27
+
28
+ export type PluginCapability =
29
+ | 'network' // Can make network requests
30
+ | 'filesystem' // Can access filesystem
31
+ | 'subprocess' // Can spawn processes
32
+ | 'memory' // Can store persistent data
33
+ | 'database' // Can access databases
34
+ | 'llm' // Can call LLM APIs
35
+ | 'mcp'; // Can register MCP tools
36
+
37
+ export interface PluginCollectionEntry {
38
+ readonly plugin: IPlugin | PluginFactory;
39
+ readonly defaultEnabled: boolean;
40
+ readonly category: PluginCategory;
41
+ readonly tags?: string[];
42
+ readonly requiredCapabilities?: PluginCapability[];
43
+ readonly description?: string;
44
+ }
45
+
46
+ export interface PluginCollection {
47
+ readonly id: string;
48
+ readonly name: string;
49
+ readonly version: string;
50
+ readonly description?: string;
51
+ readonly author?: string;
52
+ readonly license?: string;
53
+ readonly repository?: string;
54
+ readonly categories?: PluginCategory[];
55
+ readonly plugins: PluginCollectionEntry[];
56
+ }
57
+
58
+ export interface CollectionManagerState {
59
+ version: string;
60
+ collections: string[];
61
+ enabledPlugins: Record<string, string[]>; // collectionId -> pluginNames
62
+ disabledPlugins: Record<string, string[]>; // collectionId -> pluginNames (overrides default)
63
+ pluginSettings: Record<string, Record<string, unknown>>; // pluginName -> settings
64
+ }
65
+
66
+ export interface CollectionManagerConfig {
67
+ registry: PluginRegistry;
68
+ autoInitialize?: boolean;
69
+ stateFile?: string;
70
+ }
71
+
72
+ export interface CollectionStats {
73
+ totalCollections: number;
74
+ totalPlugins: number;
75
+ enabledPlugins: number;
76
+ disabledPlugins: number;
77
+ byCategory: Record<PluginCategory, number>;
78
+ }
79
+
80
+ // Internal resolved entry with plugin name cached
81
+ interface ResolvedEntry {
82
+ entry: PluginCollectionEntry;
83
+ pluginName: string;
84
+ plugin: IPlugin;
85
+ }
86
+
87
+ // ============================================================================
88
+ // Collection Manager
89
+ // ============================================================================
90
+
91
+ /**
92
+ * Manages plugin collections with activation/deactivation and persistence.
93
+ *
94
+ * Features:
95
+ * - Load/unload plugin collections
96
+ * - Enable/disable individual plugins
97
+ * - Category-based filtering
98
+ * - Tag-based search
99
+ * - State persistence
100
+ * - Bulk operations
101
+ */
102
+ export class PluginCollectionManager {
103
+ private collections = new Map<string, PluginCollection>();
104
+ private resolvedEntries = new Map<string, ResolvedEntry[]>(); // collectionId -> entries
105
+ private enabledOverrides = new Map<string, Set<string>>(); // Explicitly enabled
106
+ private disabledOverrides = new Map<string, Set<string>>(); // Explicitly disabled
107
+ private pluginSettings = new Map<string, Record<string, unknown>>();
108
+ private registry: PluginRegistry;
109
+ private autoInitialize: boolean;
110
+
111
+ constructor(config: CollectionManagerConfig) {
112
+ this.registry = config.registry;
113
+ this.autoInitialize = config.autoInitialize ?? true;
114
+ }
115
+
116
+ // =========================================================================
117
+ // Collection Management
118
+ // =========================================================================
119
+
120
+ /**
121
+ * Load a plugin collection.
122
+ */
123
+ async loadCollection(collection: PluginCollection): Promise<void> {
124
+ if (this.collections.has(collection.id)) {
125
+ throw new Error(`Collection ${collection.id} already loaded`);
126
+ }
127
+
128
+ // Resolve all plugins upfront to cache names
129
+ const resolved: ResolvedEntry[] = [];
130
+ for (const entry of collection.plugins) {
131
+ const plugin = await this.resolvePlugin(entry.plugin);
132
+ resolved.push({
133
+ entry,
134
+ pluginName: plugin.metadata.name,
135
+ plugin,
136
+ });
137
+ }
138
+
139
+ this.collections.set(collection.id, collection);
140
+ this.resolvedEntries.set(collection.id, resolved);
141
+ this.enabledOverrides.set(collection.id, new Set());
142
+ this.disabledOverrides.set(collection.id, new Set());
143
+
144
+ // Register enabled plugins
145
+ for (const { entry, pluginName, plugin } of resolved) {
146
+ if (this.isPluginEnabledSync(collection.id, pluginName, entry.defaultEnabled)) {
147
+ await this.registerResolvedPlugin(plugin, entry);
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Unload a plugin collection.
154
+ */
155
+ async unloadCollection(collectionId: string): Promise<void> {
156
+ const resolved = this.resolvedEntries.get(collectionId);
157
+ if (!resolved) {
158
+ throw new Error(`Collection ${collectionId} not found`);
159
+ }
160
+
161
+ // Unregister all plugins from this collection
162
+ for (const { pluginName } of resolved) {
163
+ if (this.registry.getPlugin(pluginName)) {
164
+ try {
165
+ await this.registry.unregister(pluginName);
166
+ } catch {
167
+ // Ignore errors during unload
168
+ }
169
+ }
170
+ }
171
+
172
+ this.collections.delete(collectionId);
173
+ this.resolvedEntries.delete(collectionId);
174
+ this.enabledOverrides.delete(collectionId);
175
+ this.disabledOverrides.delete(collectionId);
176
+ }
177
+
178
+ /**
179
+ * List all loaded collections.
180
+ */
181
+ listCollections(): PluginCollection[] {
182
+ return Array.from(this.collections.values());
183
+ }
184
+
185
+ /**
186
+ * Get a collection by ID.
187
+ */
188
+ getCollection(id: string): PluginCollection | undefined {
189
+ return this.collections.get(id);
190
+ }
191
+
192
+ // =========================================================================
193
+ // Plugin Activation
194
+ // =========================================================================
195
+
196
+ /**
197
+ * Enable a plugin from a collection.
198
+ */
199
+ async enablePlugin(collectionId: string, pluginName: string): Promise<void> {
200
+ const resolved = this.findResolvedEntry(collectionId, pluginName);
201
+ if (!resolved) {
202
+ throw new Error(`Plugin ${pluginName} not found in collection ${collectionId}`);
203
+ }
204
+
205
+ // Remove from disabled, add to enabled
206
+ this.disabledOverrides.get(collectionId)?.delete(pluginName);
207
+ this.enabledOverrides.get(collectionId)?.add(pluginName);
208
+
209
+ // Register if not already registered
210
+ if (!this.registry.getPlugin(pluginName)) {
211
+ await this.registerResolvedPlugin(resolved.plugin, resolved.entry);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Disable a plugin from a collection.
217
+ */
218
+ async disablePlugin(collectionId: string, pluginName: string): Promise<void> {
219
+ const resolved = this.findResolvedEntry(collectionId, pluginName);
220
+ if (!resolved) {
221
+ throw new Error(`Plugin ${pluginName} not found in collection ${collectionId}`);
222
+ }
223
+
224
+ // Remove from enabled, add to disabled
225
+ this.enabledOverrides.get(collectionId)?.delete(pluginName);
226
+ this.disabledOverrides.get(collectionId)?.add(pluginName);
227
+
228
+ // Unregister if registered
229
+ if (this.registry.getPlugin(pluginName)) {
230
+ try {
231
+ await this.registry.unregister(pluginName);
232
+ } catch {
233
+ // May fail if other plugins depend on it
234
+ throw new Error(`Cannot disable ${pluginName}: other plugins may depend on it`);
235
+ }
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Check if a plugin is enabled.
241
+ */
242
+ isEnabled(collectionId: string, pluginName: string): boolean {
243
+ const resolved = this.findResolvedEntry(collectionId, pluginName);
244
+ if (!resolved) return false;
245
+
246
+ return this.isPluginEnabledSync(collectionId, pluginName, resolved.entry.defaultEnabled);
247
+ }
248
+
249
+ /**
250
+ * Toggle a plugin's enabled state.
251
+ */
252
+ async togglePlugin(collectionId: string, pluginName: string): Promise<boolean> {
253
+ if (this.isEnabled(collectionId, pluginName)) {
254
+ await this.disablePlugin(collectionId, pluginName);
255
+ return false;
256
+ } else {
257
+ await this.enablePlugin(collectionId, pluginName);
258
+ return true;
259
+ }
260
+ }
261
+
262
+ // =========================================================================
263
+ // Bulk Operations
264
+ // =========================================================================
265
+
266
+ /**
267
+ * Enable all plugins in a collection.
268
+ */
269
+ async enableAll(collectionId: string): Promise<void> {
270
+ const resolved = this.resolvedEntries.get(collectionId);
271
+ if (!resolved) {
272
+ throw new Error(`Collection ${collectionId} not found`);
273
+ }
274
+
275
+ for (const { pluginName } of resolved) {
276
+ await this.enablePlugin(collectionId, pluginName);
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Disable all plugins in a collection.
282
+ */
283
+ async disableAll(collectionId: string): Promise<void> {
284
+ const resolved = this.resolvedEntries.get(collectionId);
285
+ if (!resolved) {
286
+ throw new Error(`Collection ${collectionId} not found`);
287
+ }
288
+
289
+ // Disable in reverse order to handle dependencies
290
+ const entries = [...resolved].reverse();
291
+ for (const { pluginName } of entries) {
292
+ try {
293
+ await this.disablePlugin(collectionId, pluginName);
294
+ } catch {
295
+ // Continue disabling others
296
+ }
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Enable all plugins in a category across all collections.
302
+ */
303
+ async enableCategory(category: PluginCategory): Promise<void> {
304
+ for (const [collectionId, resolved] of this.resolvedEntries) {
305
+ for (const { pluginName, entry } of resolved) {
306
+ if (entry.category === category) {
307
+ try {
308
+ await this.enablePlugin(collectionId, pluginName);
309
+ } catch {
310
+ // Continue with others
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Disable all plugins in a category across all collections.
319
+ */
320
+ async disableCategory(category: PluginCategory): Promise<void> {
321
+ for (const [collectionId, resolved] of this.resolvedEntries) {
322
+ const entries = [...resolved].reverse();
323
+ for (const { pluginName, entry } of entries) {
324
+ if (entry.category === category) {
325
+ try {
326
+ await this.disablePlugin(collectionId, pluginName);
327
+ } catch {
328
+ // Continue with others
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+
335
+ // =========================================================================
336
+ // Filtering & Search
337
+ // =========================================================================
338
+
339
+ /**
340
+ * Get all plugins by category.
341
+ */
342
+ getPluginsByCategory(category: PluginCategory): Array<{
343
+ collectionId: string;
344
+ entry: PluginCollectionEntry;
345
+ enabled: boolean;
346
+ }> {
347
+ const results: Array<{
348
+ collectionId: string;
349
+ entry: PluginCollectionEntry;
350
+ enabled: boolean;
351
+ }> = [];
352
+
353
+ for (const [collectionId, resolved] of this.resolvedEntries) {
354
+ for (const { entry, pluginName } of resolved) {
355
+ if (entry.category === category) {
356
+ results.push({
357
+ collectionId,
358
+ entry,
359
+ enabled: this.isPluginEnabledSync(collectionId, pluginName, entry.defaultEnabled),
360
+ });
361
+ }
362
+ }
363
+ }
364
+
365
+ return results;
366
+ }
367
+
368
+ /**
369
+ * Get all plugins by tag.
370
+ */
371
+ getPluginsByTag(tag: string): Array<{
372
+ collectionId: string;
373
+ entry: PluginCollectionEntry;
374
+ enabled: boolean;
375
+ }> {
376
+ const results: Array<{
377
+ collectionId: string;
378
+ entry: PluginCollectionEntry;
379
+ enabled: boolean;
380
+ }> = [];
381
+
382
+ for (const [collectionId, resolved] of this.resolvedEntries) {
383
+ for (const { entry, pluginName } of resolved) {
384
+ if (entry.tags?.includes(tag)) {
385
+ results.push({
386
+ collectionId,
387
+ entry,
388
+ enabled: this.isPluginEnabledSync(collectionId, pluginName, entry.defaultEnabled),
389
+ });
390
+ }
391
+ }
392
+ }
393
+
394
+ return results;
395
+ }
396
+
397
+ /**
398
+ * Search plugins by name or description.
399
+ */
400
+ searchPlugins(query: string): Array<{
401
+ collectionId: string;
402
+ entry: PluginCollectionEntry;
403
+ pluginName: string;
404
+ enabled: boolean;
405
+ score: number;
406
+ }> {
407
+ const results: Array<{
408
+ collectionId: string;
409
+ entry: PluginCollectionEntry;
410
+ pluginName: string;
411
+ enabled: boolean;
412
+ score: number;
413
+ }> = [];
414
+
415
+ const queryLower = query.toLowerCase();
416
+
417
+ for (const [collectionId, resolved] of this.resolvedEntries) {
418
+ for (const { entry, pluginName, plugin } of resolved) {
419
+ const name = pluginName.toLowerCase();
420
+ const description = (entry.description ?? plugin.metadata.description ?? '').toLowerCase();
421
+
422
+ let score = 0;
423
+
424
+ // Exact name match
425
+ if (name === queryLower) score += 100;
426
+ // Name contains query
427
+ else if (name.includes(queryLower)) score += 50;
428
+
429
+ // Description contains query
430
+ if (description.includes(queryLower)) score += 25;
431
+
432
+ // Tag match
433
+ if (entry.tags?.some(t => t.toLowerCase().includes(queryLower))) {
434
+ score += 30;
435
+ }
436
+
437
+ // Category match
438
+ if (entry.category.toLowerCase().includes(queryLower)) {
439
+ score += 20;
440
+ }
441
+
442
+ if (score > 0) {
443
+ results.push({
444
+ collectionId,
445
+ entry,
446
+ pluginName,
447
+ enabled: this.isPluginEnabledSync(collectionId, pluginName, entry.defaultEnabled),
448
+ score,
449
+ });
450
+ }
451
+ }
452
+ }
453
+
454
+ // Sort by score descending
455
+ return results.sort((a, b) => b.score - a.score);
456
+ }
457
+
458
+ // =========================================================================
459
+ // Settings
460
+ // =========================================================================
461
+
462
+ /**
463
+ * Get settings for a plugin.
464
+ */
465
+ getPluginSettings(pluginName: string): Record<string, unknown> {
466
+ return this.pluginSettings.get(pluginName) ?? {};
467
+ }
468
+
469
+ /**
470
+ * Set settings for a plugin.
471
+ */
472
+ setPluginSettings(pluginName: string, settings: Record<string, unknown>): void {
473
+ this.pluginSettings.set(pluginName, settings);
474
+ }
475
+
476
+ /**
477
+ * Update settings for a plugin (merge with existing).
478
+ */
479
+ updatePluginSettings(pluginName: string, settings: Record<string, unknown>): void {
480
+ const existing = this.pluginSettings.get(pluginName) ?? {};
481
+ this.pluginSettings.set(pluginName, { ...existing, ...settings });
482
+ }
483
+
484
+ // =========================================================================
485
+ // State Persistence
486
+ // =========================================================================
487
+
488
+ /**
489
+ * Export current state.
490
+ */
491
+ exportState(): CollectionManagerState {
492
+ const enabledPlugins: Record<string, string[]> = {};
493
+ const disabledPlugins: Record<string, string[]> = {};
494
+
495
+ for (const [collectionId, enabled] of this.enabledOverrides) {
496
+ if (enabled.size > 0) {
497
+ enabledPlugins[collectionId] = Array.from(enabled);
498
+ }
499
+ }
500
+
501
+ for (const [collectionId, disabled] of this.disabledOverrides) {
502
+ if (disabled.size > 0) {
503
+ disabledPlugins[collectionId] = Array.from(disabled);
504
+ }
505
+ }
506
+
507
+ const pluginSettingsObj: Record<string, Record<string, unknown>> = {};
508
+ for (const [name, settings] of this.pluginSettings) {
509
+ pluginSettingsObj[name] = settings;
510
+ }
511
+
512
+ return {
513
+ version: '1.0.0',
514
+ collections: Array.from(this.collections.keys()),
515
+ enabledPlugins,
516
+ disabledPlugins,
517
+ pluginSettings: pluginSettingsObj,
518
+ };
519
+ }
520
+
521
+ /**
522
+ * Import state (does not load collections, just restores overrides).
523
+ */
524
+ importState(state: CollectionManagerState): void {
525
+ // Restore enabled overrides
526
+ for (const [collectionId, plugins] of Object.entries(state.enabledPlugins)) {
527
+ this.enabledOverrides.set(collectionId, new Set(plugins));
528
+ }
529
+
530
+ // Restore disabled overrides
531
+ for (const [collectionId, plugins] of Object.entries(state.disabledPlugins)) {
532
+ this.disabledOverrides.set(collectionId, new Set(plugins));
533
+ }
534
+
535
+ // Restore plugin settings
536
+ for (const [name, settings] of Object.entries(state.pluginSettings)) {
537
+ this.pluginSettings.set(name, settings);
538
+ }
539
+ }
540
+
541
+ /**
542
+ * Save state to a JSON string.
543
+ */
544
+ serializeState(): string {
545
+ return JSON.stringify(this.exportState(), null, 2);
546
+ }
547
+
548
+ /**
549
+ * Load state from a JSON string.
550
+ */
551
+ deserializeState(json: string): void {
552
+ const state = JSON.parse(json) as CollectionManagerState;
553
+ this.importState(state);
554
+ }
555
+
556
+ // =========================================================================
557
+ // Statistics
558
+ // =========================================================================
559
+
560
+ /**
561
+ * Get collection statistics.
562
+ */
563
+ getStats(): CollectionStats {
564
+ const byCategory: Record<PluginCategory, number> = {
565
+ agent: 0,
566
+ task: 0,
567
+ tool: 0,
568
+ memory: 0,
569
+ provider: 0,
570
+ hook: 0,
571
+ worker: 0,
572
+ integration: 0,
573
+ database: 0,
574
+ utility: 0,
575
+ };
576
+
577
+ let totalPlugins = 0;
578
+ let enabledPlugins = 0;
579
+ let disabledPlugins = 0;
580
+
581
+ for (const [collectionId, resolved] of this.resolvedEntries) {
582
+ for (const { entry, pluginName } of resolved) {
583
+ totalPlugins++;
584
+ byCategory[entry.category]++;
585
+
586
+ if (this.isPluginEnabledSync(collectionId, pluginName, entry.defaultEnabled)) {
587
+ enabledPlugins++;
588
+ } else {
589
+ disabledPlugins++;
590
+ }
591
+ }
592
+ }
593
+
594
+ return {
595
+ totalCollections: this.collections.size,
596
+ totalPlugins,
597
+ enabledPlugins,
598
+ disabledPlugins,
599
+ byCategory,
600
+ };
601
+ }
602
+
603
+ // =========================================================================
604
+ // Private Helpers
605
+ // =========================================================================
606
+
607
+ private async resolvePlugin(plugin: IPlugin | PluginFactory): Promise<IPlugin> {
608
+ return typeof plugin === 'function' ? await plugin() : plugin;
609
+ }
610
+
611
+ private findResolvedEntry(collectionId: string, pluginName: string): ResolvedEntry | undefined {
612
+ const resolved = this.resolvedEntries.get(collectionId);
613
+ if (!resolved) return undefined;
614
+ return resolved.find(r => r.pluginName === pluginName);
615
+ }
616
+
617
+ private isPluginEnabledSync(
618
+ collectionId: string,
619
+ pluginName: string,
620
+ defaultEnabled: boolean
621
+ ): boolean {
622
+ // Check explicit overrides first
623
+ if (this.enabledOverrides.get(collectionId)?.has(pluginName)) {
624
+ return true;
625
+ }
626
+ if (this.disabledOverrides.get(collectionId)?.has(pluginName)) {
627
+ return false;
628
+ }
629
+
630
+ // Fall back to default
631
+ return defaultEnabled;
632
+ }
633
+
634
+ private async registerResolvedPlugin(
635
+ plugin: IPlugin,
636
+ entry: PluginCollectionEntry
637
+ ): Promise<void> {
638
+ const settings = this.pluginSettings.get(plugin.metadata.name);
639
+
640
+ const config: Partial<PluginConfig> = {
641
+ enabled: true,
642
+ settings: settings ?? {},
643
+ };
644
+
645
+ await this.registry.register(plugin, config);
646
+ }
647
+ }
648
+
649
+ // ============================================================================
650
+ // Default Instance
651
+ // ============================================================================
652
+
653
+ let defaultManager: PluginCollectionManager | null = null;
654
+
655
+ export function getDefaultCollectionManager(): PluginCollectionManager | null {
656
+ return defaultManager;
657
+ }
658
+
659
+ export function setDefaultCollectionManager(manager: PluginCollectionManager): void {
660
+ defaultManager = manager;
661
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Plugin Collections
3
+ *
4
+ * Re-exports for the collection management system.
5
+ */
6
+
7
+ export {
8
+ PluginCollectionManager,
9
+ getDefaultCollectionManager,
10
+ setDefaultCollectionManager,
11
+ type PluginCollection,
12
+ type PluginCollectionEntry,
13
+ type PluginCategory,
14
+ type PluginCapability,
15
+ type CollectionManagerState,
16
+ type CollectionManagerConfig,
17
+ type CollectionStats,
18
+ } from './collection-manager.js';
19
+
20
+ export {
21
+ // Individual plugins
22
+ sessionPlugin,
23
+ memoryCoordinatorPlugin,
24
+ eventBusPlugin,
25
+ coderAgentPlugin,
26
+ testerAgentPlugin,
27
+ reviewerAgentPlugin,
28
+ gitIntegrationPlugin,
29
+ linterPlugin,
30
+ sonaPlugin,
31
+ reasoningBankPlugin,
32
+ patternLearningPlugin,
33
+ hiveMindPlugin,
34
+ maestroPlugin,
35
+ consensusPlugin,
36
+ coordinatorAgentPlugin,
37
+ inputValidationPlugin,
38
+ pathSecurityPlugin,
39
+ auditLogPlugin,
40
+ securityScanPlugin,
41
+ metricsPlugin,
42
+ cachePlugin,
43
+
44
+ // Collections
45
+ coreCollection,
46
+ developmentCollection,
47
+ intelligenceCollection,
48
+ swarmCollection,
49
+ securityCollection,
50
+ utilityCollection,
51
+ officialCollections,
52
+
53
+ // Helpers
54
+ getAllOfficialPlugins,
55
+ getOfficialCollection,
56
+ } from './official/index.js';