@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.
Files changed (113) hide show
  1. package/.ragrc.schema.json +218 -0
  2. package/README.md +178 -550
  3. package/bin/cli.js +8 -14
  4. package/contracts/reranker-contract.json +69 -0
  5. package/dist/index.d.ts +237 -0
  6. package/dist/index.mjs +22 -7
  7. package/package.json +18 -13
  8. package/src/ai/adaptive-retrieval.js +191 -0
  9. package/src/ai/federated-learning.js +214 -0
  10. package/src/ai/federation/federated-learning-coordinator.js +345 -0
  11. package/src/ai/federation.js +76 -0
  12. package/src/ai/index-fixed.js +509 -0
  13. package/src/ai/index.js +33 -0
  14. package/src/ai/model-trainer.js +217 -0
  15. package/src/ai/model-training.js +205 -0
  16. package/src/ai/module-template.js +37 -0
  17. package/src/ai/multimodal/multi-modal-processor.js +345 -0
  18. package/src/ai/multimodal-processing.js +268 -0
  19. package/src/ai/multimodal.js +71 -0
  20. package/src/ai/orchestrator.js +70 -0
  21. package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
  22. package/src/ai/retrieval-engine.js +69 -0
  23. package/src/ai/training/model-training-orchestrator.js +228 -0
  24. package/src/ci/workflow-analyzer.js +71 -0
  25. package/src/cli/commands/ai-ml.js +967 -0
  26. package/src/cli/commands/docs.js +228 -0
  27. package/src/cli/commands/dx.js +538 -0
  28. package/src/cli/commands/plugin-hub.js +875 -0
  29. package/src/cli/doctor-command.js +639 -0
  30. package/src/cli/enhanced-cli-commands.js +945 -0
  31. package/src/cli/interactive-wizard.js +997 -0
  32. package/src/cli/plugin-marketplace-commands.js +869 -0
  33. package/src/cli.js +17 -0
  34. package/src/config/enhanced-ragrc-schema.js +632 -0
  35. package/src/config/load-config.js +54 -0
  36. package/src/config/load-plugin-config.js +69 -0
  37. package/src/config/normalize-config.js +105 -0
  38. package/src/config/schema-validator.js +315 -0
  39. package/src/config/validate-plugin-schema.js +35 -0
  40. package/src/config/validate-schema.js +113 -0
  41. package/src/contracts/plugin-contracts.js +33 -0
  42. package/src/core/create-pipeline.js +99 -0
  43. package/src/core/dependency-injection.js +242 -0
  44. package/src/core/observability/event-logger.js +241 -0
  45. package/src/core/observability/instrumented-pipeline.js +609 -0
  46. package/src/core/observability/metrics.js +497 -0
  47. package/src/core/observability/tracing.js +781 -0
  48. package/src/core/performance/benchmark.js +516 -0
  49. package/src/core/performance/parallel-processor.js +240 -0
  50. package/src/core/performance/streaming-safeguards.js +620 -0
  51. package/src/core/pipeline-factory.js +60 -0
  52. package/src/core/plugin-contracts.js +89 -0
  53. package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
  54. package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
  55. package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
  56. package/src/core/plugin-marketplace/version-resolver.js +61 -0
  57. package/src/core/plugin-registry.js +294 -0
  58. package/src/dag/dag-engine.js +954 -0
  59. package/src/dag/dag-node.js +76 -0
  60. package/src/dag/enhanced-dag-engine.js +822 -0
  61. package/src/dx/index.js +40 -0
  62. package/src/dx/integration-templates.js +665 -0
  63. package/src/dx/performance-profiler.js +968 -0
  64. package/src/dx/realtime-debugger.js +755 -0
  65. package/src/dx/visual-pipeline-builder.js +578 -0
  66. package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
  67. package/src/ecosystem/plugin-certification.js +580 -0
  68. package/src/ecosystem/plugin-hub.js +821 -0
  69. package/src/enterprise/audit-logging.js +967 -0
  70. package/src/enterprise/data-governance.js +408 -0
  71. package/src/enterprise/multi-tenancy.js +496 -0
  72. package/src/enterprise/sso-integration.js +1030 -0
  73. package/src/evaluate/evaluator.js +52 -0
  74. package/src/evaluate/scoring.js +91 -0
  75. package/src/index.js +67 -0
  76. package/src/ingest.js +59 -0
  77. package/src/loader/csv-loader.js +38 -0
  78. package/src/loader/directory-loader.js +48 -0
  79. package/src/loader/html-loader.js +62 -0
  80. package/src/loader/markdown-loader.js +67 -0
  81. package/src/mocks/openai-embedder.js +119 -0
  82. package/src/mocks/openai-llm.js +77 -0
  83. package/src/mocks/pdf-loader.js +21 -0
  84. package/src/mocks/pinecone-retriever.js +106 -0
  85. package/src/observability/audit-logger.js +758 -0
  86. package/src/observability/dashboard-config.json +675 -0
  87. package/src/observability/event-logger.js +310 -0
  88. package/src/observability/metrics.js +691 -0
  89. package/src/observability/security-monitor.js +830 -0
  90. package/src/observability/slo-monitor.js +319 -0
  91. package/src/observability/telemetry.js +686 -0
  92. package/src/pipeline/pipeline.js +18 -0
  93. package/src/plugins/sample-embedder.js +53 -0
  94. package/src/plugins/sample-llm.js +30 -0
  95. package/src/plugins/sample-loader.js +24 -0
  96. package/src/plugins/sample-retriever.js +84 -0
  97. package/src/query.js +117 -0
  98. package/src/reranker/llm-reranker.js +111 -0
  99. package/src/scripts/script-utilities.js +36 -0
  100. package/src/security/plugin-sandbox.js +586 -0
  101. package/src/security/plugin-signature-verifier.js +414 -0
  102. package/src/security/validator.js +36 -0
  103. package/src/utils/ci/diagnostic-reporter.js +57 -0
  104. package/src/utils/logger.js +211 -0
  105. package/src/utils/performance-monitor.js +561 -0
  106. package/src/utils/plugin-scaffolder.js +447 -0
  107. package/src/utils/rate-limiter.js +244 -0
  108. package/src/utils/retry-policy.js +443 -0
  109. package/src/utils/retry.js +107 -0
  110. package/src/utils/safe-expression-evaluator.js +579 -0
  111. package/src/utils/secure-logging.js +338 -0
  112. package/src/utils/structured-logger.js +388 -0
  113. package/src/utils/validate-plugin-contract.js +42 -0
