@devilsdev/rag-pipeline-utils 2.1.11 → 2.2.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 (110) hide show
  1. package/.ragrc.schema.json +218 -0
  2. package/README.md +651 -393
  3. package/bin/cli.js +8 -14
  4. package/dist/index.d.ts +237 -0
  5. package/dist/index.mjs +22 -7
  6. package/package.json +17 -13
  7. package/src/ai/adaptive-retrieval.js +191 -0
  8. package/src/ai/federated-learning.js +214 -0
  9. package/src/ai/federation/federated-learning-coordinator.js +345 -0
  10. package/src/ai/federation.js +76 -0
  11. package/src/ai/index-fixed.js +509 -0
  12. package/src/ai/index.js +33 -0
  13. package/src/ai/model-trainer.js +217 -0
  14. package/src/ai/model-training.js +205 -0
  15. package/src/ai/module-template.js +37 -0
  16. package/src/ai/multimodal/multi-modal-processor.js +345 -0
  17. package/src/ai/multimodal-processing.js +268 -0
  18. package/src/ai/multimodal.js +71 -0
  19. package/src/ai/orchestrator.js +70 -0
  20. package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
  21. package/src/ai/retrieval-engine.js +69 -0
  22. package/src/ai/training/model-training-orchestrator.js +228 -0
  23. package/src/ci/workflow-analyzer.js +71 -0
  24. package/src/cli/commands/ai-ml.js +967 -0
  25. package/src/cli/commands/docs.js +228 -0
  26. package/src/cli/commands/dx.js +538 -0
  27. package/src/cli/commands/plugin-hub.js +875 -0
  28. package/src/cli/doctor-command.js +639 -0
  29. package/src/cli/enhanced-cli-commands.js +945 -0
  30. package/src/cli/interactive-wizard.js +997 -0
  31. package/src/cli/plugin-marketplace-commands.js +869 -0
  32. package/src/cli.js +17 -0
  33. package/src/config/enhanced-ragrc-schema.js +632 -0
  34. package/src/config/load-config.js +54 -0
  35. package/src/config/load-plugin-config.js +69 -0
  36. package/src/config/normalize-config.js +105 -0
  37. package/src/config/schema-validator.js +315 -0
  38. package/src/config/validate-plugin-schema.js +35 -0
  39. package/src/config/validate-schema.js +113 -0
  40. package/src/contracts/plugin-contracts.js +33 -0
  41. package/src/core/create-pipeline.js +99 -0
  42. package/src/core/dependency-injection.js +242 -0
  43. package/src/core/observability/event-logger.js +241 -0
  44. package/src/core/observability/instrumented-pipeline.js +609 -0
  45. package/src/core/observability/metrics.js +497 -0
  46. package/src/core/observability/tracing.js +781 -0
  47. package/src/core/performance/benchmark.js +516 -0
  48. package/src/core/performance/parallel-processor.js +240 -0
  49. package/src/core/performance/streaming-safeguards.js +611 -0
  50. package/src/core/pipeline-factory.js +60 -0
  51. package/src/core/plugin-contracts.js +89 -0
  52. package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
  53. package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
  54. package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
  55. package/src/core/plugin-marketplace/version-resolver.js +61 -0
  56. package/src/core/plugin-registry.js +265 -0
  57. package/src/dag/dag-engine.js +954 -0
  58. package/src/dag/dag-node.js +76 -0
  59. package/src/dag/enhanced-dag-engine.js +822 -0
  60. package/src/dx/index.js +40 -0
  61. package/src/dx/integration-templates.js +665 -0
  62. package/src/dx/performance-profiler.js +968 -0
  63. package/src/dx/realtime-debugger.js +755 -0
  64. package/src/dx/visual-pipeline-builder.js +578 -0
  65. package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
  66. package/src/ecosystem/plugin-certification.js +580 -0
  67. package/src/ecosystem/plugin-hub.js +821 -0
  68. package/src/enterprise/audit-logging.js +967 -0
  69. package/src/enterprise/data-governance.js +408 -0
  70. package/src/enterprise/multi-tenancy.js +496 -0
  71. package/src/enterprise/sso-integration.js +903 -0
  72. package/src/evaluate/evaluator.js +52 -0
  73. package/src/evaluate/scoring.js +91 -0
  74. package/src/index.js +67 -0
  75. package/src/ingest.js +59 -0
  76. package/src/loader/csv-loader.js +38 -0
  77. package/src/loader/directory-loader.js +48 -0
  78. package/src/loader/html-loader.js +62 -0
  79. package/src/loader/markdown-loader.js +67 -0
  80. package/src/mocks/openai-embedder.js +119 -0
  81. package/src/mocks/openai-llm.js +77 -0
  82. package/src/mocks/pdf-loader.js +21 -0
  83. package/src/mocks/pinecone-retriever.js +106 -0
  84. package/src/observability/audit-logger.js +758 -0
  85. package/src/observability/dashboard-config.json +675 -0
  86. package/src/observability/event-logger.js +310 -0
  87. package/src/observability/metrics.js +691 -0
  88. package/src/observability/security-monitor.js +830 -0
  89. package/src/observability/slo-monitor.js +319 -0
  90. package/src/observability/telemetry.js +686 -0
  91. package/src/pipeline/pipeline.js +18 -0
  92. package/src/plugins/sample-embedder.js +53 -0
  93. package/src/plugins/sample-llm.js +30 -0
  94. package/src/plugins/sample-loader.js +24 -0
  95. package/src/plugins/sample-retriever.js +84 -0
  96. package/src/query.js +117 -0
  97. package/src/reranker/llm-reranker.js +85 -0
  98. package/src/scripts/script-utilities.js +36 -0
  99. package/src/security/plugin-sandbox.js +586 -0
  100. package/src/security/plugin-signature-verifier.js +414 -0
  101. package/src/security/validator.js +36 -0
  102. package/src/utils/ci/diagnostic-reporter.js +57 -0
  103. package/src/utils/logger.js +211 -0
  104. package/src/utils/performance-monitor.js +561 -0
  105. package/src/utils/plugin-scaffolder.js +447 -0
  106. package/src/utils/retry-policy.js +443 -0
  107. package/src/utils/retry.js +107 -0
  108. package/src/utils/safe-expression-evaluator.js +579 -0
  109. package/src/utils/structured-logger.js +361 -0
  110. package/src/utils/validate-plugin-contract.js +42 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Version: 2.0.0
