@devilsdev/rag-pipeline-utils 2.1.12 → 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.
- package/.ragrc.schema.json +218 -0
- package/README.md +292 -32
- package/bin/cli.js +8 -14
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +22 -7
- package/package.json +17 -13
- package/src/ai/adaptive-retrieval.js +191 -0
- package/src/ai/federated-learning.js +214 -0
- package/src/ai/federation/federated-learning-coordinator.js +345 -0
- package/src/ai/federation.js +76 -0
- package/src/ai/index-fixed.js +509 -0
- package/src/ai/index.js +33 -0
- package/src/ai/model-trainer.js +217 -0
- package/src/ai/model-training.js +205 -0
- package/src/ai/module-template.js +37 -0
- package/src/ai/multimodal/multi-modal-processor.js +345 -0
- package/src/ai/multimodal-processing.js +268 -0
- package/src/ai/multimodal.js +71 -0
- package/src/ai/orchestrator.js +70 -0
- package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
- package/src/ai/retrieval-engine.js +69 -0
- package/src/ai/training/model-training-orchestrator.js +228 -0
- package/src/ci/workflow-analyzer.js +71 -0
- package/src/cli/commands/ai-ml.js +967 -0
- package/src/cli/commands/docs.js +228 -0
- package/src/cli/commands/dx.js +538 -0
- package/src/cli/commands/plugin-hub.js +875 -0
- package/src/cli/doctor-command.js +639 -0
- package/src/cli/enhanced-cli-commands.js +945 -0
- package/src/cli/interactive-wizard.js +997 -0
- package/src/cli/plugin-marketplace-commands.js +869 -0
- package/src/cli.js +17 -0
- package/src/config/enhanced-ragrc-schema.js +632 -0
- package/src/config/load-config.js +54 -0
- package/src/config/load-plugin-config.js +69 -0
- package/src/config/normalize-config.js +105 -0
- package/src/config/schema-validator.js +315 -0
- package/src/config/validate-plugin-schema.js +35 -0
- package/src/config/validate-schema.js +113 -0
- package/src/contracts/plugin-contracts.js +33 -0
- package/src/core/create-pipeline.js +99 -0
- package/src/core/dependency-injection.js +242 -0
- package/src/core/observability/event-logger.js +241 -0
- package/src/core/observability/instrumented-pipeline.js +609 -0
- package/src/core/observability/metrics.js +497 -0
- package/src/core/observability/tracing.js +781 -0
- package/src/core/performance/benchmark.js +516 -0
- package/src/core/performance/parallel-processor.js +240 -0
- package/src/core/performance/streaming-safeguards.js +611 -0
- package/src/core/pipeline-factory.js +60 -0
- package/src/core/plugin-contracts.js +89 -0
- package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
- package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
- package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
- package/src/core/plugin-marketplace/version-resolver.js +61 -0
- package/src/core/plugin-registry.js +265 -0
- package/src/dag/dag-engine.js +954 -0
- package/src/dag/dag-node.js +76 -0
- package/src/dag/enhanced-dag-engine.js +822 -0
- package/src/dx/index.js +40 -0
- package/src/dx/integration-templates.js +665 -0
- package/src/dx/performance-profiler.js +968 -0
- package/src/dx/realtime-debugger.js +755 -0
- package/src/dx/visual-pipeline-builder.js +578 -0
- package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
- package/src/ecosystem/plugin-certification.js +580 -0
- package/src/ecosystem/plugin-hub.js +821 -0
- package/src/enterprise/audit-logging.js +967 -0
- package/src/enterprise/data-governance.js +408 -0
- package/src/enterprise/multi-tenancy.js +496 -0
- package/src/enterprise/sso-integration.js +903 -0
- package/src/evaluate/evaluator.js +52 -0
- package/src/evaluate/scoring.js +91 -0
- package/src/index.js +67 -0
- package/src/ingest.js +59 -0
- package/src/loader/csv-loader.js +38 -0
- package/src/loader/directory-loader.js +48 -0
- package/src/loader/html-loader.js +62 -0
- package/src/loader/markdown-loader.js +67 -0
- package/src/mocks/openai-embedder.js +119 -0
- package/src/mocks/openai-llm.js +77 -0
- package/src/mocks/pdf-loader.js +21 -0
- package/src/mocks/pinecone-retriever.js +106 -0
- package/src/observability/audit-logger.js +758 -0
- package/src/observability/dashboard-config.json +675 -0
- package/src/observability/event-logger.js +310 -0
- package/src/observability/metrics.js +691 -0
- package/src/observability/security-monitor.js +830 -0
- package/src/observability/slo-monitor.js +319 -0
- package/src/observability/telemetry.js +686 -0
- package/src/pipeline/pipeline.js +18 -0
- package/src/plugins/sample-embedder.js +53 -0
- package/src/plugins/sample-llm.js +30 -0
- package/src/plugins/sample-loader.js +24 -0
- package/src/plugins/sample-retriever.js +84 -0
- package/src/query.js +117 -0
- package/src/reranker/llm-reranker.js +85 -0
- package/src/scripts/script-utilities.js +36 -0
- package/src/security/plugin-sandbox.js +586 -0
- package/src/security/plugin-signature-verifier.js +414 -0
- package/src/security/validator.js +36 -0
- package/src/utils/ci/diagnostic-reporter.js +57 -0
- package/src/utils/logger.js +211 -0
- package/src/utils/performance-monitor.js +561 -0
- package/src/utils/plugin-scaffolder.js +447 -0
- package/src/utils/retry-policy.js +443 -0
- package/src/utils/retry.js +107 -0
- package/src/utils/safe-expression-evaluator.js +579 -0
- package/src/utils/structured-logger.js +361 -0
- package/src/utils/validate-plugin-contract.js +42 -0
|
@@ -0,0 +1,869 @@
|
|
|
1
|
+
/**
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
* CLI Commands for Plugin Marketplace
|
|
4
|
+
* Provides commands for plugin discovery, installation, publishing, and management
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Command } = require('commander');
|
|
8
|
+
// eslint-disable-line global-require
|
|
9
|
+
const fs = require('fs/promises');
|
|
10
|
+
// eslint-disable-line global-require
|
|
11
|
+
const path = require('path');
|
|
12
|
+
// eslint-disable-line global-require
|
|
13
|
+
const {
|
|
14
|
+
PluginPublisher,
|
|
15
|
+
PublishingUtils,
|
|
16
|
+
} = require('../core/plugin-marketplace/plugin-publisher.js');
|
|
17
|
+
// eslint-disable-line global-require
|
|
18
|
+
const {
|
|
19
|
+
createVersionResolver,
|
|
20
|
+
} = require('../core/plugin-marketplace/version-resolver.js');
|
|
21
|
+
// eslint-disable-line global-require
|
|
22
|
+
const {
|
|
23
|
+
MetadataUtils,
|
|
24
|
+
} = require('../core/plugin-marketplace/plugin-metadata.js');
|
|
25
|
+
// eslint-disable-line global-require
|
|
26
|
+
const {
|
|
27
|
+
DEFAULT_REGISTRY_URLS,
|
|
28
|
+
} = require('../core/plugin-marketplace/plugin-registry-format.js');
|
|
29
|
+
// eslint-disable-line global-require
|
|
30
|
+
// REGISTRY_SCHEMA and LOCAL_REGISTRY_FILE unused - reserved for future use
|
|
31
|
+
const { logger } = require('../utils/logger.js');
|
|
32
|
+
// eslint-disable-line global-require
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Plugin marketplace CLI commands
|
|
36
|
+
*/
|
|
37
|
+
function createPluginMarketplaceCommands() {
|
|
38
|
+
const _metadata = {};
|
|
39
|
+
const pluginCmd = new Command('plugin');
|
|
40
|
+
pluginCmd.description('Plugin marketplace commands');
|
|
41
|
+
|
|
42
|
+
// Plugin search command
|
|
43
|
+
pluginCmd
|
|
44
|
+
.command('search')
|
|
45
|
+
.description('Search for plugins in the marketplace')
|
|
46
|
+
.argument('[query]', 'Search query')
|
|
47
|
+
.option(
|
|
48
|
+
'--_type <_type>',
|
|
49
|
+
'Filter by plugin _type (loader, embedder, retriever, llm, reranker)',
|
|
50
|
+
)
|
|
51
|
+
.option('--tag <tag>', 'Filter by tag')
|
|
52
|
+
.option('--author <author>', 'Filter by author')
|
|
53
|
+
.option('--limit <number>', 'Limit number of results', '20')
|
|
54
|
+
.option('--registry <url>', 'Custom registry URL')
|
|
55
|
+
.action(async (query, _options) => {
|
|
56
|
+
try {
|
|
57
|
+
console.log('🔍 Searching plugins...');
|
|
58
|
+
// eslint-disable-line no-console
|
|
59
|
+
|
|
60
|
+
const _registryUrl = _options.registry || DEFAULT_REGISTRY_URLS[0];
|
|
61
|
+
const registry = await fetchRegistry(_registryUrl);
|
|
62
|
+
|
|
63
|
+
const results = searchPlugins(registry, query, _options);
|
|
64
|
+
|
|
65
|
+
if (results.length === 0) {
|
|
66
|
+
console.log('No plugins found matching your criteria.');
|
|
67
|
+
// eslint-disable-line no-console
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`\nFound ${results.length} plugin(s):\n`);
|
|
72
|
+
// eslint-disable-line no-console
|
|
73
|
+
|
|
74
|
+
results.forEach((plugin) => {
|
|
75
|
+
console.log(`📦 ${plugin.metadata.name} v${plugin.latest}`);
|
|
76
|
+
// eslint-disable-line no-console
|
|
77
|
+
console.log(` ${plugin.metadata.description}`);
|
|
78
|
+
// eslint-disable-line no-console
|
|
79
|
+
console.log(` Author: ${plugin.metadata.author}`);
|
|
80
|
+
// eslint-disable-line no-console
|
|
81
|
+
console.log(` Type: ${plugin.metadata._type}`);
|
|
82
|
+
// eslint-disable-line no-console
|
|
83
|
+
if (plugin.metadata.keywords.length > 0) {
|
|
84
|
+
console.log(` Keywords: ${plugin.metadata.keywords.join(', ')}`);
|
|
85
|
+
// eslint-disable-line no-console
|
|
86
|
+
}
|
|
87
|
+
if (plugin.downloads?.total) {
|
|
88
|
+
console.log(
|
|
89
|
+
` Downloads: ${plugin.downloads.total.toLocaleString()}`,
|
|
90
|
+
);
|
|
91
|
+
// eslint-disable-line no-console
|
|
92
|
+
}
|
|
93
|
+
console.log('');
|
|
94
|
+
// eslint-disable-line no-console
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
logger.error('❌ Plugin search failed:', error.message);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Plugin info command
|
|
103
|
+
pluginCmd
|
|
104
|
+
.command('info')
|
|
105
|
+
.description('Show detailed information about a plugin')
|
|
106
|
+
.argument('<name>', 'Plugin name')
|
|
107
|
+
.option('--version <version>', 'Specific version to show info for')
|
|
108
|
+
.option('--registry <url>', 'Custom registry URL')
|
|
109
|
+
.action(async (name, _options) => {
|
|
110
|
+
try {
|
|
111
|
+
const _registryUrl = _options.registry || DEFAULT_REGISTRY_URLS[0];
|
|
112
|
+
const registry = await fetchRegistry(_registryUrl);
|
|
113
|
+
|
|
114
|
+
const plugin = registry.plugins[name];
|
|
115
|
+
if (!plugin) {
|
|
116
|
+
console.log(`❌ Plugin '${name}' not found in registry.`);
|
|
117
|
+
// eslint-disable-line no-console
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const version = _options.version || plugin.latest;
|
|
122
|
+
const versionData = plugin.versions[version];
|
|
123
|
+
|
|
124
|
+
if (!versionData) {
|
|
125
|
+
console.log(
|
|
126
|
+
`❌ Version '${version}' not found for plugin '${name}'.`,
|
|
127
|
+
);
|
|
128
|
+
// eslint-disable-line no-console
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`\n📦 ${plugin.metadata.name} v${version}\n`);
|
|
133
|
+
// eslint-disable-line no-console
|
|
134
|
+
console.log(`Description: ${plugin.metadata.description}`);
|
|
135
|
+
// eslint-disable-line no-console
|
|
136
|
+
console.log(`Author: ${plugin.metadata.author}`);
|
|
137
|
+
// eslint-disable-line no-console
|
|
138
|
+
console.log(`Type: ${plugin.metadata._type}`);
|
|
139
|
+
// eslint-disable-line no-console
|
|
140
|
+
console.log(`License: ${plugin.metadata.license || 'Not specified'}`);
|
|
141
|
+
// eslint-disable-line no-console
|
|
142
|
+
|
|
143
|
+
if (plugin.metadata.homepage) {
|
|
144
|
+
console.log(`Homepage: ${plugin.metadata.homepage}`);
|
|
145
|
+
// eslint-disable-line no-console
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (plugin.metadata.repository) {
|
|
149
|
+
console.log(`Repository: ${plugin.metadata.repository.url}`);
|
|
150
|
+
// eslint-disable-line no-console
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (plugin.metadata.keywords.length > 0) {
|
|
154
|
+
console.log(`Keywords: ${plugin.metadata.keywords.join(', ')}`);
|
|
155
|
+
// eslint-disable-line no-console
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log('\nVersions available:');
|
|
159
|
+
// eslint-disable-line no-console
|
|
160
|
+
const versions = Object.keys(plugin.versions).sort((a, b) => {
|
|
161
|
+
const semver = require('semver');
|
|
162
|
+
// eslint-disable-line global-require
|
|
163
|
+
return semver.rcompare(a, b);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
versions.slice(0, 10).forEach((v) => {
|
|
167
|
+
const isLatest = v === plugin.latest;
|
|
168
|
+
const isBeta = v === plugin.beta;
|
|
169
|
+
const isAlpha = v === plugin.alpha;
|
|
170
|
+
|
|
171
|
+
let tags = [];
|
|
172
|
+
if (isLatest) tags.push('latest');
|
|
173
|
+
if (isBeta) tags.push('beta');
|
|
174
|
+
if (isAlpha) tags.push('alpha');
|
|
175
|
+
|
|
176
|
+
const tagStr = tags.length > 0 ? ` (${tags.join(', ')})` : '';
|
|
177
|
+
console.log(
|
|
178
|
+
` ${v}${tagStr} - ${plugin.versions[v].publishedAt.split('T')[0]}`,
|
|
179
|
+
);
|
|
180
|
+
// eslint-disable-line no-console
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (versions.length > 10) {
|
|
184
|
+
console.log(` ... and ${versions.length - 10} more versions`);
|
|
185
|
+
// eslint-disable-line no-console
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (plugin.downloads) {
|
|
189
|
+
console.log('\nDownloads:');
|
|
190
|
+
// eslint-disable-line no-console
|
|
191
|
+
console.log(
|
|
192
|
+
` Total: ${plugin.downloads.total?.toLocaleString() || 'N/A'}`,
|
|
193
|
+
);
|
|
194
|
+
// eslint-disable-line no-console
|
|
195
|
+
console.log(
|
|
196
|
+
` Monthly: ${plugin.downloads.monthly?.toLocaleString() || 'N/A'}`,
|
|
197
|
+
);
|
|
198
|
+
// eslint-disable-line no-console
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
logger.error('❌ Failed to get plugin info:', error.message);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Plugin install command
|
|
207
|
+
pluginCmd
|
|
208
|
+
.command('install')
|
|
209
|
+
.description('Install a plugin from the marketplace')
|
|
210
|
+
.argument('<name>', 'Plugin name')
|
|
211
|
+
.option('--version <version>', 'Specific version to install', 'latest')
|
|
212
|
+
.option('--registry <url>', 'Custom registry URL')
|
|
213
|
+
.option('--save', 'Add to .ragrc.json configuration')
|
|
214
|
+
.option('--dev', 'Install as development dependency')
|
|
215
|
+
.action(async (name, _options) => {
|
|
216
|
+
try {
|
|
217
|
+
console.log(`📦 Installing plugin '${name}'...`);
|
|
218
|
+
// eslint-disable-line no-console
|
|
219
|
+
|
|
220
|
+
const _registryUrl = _options.registry || DEFAULT_REGISTRY_URLS[0];
|
|
221
|
+
const registry = await fetchRegistry(_registryUrl);
|
|
222
|
+
|
|
223
|
+
const resolver = createVersionResolver(registry);
|
|
224
|
+
const resolution = await resolver.resolveVersion(
|
|
225
|
+
name,
|
|
226
|
+
_options.version,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
console.log(`✅ Resolved ${name}@${resolution.version}`);
|
|
230
|
+
// eslint-disable-line no-console
|
|
231
|
+
|
|
232
|
+
// In a real implementation, this would download and install the plugin
|
|
233
|
+
console.log(`📥 Downloading from: ${resolution.downloadUrl}`);
|
|
234
|
+
// eslint-disable-line no-console
|
|
235
|
+
console.log(`🔒 Integrity: ${resolution.integrity}`);
|
|
236
|
+
// eslint-disable-line no-console
|
|
237
|
+
console.log(`📊 Size: ${(resolution.size / 1024).toFixed(1)} KB`);
|
|
238
|
+
// eslint-disable-line no-console
|
|
239
|
+
|
|
240
|
+
if (_options.save) {
|
|
241
|
+
await addToRagrcConfig(name, resolution.version, _options.dev);
|
|
242
|
+
console.log('💾 Added to .ragrc.json');
|
|
243
|
+
// eslint-disable-line no-console
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log(
|
|
247
|
+
`🎉 Plugin '${name}@${resolution.version}' installed successfully!`,
|
|
248
|
+
);
|
|
249
|
+
// eslint-disable-line no-console
|
|
250
|
+
} catch (error) {
|
|
251
|
+
logger.error('❌ Plugin installation failed:', error.message);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Plugin publish command
|
|
257
|
+
pluginCmd
|
|
258
|
+
.command('publish')
|
|
259
|
+
.description('Publish a plugin to the marketplace')
|
|
260
|
+
.argument('[path]', 'Plugin directory path', '.')
|
|
261
|
+
.option('--registry-url <url>', 'Registry URL')
|
|
262
|
+
.option('--auth-token <token>', 'Authentication token')
|
|
263
|
+
.option('--dry-run', 'Perform a dry run without actually publishing')
|
|
264
|
+
.option('--output-dir <dir>', 'Output directory for package')
|
|
265
|
+
.action(async (pluginPath, _options) => {
|
|
266
|
+
try {
|
|
267
|
+
const publisher = new PluginPublisher({
|
|
268
|
+
registryUrl: _options.registryUrl,
|
|
269
|
+
authToken: _options.authToken,
|
|
270
|
+
dryRun: _options.dryRun,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const result = await publisher.publishPlugin(pluginPath, {
|
|
274
|
+
outputDir: _options.outputDir,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (result.success) {
|
|
278
|
+
if (result.dryRun) {
|
|
279
|
+
console.log('\n🧪 Dry run completed successfully!');
|
|
280
|
+
// eslint-disable-line no-console
|
|
281
|
+
console.log(
|
|
282
|
+
`Plugin: ${result.metadata.name}@${result.metadata.version}`,
|
|
283
|
+
);
|
|
284
|
+
// eslint-disable-line no-console
|
|
285
|
+
console.log(
|
|
286
|
+
`Package size: ${(result.packageInfo.size / 1024).toFixed(1)} KB`,
|
|
287
|
+
);
|
|
288
|
+
// eslint-disable-line no-console
|
|
289
|
+
console.log(`Files: ${result.packageInfo.files.length}`);
|
|
290
|
+
// eslint-disable-line no-console
|
|
291
|
+
} else {
|
|
292
|
+
console.log('\n🎉 Plugin published successfully!');
|
|
293
|
+
// eslint-disable-line no-console
|
|
294
|
+
console.log(`Download URL: ${result.publishResult.downloadUrl}`);
|
|
295
|
+
// eslint-disable-line no-console
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
console.error(`❌ Publishing failed: ${result.error}`);
|
|
299
|
+
// eslint-disable-line no-console
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
logger.error('❌ Plugin publishing failed:', error.message);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Plugin validate command
|
|
309
|
+
pluginCmd
|
|
310
|
+
.command('validate')
|
|
311
|
+
.description('Validate a plugin for marketplace publishing')
|
|
312
|
+
.argument('[path]', 'Plugin directory path', '.')
|
|
313
|
+
.action(async (pluginPath) => {
|
|
314
|
+
try {
|
|
315
|
+
console.log('🔍 Validating plugin...');
|
|
316
|
+
// eslint-disable-line no-console
|
|
317
|
+
|
|
318
|
+
const { ready, issues } =
|
|
319
|
+
await PublishingUtils.validateForPublishing(pluginPath);
|
|
320
|
+
|
|
321
|
+
if (ready) {
|
|
322
|
+
console.log('✅ Plugin is ready for publishing!');
|
|
323
|
+
// eslint-disable-line no-console
|
|
324
|
+
|
|
325
|
+
// Show publishing checklist
|
|
326
|
+
const checklist = PublishingUtils.generatePublishingChecklist({});
|
|
327
|
+
console.log('\n📋 Publishing checklist:');
|
|
328
|
+
// eslint-disable-line no-console
|
|
329
|
+
checklist.forEach((item) => console.log(` ${item}`));
|
|
330
|
+
// eslint-disable-line no-console
|
|
331
|
+
} else {
|
|
332
|
+
console.log('❌ Plugin validation failed:');
|
|
333
|
+
// eslint-disable-line no-console
|
|
334
|
+
issues.forEach((issue) => console.log(` • ${issue}`));
|
|
335
|
+
// eslint-disable-line no-console
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
} catch (error) {
|
|
339
|
+
logger.error('❌ Plugin validation failed:', error.message);
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Plugin init command
|
|
345
|
+
pluginCmd
|
|
346
|
+
.command('init')
|
|
347
|
+
.description('Initialize a new plugin project')
|
|
348
|
+
.argument('<name>', 'Plugin name')
|
|
349
|
+
.option(
|
|
350
|
+
'--_type <_type>',
|
|
351
|
+
'Plugin _type (loader, embedder, retriever, llm, reranker)',
|
|
352
|
+
'loader',
|
|
353
|
+
)
|
|
354
|
+
.option('--author <author>', 'Plugin author')
|
|
355
|
+
.option('--license <license>', 'Plugin license', 'MIT')
|
|
356
|
+
.option('--template <template>', 'Template to use', 'basic')
|
|
357
|
+
.action(async (name, _options) => {
|
|
358
|
+
try {
|
|
359
|
+
console.log(`🚀 Initializing plugin '${name}'...`);
|
|
360
|
+
// eslint-disable-line no-console
|
|
361
|
+
|
|
362
|
+
const pluginDir = path.join(process.cwd(), name);
|
|
363
|
+
|
|
364
|
+
// Check if directory already exists
|
|
365
|
+
try {
|
|
366
|
+
await fs.access(pluginDir);
|
|
367
|
+
console.log(`❌ Directory '${name}' already exists.`);
|
|
368
|
+
// eslint-disable-line no-console
|
|
369
|
+
process.exit(1);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
// Directory doesn't exist, which is good
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Create plugin directory
|
|
375
|
+
await fs.mkdir(pluginDir, { recursive: true });
|
|
376
|
+
|
|
377
|
+
// Generate plugin metadata
|
|
378
|
+
const metadata = MetadataUtils.createTemplate(_options._type, name, {
|
|
379
|
+
author: _options.author,
|
|
380
|
+
license: _options.license,
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Create package.json
|
|
384
|
+
const packageJson = {
|
|
385
|
+
name,
|
|
386
|
+
version: metadata.version,
|
|
387
|
+
description: metadata.description,
|
|
388
|
+
main: 'index.js',
|
|
389
|
+
keywords: metadata.keywords,
|
|
390
|
+
author: metadata.author,
|
|
391
|
+
license: metadata.license,
|
|
392
|
+
engines: metadata.engines,
|
|
393
|
+
dependencies: {},
|
|
394
|
+
devDependencies: {
|
|
395
|
+
jest: '^29.0.0',
|
|
396
|
+
},
|
|
397
|
+
scripts: {
|
|
398
|
+
test: 'jest',
|
|
399
|
+
lint: 'eslint .',
|
|
400
|
+
prepare: 'npm test',
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
await fs.writeFile(
|
|
405
|
+
path.join(pluginDir, 'package.json'),
|
|
406
|
+
JSON.stringify(packageJson, null, 2),
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
// Create main plugin file
|
|
410
|
+
const pluginCode = generatePluginTemplate(
|
|
411
|
+
_options._type,
|
|
412
|
+
name,
|
|
413
|
+
metadata,
|
|
414
|
+
);
|
|
415
|
+
await fs.writeFile(path.join(pluginDir, 'index.js'), pluginCode);
|
|
416
|
+
|
|
417
|
+
// Create README.md
|
|
418
|
+
const readme = generateReadmeTemplate(name, _options._type, metadata);
|
|
419
|
+
await fs.writeFile(path.join(pluginDir, 'README.md'), readme);
|
|
420
|
+
|
|
421
|
+
// Create LICENSE file
|
|
422
|
+
const license = generateLicenseTemplate(
|
|
423
|
+
_options.license,
|
|
424
|
+
metadata.author,
|
|
425
|
+
);
|
|
426
|
+
await fs.writeFile(path.join(pluginDir, 'LICENSE'), license);
|
|
427
|
+
|
|
428
|
+
// Create test file
|
|
429
|
+
const testCode = generateTestTemplate(_options._type, name);
|
|
430
|
+
await fs.writeFile(path.join(pluginDir, `${name}.test.js`), testCode);
|
|
431
|
+
|
|
432
|
+
console.log(`✅ Plugin '${name}' initialized successfully!`);
|
|
433
|
+
// eslint-disable-line no-console
|
|
434
|
+
console.log('\nNext steps:');
|
|
435
|
+
// eslint-disable-line no-console
|
|
436
|
+
console.log(` cd ${name}`);
|
|
437
|
+
// eslint-disable-line no-console
|
|
438
|
+
console.log(' npm install');
|
|
439
|
+
// eslint-disable-line no-console
|
|
440
|
+
console.log(' npm test');
|
|
441
|
+
// eslint-disable-line no-console
|
|
442
|
+
console.log(' rag-pipeline plugin validate');
|
|
443
|
+
// eslint-disable-line no-console
|
|
444
|
+
} catch (error) {
|
|
445
|
+
logger.error('❌ Plugin initialization failed:', error.message);
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Plugin list command
|
|
451
|
+
pluginCmd
|
|
452
|
+
.command('list')
|
|
453
|
+
.description('List installed plugins')
|
|
454
|
+
.option('--_type <_type>', 'Filter by plugin _type')
|
|
455
|
+
.option('--registry <url>', 'Custom registry URL')
|
|
456
|
+
.action(async (_options) => {
|
|
457
|
+
try {
|
|
458
|
+
// Read local .ragrc.json to see configured plugins
|
|
459
|
+
const configPath = path.join(process.cwd(), '.ragrc.json');
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
const configContent = await fs.readFile(configPath, 'utf-8');
|
|
463
|
+
const _config = JSON.parse(configContent);
|
|
464
|
+
|
|
465
|
+
console.log('📦 Configured plugins:\n');
|
|
466
|
+
// eslint-disable-line no-console
|
|
467
|
+
|
|
468
|
+
const pluginTypes = [
|
|
469
|
+
'loader',
|
|
470
|
+
'embedder',
|
|
471
|
+
'retriever',
|
|
472
|
+
'llm',
|
|
473
|
+
'reranker',
|
|
474
|
+
];
|
|
475
|
+
|
|
476
|
+
for (const _type of pluginTypes) {
|
|
477
|
+
if (_options._type && _options._type !== _type) continue;
|
|
478
|
+
|
|
479
|
+
const plugins = _config.plugins?.[_type] || _config[_type] || {};
|
|
480
|
+
|
|
481
|
+
if (Object.keys(plugins).length > 0) {
|
|
482
|
+
console.log(`${_type.toUpperCase()}:`);
|
|
483
|
+
// eslint-disable-line no-console
|
|
484
|
+
for (const [name, spec] of Object.entries(plugins)) {
|
|
485
|
+
const version =
|
|
486
|
+
typeof spec === 'object'
|
|
487
|
+
? spec.version || 'latest'
|
|
488
|
+
: 'latest';
|
|
489
|
+
console.log(` ${name}@${version}`);
|
|
490
|
+
// eslint-disable-line no-console
|
|
491
|
+
}
|
|
492
|
+
console.log('');
|
|
493
|
+
// eslint-disable-line no-console
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
} catch (error) {
|
|
497
|
+
console.log('No .ragrc.json found in current directory.');
|
|
498
|
+
// eslint-disable-line no-console
|
|
499
|
+
}
|
|
500
|
+
} catch (error) {
|
|
501
|
+
logger.error('❌ Failed to list plugins:', error.message);
|
|
502
|
+
process.exit(1);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
return pluginCmd;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Fetch plugin registry from URL
|
|
511
|
+
* @param {string} registryUrl - Registry URL
|
|
512
|
+
* @returns {Promise<object>} Registry data
|
|
513
|
+
*/
|
|
514
|
+
async function fetchRegistry(_registryUrl) {
|
|
515
|
+
// In a real implementation, this would make an HTTP request
|
|
516
|
+
// For now, return a mock registry
|
|
517
|
+
return {
|
|
518
|
+
version: '1.0.0',
|
|
519
|
+
plugins: {},
|
|
520
|
+
updatedAt: new Date().toISOString(),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Search plugins in registry
|
|
526
|
+
* @param {object} registry - Plugin registry
|
|
527
|
+
* @param {string} query - Search query
|
|
528
|
+
* @param {object} _options - Search _options
|
|
529
|
+
* @returns {Array<object>} Search results
|
|
530
|
+
*/
|
|
531
|
+
function searchPlugins(_registry, _query, _options) {
|
|
532
|
+
const results = [];
|
|
533
|
+
|
|
534
|
+
for (const [name, plugin] of Object.entries(_registry.plugins)) {
|
|
535
|
+
let matches = true;
|
|
536
|
+
|
|
537
|
+
// Query matching
|
|
538
|
+
if (_query) {
|
|
539
|
+
const searchText =
|
|
540
|
+
`${name} ${plugin.metadata.description} ${plugin.metadata.keywords.join(' ')}`.toLowerCase();
|
|
541
|
+
matches = matches && searchText.includes(_query.toLowerCase());
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Type filtering
|
|
545
|
+
if (_options._type) {
|
|
546
|
+
matches = matches && plugin.metadata._type === _options._type;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Tag filtering
|
|
550
|
+
if (_options.tag) {
|
|
551
|
+
matches = matches && plugin.metadata.tags.includes(_options.tag);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Author filtering
|
|
555
|
+
if (_options.author) {
|
|
556
|
+
matches =
|
|
557
|
+
matches &&
|
|
558
|
+
plugin.metadata.author
|
|
559
|
+
.toLowerCase()
|
|
560
|
+
.includes(_options.author.toLowerCase());
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (matches) {
|
|
564
|
+
results.push(plugin);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Sort by relevance (downloads, then name)
|
|
569
|
+
results.sort((a, b) => {
|
|
570
|
+
const aDownloads = a.downloads?.total || 0;
|
|
571
|
+
const bDownloads = b.downloads?.total || 0;
|
|
572
|
+
|
|
573
|
+
if (aDownloads !== bDownloads) {
|
|
574
|
+
return bDownloads - aDownloads;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return a.metadata.name.localeCompare(b.metadata.name);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
return results.slice(0, parseInt(_options.limit));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Add plugin to .ragrc.json configuration
|
|
585
|
+
* @param {string} name - Plugin name
|
|
586
|
+
* @param {string} version - Plugin version
|
|
587
|
+
* @param {boolean} dev - Development dependency
|
|
588
|
+
* @returns {Promise<void>}
|
|
589
|
+
*/
|
|
590
|
+
async function addToRagrcConfig(_name, _version, _dev = false) {
|
|
591
|
+
const configPath = path.join(process.cwd(), '.ragrc.json');
|
|
592
|
+
|
|
593
|
+
let _config = {};
|
|
594
|
+
try {
|
|
595
|
+
const configContent = await fs.readFile(configPath, 'utf-8');
|
|
596
|
+
_config = JSON.parse(configContent);
|
|
597
|
+
} catch (error) {
|
|
598
|
+
// File doesn't exist, create new config
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Determine plugin type (would need to be detected from registry)
|
|
602
|
+
const pluginType = 'loader'; // Placeholder
|
|
603
|
+
|
|
604
|
+
if (!_config.plugins) {
|
|
605
|
+
_config.plugins = {};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (!_config.plugins[pluginType]) {
|
|
609
|
+
_config.plugins[pluginType] = {};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
_config.plugins[pluginType][_name] = {
|
|
613
|
+
name: _name,
|
|
614
|
+
version: _version,
|
|
615
|
+
source: 'registry',
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
await fs.writeFile(configPath, JSON.stringify(_config, null, 2));
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Generate plugin template code
|
|
623
|
+
* @param {string} _type - Plugin _type
|
|
624
|
+
* @param {string} name - Plugin name
|
|
625
|
+
* @param {object} metadata - Plugin metadata
|
|
626
|
+
* @returns {string} Plugin code
|
|
627
|
+
*/
|
|
628
|
+
function generatePluginTemplate(_type, _name, _metadata) {
|
|
629
|
+
const className = name
|
|
630
|
+
.split('-')
|
|
631
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
632
|
+
.join('');
|
|
633
|
+
|
|
634
|
+
return `/**
|
|
635
|
+
* ${metadata.description}
|
|
636
|
+
* @author ${metadata.author}
|
|
637
|
+
* @version ${metadata.version}
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Plugin metadata - required for marketplace
|
|
642
|
+
*/
|
|
643
|
+
const metadata = ${JSON.stringify(metadata, null, 2)};
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* ${className} plugin implementation
|
|
647
|
+
*/
|
|
648
|
+
class ${className} {
|
|
649
|
+
constructor(_config = {}) {
|
|
650
|
+
this._config = _config;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* ${
|
|
655
|
+
_type === 'loader'
|
|
656
|
+
? 'Load documents from source'
|
|
657
|
+
: _type === 'embedder'
|
|
658
|
+
? 'Generate embeddings for text chunks'
|
|
659
|
+
: _type === 'retriever'
|
|
660
|
+
? 'Retrieve relevant documents'
|
|
661
|
+
: _type === 'llm'
|
|
662
|
+
? 'Generate text using language model'
|
|
663
|
+
: 'Rerank search results'
|
|
664
|
+
}
|
|
665
|
+
* @param {any} input - Input data
|
|
666
|
+
* @returns {Promise<any>} Processed output
|
|
667
|
+
*/
|
|
668
|
+
async ${
|
|
669
|
+
_type === 'loader'
|
|
670
|
+
? 'load'
|
|
671
|
+
: _type === 'embedder'
|
|
672
|
+
? 'embed'
|
|
673
|
+
: _type === 'retriever'
|
|
674
|
+
? 'retrieve'
|
|
675
|
+
: _type === 'llm'
|
|
676
|
+
? 'generate'
|
|
677
|
+
: 'rerank'
|
|
678
|
+
}(input) {
|
|
679
|
+
// TODO: Implement ${_type} logic
|
|
680
|
+
throw new Error('${className}.${
|
|
681
|
+
_type === 'loader'
|
|
682
|
+
? 'load'
|
|
683
|
+
: _type === 'embedder'
|
|
684
|
+
? 'embed'
|
|
685
|
+
: _type === 'retriever'
|
|
686
|
+
? 'retrieve'
|
|
687
|
+
: _type === 'llm'
|
|
688
|
+
? 'generate'
|
|
689
|
+
: 'rerank'
|
|
690
|
+
} not implemented');
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
module.exports = ${className};
|
|
695
|
+
`;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Generate README template
|
|
700
|
+
* @param {string} name - Plugin name
|
|
701
|
+
* @param {string} _type - Plugin _type
|
|
702
|
+
* @param {object} metadata - Plugin metadata
|
|
703
|
+
* @returns {string} README content
|
|
704
|
+
*/
|
|
705
|
+
function generateReadmeTemplate(_name, _type, _metadata) {
|
|
706
|
+
return `# ${name}
|
|
707
|
+
|
|
708
|
+
${metadata.description}
|
|
709
|
+
|
|
710
|
+
## Installation
|
|
711
|
+
|
|
712
|
+
\`\`\`bash
|
|
713
|
+
rag-pipeline plugin install ${name}
|
|
714
|
+
\`\`\`
|
|
715
|
+
|
|
716
|
+
## Usage
|
|
717
|
+
|
|
718
|
+
\`\`\`javascript
|
|
719
|
+
const { ${name
|
|
720
|
+
.split('-')
|
|
721
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
722
|
+
.join('')} } = require('${name}');
|
|
723
|
+
|
|
724
|
+
const ${_type} = new ${name
|
|
725
|
+
.split('-')
|
|
726
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
727
|
+
.join('')}({
|
|
728
|
+
// Configuration options
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// Use the ${_type}
|
|
732
|
+
const result = await ${_type}.${
|
|
733
|
+
_type === 'loader'
|
|
734
|
+
? 'load'
|
|
735
|
+
: _type === 'embedder'
|
|
736
|
+
? 'embed'
|
|
737
|
+
: _type === 'retriever'
|
|
738
|
+
? 'retrieve'
|
|
739
|
+
: _type === 'llm'
|
|
740
|
+
? 'generate'
|
|
741
|
+
: 'rerank'
|
|
742
|
+
}(input);
|
|
743
|
+
\`\`\`
|
|
744
|
+
|
|
745
|
+
## Configuration
|
|
746
|
+
|
|
747
|
+
| Option | Type | Default | Description |
|
|
748
|
+
|--------|------|---------|-------------|
|
|
749
|
+
| \`option1\` | \`string\` | \`"default"\` | Description of option1 |
|
|
750
|
+
|
|
751
|
+
## License
|
|
752
|
+
|
|
753
|
+
${metadata.license}
|
|
754
|
+
`;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Generate LICENSE template
|
|
759
|
+
* @param {string} license - License _type
|
|
760
|
+
* @param {string} author - Author name
|
|
761
|
+
* @returns {string} License content
|
|
762
|
+
*/
|
|
763
|
+
function generateLicenseTemplate(_license, _author) {
|
|
764
|
+
if (_license === 'MIT') {
|
|
765
|
+
return `MIT License
|
|
766
|
+
|
|
767
|
+
Copyright (c) ${new Date().getFullYear()} ${_author}
|
|
768
|
+
|
|
769
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
770
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
771
|
+
in the Software without restriction, including without limitation the rights
|
|
772
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
773
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
774
|
+
furnished to do so, subject to the following conditions:
|
|
775
|
+
|
|
776
|
+
The above copyright notice and this permission notice shall be included in all
|
|
777
|
+
copies or substantial portions of the Software.
|
|
778
|
+
|
|
779
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
780
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
781
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
782
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
783
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
784
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
785
|
+
SOFTWARE.
|
|
786
|
+
`;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return `Copyright (c) ${new Date().getFullYear()} ${_author}
|
|
790
|
+
|
|
791
|
+
All rights reserved.
|
|
792
|
+
`;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Generate test template
|
|
797
|
+
* @param {string} _type - Plugin _type
|
|
798
|
+
* @param {string} name - Plugin name
|
|
799
|
+
* @returns {string} Test code
|
|
800
|
+
*/
|
|
801
|
+
function generateTestTemplate(_type, _name) {
|
|
802
|
+
const className = _name
|
|
803
|
+
.split('-')
|
|
804
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
805
|
+
.join('');
|
|
806
|
+
|
|
807
|
+
return `/**
|
|
808
|
+
* Tests for ${_name} plugin
|
|
809
|
+
*/
|
|
810
|
+
|
|
811
|
+
const { ${className} } = require('./index.js');
|
|
812
|
+
|
|
813
|
+
describe('${className}', () => {
|
|
814
|
+
let ${_type};
|
|
815
|
+
|
|
816
|
+
beforeEach(() => {
|
|
817
|
+
${_type} = new ${className}();
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
describe('constructor', () => {
|
|
821
|
+
it('should initialize with default _config', () => {
|
|
822
|
+
expect(${_type}).toBeInstanceOf(${className});
|
|
823
|
+
expect(${_type}._config).toEqual({});
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
it('should accept custom _config', () => {
|
|
827
|
+
const _config = { option1: 'value1' };
|
|
828
|
+
const customPlugin = new ${className}(_config);
|
|
829
|
+
expect(customPlugin._config).toEqual(_config);
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
describe('${
|
|
834
|
+
_type === 'loader'
|
|
835
|
+
? 'load'
|
|
836
|
+
: _type === 'embedder'
|
|
837
|
+
? 'embed'
|
|
838
|
+
: _type === 'retriever'
|
|
839
|
+
? 'retrieve'
|
|
840
|
+
: _type === 'llm'
|
|
841
|
+
? 'generate'
|
|
842
|
+
: 'rerank'
|
|
843
|
+
}', () => {
|
|
844
|
+
it('should be implemented', async () => {
|
|
845
|
+
// TODO: Add actual tests once method is implemented
|
|
846
|
+
await expect(${_type}.${
|
|
847
|
+
_type === 'loader'
|
|
848
|
+
? 'load'
|
|
849
|
+
: _type === 'embedder'
|
|
850
|
+
? 'embed'
|
|
851
|
+
: _type === 'retriever'
|
|
852
|
+
? 'retrieve'
|
|
853
|
+
: _type === 'llm'
|
|
854
|
+
? 'generate'
|
|
855
|
+
: 'rerank'
|
|
856
|
+
}('test input'))
|
|
857
|
+
.rejects.toThrow('not implemented');
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
`;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const metadata = {}; // Initialize metadata object
|
|
865
|
+
|
|
866
|
+
module.exports = {
|
|
867
|
+
createPluginMarketplaceCommands,
|
|
868
|
+
metadata,
|
|
869
|
+
};
|