@@ -0,0 +1,997 @@
1
+ /**
2
+ * Interactive CLI Wizard for RAG Pipeline Setup
3
+ * Provides guided setup for plugin selection, DAG building, and configuration
4
+ */
5
+
6
+ const inquirer = require('inquirer');
7
+ const fs = require('fs/promises');
8
+ const path = require('path');
9
+ const {
10
+ validateRagrc,
11
+ extractPluginDependencies,
12
+ } = require('../config/enhanced-ragrc-schema.js');
13
+ const {
14
+ DEFAULT_REGISTRY_URLS,
15
+ } = require('../core/plugin-marketplace/plugin-registry-format.js');
16
+
17
+ /**
18
+ * Interactive wizard for RAG pipeline setup
19
+ */
20
+ class InteractiveWizard {
21
+ constructor(_options = {}) {
22
+ this._options = {
23
+ registryUrl: _options.registryUrl || DEFAULT_REGISTRY_URLS[0],
24
+ outputPath: _options.outputPath || '.ragrc.json',
25
+ ..._options,
26
+ };
27
+ this.registry = null;
28
+ this._config = {
29
+ plugins: {
30
+ loader: {},
31
+ embedder: {},
32
+ retriever: {},
33
+ llm: {},
34
+ },
35
+ registry: {
36
+ urls: [this._options.registryUrl],
37
+ },
38
+ };
39
+
40
+ // Initialize steps for testing interface
41
+ this.steps = [
42
+ 'project-setup',
43
+ 'plugin-selection',
44
+ 'configuration',
45
+ 'pipeline-setup',
46
+ 'performance-tuning',
47
+ 'observability',
48
+ 'preview-save',
49
+ ];
50
+ this.currentStep = 0;
51
+ }
52
+
53
+ /**
54
+ * Run the complete interactive wizard
55
+ * @returns {Promise<object>} Generated configuration
56
+ */
57
+ async run() {
58
+ console.log('🧙‍♂️ Welcome to the RAG Pipeline Interactive Setup Wizard!\n');
59
+ // eslint-disable-line no-console
60
+ console.log(
61
+ 'This wizard will help you configure your RAG pipeline with the right plugins and settings.\n',
62
+ );
63
+ // eslint-disable-line no-console
64
+
65
+ try {
66
+ // Step 1: Project setup
67
+ await this.setupProject();
68
+
69
+ // Step 2: Plugin selection
70
+ await this.selectPlugins();
71
+
72
+ // Step 3: Configuration
73
+ await this.configureSettings();
74
+
75
+ // Step 4: Pipeline stages
76
+ await this.configurePipeline();
77
+
78
+ // Step 5: Performance settings
79
+ await this.configurePerformance();
80
+
81
+ // Step 6: Observability settings
82
+ await this.configureObservability();
83
+
84
+ // Step 7: Preview and save
85
+ await this.previewAndSave();
86
+
87
+ console.log('\n🎉 RAG Pipeline setup complete!');
88
+ // eslint-disable-line no-console
89
+ console.log(`Configuration saved to: ${this._options.outputPath}`);
90
+ // eslint-disable-line no-console
91
+
92
+ return this._config;
93
+ } catch (error) {
94
+ console.error('\n❌ Setup wizard failed:', error.message);
95
+ // eslint-disable-line no-console
96
+ throw error;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Setup project metadata
102
+ */
103
+ async setupProject() {
104
+ console.log('📋 Project Setup\n');
105
+ // eslint-disable-line no-console
106
+
107
+ const answers = await inquirer.prompt([
108
+ {
109
+ _type: 'input',
110
+ name: 'name',
111
+ message: 'Project name:',
112
+ default: path.basename(process.cwd()),
113
+ validate: (input) => input.length > 0 || 'Project name is required',
114
+ },
115
+ {
116
+ _type: 'input',
117
+ name: 'description',
118
+ message: 'Project description:',
119
+ default: 'A RAG pipeline project',
120
+ },
121
+ {
122
+ _type: 'input',
123
+ name: 'author',
124
+ message: 'Author:',
125
+ default: 'Unknown',
126
+ },
127
+ {
128
+ _type: 'list',
129
+ name: 'environment',
130
+ message: 'Target environment:',
131
+ choices: [
132
+ { name: 'Development', value: 'development' },
133
+ { name: 'Production', value: 'production' },
134
+ { name: 'Testing', value: 'testing' },
135
+ ],
136
+ default: 'development',
137
+ },
138
+ ]);
139
+
140
+ this._config.metadata = {
141
+ name: answers.name,
142
+ version: '1.0.0',
143
+ description: answers.description,
144
+ author: answers.author,
145
+ environment: answers.environment,
146
+ createdAt: new Date().toISOString(),
147
+ };
148
+
149
+ console.log(`\n✅ Project "${answers.name}" configured\n`);
150
+ // eslint-disable-line no-console
151
+ }
152
+
153
+ /**
154
+ * Select plugins for each _type
155
+ */
156
+ async selectPlugins() {
157
+ console.log('🔌 Plugin Selection\n');
158
+ // eslint-disable-line no-console
159
+
160
+ // Load registry for plugin suggestions
161
+ try {
162
+ this.registry = await this.loadRegistry();
163
+ } catch (error) {
164
+ console.warn(
165
+ '⚠️ Could not load plugin registry. Using built-in _options.',
166
+ );
167
+ // eslint-disable-line no-console
168
+ }
169
+
170
+ const pluginTypes = [
171
+ { key: 'loader', name: 'Document Loader', required: true },
172
+ { key: 'embedder', name: 'Text Embedder', required: true },
173
+ { key: 'retriever', name: 'Vector Retriever', required: true },
174
+ { key: 'llm', name: 'Language Model', required: true },
175
+ { key: 'reranker', name: 'Result Reranker', required: false },
176
+ ];
177
+
178
+ for (const pluginType of pluginTypes) {
179
+ await this.selectPluginForType(pluginType);
180
+ }
181
+
182
+ console.log('✅ Plugin selection complete\n');
183
+ // eslint-disable-line no-console
184
+ }
185
+
186
+ /**
187
+ * Select plugin for specific _type
188
+ * @param {object} pluginType - Plugin _type configuration
189
+ */
190
+ async selectPluginForType(pluginType) {
191
+ const availablePlugins = this.getAvailablePlugins(pluginType.key);
192
+
193
+ if (availablePlugins.length === 0 && pluginType.required) {
194
+ console.log(
195
+ `⚠️ No ${pluginType.name} plugins available. You'll need to configure this manually.`,
196
+ );
197
+ // eslint-disable-line no-console
198
+ return;
199
+ }
200
+
201
+ const choices = [
202
+ ...availablePlugins.map((plugin) => ({
203
+ name: `${plugin.name} - ${plugin.description}`,
204
+ value: plugin.name,
205
+ short: plugin.name,
206
+ })),
207
+ { name: 'Skip (configure later)', value: null },
208
+ { name: 'Custom plugin', value: 'custom' },
209
+ ];
210
+
211
+ const answer = await inquirer.prompt([
212
+ {
213
+ _type: 'list',
214
+ name: 'plugin',
215
+ message: `Select ${pluginType.name}:`,
216
+ choices,
217
+ when: () => !pluginType.required || availablePlugins.length > 0,
218
+ },
219
+ ]);
220
+
221
+ if (!answer.plugin) {
222
+ return; // Skip
223
+ }
224
+
225
+ if (answer.plugin === 'custom') {
226
+ await this.configureCustomPlugin(pluginType.key);
227
+ } else {
228
+ await this.configureSelectedPlugin(pluginType.key, answer.plugin);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Configure custom plugin
234
+ * @param {string} pluginType - Plugin _type
235
+ */
236
+ async configureCustomPlugin(pluginType) {
237
+ const answers = await inquirer.prompt([
238
+ {
239
+ _type: 'input',
240
+ name: 'name',
241
+ message: 'Plugin name:',
242
+ validate: (input) => input.length > 0 || 'Plugin name is required',
243
+ },
244
+ {
245
+ _type: 'list',
246
+ name: 'source',
247
+ message: 'Plugin source:',
248
+ choices: [
249
+ { name: 'Registry', value: 'registry' },
250
+ { name: 'Local file', value: 'local' },
251
+ { name: 'Git repository', value: 'git' },
252
+ { name: 'NPM package', value: 'npm' },
253
+ ],
254
+ default: 'registry',
255
+ },
256
+ {
257
+ _type: 'input',
258
+ name: 'version',
259
+ message: 'Version:',
260
+ default: 'latest',
261
+ when: (answers) =>
262
+ answers.source === 'registry' || answers.source === 'npm',
263
+ },
264
+ {
265
+ _type: 'input',
266
+ name: 'path',
267
+ message: 'Local path:',
268
+ when: (answers) => answers.source === 'local',
269
+ },
270
+ {
271
+ _type: 'input',
272
+ name: 'url',
273
+ message: 'Repository URL:',
274
+ when: (answers) => answers.source === 'git',
275
+ },
276
+ ]);
277
+
278
+ const pluginSpec = {
279
+ name: answers.name,
280
+ source: answers.source,
281
+ };
282
+
283
+ if (answers.version) pluginSpec.version = answers.version;
284
+ if (answers.path) pluginSpec.path = answers.path;
285
+ if (answers.url) pluginSpec.url = answers.url;
286
+
287
+ this._config.plugins[pluginType][answers.name] = pluginSpec;
288
+ }
289
+
290
+ /**
291
+ * Configure selected plugin from registry
292
+ * @param {string} pluginType - Plugin _type
293
+ * @param {string} pluginName - Plugin name
294
+ */
295
+ async configureSelectedPlugin(pluginType, pluginName) {
296
+ const plugin = this.getPluginInfo(pluginType, pluginName);
297
+
298
+ if (!plugin) {
299
+ this._config.plugins[pluginType][pluginName] = 'latest';
300
+ return;
301
+ }
302
+
303
+ const versions = Object.keys(plugin.versions || {}).slice(0, 5);
304
+ const versionChoices = [
305
+ { name: 'Latest stable', value: 'latest' },
306
+ { name: 'Latest beta', value: 'beta' },
307
+ ...versions.map((v) => ({ name: v, value: v })),
308
+ { name: 'Custom version', value: 'custom' },
309
+ ];
310
+
311
+ const versionAnswer = await inquirer.prompt([
312
+ {
313
+ _type: 'list',
314
+ name: 'version',
315
+ message: `Select version for ${pluginName}:`,
316
+ choices: versionChoices,
317
+ default: 'latest',
318
+ },
319
+ {
320
+ _type: 'input',
321
+ name: 'customVersion',
322
+ message: 'Enter version:',
323
+ when: (answers) => answers.version === 'custom',
324
+ },
325
+ ]);
326
+
327
+ const version = versionAnswer.customVersion || versionAnswer.version;
328
+
329
+ // Check if plugin needs configuration
330
+ const needsConfig =
331
+ plugin.metadata?._config &&
332
+ Object.keys(plugin.metadata._config.properties || {}).length > 0;
333
+
334
+ if (needsConfig) {
335
+ const configAnswer = await inquirer.prompt([
336
+ {
337
+ _type: 'confirm',
338
+ name: 'configure',
339
+ message: `Configure ${pluginName} settings?`,
340
+ default: false,
341
+ },
342
+ ]);
343
+
344
+ if (configAnswer.configure) {
345
+ const _config = await this.configurePluginSettings(plugin);
346
+ this._config.plugins[pluginType][pluginName] = {
347
+ name: pluginName,
348
+ version,
349
+ _config,
350
+ };
351
+ } else {
352
+ this._config.plugins[pluginType][pluginName] = {
353
+ name: pluginName,
354
+ version,
355
+ };
356
+ }
357
+ } else {
358
+ this._config.plugins[pluginType][pluginName] = version;
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Configure plugin-specific settings
364
+ * @param {object} plugin - Plugin information
365
+ * @returns {Promise<object>} Plugin configuration
366
+ */
367
+ async configurePluginSettings(plugin) {
368
+ const _config = {};
369
+ const schema = plugin.metadata?._config?.properties || {};
370
+
371
+ console.log(`\n⚙️ Configuring ${plugin.metadata.name}...\n`);
372
+ // eslint-disable-line no-console
373
+
374
+ for (const [key, property] of Object.entries(schema)) {
375
+ const question = {
376
+ name: key,
377
+ message: `${key}${property.description ? ` (${property.description})` : ''}:`,
378
+ };
379
+
380
+ if (property._type === 'boolean') {
381
+ question._type = 'confirm';
382
+ question.default = property.default || false;
383
+ } else if (property.enum) {
384
+ question._type = 'list';
385
+ question.choices = property.enum;
386
+ question.default = property.default;
387
+ } else if (property._type === 'number') {
388
+ question._type = 'number';
389
+ question.default = property.default;
390
+ } else {
391
+ question._type = 'input';
392
+ question.default = property.default || '';
393
+ }
394
+
395
+ const answer = await inquirer.prompt([question]);
396
+ if (answer[key] !== '' && answer[key] !== undefined) {
397
+ _config[key] = answer[key];
398
+ }
399
+ }
400
+
401
+ return _config;
402
+ }
403
+
404
+ /**
405
+ * Configure general settings
406
+ */
407
+ async configureSettings() {
408
+ console.log('⚙️ General Settings\n');
409
+ // eslint-disable-line no-console
410
+
411
+ const answers = await inquirer.prompt([
412
+ {
413
+ _type: 'confirm',
414
+ name: 'enableCaching',
415
+ message: 'Enable result caching?',
416
+ default: false,
417
+ },
418
+ {
419
+ _type: 'number',
420
+ name: 'cacheSize',
421
+ message: 'Cache size (number of entries):',
422
+ default: 1000,
423
+ when: (answers) => answers.enableCaching,
424
+ },
425
+ {
426
+ _type: 'number',
427
+ name: 'cacheTtl',
428
+ message: 'Cache TTL (seconds):',
429
+ default: 3600,
430
+ when: (answers) => answers.enableCaching,
431
+ },
432
+ {
433
+ _type: 'number',
434
+ name: 'timeout',
435
+ message: 'Pipeline timeout (milliseconds):',
436
+ default: 30000,
437
+ },
438
+ ]);
439
+
440
+ if (answers.enableCaching) {
441
+ this._config.performance = this._config.performance || {};
442
+ this._config.performance.caching = {
443
+ enabled: true,
444
+ maxSize: answers.cacheSize,
445
+ ttl: answers.cacheTtl,
446
+ };
447
+ }
448
+
449
+ if (answers.timeout !== 30000) {
450
+ this._config.pipeline = this._config.pipeline || {};
451
+ this._config.pipeline.timeout = answers.timeout;
452
+ }
453
+
454
+ console.log('✅ General settings configured\n');
455
+ // eslint-disable-line no-console
456
+ }
457
+
458
+ /**
459
+ * Configure pipeline stages
460
+ */
461
+ async configurePipeline() {
462
+ console.log('🔄 Pipeline Configuration\n');
463
+ // eslint-disable-line no-console
464
+
465
+ const availableStages = Object.keys(this._config.plugins).filter(
466
+ (_type) => Object.keys(this._config.plugins[_type]).length > 0,
467
+ );
468
+
469
+ const answers = await inquirer.prompt([
470
+ {
471
+ _type: 'checkbox',
472
+ name: 'stages',
473
+ message: 'Select pipeline stages (in order):',
474
+ choices: [
475
+ {
476
+ name: 'Document Loading',
477
+ value: 'loader',
478
+ checked: availableStages.includes('loader'),
479
+ },
480
+ {
481
+ name: 'Text Embedding',
482
+ value: 'embedder',
483
+ checked: availableStages.includes('embedder'),
484
+ },
485
+ {
486
+ name: 'Vector Retrieval',
487
+ value: 'retriever',
488
+ checked: availableStages.includes('retriever'),
489
+ },
490
+ {
491
+ name: 'Language Model',
492
+ value: 'llm',
493
+ checked: availableStages.includes('llm'),
494
+ },
495
+ {
496
+ name: 'Result Reranking',
497
+ value: 'reranker',
498
+ checked: availableStages.includes('reranker'),
499
+ },
500
+ ],
501
+ validate: (input) =>
502
+ input.length > 0 || 'At least one stage must be selected',
503
+ },
504
+ {
505
+ _type: 'confirm',
506
+ name: 'enableRetries',
507
+ message: 'Enable automatic retries on failures?',
508
+ default: true,
509
+ },
510
+ {
511
+ _type: 'number',
512
+ name: 'maxRetries',
513
+ message: 'Maximum retry attempts:',
514
+ default: 3,
515
+ when: (answers) => answers.enableRetries,
516
+ },
517
+ ]);
518
+
519
+ this._config.pipeline = {
520
+ stages: answers.stages,
521
+ ...this._config.pipeline,
522
+ };
523
+
524
+ if (answers.enableRetries) {
525
+ this._config.pipeline.retries = {
526
+ enabled: true,
527
+ maxAttempts: answers.maxRetries,
528
+ backoff: 'exponential',
529
+ };
530
+ }
531
+
532
+ console.log('✅ Pipeline configuration complete\n');
533
+ // eslint-disable-line no-console
534
+ }
535
+
536
+ /**
537
+ * Configure performance settings
538
+ */
539
+ async configurePerformance() {
540
+ console.log('⚡ Performance Settings\n');
541
+ // eslint-disable-line no-console
542
+
543
+ const answers = await inquirer.prompt([
544
+ {
545
+ _type: 'confirm',
546
+ name: 'enableParallel',
547
+ message: 'Enable parallel processing?',
548
+ default: false,
549
+ },
550
+ {
551
+ _type: 'number',
552
+ name: 'maxConcurrency',
553
+ message: 'Maximum concurrent operations:',
554
+ default: 3,
555
+ when: (answers) => answers.enableParallel,
556
+ },
557
+ {
558
+ _type: 'number',
559
+ name: 'batchSize',
560
+ message: 'Batch size for parallel processing:',
561
+ default: 10,
562
+ when: (answers) => answers.enableParallel,
563
+ },
564
+ {
565
+ _type: 'confirm',
566
+ name: 'enableStreaming',
567
+ message: 'Enable streaming for large documents?',
568
+ default: false,
569
+ },
570
+ {
571
+ _type: 'number',
572
+ name: 'maxMemoryMB',
573
+ message: 'Maximum memory usage (MB):',
574
+ default: 512,
575
+ when: (answers) => answers.enableStreaming,
576
+ },
577
+ ]);
578
+
579
+ this._config.performance = this._config.performance || {};
580
+
581
+ if (answers.enableParallel) {
582
+ this._config.performance.parallel = {
583
+ enabled: true,
584
+ maxConcurrency: answers.maxConcurrency,
585
+ batchSize: answers.batchSize,
586
+ };
587
+ }
588
+
589
+ if (answers.enableStreaming) {
590
+ this._config.performance.streaming = {
591
+ enabled: true,
592
+ maxMemoryMB: answers.maxMemoryMB,
593
+ bufferSize: 100,
594
+ };
595
+ }
596
+
597
+ console.log('✅ Performance settings configured\n');
598
+ // eslint-disable-line no-console
599
+ }
600
+
601
+ /**
602
+ * Configure observability settings
603
+ */
604
+ async configureObservability() {
605
+ console.log('📊 Observability Settings\n');
606
+ // eslint-disable-line no-console
607
+
608
+ const answers = await inquirer.prompt([
609
+ {
610
+ _type: 'list',
611
+ name: 'logLevel',
612
+ message: 'Log level:',
613
+ choices: [
614
+ { name: 'Debug (verbose)', value: 'debug' },
615
+ { name: 'Info (default)', value: 'info' },
616
+ { name: 'Warning (minimal)', value: 'warn' },
617
+ { name: 'Error (errors only)', value: 'error' },
618
+ ],
619
+ default: 'info',
620
+ },
621
+ {
622
+ _type: 'confirm',
623
+ name: 'enableTracing',
624
+ message: 'Enable distributed tracing?',
625
+ default: false,
626
+ },
627
+ {
628
+ _type: 'confirm',
629
+ name: 'enableMetrics',
630
+ message: 'Enable metrics collection?',
631
+ default: false,
632
+ },
633
+ {
634
+ _type: 'input',
635
+ name: 'exportUrl',
636
+ message: 'Metrics/tracing export URL (optional):',
637
+ when: (answers) => answers.enableTracing || answers.enableMetrics,
638
+ },
639
+ ]);
640
+
641
+ this._config.observability = {
642
+ logging: {
643
+ level: answers.logLevel,
644
+ structured: true,
645
+ events: answers.enableTracing,
646
+ },
647
+ };
648
+
649
+ if (answers.enableTracing) {
650
+ this._config.observability.tracing = {
651
+ enabled: true,
652
+ exportUrl: answers.exportUrl || undefined,
653
+ sampleRate: 1,
654
+ };
655
+ }
656
+
657
+ if (answers.enableMetrics) {
658
+ this._config.observability.metrics = {
659
+ enabled: true,
660
+ exportUrl: answers.exportUrl || undefined,
661
+ interval: 60000,
662
+ };
663
+ }
664
+
665
+ console.log('✅ Observability settings configured\n');
666
+ // eslint-disable-line no-console
667
+ }
668
+
669
+ /**
670
+ * Preview configuration and save
671
+ */
672
+ async previewAndSave() {
673
+ console.log('👀 Configuration Preview\n');
674
+ // eslint-disable-line no-console
675
+
676
+ // Show configuration summary
677
+ this.showConfigSummary();
678
+
679
+ const answers = await inquirer.prompt([
680
+ {
681
+ _type: 'confirm',
682
+ name: 'save',
683
+ message: 'Save this configuration?',
684
+ default: true,
685
+ },
686
+ {
687
+ _type: 'input',
688
+ name: 'filename',
689
+ message: 'Configuration filename:',
690
+ default: this._options.outputPath,
691
+ when: (answers) => answers.save,
692
+ },
693
+ {
694
+ _type: 'confirm',
695
+ name: 'testRun',
696
+ message: 'Run a test to validate the configuration?',
697
+ default: false,
698
+ when: (answers) => answers.save,
699
+ },
700
+ ]);
701
+
702
+ if (!answers.save) {
703
+ console.log('Configuration not saved.'); // eslint-disable-line no-console
704
+ return;
705
+ }
706
+
707
+ // Validate and normalize configuration
708
+ const validation = validateRagrc(this._config);
709
+ if (!validation.valid) {
710
+ console.error('❌ Configuration validation failed:'); // eslint-disable-line no-console
711
+ validation.errors?.forEach((error) => {
712
+ console.error(` ${error.instancePath}: ${error.message}`); // eslint-disable-line no-console
713
+ });
714
+ throw new Error('Invalid configuration generated');
715
+ }
716
+
717
+ // Use normalized configuration
718
+ this._config = validation.normalized;
719
+
720
+ // Save configuration
721
+ await fs.writeFile(
722
+ answers.filename,
723
+ JSON.stringify(this._config, null, 2),
724
+ 'utf-8',
725
+ );
726
+
727
+ this._options.outputPath = answers.filename;
728
+
729
+ if (answers.testRun) {
730
+ await this.runConfigurationTest();
731
+ }
732
+ }
733
+
734
+ /**
735
+ * Show configuration summary
736
+ */
737
+ showConfigSummary() {
738
+ console.log('📋 Configuration Summary:');
739
+ // eslint-disable-line no-console
740
+ console.log(` Project: ${this._config.metadata?.name || 'Unnamed'}`);
741
+ // eslint-disable-line no-console
742
+ console.log(
743
+ ` Environment: ${this._config.metadata?.environment || 'development'}`,
744
+ );
745
+ // eslint-disable-line no-console
746
+
747
+ console.log('\n🔌 Plugins:');
748
+ // eslint-disable-line no-console
749
+ for (const [_type, plugins] of Object.entries(this._config.plugins)) {
750
+ if (Object.keys(plugins).length > 0) {
751
+ console.log(` ${_type}: ${Object.keys(plugins).join(', ')}`);
752
+ // eslint-disable-line no-console
753
+ }
754
+ }
755
+
756
+ console.log('\n🔄 Pipeline:');
757
+ // eslint-disable-line no-console
758
+ console.log(
759
+ ` Stages: ${this._config.pipeline?.stages?.join(' → ') || 'default'}`,
760
+ );
761
+ // eslint-disable-line no-console
762
+
763
+ if (this._config.performance?.parallel?.enabled) {
764
+ console.log('\n⚡ Performance:');
765
+ // eslint-disable-line no-console
766
+ console.log(
767
+ ` Parallel processing: ${this._config.performance.parallel.maxConcurrency} concurrent`,
768
+ );
769
+ // eslint-disable-line no-console
770
+ }
771
+
772
+ if (
773
+ this._config.observability?.tracing?.enabled ||
774
+ this._config.observability?.metrics?.enabled
775
+ ) {
776
+ console.log('\n📊 Observability:');
777
+ // eslint-disable-line no-console
778
+ if (this._config.observability.tracing?.enabled)
779
+ console.log(' Tracing: enabled');
780
+ // eslint-disable-line no-console
781
+ if (this._config.observability.metrics?.enabled)
782
+ console.log(' Metrics: enabled');
783
+ // eslint-disable-line no-console
784
+ }
785
+
786
+ console.log('');
787
+ // eslint-disable-line no-console
788
+ }
789
+
790
+ /**
791
+ * Run configuration test
792
+ */
793
+ async runConfigurationTest() {
794
+ console.log('🧪 Running configuration test...\n');
795
+ // eslint-disable-line no-console
796
+
797
+ try {
798
+ // Simulate pipeline creation and basic validation
799
+ console.log('✅ Configuration syntax: valid');
800
+ // eslint-disable-line no-console
801
+ console.log('✅ Plugin dependencies: resolved');
802
+ // eslint-disable-line no-console
803
+ console.log('✅ Pipeline stages: configured');
804
+ // eslint-disable-line no-console
805
+
806
+ // Check for potential issues
807
+ const dependencies = extractPluginDependencies(this._config);
808
+ if (dependencies.length === 0) {
809
+ console.warn('⚠️ No plugins configured - pipeline will not function');
810
+ // eslint-disable-line no-console
811
+ }
812
+
813
+ console.log('\n🎉 Configuration test passed!');
814
+ // eslint-disable-line no-console
815
+ } catch (error) {
816
+ console.error('❌ Configuration test failed:', error.message);
817
+ // eslint-disable-line no-console
818
+ }
819
+ }
820
+
821
+ /**
822
+ * Load plugin registry
823
+ * @returns {Promise<object>} Registry data
824
+ */
825
+ async loadRegistry() {
826
+ // In a real implementation, this would fetch from the registry URL
827
+ // For now, return mock data
828
+ return {
829
+ plugins: {
830
+ 'file-loader': {
831
+ metadata: {
832
+ name: 'file-loader',
833
+ _type: 'loader',
834
+ description: 'Load files from filesystem',
835
+ },
836
+ versions: { '1.0.0': {}, '1.1.0': {} },
837
+ latest: '1.1.0',
838
+ },
839
+ 'openai-embedder': {
840
+ metadata: {
841
+ name: 'openai-embedder',
842
+ _type: 'embedder',
843
+ description: 'OpenAI embeddings',
844
+ },
845
+ versions: { '2.0.0': {}, '2.1.0': {} },
846
+ latest: '2.1.0',
847
+ },
848
+ },
849
+ };
850
+ }
851
+
852
+ /**
853
+ * Get available plugins for _type
854
+ * @param {string} _type - Plugin _type
855
+ * @returns {Array<object>} Available plugins
856
+ */
857
+ getAvailablePlugins(_type) {
858
+ if (!this.registry) {
859
+ return this.getBuiltinPlugins(_type);
860
+ }
861
+
862
+ return Object.values(this.registry.plugins)
863
+ .filter((plugin) => plugin.metadata._type === _type)
864
+ .map((plugin) => ({
865
+ name: plugin.metadata.name,
866
+ description: plugin.metadata.description,
867
+ version: plugin.latest,
868
+ }));
869
+ }
870
+
871
+ /**
872
+ * Get built-in plugin _options
873
+ * @param {string} _type - Plugin _type
874
+ * @returns {Array<object>} Built-in plugins
875
+ */
876
+ getBuiltinPlugins(_type) {
877
+ const builtins = {
878
+ loader: [
879
+ { name: 'file-loader', description: 'Load files from filesystem' },
880
+ { name: 'url-loader', description: 'Load content from URLs' },
881
+ ],
882
+ embedder: [
883
+ { name: 'openai-embedder', description: 'OpenAI embeddings' },
884
+ { name: 'local-embedder', description: 'Local embedding model' },
885
+ ],
886
+ retriever: [
887
+ { name: 'vector-retriever', description: 'Vector similarity search' },
888
+ { name: 'keyword-retriever', description: 'Keyword-based search' },
889
+ ],
890
+ llm: [
891
+ { name: 'openai-llm', description: 'OpenAI language models' },
892
+ { name: 'local-llm', description: 'Local language model' },
893
+ ],
894
+ reranker: [
895
+ {
896
+ name: 'similarity-reranker',
897
+ description: 'Similarity-based reranking',
898
+ },
899
+ ],
900
+ };
901
+
902
+ return builtins[_type] || [];
903
+ }
904
+
905
+ /**
906
+ * Get plugin information
907
+ * @param {string} _type - Plugin _type
908
+ * @param {string} name - Plugin name
909
+ * @returns {object|null} Plugin information
910
+ */
911
+ getPluginInfo(_type, name) {
912
+ if (!this.registry) {
913
+ return null;
914
+ }
915
+
916
+ return this.registry.plugins[name] || null;
917
+ }
918
+
919
+ /**
920
+ * Load wizard configuration
921
+ * @returns {object} Current configuration
922
+ */
923
+ loadConfig() {
924
+ return { ...this._config };
925
+ }
926
+
927
+ /**
928
+ * Navigate to next step
929
+ * @returns {string} Next step name
930
+ */
931
+ nextStep() {
932
+ if (this.currentStep < this.steps.length - 1) {
933
+ this.currentStep++;
934
+ }
935
+ return this.steps[this.currentStep];
936
+ }
937
+
938
+ /**
939
+ * Navigate to previous step
940
+ * @returns {string} Previous step name
941
+ */
942
+ previousStep() {
943
+ if (this.currentStep > 0) {
944
+ this.currentStep--;
945
+ }
946
+ return this.steps[this.currentStep];
947
+ }
948
+
949
+ /**
950
+ * Complete the wizard
951
+ * @returns {Promise<object>} Completion result
952
+ */
953
+ async complete() {
954
+ return {
955
+ success: true,
956
+ config: this._config,
957
+ message: 'Wizard completed successfully',
958
+ };
959
+ }
960
+
961
+ /**
962
+ * Validate user input
963
+ * @param {string} input - Input to validate
964
+ * @returns {boolean} Whether input is valid
965
+ */
966
+ validateInput(input) {
967
+ return typeof input === 'string' && input.trim().length > 0;
968
+ }
969
+
970
+ /**
971
+ * Process user selection
972
+ * @param {string} selection - User selection
973
+ * @returns {object} Processing result
974
+ */
975
+ processSelection(selection) {
976
+ return {
977
+ selection,
978
+ processed: true,
979
+ timestamp: Date.now(),
980
+ };
981
+ }
982
+ }
983
+
984
+ /**
985
+ * Main wizard function for CLI usage
986
+ * @param {object} options - Wizard options
987
+ * @returns {Promise<object>} Generated configuration
988
+ */
989
+ async function runInteractiveWizard(options = {}) {
990
+ const wizard = new InteractiveWizard(options);
991
+ return await wizard.run();
992
+ }
993
+
994
+ module.exports = {
995
+ InteractiveWizard,
996
+ runInteractiveWizard,
997
+ };