3
+ * Description: Shared plugin interface contracts for runtime + CI mock validation
4
+ * Author: Ali Kahwaji
5
+ */
6
+
7
+ const pluginContracts = {
8
+ loader: {
9
+ requiredMethods: ['load'],
10
+ methodSignatures: {
11
+ load: {
12
+ params: ['_filePath'],
13
+ paramTypes: ['string'],
14
+ returnType: 'Promise<Array<{chunk: () => string[]}>>',
15
+ description: 'Load and parse a document from the given file path',
16
+ },
17
+ },
18
+ },
19
+ embedder: {
20
+ requiredMethods: ['embed', 'embedQuery'],
21
+ methodSignatures: {
22
+ embed: {
23
+ params: ['chunks'],
24
+ paramTypes: ['string[]'],
25
+ returnType: 'Promise<number[][]>',
26
+ description: 'Generate embeddings for an array of text chunks',
27
+ },
28
+ embedQuery: {
29
+ params: ['query'],
30
+ paramTypes: ['string'],
31
+ returnType: 'Promise<number[]>',
32
+ description: 'Generate embedding for a single query string',
33
+ },
34
+ },
35
+ },
36
+ retriever: {
37
+ requiredMethods: ['store', 'retrieve'],
38
+ methodSignatures: {
39
+ store: {
40
+ params: ['vectors'],
41
+ paramTypes: ['number[][]'],
42
+ returnType: 'Promise<void>',
43
+ description: 'Store vectors in the retrieval system',
44
+ },
45
+ retrieve: {
46
+ params: ['queryVector'],
47
+ paramTypes: ['number[]'],
48
+ returnType: 'Promise<string[]>',
49
+ description: 'Retrieve relevant context based on query vector',
50
+ },
51
+ },
52
+ },
53
+ llm: {
54
+ requiredMethods: ['generate'],
55
+ optionalMethods: ['generateStream'],
56
+ methodSignatures: {
57
+ generate: {
58
+ params: ['prompt', 'context'],
59
+ paramTypes: ['string', 'string[]'],
60
+ returnType: 'Promise<string>',
61
+ description: 'Generate response based on prompt and retrieved context',
62
+ },
63
+ generateStream: {
64
+ params: ['prompt', 'context'],
65
+ paramTypes: ['string', 'string[]'],
66
+ returnType: 'AsyncIterable<string>',
67
+ description:
68
+ 'Generate streaming response token-by-token based on prompt and retrieved context',
69
+ },
70
+ },
71
+ },
72
+ reranker: {
73
+ requiredMethods: ['rerank'],
74
+ methodSignatures: {
75
+ rerank: {
76
+ params: ['query', 'documents'],
77
+ paramTypes: ['string', 'string[]'],
78
+ returnType: 'Promise<string[]>',
79
+ description: 'Rerank documents based on relevance to query',
80
+ },
81
+ },
82
+ },
83
+ };
84
+
85
+ // Default export
86
+
87
+ module.exports = {
88
+ pluginContracts,
89
+ };
@@ -0,0 +1,485 @@
1
+ /**
2
+ * Plugin Metadata Export System
3
+ * Requires all plugins to export standardized metadata for marketplace compatibility
4
+ */
5
+
6
+ const {
7
+ validatePluginMetadata,
8
+ PLUGIN_NAMING,
9
+ } = require('./plugin-registry-format.js');
10
+ // eslint-disable-line global-require
11
+ const { VersionUtils } = require('./version-resolver.js');
12
+ // eslint-disable-line global-require
13
+
14
+ /**
15
+ * Plugin metadata extractor and validator
16
+ */
17
+ class PluginMetadataExtractor {
18
+ constructor() {
19
+ this.requiredFields = ['name', 'version', '_type', 'description', 'author'];
20
+ this.optionalFields = [
21
+ 'homepage',
22
+ 'repository',
23
+ 'keywords',
24
+ 'license',
25
+ 'engines',
26
+ 'dependencies',
27
+ 'peerDependencies',
28
+ '_config',
29
+ 'examples',
30
+ 'tags',
31
+ ];
32
+ }
33
+
34
+ /**
35
+ * Extract metadata from plugin module
36
+ * @param {object} pluginModule - Plugin module or class
37
+ * @param {string} pluginType - Plugin _type (loader, embedder, etc.)
38
+ * @returns {object} Extracted metadata
39
+ */
40
+ extractMetadata(pluginModule, pluginType) {
41
+ // Try different metadata export patterns
42
+ let metadata = null;
43
+
44
+ // Pattern 1: Static metadata property
45
+ if (pluginModule.metadata) {
46
+ metadata = pluginModule.metadata;
47
+ }
48
+ // Pattern 2: getMetadata() method
49
+ else if (typeof pluginModule.getMetadata === 'function') {
50
+ metadata = pluginModule.getMetadata();
51
+ }
52
+ // Pattern 3: Class constructor with static metadata
53
+ else if (
54
+ typeof pluginModule === 'function' &&
55
+ pluginModule.prototype &&
56
+ pluginModule.constructor.metadata
57
+ ) {
58
+ metadata = pluginModule.constructor.metadata;
59
+ }
60
+ // Pattern 4: Default export with metadata
61
+ else if (pluginModule.default && pluginModule.default.metadata) {
62
+ metadata = pluginModule.default.metadata;
63
+ }
64
+ // Pattern 5: Package.json style metadata
65
+ else if (pluginModule.package) {
66
+ metadata = this.convertPackageJsonMetadata(
67
+ pluginModule.package,
68
+ pluginType,
69
+ );
70
+ }
71
+
72
+ if (!metadata) {
73
+ throw new Error(
74
+ 'Plugin does not export required metadata. Please add a \'metadata\' property or \'getMetadata()\' method.',
75
+ );
76
+ }
77
+
78
+ // Ensure type is set correctly
79
+ if (!metadata._type) {
80
+ metadata._type = pluginType;
81
+ } else if (metadata._type !== pluginType) {
82
+ throw new Error(
83
+ `Plugin metadata _type '${metadata._type}' does not match expected _type '${pluginType}'`,
84
+ );
85
+ }
86
+
87
+ return this.validateAndNormalizeMetadata(metadata);
88
+ }
89
+
90
+ /**
91
+ * Convert package.json style metadata to plugin metadata format
92
+ * @param {object} packageData - Package.json data
93
+ * @param {string} pluginType - Plugin _type
94
+ * @returns {object} Plugin metadata
95
+ */
96
+ convertPackageJsonMetadata(packageData, pluginType) {
97
+ return {
98
+ name: packageData.name,
99
+ version: packageData.version,
100
+ _type: pluginType,
101
+ description: packageData.description,
102
+ author:
103
+ typeof packageData.author === 'string'
104
+ ? packageData.author
105
+ : packageData.author?.name,
106
+ homepage: packageData.homepage,
107
+ repository: packageData.repository,
108
+ keywords: packageData.keywords,
109
+ license: packageData.license,
110
+ engines: packageData.engines,
111
+ dependencies: packageData.dependencies,
112
+ peerDependencies: packageData.peerDependencies,
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Validate and normalize plugin metadata
118
+ * @param {object} metadata - Raw metadata
119
+ * @returns {object} Validated and normalized metadata
120
+ */
121
+ validateAndNormalizeMetadata(metadata) {
122
+ // Validate required fields
123
+ for (const field of this.requiredFields) {
124
+ if (!metadata[field]) {
125
+ throw new Error(`Plugin metadata missing required field: ${field}`);
126
+ }
127
+ }
128
+
129
+ // Validate plugin name
130
+ const nameValidation = PLUGIN_NAMING.validateName(metadata.name);
131
+ if (!nameValidation.valid) {
132
+ throw new Error(`Invalid plugin name: ${nameValidation.reason}`);
133
+ }
134
+
135
+ // Validate version format
136
+ if (!VersionUtils.parseVersion(metadata.version)) {
137
+ throw new Error(`Invalid version format: ${metadata.version}`);
138
+ }
139
+
140
+ // Validate using schema
141
+ const schemaValidation = validatePluginMetadata(metadata);
142
+ if (!schemaValidation.valid) {
143
+ const errors = schemaValidation.errors
144
+ .map((err) => `${err.instancePath}: ${err.message}`)
145
+ .join(', ');
146
+ throw new Error(`Plugin metadata validation failed: ${errors}`);
147
+ }
148
+
149
+ // Normalize and set defaults
150
+ const normalized = {
151
+ ...metadata,
152
+ keywords: metadata.keywords || [],
153
+ tags: metadata.tags || [],
154
+ engines: metadata.engines || {},
155
+ dependencies: metadata.dependencies || {},
156
+ peerDependencies: metadata.peerDependencies || {},
157
+ _config: metadata._config || {},
158
+ examples: metadata.examples || [],
159
+ };
160
+
161
+ // Add automatic tags based on plugin characteristics
162
+ normalized.tags = this.addAutomaticTags(normalized);
163
+
164
+ return normalized;
165
+ }
166
+
167
+ /**
168
+ * Add automatic tags based on plugin characteristics
169
+ * @param {object} metadata - Plugin metadata
170
+ * @returns {Array<string>} Updated tags
171
+ */
172
+ addAutomaticTags(metadata) {
173
+ const tags = new Set(metadata.tags || []);
174
+
175
+ // Add type-based tag
176
+ tags.add(metadata._type);
177
+
178
+ // Add version stability tags
179
+ const version = VersionUtils.parseVersion(metadata.version);
180
+ if (version.isPrerelease) {
181
+ if (version.prerelease[0] === 'alpha') {
182
+ tags.add('alpha');
183
+ } else if (version.prerelease[0] === 'beta') {
184
+ tags.add('beta');
185
+ } else {
186
+ tags.add('prerelease');
187
+ }
188
+ } else {
189
+ tags.add('stable');
190
+ }
191
+
192
+ // Add dependency-based tags
193
+ if (Object.keys(metadata.dependencies).length === 0) {
194
+ tags.add('zero-dependencies');
195
+ }
196
+
197
+ // Add feature tags based on config schema
198
+ if (metadata._config && Object.keys(metadata._config).length > 0) {
199
+ tags.add('configurable');
200
+ }
201
+
202
+ // Add example tags
203
+ if (metadata.examples && metadata.examples.length > 0) {
204
+ tags.add('documented');
205
+ }
206
+
207
+ return Array.from(tags);
208
+ }
209
+
210
+ /**
211
+ * Generate plugin manifest for publishing
212
+ * @param {object} metadata - Plugin metadata
213
+ * @param {object} _options - Generation _options
214
+ * @returns {object} Plugin manifest
215
+ */
216
+ generateManifest(metadata, _options = {}) {
217
+ const manifest = {
218
+ ...metadata,
219
+ publishedAt: new Date().toISOString(),
220
+ integrity: _options.integrity,
221
+ size: _options.size,
222
+ downloadUrl: _options.downloadUrl,
223
+ };
224
+
225
+ // Add build information if available
226
+ if (_options.buildInfo) {
227
+ manifest.build = {
228
+ timestamp: _options.buildInfo.timestamp,
229
+ commit: _options.buildInfo.commit,
230
+ branch: _options.buildInfo.branch,
231
+ environment: _options.buildInfo.environment,
232
+ };
233
+ }
234
+
235
+ return manifest;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Plugin metadata decorator for easy metadata definition
241
+ * @param {object} metadata - Plugin metadata
242
+ * @returns {Function} Class decorator
243
+ */
244
+ function pluginMetadata(metadata) {
245
+ return function (target) {
246
+ target.metadata = metadata;
247
+ return target;
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Plugin metadata validation middleware
253
+ * Validates plugin metadata during registration
254
+ */
255
+ class PluginMetadataValidator {
256
+ constructor() {
257
+ this.extractor = new PluginMetadataExtractor();
258
+ }
259
+
260
+ /**
261
+ * Validate plugin during registration
262
+ * @param {string} _type - Plugin _type
263
+ * @param {string} name - Plugin name
264
+ * @param {object} plugin - Plugin _instance
265
+ * @returns {object} Validation result with metadata
266
+ */
267
+ validatePlugin(_type, name, plugin) {
268
+ try {
269
+ const metadata = this.extractor.extractMetadata(plugin, _type);
270
+
271
+ // Verify name matches registration name
272
+ if (metadata.name !== name) {
273
+ throw new Error(
274
+ `Plugin metadata name '${metadata.name}' does not match registration name '${name}'`,
275
+ );
276
+ }
277
+
278
+ return {
279
+ valid: true,
280
+ metadata,
281
+ warnings: this.generateWarnings(metadata),
282
+ };
283
+ } catch (error) {
284
+ return {
285
+ valid: false,
286
+ error: error.message,
287
+ metadata: null,
288
+ warnings: [],
289
+ };
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Generate warnings for plugin metadata
295
+ * @param {object} metadata - Plugin metadata
296
+ * @returns {Array<string>} Warning messages
297
+ */
298
+ generateWarnings(metadata) {
299
+ const warnings = [];
300
+
301
+ // Check for missing optional but recommended fields
302
+ if (!metadata.homepage) {
303
+ warnings.push(
304
+ 'Consider adding a homepage URL for better discoverability',
305
+ );
306
+ }
307
+
308
+ if (!metadata.repository) {
309
+ warnings.push('Consider adding repository information for transparency');
310
+ }
311
+
312
+ if (!metadata.license) {
313
+ warnings.push('Consider specifying a license for legal clarity');
314
+ }
315
+
316
+ if (!metadata.keywords || metadata.keywords.length === 0) {
317
+ warnings.push('Consider adding keywords to improve searchability');
318
+ }
319
+
320
+ if (!metadata.examples || metadata.examples.length === 0) {
321
+ warnings.push('Consider adding usage examples for better documentation');
322
+ }
323
+
324
+ // Check version format
325
+ const version = VersionUtils.parseVersion(metadata.version);
326
+ if (version.major === 0) {
327
+ warnings.push(
328
+ 'Version 0.x.x indicates unstable API - consider releasing 1.0.0 when stable',
329
+ );
330
+ }
331
+
332
+ // Check description length
333
+ if (metadata.description.length < 20) {
334
+ warnings.push('Consider providing a more detailed description');
335
+ }
336
+
337
+ return warnings;
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Plugin metadata utilities
343
+ */
344
+ const MetadataUtils = {
345
+ /**
346
+ * Create metadata template for new plugins
347
+ * @param {string} _type - Plugin _type
348
+ * @param {string} name - Plugin name
349
+ * @param {object} _options - Template _options
350
+ * @returns {object} Metadata template
351
+ */
352
+ createTemplate(_type, name, _options = {}) {
353
+ return {
354
+ name,
355
+ version: '1.0.0',
356
+ _type,
357
+ description: `A ${_type} plugin for RAG pipeline`,
358
+ author: _options.author || 'Unknown',
359
+ homepage: _options.homepage || '',
360
+ repository: _options.repository || {
361
+ _type: 'git',
362
+ url: '',
363
+ },
364
+ keywords: [_type, 'rag', 'plugin'],
365
+ license: _options.license || 'MIT',
366
+ engines: {
367
+ node: '>=18.0.0',
368
+ 'rag-pipeline-utils': '>=2.0.0',
369
+ },
370
+ dependencies: {},
371
+ peerDependencies: {},
372
+ _config: {
373
+ _type: 'object',
374
+ properties: {},
375
+ additionalProperties: false,
376
+ },
377
+ examples: [
378
+ {
379
+ title: 'Basic Usage',
380
+ description: `Basic ${_type} plugin usage`,
381
+ _config: {},
382
+ },
383
+ ],
384
+ tags: [],
385
+ };
386
+ },
387
+
388
+ /**
389
+ * Merge metadata with defaults
390
+ * @param {object} metadata - User metadata
391
+ * @param {object} defaults - Default metadata
392
+ * @returns {object} Merged metadata
393
+ */
394
+ mergeWithDefaults(metadata, defaults) {
395
+ return {
396
+ ...defaults,
397
+ ...metadata,
398
+ keywords: [...(defaults.keywords || []), ...(metadata.keywords || [])],
399
+ tags: [...(defaults.tags || []), ...(metadata.tags || [])],
400
+ engines: { ...defaults.engines, ...metadata.engines },
401
+ dependencies: { ...defaults.dependencies, ...metadata.dependencies },
402
+ peerDependencies: {
403
+ ...defaults.peerDependencies,
404
+ ...metadata.peerDependencies,
405
+ },
406
+ examples: [...(defaults.examples || []), ...(metadata.examples || [])],
407
+ };
408
+ },
409
+
410
+ /**
411
+ * Compare metadata versions
412
+ * @param {object} metadata1 - First metadata
413
+ * @param {object} metadata2 - Second metadata
414
+ * @returns {number} Comparison result (-1, 0, 1)
415
+ */
416
+ compareVersions(metadata1, metadata2) {
417
+ return VersionUtils.compareVersions(metadata1.version, metadata2.version);
418
+ },
419
+
420
+ /**
421
+ * Check if metadata is compatible with requirements
422
+ * @param {object} metadata - Plugin metadata
423
+ * @param {object} requirements - Compatibility requirements
424
+ * @returns {{ compatible: boolean, issues: Array<string> }}
425
+ */
426
+ checkCompatibility(metadata, requirements) {
427
+ const issues = [];
428
+
429
+ // Check engine requirements
430
+ if (requirements.engines) {
431
+ for (const [engine, requiredVersion] of Object.entries(
432
+ requirements.engines,
433
+ )) {
434
+ const pluginVersion = metadata.engines?.[engine];
435
+ if (
436
+ pluginVersion &&
437
+ !VersionUtils.satisfiesRequirement(requiredVersion, pluginVersion)
438
+ ) {
439
+ issues.push(
440
+ `Engine '${engine}' requirement not satisfied: requires ${pluginVersion}, have ${requiredVersion}`,
441
+ );
442
+ }
443
+ }
444
+ }
445
+
446
+ // Check peer dependencies
447
+ if (requirements.peerDependencies && metadata.peerDependencies) {
448
+ for (const [dep, requiredVersion] of Object.entries(
449
+ requirements.peerDependencies,
450
+ )) {
451
+ const pluginVersion = metadata.peerDependencies[dep];
452
+ if (
453
+ pluginVersion &&
454
+ !VersionUtils.satisfiesRequirement(requiredVersion, pluginVersion)
455
+ ) {
456
+ issues.push(
457
+ `Peer dependency '${dep}' version mismatch: requires ${pluginVersion}, have ${requiredVersion}`,
458
+ );
459
+ }
460
+ }
461
+ }
462
+
463
+ return {
464
+ compatible: issues.length === 0,
465
+ issues,
466
+ };
467
+ },
468
+ };
469
+
470
+ // Global metadata extractor instance
471
+ const metadataExtractor = new PluginMetadataExtractor();
472
+
473
+ // Global metadata validator instance
474
+ const metadataValidator = new PluginMetadataValidator();
475
+
476
+ // Default export
477
+
478
+ module.exports = {
479
+ PluginMetadataExtractor,
480
+ PluginMetadataValidator,
481
+ pluginMetadata,
482
+ MetadataUtils,
483
+ metadataExtractor,
484
+ metadataValidator,
485
+ };