@devilsdev/rag-pipeline-utils 2.1.12 โ 2.2.1
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 +178 -550
- package/bin/cli.js +8 -14
- package/contracts/reranker-contract.json +69 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +22 -7
- package/package.json +18 -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 +620 -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 +294 -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 +1030 -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 +111 -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/rate-limiter.js +244 -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/secure-logging.js +338 -0
- package/src/utils/structured-logger.js +388 -0
- package/src/utils/validate-plugin-contract.js +42 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Publishing System
|
|
3
|
+
* Handles plugin packaging, validation, and publishing to registries
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs/promises');
|
|
7
|
+
// eslint-disable-line global-require
|
|
8
|
+
const path = require('path');
|
|
9
|
+
// eslint-disable-line global-require
|
|
10
|
+
const crypto = require('crypto');
|
|
11
|
+
// eslint-disable-line global-require
|
|
12
|
+
const { logger } = require('../../utils/structured-logger.js');
|
|
13
|
+
const {
|
|
14
|
+
metadataExtractor,
|
|
15
|
+
metadataValidator,
|
|
16
|
+
} = require('./plugin-metadata.js');
|
|
17
|
+
// eslint-disable-line global-require
|
|
18
|
+
const {
|
|
19
|
+
validatePluginRegistry,
|
|
20
|
+
createEmptyRegistry,
|
|
21
|
+
} = require('./plugin-registry-format.js');
|
|
22
|
+
// eslint-disable-line global-require
|
|
23
|
+
const { VersionUtils } = require('./version-resolver.js');
|
|
24
|
+
// eslint-disable-line global-require
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Plugin publisher for marketplace publishing
|
|
28
|
+
*/
|
|
29
|
+
class PluginPublisher {
|
|
30
|
+
constructor(_options = {}) {
|
|
31
|
+
this._options = {
|
|
32
|
+
registryUrl: _options.registryUrl || 'https://registry.rag-pipeline.dev',
|
|
33
|
+
authToken: _options.authToken,
|
|
34
|
+
timeout: _options.timeout || 30000,
|
|
35
|
+
dryRun: _options.dryRun || false,
|
|
36
|
+
..._options,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Publish plugin to registry
|
|
42
|
+
* @param {string} pluginPath - Path to plugin directory
|
|
43
|
+
* @param {object} publishOptions - Publishing _options
|
|
44
|
+
* @returns {Promise<object>} Publishing result
|
|
45
|
+
*/
|
|
46
|
+
async publishPlugin(pluginPath, publishOptions = {}) {
|
|
47
|
+
const startTime = Date.now();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
// Step 1: Validate plugin structure
|
|
51
|
+
logger.info('Validating plugin structure', { pluginPath });
|
|
52
|
+
const validation = await this.validatePluginStructure(pluginPath);
|
|
53
|
+
if (!validation.valid) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Plugin validation failed: ${validation.errors.join(', ')}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Step 2: Extract and validate metadata
|
|
60
|
+
logger.info('Extracting plugin metadata', { pluginPath });
|
|
61
|
+
const metadata = await this.extractPluginMetadata(pluginPath);
|
|
62
|
+
|
|
63
|
+
// Step 3: Package plugin
|
|
64
|
+
logger.info('Packaging plugin', {
|
|
65
|
+
pluginName: metadata.name,
|
|
66
|
+
version: metadata.version,
|
|
67
|
+
});
|
|
68
|
+
const packageInfo = await this.packagePlugin(
|
|
69
|
+
pluginPath,
|
|
70
|
+
metadata,
|
|
71
|
+
publishOptions,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Step 4: Upload to registry (unless dry run)
|
|
75
|
+
if (this._options.dryRun) {
|
|
76
|
+
logger.info('Dry run - skipping actual upload');
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
dryRun: true,
|
|
80
|
+
metadata,
|
|
81
|
+
packageInfo,
|
|
82
|
+
duration: Date.now() - startTime,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logger.info('Publishing to registry', {
|
|
87
|
+
pluginName: metadata.name,
|
|
88
|
+
version: metadata.version,
|
|
89
|
+
});
|
|
90
|
+
const publishResult = await this.uploadToRegistry(
|
|
91
|
+
packageInfo,
|
|
92
|
+
metadata,
|
|
93
|
+
publishOptions,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
logger.info('Plugin published successfully', {
|
|
97
|
+
pluginName: metadata.name,
|
|
98
|
+
version: metadata.version,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
metadata,
|
|
104
|
+
packageInfo,
|
|
105
|
+
publishResult,
|
|
106
|
+
duration: Date.now() - startTime,
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
logger.error('Publishing failed', { error: error.message, pluginPath });
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: error.message,
|
|
113
|
+
duration: Date.now() - startTime,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Validate plugin directory structure
|
|
120
|
+
* @param {string} pluginPath - Plugin directory path
|
|
121
|
+
* @returns {Promise<{valid: boolean, errors: Array<string>}>}
|
|
122
|
+
*/
|
|
123
|
+
async validatePluginStructure(pluginPath) {
|
|
124
|
+
const errors = [];
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const stats = await fs.stat(pluginPath);
|
|
128
|
+
if (!stats.isDirectory()) {
|
|
129
|
+
errors.push('Plugin path must be a directory');
|
|
130
|
+
return { valid: false, errors };
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
errors.push(`Plugin directory not found: ${pluginPath}`);
|
|
134
|
+
return { valid: false, errors };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check for required files
|
|
138
|
+
const requiredFiles = ['index.js', 'package.json'];
|
|
139
|
+
for (const file of requiredFiles) {
|
|
140
|
+
const _filePath = path.join(pluginPath, file);
|
|
141
|
+
try {
|
|
142
|
+
await fs.access(_filePath);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
errors.push(`Required file missing: ${file}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check for recommended files
|
|
149
|
+
const recommendedFiles = ['README.md', 'LICENSE'];
|
|
150
|
+
for (const file of recommendedFiles) {
|
|
151
|
+
const _filePath = path.join(pluginPath, file);
|
|
152
|
+
try {
|
|
153
|
+
await fs.access(_filePath);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logger.warn('Recommended file missing', { file });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Validate package.json structure
|
|
160
|
+
try {
|
|
161
|
+
const packageJsonPath = path.join(pluginPath, 'package.json');
|
|
162
|
+
const packageJson = JSON.parse(
|
|
163
|
+
await fs.readFile(packageJsonPath, 'utf-8'),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (!packageJson.name) {
|
|
167
|
+
errors.push('package.json missing name field');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!packageJson.version) {
|
|
171
|
+
errors.push('package.json missing version field');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!packageJson.main && !packageJson.exports) {
|
|
175
|
+
errors.push('package.json missing main or exports field');
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
errors.push(`Invalid package.json: ${error.message}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { valid: errors.length === 0, errors };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Extract plugin metadata from directory
|
|
186
|
+
* @param {string} pluginPath - Plugin directory path
|
|
187
|
+
* @returns {Promise<object>} Plugin metadata
|
|
188
|
+
*/
|
|
189
|
+
async extractPluginMetadata(pluginPath) {
|
|
190
|
+
// Load plugin module
|
|
191
|
+
const pluginIndexPath = path.join(pluginPath, 'index.js');
|
|
192
|
+
const pluginModule = await import(pluginIndexPath);
|
|
193
|
+
|
|
194
|
+
// Load package.json for additional metadata
|
|
195
|
+
const packageJsonPath = path.join(pluginPath, 'package.json');
|
|
196
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
197
|
+
|
|
198
|
+
// Determine plugin type from package.json or metadata
|
|
199
|
+
let pluginType = null;
|
|
200
|
+
if (packageJson.keywords) {
|
|
201
|
+
const typeKeywords = [
|
|
202
|
+
'loader',
|
|
203
|
+
'embedder',
|
|
204
|
+
'retriever',
|
|
205
|
+
'llm',
|
|
206
|
+
'reranker',
|
|
207
|
+
];
|
|
208
|
+
pluginType = packageJson.keywords.find((k) => typeKeywords.includes(k));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!pluginType) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
'Cannot determine plugin _type. Add plugin _type to package.json keywords or metadata.',
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Extract metadata using the extractor
|
|
218
|
+
const extractedMetadata = metadataExtractor.extractMetadata(
|
|
219
|
+
pluginModule,
|
|
220
|
+
pluginType,
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
// Merge with package.json data
|
|
224
|
+
const mergedMetadata = {
|
|
225
|
+
...extractedMetadata,
|
|
226
|
+
name: packageJson.name || extractedMetadata.name,
|
|
227
|
+
version: packageJson.version || extractedMetadata.version,
|
|
228
|
+
description: packageJson.description || extractedMetadata.description,
|
|
229
|
+
author: packageJson.author || extractedMetadata.author,
|
|
230
|
+
homepage: packageJson.homepage || extractedMetadata.homepage,
|
|
231
|
+
repository: packageJson.repository || extractedMetadata.repository,
|
|
232
|
+
license: packageJson.license || extractedMetadata.license,
|
|
233
|
+
keywords: [
|
|
234
|
+
...(packageJson.keywords || []),
|
|
235
|
+
...(extractedMetadata.keywords || []),
|
|
236
|
+
],
|
|
237
|
+
dependencies:
|
|
238
|
+
packageJson.dependencies || extractedMetadata.dependencies || {},
|
|
239
|
+
peerDependencies:
|
|
240
|
+
packageJson.peerDependencies ||
|
|
241
|
+
extractedMetadata.peerDependencies ||
|
|
242
|
+
{},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Validate merged metadata
|
|
246
|
+
const validation = metadataValidator.validatePlugin(
|
|
247
|
+
pluginType,
|
|
248
|
+
mergedMetadata.name,
|
|
249
|
+
pluginModule,
|
|
250
|
+
);
|
|
251
|
+
if (!validation.valid) {
|
|
252
|
+
throw new Error(`Metadata validation failed: ${validation.error}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Show warnings
|
|
256
|
+
if (validation.warnings.length > 0) {
|
|
257
|
+
logger.warn('Metadata validation warnings', {
|
|
258
|
+
warnings: validation.warnings,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return mergedMetadata;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Package plugin for distribution
|
|
267
|
+
* @param {string} pluginPath - Plugin directory path
|
|
268
|
+
* @param {object} metadata - Plugin metadata
|
|
269
|
+
* @param {object} _options - Packaging _options
|
|
270
|
+
* @returns {Promise<object>} Package information
|
|
271
|
+
*/
|
|
272
|
+
async packagePlugin(pluginPath, metadata, _options) {
|
|
273
|
+
const packageName = `${metadata.name}-${metadata.version}.tgz`;
|
|
274
|
+
const packagePath = path.join(
|
|
275
|
+
_options.outputDir || pluginPath,
|
|
276
|
+
packageName,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// Create package archive (simplified - in real implementation would use tar)
|
|
280
|
+
const packageFiles = await this.collectPackageFiles(pluginPath, _options);
|
|
281
|
+
|
|
282
|
+
// Calculate package size and integrity hash
|
|
283
|
+
const packageSize = await this.calculatePackageSize(packageFiles);
|
|
284
|
+
const integrity = await this.calculateIntegrity(packageFiles);
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
name: packageName,
|
|
288
|
+
path: packagePath,
|
|
289
|
+
size: packageSize,
|
|
290
|
+
integrity,
|
|
291
|
+
files: packageFiles.map((f) => f.relativePath),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Collect files to include in package
|
|
297
|
+
* @param {string} pluginPath - Plugin directory path
|
|
298
|
+
* @param {object} _options - Collection _options
|
|
299
|
+
* @returns {Promise<Array<object>>} Package files
|
|
300
|
+
*/
|
|
301
|
+
async collectPackageFiles(pluginPath, _options) {
|
|
302
|
+
const files = [];
|
|
303
|
+
const excludePatterns = _options.exclude || [
|
|
304
|
+
'node_modules',
|
|
305
|
+
'.git',
|
|
306
|
+
'.DS_Store',
|
|
307
|
+
'*.log',
|
|
308
|
+
'coverage',
|
|
309
|
+
'.nyc_output',
|
|
310
|
+
'test',
|
|
311
|
+
'tests',
|
|
312
|
+
'__tests__',
|
|
313
|
+
'*.test.js',
|
|
314
|
+
'*.spec.js',
|
|
315
|
+
];
|
|
316
|
+
|
|
317
|
+
const collectDir = async (dir, relativePath = '') => {
|
|
318
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
319
|
+
|
|
320
|
+
for (const entry of entries) {
|
|
321
|
+
const fullPath = path.join(dir, entry.name);
|
|
322
|
+
const relPath = path.join(relativePath, entry.name);
|
|
323
|
+
|
|
324
|
+
// Check exclude patterns
|
|
325
|
+
if (
|
|
326
|
+
excludePatterns.some((pattern) => {
|
|
327
|
+
if (pattern.includes('*')) {
|
|
328
|
+
return relPath.match(new RegExp(pattern.replace('*', '.*')));
|
|
329
|
+
}
|
|
330
|
+
return relPath.includes(pattern);
|
|
331
|
+
})
|
|
332
|
+
) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (entry.isDirectory()) {
|
|
337
|
+
await collectDir(fullPath, relPath);
|
|
338
|
+
} else {
|
|
339
|
+
const stats = await fs.stat(fullPath);
|
|
340
|
+
files.push({
|
|
341
|
+
fullPath,
|
|
342
|
+
relativePath: relPath,
|
|
343
|
+
size: stats.size,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
await collectDir(pluginPath);
|
|
350
|
+
return files;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Calculate total package size
|
|
355
|
+
* @param {Array<object>} files - Package files
|
|
356
|
+
* @returns {number} Total size in bytes
|
|
357
|
+
*/
|
|
358
|
+
async calculatePackageSize(files) {
|
|
359
|
+
return files.reduce((total, file) => total + file.size, 0);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Calculate package integrity hash
|
|
364
|
+
* @param {Array<object>} files - Package files
|
|
365
|
+
* @returns {Promise<string>} SHA-256 hash
|
|
366
|
+
*/
|
|
367
|
+
async calculateIntegrity(files) {
|
|
368
|
+
const hash = crypto.createHash('sha256');
|
|
369
|
+
|
|
370
|
+
// Sort files by path for consistent hashing
|
|
371
|
+
const sortedFiles = files.sort((a, b) =>
|
|
372
|
+
a.relativePath.localeCompare(b.relativePath),
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
for (const file of sortedFiles) {
|
|
376
|
+
const content = await fs.readFile(file.fullPath);
|
|
377
|
+
hash.update(file.relativePath);
|
|
378
|
+
hash.update(content);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return `sha256-${hash.digest('base64')}`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Upload package to registry
|
|
386
|
+
* @param {object} packageInfo - Package information
|
|
387
|
+
* @param {object} metadata - Plugin metadata
|
|
388
|
+
* @param {object} _options - Upload _options
|
|
389
|
+
* @returns {Promise<object>} Upload result
|
|
390
|
+
*/
|
|
391
|
+
async uploadToRegistry(packageInfo, metadata, _options) {
|
|
392
|
+
// In a real implementation, this would make HTTP requests to the registry API
|
|
393
|
+
// For now, we'll simulate the upload process
|
|
394
|
+
|
|
395
|
+
const uploadUrl = `${this._options.registryUrl}/api/plugins/${metadata.name}/versions/${metadata.version}`;
|
|
396
|
+
|
|
397
|
+
// Simulate upload delay
|
|
398
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
uploadUrl,
|
|
402
|
+
downloadUrl: `${this._options.registryUrl}/packages/${metadata.name}/${packageInfo.name}`,
|
|
403
|
+
publishedAt: new Date().toISOString(),
|
|
404
|
+
integrity: packageInfo.integrity,
|
|
405
|
+
size: packageInfo.size,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Update local registry with published plugin
|
|
411
|
+
* @param {string} registryPath - Local registry file path
|
|
412
|
+
* @param {object} metadata - Plugin metadata
|
|
413
|
+
* @param {object} publishResult - Publishing result
|
|
414
|
+
* @returns {Promise<void>}
|
|
415
|
+
*/
|
|
416
|
+
async updateLocalRegistry(registryPath, metadata, publishResult) {
|
|
417
|
+
let registry;
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
const registryContent = await fs.readFile(registryPath, 'utf-8');
|
|
421
|
+
registry = JSON.parse(registryContent);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
// Create new registry if file doesn't exist
|
|
424
|
+
registry = createEmptyRegistry();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Add or update plugin entry
|
|
428
|
+
if (!registry.plugins[metadata.name]) {
|
|
429
|
+
registry.plugins[metadata.name] = {
|
|
430
|
+
metadata,
|
|
431
|
+
versions: {},
|
|
432
|
+
latest: metadata.version,
|
|
433
|
+
createdAt: new Date().toISOString(),
|
|
434
|
+
updatedAt: new Date().toISOString(),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const pluginEntry = registry.plugins[metadata.name];
|
|
439
|
+
|
|
440
|
+
// Add new version
|
|
441
|
+
pluginEntry.versions[metadata.version] = {
|
|
442
|
+
version: metadata.version,
|
|
443
|
+
publishedAt: publishResult.publishedAt,
|
|
444
|
+
downloadUrl: publishResult.downloadUrl,
|
|
445
|
+
integrity: publishResult.integrity,
|
|
446
|
+
size: publishResult.size,
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Update latest version if this is newer
|
|
450
|
+
if (
|
|
451
|
+
!pluginEntry.latest ||
|
|
452
|
+
VersionUtils.compareVersions(metadata.version, pluginEntry.latest) > 0
|
|
453
|
+
) {
|
|
454
|
+
pluginEntry.latest = metadata.version;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Update timestamps
|
|
458
|
+
pluginEntry.updatedAt = new Date().toISOString();
|
|
459
|
+
registry.updatedAt = new Date().toISOString();
|
|
460
|
+
|
|
461
|
+
// Validate registry before saving
|
|
462
|
+
const validation = validatePluginRegistry(registry);
|
|
463
|
+
if (!validation.valid) {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`Registry validation failed: ${validation.errors.map((e) => e.message).join(', ')}`,
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Save updated registry
|
|
470
|
+
await fs.writeFile(registryPath, JSON.stringify(registry, null, 2));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Plugin publishing utilities
|
|
476
|
+
*/
|
|
477
|
+
const PublishingUtils = {
|
|
478
|
+
/**
|
|
479
|
+
* Generate GitHub Action workflow for automated publishing
|
|
480
|
+
* @param {object} _options - Workflow _options
|
|
481
|
+
* @returns {string} GitHub Action YAML
|
|
482
|
+
*/
|
|
483
|
+
generateGitHubAction(_options = {}) {
|
|
484
|
+
return `name: Publish Plugin
|
|
485
|
+
|
|
486
|
+
on:
|
|
487
|
+
release:
|
|
488
|
+
types: [published]
|
|
489
|
+
workflow_dispatch:
|
|
490
|
+
inputs:
|
|
491
|
+
version:
|
|
492
|
+
description: 'Version to publish'
|
|
493
|
+
required: true
|
|
494
|
+
default: 'latest'
|
|
495
|
+
|
|
496
|
+
jobs:
|
|
497
|
+
publish:
|
|
498
|
+
runs-on: ubuntu-latest
|
|
499
|
+
|
|
500
|
+
steps:
|
|
501
|
+
- name: Checkout code
|
|
502
|
+
uses: actions/checkout@v3
|
|
503
|
+
|
|
504
|
+
- name: Setup Node.js
|
|
505
|
+
uses: actions/setup-node@v3
|
|
506
|
+
with:
|
|
507
|
+
node-version: '18'
|
|
508
|
+
|
|
509
|
+
- name: Install dependencies
|
|
510
|
+
run: npm ci
|
|
511
|
+
|
|
512
|
+
- name: Run tests
|
|
513
|
+
run: npm test
|
|
514
|
+
|
|
515
|
+
- name: Publish plugin
|
|
516
|
+
run: |
|
|
517
|
+
npx rag-pipeline publish \\
|
|
518
|
+
--registry-url \${{ secrets.REGISTRY_URL || 'https://registry.rag-pipeline.dev' }} \\
|
|
519
|
+
--auth-token \${{ secrets.REGISTRY_TOKEN }} \\
|
|
520
|
+
--version \${{ github.event.inputs.version || github.event.release.tag_name }}
|
|
521
|
+
env:
|
|
522
|
+
NODE_ENV: production
|
|
523
|
+
`;
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Generate plugin publishing checklist
|
|
528
|
+
* @param {object} metadata - Plugin metadata
|
|
529
|
+
* @returns {Array<string>} Checklist items
|
|
530
|
+
*/
|
|
531
|
+
generatePublishingChecklist(_metadata) {
|
|
532
|
+
return [
|
|
533
|
+
'๐ Plugin metadata is complete and valid',
|
|
534
|
+
'๐งช All tests are passing',
|
|
535
|
+
'๐ Documentation is up to date',
|
|
536
|
+
'๐ Version number follows semantic versioning',
|
|
537
|
+
'๐ LICENSE file is present',
|
|
538
|
+
'๐ README.md includes usage examples',
|
|
539
|
+
'๐ท๏ธ Keywords are relevant and descriptive',
|
|
540
|
+
'๐ Repository URL is accessible',
|
|
541
|
+
'๐ Homepage URL is valid (if provided)',
|
|
542
|
+
'๐ฆ Package size is reasonable (< 10MB recommended)',
|
|
543
|
+
'๐ No sensitive information in code',
|
|
544
|
+
'โ
Plugin works with latest rag-pipeline-utils version',
|
|
545
|
+
];
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Validate plugin before publishing
|
|
550
|
+
* @param {string} pluginPath - Plugin directory path
|
|
551
|
+
* @returns {Promise<{ready: boolean, issues: Array<string>}>}
|
|
552
|
+
*/
|
|
553
|
+
async validateForPublishing(pluginPath) {
|
|
554
|
+
const publisher = new PluginPublisher({ dryRun: true });
|
|
555
|
+
const result = await publisher.publishPlugin(pluginPath);
|
|
556
|
+
|
|
557
|
+
if (result.success) {
|
|
558
|
+
return { ready: true, issues: [] };
|
|
559
|
+
} else {
|
|
560
|
+
return { ready: false, issues: [result.error] };
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// Export default publisher instance
|
|
566
|
+
const pluginPublisher = new PluginPublisher();
|
|
567
|
+
|
|
568
|
+
// Default export
|
|
569
|
+
|
|
570
|
+
module.exports = {
|
|
571
|
+
PluginPublisher,
|
|
572
|
+
PublishingUtils,
|
|
573
|
+
pluginPublisher,
|
|
574
|
+
};
|