@devilsdev/rag-pipeline-utils 2.3.1 → 2.4.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 (160) hide show
  1. package/README.md +94 -480
  2. package/contracts/loader-contract.json +11 -6
  3. package/contracts/reranker-contract.json +18 -26
  4. package/dist/index.cjs +21190 -47
  5. package/dist/index.d.ts +298 -68
  6. package/dist/index.mjs +9 -76
  7. package/package.json +37 -11
  8. package/src/agentic/agentic-pipeline.js +235 -0
  9. package/src/agentic/iterative-retriever.js +213 -0
  10. package/src/agentic/query-planner.js +208 -0
  11. package/src/agentic/self-critique.js +102 -0
  12. package/src/ai/adaptive-retrieval.js +0 -3
  13. package/src/ai/federated-learning.js +0 -3
  14. package/src/ai/federation.js +1 -6
  15. package/src/ai/index.js +9 -20
  16. package/src/ai/model-training.js +0 -3
  17. package/src/ai/multimodal-processing.js +0 -3
  18. package/src/ai/multimodal.js +1 -6
  19. package/src/ai/orchestrator.js +1 -6
  20. package/src/ai/retrieval-engine.js +1 -6
  21. package/src/chunking/chunking-engine.js +142 -0
  22. package/src/chunking/strategies/fixed-size.js +54 -0
  23. package/src/chunking/strategies/recursive.js +127 -0
  24. package/src/chunking/strategies/semantic.js +128 -0
  25. package/src/chunking/strategies/sentence.js +32 -0
  26. package/src/chunking/strategies/structure-aware.js +138 -0
  27. package/src/citation/citation-tracker.js +161 -0
  28. package/src/citation/hallucination-detector.js +74 -0
  29. package/src/citation/source-mapper.js +95 -0
  30. package/src/cli/commands/ai-ml/adaptive-commands.js +178 -0
  31. package/src/cli/commands/ai-ml/federated-commands.js +207 -0
  32. package/src/cli/commands/ai-ml/index.js +17 -0
  33. package/src/cli/commands/ai-ml/multimodal-commands.js +187 -0
  34. package/src/cli/commands/ai-ml/shared.js +51 -0
  35. package/src/cli/commands/ai-ml/training-commands.js +228 -0
  36. package/src/cli/commands/ai-ml.js +176 -757
  37. package/src/cli/commands/plugin-hub/certification-commands.js +221 -0
  38. package/src/cli/commands/plugin-hub/event-handlers.js +64 -0
  39. package/src/cli/commands/plugin-hub/hub-commands.js +290 -0
  40. package/src/cli/commands/plugin-hub/review-commands.js +78 -0
  41. package/src/cli/commands/plugin-hub.js +106 -782
  42. package/src/cli/diagnostics/config-checker.js +81 -0
  43. package/src/cli/diagnostics/dependency-checker.js +69 -0
  44. package/src/cli/diagnostics/environment-checker.js +45 -0
  45. package/src/cli/diagnostics/performance-checker.js +51 -0
  46. package/src/cli/diagnostics/plugin-checker.js +106 -0
  47. package/src/cli/diagnostics/security-checker.js +61 -0
  48. package/src/cli/doctor-command.js +70 -369
  49. package/src/cli/enhanced-cli-commands.js +162 -706
  50. package/src/cli/handlers/config-handler.js +126 -0
  51. package/src/cli/handlers/diagnostics-handler.js +113 -0
  52. package/src/cli/handlers/ingest-handler.js +42 -0
  53. package/src/cli/handlers/init-handler.js +51 -0
  54. package/src/cli/handlers/query-handler.js +45 -0
  55. package/src/cli/handlers/run-handler.js +181 -0
  56. package/src/cli/interactive-wizard.js +99 -723
  57. package/src/cli/shared/cli-utils.js +89 -0
  58. package/src/cli/wizard/configuration.js +148 -0
  59. package/src/cli/wizard/observability.js +79 -0
  60. package/src/cli/wizard/performance.js +76 -0
  61. package/src/cli/wizard/plugin-selection.js +297 -0
  62. package/src/cli/wizard/preview-save.js +172 -0
  63. package/src/cli/wizard/project-setup.js +66 -0
  64. package/src/config/memory-optimization.js +3 -3
  65. package/src/connectors/anthropic-connector.js +179 -0
  66. package/src/connectors/base-connector.js +94 -0
  67. package/src/connectors/cohere-connector.js +143 -0
  68. package/src/connectors/local-embedder.js +171 -0
  69. package/src/connectors/memory-retriever.js +150 -0
  70. package/src/connectors/ollama-connector.js +205 -0
  71. package/src/connectors/openai-connector.js +173 -0
  72. package/src/core/create-pipeline.js +21 -1
  73. package/src/core/observability/tracing.js +2 -1
  74. package/src/core/pipeline-factory.js +0 -1
  75. package/src/core/plugin-registry.js +14 -14
  76. package/src/cost/cost-calculator.js +146 -0
  77. package/src/cost/cost-tracker.js +260 -0
  78. package/src/cost/token-budget.js +245 -0
  79. package/src/dag/core/execution-scheduler.js +2 -1
  80. package/src/dag/core/topology-validation.js +0 -3
  81. package/src/dag/dag-engine.js +3 -5
  82. package/src/dag/dag-node.js +0 -1
  83. package/src/dag/enhanced-dag-engine.js +171 -99
  84. package/src/dashboard/dashboard-generator.js +642 -0
  85. package/src/dashboard/metrics-aggregator.js +409 -0
  86. package/src/debug/execution-tracer.js +210 -0
  87. package/src/debug/trace-inspector.js +281 -0
  88. package/src/dev/dev-server.js +5 -5
  89. package/src/dev/hot-reload.js +3 -2
  90. package/src/dx/integration-templates.js +0 -3
  91. package/src/ecosystem/plugin-analytics-dashboard.js +2 -2
  92. package/src/ecosystem/plugin-hub.js +2 -2
  93. package/src/enterprise/audit-logging.js +2 -2
  94. package/src/enterprise/sso-integration.js +52 -32
  95. package/src/evaluate/context-metrics.js +127 -0
  96. package/src/evaluate/evaluator.js +4 -2
  97. package/src/evaluate/faithfulness.js +117 -0
  98. package/src/evaluate/groundedness.js +60 -0
  99. package/src/evaluate/pipeline-evaluator.js +156 -0
  100. package/src/evaluate/relevance.js +129 -0
  101. package/src/evaluate/scoring.js +27 -0
  102. package/src/graph/entity-extractor.js +183 -0
  103. package/src/graph/graph-index.js +113 -0
  104. package/src/graph/graph-retriever.js +244 -0
  105. package/src/graph/knowledge-graph.js +256 -0
  106. package/src/guardrails/guardrails-pipeline.js +136 -0
  107. package/src/guardrails/post-generation-guard.js +170 -0
  108. package/src/guardrails/pre-retrieval-guard.js +161 -0
  109. package/src/guardrails/retrieval-guard.js +126 -0
  110. package/src/index.js +255 -9
  111. package/src/loader/html-loader.js +4 -15
  112. package/src/loader/markdown-loader.js +4 -15
  113. package/src/mcp/mcp-server.js +199 -0
  114. package/src/mcp/mcp-tool-builder.js +121 -0
  115. package/src/observability/audit-logger.js +0 -2
  116. package/src/observability/event-logger.js +2 -1
  117. package/src/observability/security-monitor.js +0 -2
  118. package/src/observability/telemetry.js +0 -2
  119. package/src/reranker/cascade-reranker.js +79 -0
  120. package/src/reranker/embedding-reranker.js +124 -0
  121. package/src/reranker/llm-reranker.js +6 -3
  122. package/src/reranker/scoring-reranker.js +123 -0
  123. package/src/retrieval/bm25-search.js +157 -0
  124. package/src/retrieval/hybrid-retriever.js +111 -0
  125. package/src/retrieval/rank-fusion.js +62 -0
  126. package/src/security/jwt-config.js +4 -3
  127. package/src/security/jwt-validator.js +2 -1
  128. package/src/security/plugin-sandbox.js +0 -3
  129. package/src/security/plugin-signature-verifier.js +4 -6
  130. package/src/security/validator.js +0 -2
  131. package/src/streaming/embedding-stream.js +197 -0
  132. package/src/streaming/sse-adapter.js +168 -0
  133. package/src/streaming/stream-router.js +210 -0
  134. package/src/streaming/streaming-embedder.js +231 -0
  135. package/src/streaming/websocket-adapter.js +171 -0
  136. package/src/templates/scaffold.js +147 -0
  137. package/src/templates/template-registry.js +272 -0
  138. package/src/utils/contract-validator.js +2 -1
  139. package/src/utils/input-sanitizer.js +80 -99
  140. package/src/utils/performance-monitor.js +0 -3
  141. package/src/utils/plugin-scaffolder.js +9 -16
  142. package/src/utils/rate-limiter.js +0 -1
  143. package/src/utils/retry-policy.js +0 -3
  144. package/src/utils/safe-expression-evaluator.js +0 -3
  145. package/src/utils/secure-logger-config.js +2 -4
  146. package/src/utils/secure-logging.js +0 -3
  147. package/src/utils/structured-logger.js +0 -3
  148. package/src/ai/index-fixed.js +0 -509
  149. package/src/ai/module-template.js +0 -37
  150. package/src/ci/workflow-analyzer.js +0 -71
  151. package/src/cli/plugin-marketplace-commands.js +0 -869
  152. package/src/dev/README.md +0 -126
  153. package/src/dev/examples/hot-reload-usage.js +0 -355
  154. package/src/mocks/openai-embedder.js +0 -119
  155. package/src/mocks/openai-llm.js +0 -77
  156. package/src/mocks/pdf-loader.js +0 -21
  157. package/src/mocks/pinecone-retriever.js +0 -106
  158. package/src/scripts/script-utilities.js +0 -36
  159. package/src/utils/ci/diagnostic-reporter.js +0 -57
  160. package/src/utils/examples/error-formatter-usage.js +0 -351
@@ -1,31 +1,41 @@
1
1
  /**
2
2
  * Doctor Command for RAG Pipeline Diagnostics
3
3
  * Scans for common issues and provides actionable solutions
4
+ *
5
+ * This module serves as the orchestrator, delegating individual checks
6
+ * to focused checker modules in the diagnostics/ directory.
4
7
  */
5
8
 
6
- const fs = require('fs/promises');
7
- const path = require('path');
9
+ const fs = require("fs/promises");
10
+ const path = require("path");
11
+
12
+ const { checkConfiguration } = require("./diagnostics/config-checker.js");
13
+ const { checkPlugins } = require("./diagnostics/plugin-checker.js");
14
+ const { checkDependencies } = require("./diagnostics/dependency-checker.js");
15
+ const { checkPerformance } = require("./diagnostics/performance-checker.js");
16
+ const { checkSecurity } = require("./diagnostics/security-checker.js");
17
+ const { checkEnvironment } = require("./diagnostics/environment-checker.js");
8
18
 
9
19
  /**
10
20
  * Diagnostic categories
11
21
  */
12
22
  const DIAGNOSTIC_CATEGORIES = {
13
- CONFIGURATION: 'configuration',
14
- PLUGINS: 'plugins',
15
- DEPENDENCIES: 'dependencies',
16
- PERFORMANCE: 'performance',
17
- SECURITY: 'security',
18
- ENVIRONMENT: 'environment',
23
+ CONFIGURATION: "configuration",
24
+ PLUGINS: "plugins",
25
+ DEPENDENCIES: "dependencies",
26
+ PERFORMANCE: "performance",
27
+ SECURITY: "security",
28
+ ENVIRONMENT: "environment",
19
29
  };
20
30
 
21
31
  /**
22
32
  * Issue severity levels
23
33
  */
24
34
  const SEVERITY_LEVELS = {
25
- ERROR: 'error',
26
- WARNING: 'warning',
27
- INFO: 'info',
28
- SUCCESS: 'success',
35
+ ERROR: "error",
36
+ WARNING: "warning",
37
+ INFO: "info",
38
+ SUCCESS: "success",
29
39
  };
30
40
 
31
41
  /**
@@ -34,10 +44,10 @@ const SEVERITY_LEVELS = {
34
44
  class PipelineDoctor {
35
45
  constructor(_options = {}) {
36
46
  this.options = {
37
- configPath: _options.configPath || '.ragrc.json',
47
+ configPath: _options.configPath || ".ragrc.json",
38
48
  verbose: _options.verbose || false,
39
49
  autoFix: _options.autoFix || false,
40
- categories: _options.categories || ['all'],
50
+ categories: _options.categories || ["all"],
41
51
  ..._options,
42
52
  };
43
53
  }
@@ -47,71 +57,7 @@ class PipelineDoctor {
47
57
  * @returns {Promise<Array>} Array of configuration issues
48
58
  */
49
59
  async checkConfiguration() {
50
- const issues = [];
51
-
52
- try {
53
- await fs.access(this.options.configPath);
54
- } catch (error) {
55
- issues.push({
56
- category: 'configuration',
57
- severity: 'error',
58
- code: 'CONFIG_MISSING',
59
- message: `Configuration file not found: ${this.options.configPath}`,
60
- fix: 'Run "rag-pipeline init" to create a configuration file',
61
- autoFixable: false,
62
- });
63
- return issues;
64
- }
65
-
66
- try {
67
- const configContent = await fs.readFile(this.options.configPath, 'utf8');
68
- const config = JSON.parse(configContent);
69
-
70
- // Check if config is empty
71
- if (Object.keys(config).length === 0 || !config.plugins) {
72
- issues.push({
73
- category: 'configuration',
74
- severity: 'warning',
75
- code: 'CONFIG_EMPTY',
76
- message: 'Configuration file is empty or missing required sections',
77
- fix: 'Add plugin configurations and pipeline settings',
78
- autoFixable: false,
79
- });
80
- }
81
-
82
- // Validate schema if available
83
- try {
84
- const {
85
- validateEnhancedRagrcSchema,
86
- } = require('../config/enhanced-ragrc-schema.js');
87
- const validation = validateEnhancedRagrcSchema(config);
88
- if (!validation.valid && validation.errors) {
89
- validation.errors.forEach((error) => {
90
- issues.push({
91
- category: 'configuration',
92
- severity: 'error',
93
- code: 'CONFIG_SCHEMA_ERROR',
94
- message: `Schema validation failed: ${error.instancePath} ${error.message}`,
95
- fix: 'Fix configuration schema errors',
96
- autoFixable: false,
97
- });
98
- });
99
- }
100
- } catch (schemaError) {
101
- // Schema validation not available, skip
102
- }
103
- } catch (parseError) {
104
- issues.push({
105
- category: 'configuration',
106
- severity: 'error',
107
- code: 'CONFIG_INVALID_JSON',
108
- message: 'Configuration file contains invalid JSON syntax',
109
- fix: `Fix JSON syntax errors in ${this.options.configPath}`,
110
- autoFixable: false,
111
- });
112
- }
113
-
114
- return issues;
60
+ return checkConfiguration(this.options);
115
61
  }
116
62
 
117
63
  /**
@@ -119,95 +65,7 @@ class PipelineDoctor {
119
65
  * @returns {Promise<Array>} Array of plugin issues
120
66
  */
121
67
  async checkPlugins() {
122
- const issues = [];
123
-
124
- try {
125
- // First check if config file exists (this accounts for the first fs.access call in the test)
126
- await fs.access(this.options.configPath);
127
-
128
- const configContent = await fs.readFile(this.options.configPath, 'utf8');
129
- const config = JSON.parse(configContent);
130
-
131
- if (config.plugins) {
132
- // Process plugins in the order expected by tests: loader first, then embedder
133
- const categories = ['loader', 'embedder'];
134
- for (const category of categories) {
135
- if (config.plugins[category]) {
136
- const plugins = config.plugins[category];
137
- const sortedPlugins = Object.keys(plugins).sort();
138
- for (const pluginName of sortedPlugins) {
139
- try {
140
- // Check if plugin file exists (simplified check)
141
- await fs.access(path.join('node_modules', pluginName));
142
- } catch (error) {
143
- issues.push({
144
- category: 'plugins',
145
- severity: 'error',
146
- code: 'PLUGIN_MISSING',
147
- message: `Plugin not found: ${pluginName}`,
148
- fix: `Install plugin: npm install ${pluginName}`,
149
- autoFixable: true,
150
- });
151
- }
152
- }
153
- }
154
- }
155
-
156
- // Check for version conflicts
157
- try {
158
- const {
159
- resolvePluginVersions,
160
- } = require('../core/plugin-marketplace/version-resolver.js');
161
- const resolution = await resolvePluginVersions(config.plugins);
162
- if (resolution.conflicts) {
163
- resolution.conflicts.forEach((conflict) => {
164
- issues.push({
165
- category: 'plugins',
166
- severity: 'warning',
167
- code: 'PLUGIN_VERSION_CONFLICT',
168
- message: `Version conflict: ${conflict.plugin} - ${conflict.conflict}`,
169
- fix: 'Update plugin versions to resolve conflicts',
170
- autoFixable: false,
171
- });
172
- });
173
- }
174
- } catch (resolverError) {
175
- // Version resolver not available, skip
176
- }
177
-
178
- // Check for outdated plugins
179
- try {
180
- const registryUrl = 'https://registry.rag-pipeline.dev';
181
- const response = await fetch(`${registryUrl}/plugins`);
182
- if (response.ok) {
183
- const registry = await response.json();
184
- for (const [category, plugins] of Object.entries(config.plugins)) {
185
- for (const [pluginName, version] of Object.entries(plugins)) {
186
- if (registry.plugins && registry.plugins[pluginName]) {
187
- const latest = registry.plugins[pluginName].versions.latest;
188
- if (version !== 'latest' && version !== latest) {
189
- issues.push({
190
- category: 'plugins',
191
- severity: 'info',
192
- code: 'PLUGIN_OUTDATED',
193
- message: `Plugin outdated: ${pluginName}@${version} (latest: ${latest})`,
194
- fix: `Update to latest version: rag-pipeline plugin install ${pluginName}@latest`,
195
- autoFixable: true,
196
- });
197
- }
198
- }
199
- }
200
- }
201
- }
202
- } catch (fetchError) {
203
- // Registry not available, skip
204
- }
205
- }
206
- } catch (configError) {
207
- // Config issues handled in checkConfiguration
208
- }
209
-
210
- return issues;
68
+ return checkPlugins(this.options);
211
69
  }
212
70
 
213
71
  /**
@@ -215,58 +73,7 @@ class PipelineDoctor {
215
73
  * @returns {Promise<Array>} Array of dependency issues
216
74
  */
217
75
  async checkDependencies() {
218
- const issues = [];
219
-
220
- // Check Node.js version
221
- const nodeVersion = process.version;
222
- const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
223
- if (majorVersion < 18) {
224
- issues.push({
225
- category: 'dependencies',
226
- severity: 'error',
227
- code: 'NODE_VERSION_INCOMPATIBLE',
228
- message: `Node.js version ${nodeVersion} is not supported (required: >=18.0.0)`,
229
- fix: 'Upgrade Node.js to version 18.0.0 or higher',
230
- autoFixable: false,
231
- });
232
- }
233
-
234
- // Check package.json
235
- try {
236
- await fs.access('package.json');
237
- const packageContent = await fs.readFile('package.json', 'utf8');
238
- const packageJson = JSON.parse(packageContent);
239
-
240
- if (packageJson.dependencies) {
241
- for (const [depName, version] of Object.entries(
242
- packageJson.dependencies,
243
- )) {
244
- try {
245
- await fs.access(path.join('node_modules', depName));
246
- } catch (error) {
247
- issues.push({
248
- category: 'dependencies',
249
- severity: 'error',
250
- code: 'NPM_DEPENDENCY_MISSING',
251
- message: `NPM dependency missing: ${depName}`,
252
- fix: 'Install missing dependencies: npm install',
253
- autoFixable: true,
254
- });
255
- }
256
- }
257
- }
258
- } catch (error) {
259
- issues.push({
260
- category: 'dependencies',
261
- severity: 'warning',
262
- code: 'PACKAGE_JSON_MISSING',
263
- message: 'package.json not found in current directory',
264
- fix: 'Initialize npm project: npm init',
265
- autoFixable: false,
266
- });
267
- }
268
-
269
- return issues;
76
+ return checkDependencies(this.options);
270
77
  }
271
78
 
272
79
  /**
@@ -274,41 +81,7 @@ class PipelineDoctor {
274
81
  * @returns {Promise<Array>} Array of performance issues
275
82
  */
276
83
  async checkPerformance() {
277
- const issues = [];
278
-
279
- // Check memory usage
280
- const memUsage = process.memoryUsage();
281
- const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);
282
- if (heapUsedMB > 512) {
283
- issues.push({
284
- category: 'performance',
285
- severity: 'warning',
286
- code: 'MEMORY_USAGE_HIGH',
287
- message: `High memory usage detected: ${heapUsedMB}MB used`,
288
- fix: 'Consider reducing batch sizes or enabling streaming',
289
- autoFixable: false,
290
- });
291
- }
292
-
293
- // Check config file size
294
- try {
295
- const stats = await fs.stat(this.options.configPath);
296
- const sizeMB = stats.size / 1024 / 1024;
297
- if (sizeMB > 1) {
298
- issues.push({
299
- category: 'performance',
300
- severity: 'warning',
301
- code: 'CONFIG_FILE_LARGE',
302
- message: `Configuration file is unusually large: ${sizeMB.toFixed(1)}MB`,
303
- fix: 'Consider splitting configuration or removing unused sections',
304
- autoFixable: false,
305
- });
306
- }
307
- } catch (error) {
308
- // File doesn't exist, handled elsewhere
309
- }
310
-
311
- return issues;
84
+ return checkPerformance(this.options);
312
85
  }
313
86
 
314
87
  /**
@@ -316,51 +89,7 @@ class PipelineDoctor {
316
89
  * @returns {Promise<Array>} Array of security issues
317
90
  */
318
91
  async checkSecurity() {
319
- const issues = [];
320
-
321
- // Check for hardcoded API keys in config content
322
- try {
323
- const configContent = await fs.readFile(this.options.configPath, 'utf8');
324
- const config = JSON.parse(configContent);
325
-
326
- const configStr = JSON.stringify(config);
327
- if (
328
- configStr.includes('sk-') ||
329
- configStr.includes('apiKey') ||
330
- configStr.includes('api_key')
331
- ) {
332
- issues.push({
333
- category: 'security',
334
- severity: 'error',
335
- code: 'HARDCODED_API_KEY',
336
- message: 'Hardcoded API key detected in configuration',
337
- fix: 'Move API keys to environment variables',
338
- autoFixable: false,
339
- });
340
- }
341
- } catch (configError) {
342
- // Config reading issues handled elsewhere
343
- }
344
-
345
- // Check file permissions (independent of config content)
346
- try {
347
- const stats = await fs.stat(this.options.configPath);
348
- const mode = stats.mode & 0o777;
349
- if (mode === 0o777) {
350
- issues.push({
351
- category: 'security',
352
- severity: 'warning',
353
- code: 'INSECURE_PERMISSIONS',
354
- message: 'Configuration file has insecure permissions (777)',
355
- fix: `Set secure permissions: chmod 600 ${this.options.configPath}`,
356
- autoFixable: true,
357
- });
358
- }
359
- } catch (statError) {
360
- // File stat issues handled elsewhere
361
- }
362
-
363
- return issues;
92
+ return checkSecurity(this.options);
364
93
  }
365
94
 
366
95
  /**
@@ -368,35 +97,7 @@ class PipelineDoctor {
368
97
  * @returns {Promise<Array>} Array of environment issues
369
98
  */
370
99
  async checkEnvironment() {
371
- const issues = [];
372
-
373
- try {
374
- const configContent = await fs.readFile(this.options.configPath, 'utf8');
375
- const config = JSON.parse(configContent);
376
-
377
- // Check for missing environment variables
378
- const configStr = JSON.stringify(config);
379
- const envVarMatches = configStr.match(/\$\{([^}]+)\}/g);
380
- if (envVarMatches) {
381
- envVarMatches.forEach((match) => {
382
- const envVar = match.slice(2, -1);
383
- if (!process.env[envVar]) {
384
- issues.push({
385
- category: 'environment',
386
- severity: 'error',
387
- code: 'ENV_VAR_MISSING',
388
- message: `Required environment variable missing: ${envVar}`,
389
- fix: `Set environment variable: export ${envVar}=your_key`,
390
- autoFixable: false,
391
- });
392
- }
393
- });
394
- }
395
- } catch (error) {
396
- // Config issues handled elsewhere
397
- }
398
-
399
- return issues;
100
+ return checkEnvironment(this.options);
400
101
  }
401
102
 
402
103
  /**
@@ -407,23 +108,23 @@ class PipelineDoctor {
407
108
  * @returns {Promise<object>} Execution result
408
109
  */
409
110
  async execSafe(command, args = [], options = {}) {
410
- const { execFile } = require('child_process');
411
- const { promisify } = require('util');
111
+ const { execFile } = require("child_process");
112
+ const { promisify } = require("util");
412
113
  const execFileAsync = promisify(execFile);
413
114
 
414
115
  // Validate command is in allowlist
415
- const ALLOWED_COMMANDS = ['npm', 'chmod', 'node', 'icacls'];
116
+ const ALLOWED_COMMANDS = ["npm", "chmod", "node", "icacls"];
416
117
  if (!ALLOWED_COMMANDS.includes(command)) {
417
118
  throw new Error(`Command not allowed: ${command}`);
418
119
  }
419
120
 
420
121
  // Sanitize arguments
421
122
  const sanitizedArgs = args.map((arg) => {
422
- if (typeof arg !== 'string') {
423
- throw new Error('All arguments must be strings');
123
+ if (typeof arg !== "string") {
124
+ throw new Error("All arguments must be strings");
424
125
  }
425
126
  // Remove shell metacharacters
426
- return arg.replace(/[;&|`$(){}[\]<>"'\\]/g, '');
127
+ return arg.replace(/[;&|`$(){}[\]<>"'\\]/g, "");
427
128
  });
428
129
 
429
130
  const execOptions = {
@@ -445,41 +146,41 @@ class PipelineDoctor {
445
146
  if (!issue.autoFixable) {
446
147
  return {
447
148
  success: false,
448
- message: 'Issue is not auto-fixable',
149
+ message: "Issue is not auto-fixable",
449
150
  };
450
151
  }
451
152
 
452
153
  try {
453
- if (issue.code === 'NPM_DEPENDENCY_MISSING') {
154
+ if (issue.code === "NPM_DEPENDENCY_MISSING") {
454
155
  // Use execSafe with validated command and args
455
- const result = await this.execSafe('npm', [
456
- 'install',
457
- '--no-fund',
458
- '--no-audit',
156
+ const result = await this.execSafe("npm", [
157
+ "install",
158
+ "--no-fund",
159
+ "--no-audit",
459
160
  ]);
460
161
  return {
461
162
  success: true,
462
- message: result.stdout || 'Dependencies installed',
163
+ message: result.stdout || "Dependencies installed",
463
164
  };
464
165
  }
465
166
 
466
- if (issue.code === 'INSECURE_PERMISSIONS') {
167
+ if (issue.code === "INSECURE_PERMISSIONS") {
467
168
  // Validate config path is within project directory
468
169
  const configPath = path.resolve(this.options.configPath);
469
- const projectDir = path.resolve('.');
170
+ const projectDir = path.resolve(".");
470
171
  if (!configPath.startsWith(projectDir)) {
471
- throw new Error('Config path outside project directory');
172
+ throw new Error("Config path outside project directory");
472
173
  }
473
174
 
474
175
  // Check if running on Windows
475
- if (process.platform === 'win32') {
176
+ if (process.platform === "win32") {
476
177
  // On Windows, attempt to use icacls or fall back to fs.chmod
477
178
  try {
478
- await this.execSafe('icacls', [
179
+ await this.execSafe("icacls", [
479
180
  configPath,
480
- '/inheritance:r',
481
- '/grant',
482
- `${require('os').userInfo().username}:F`,
181
+ "/inheritance:r",
182
+ "/grant",
183
+ `${require("os").userInfo().username}:F`,
483
184
  ]);
484
185
  } catch (icaclsError) {
485
186
  // Fall back to fs.chmod if icacls fails
@@ -493,18 +194,18 @@ class PipelineDoctor {
493
194
  }
494
195
  } else {
495
196
  // Use chmod on Unix-like systems
496
- await this.execSafe('chmod', ['600', configPath]);
197
+ await this.execSafe("chmod", ["600", configPath]);
497
198
  }
498
199
 
499
200
  return {
500
201
  success: true,
501
- message: 'Permissions updated',
202
+ message: "Permissions updated",
502
203
  };
503
204
  }
504
205
 
505
206
  return {
506
207
  success: false,
507
- message: 'Auto-fix not implemented for this issue type',
208
+ message: "Auto-fix not implemented for this issue type",
508
209
  };
509
210
  } catch (error) {
510
211
  return {
@@ -522,15 +223,15 @@ class PipelineDoctor {
522
223
  generateReport(issues) {
523
224
  const summary = {
524
225
  totalIssues: issues.length,
525
- errors: issues.filter((i) => i.severity === 'error').length,
526
- warnings: issues.filter((i) => i.severity === 'warning').length,
527
- info: issues.filter((i) => i.severity === 'info').length,
226
+ errors: issues.filter((i) => i.severity === "error").length,
227
+ warnings: issues.filter((i) => i.severity === "warning").length,
228
+ info: issues.filter((i) => i.severity === "info").length,
528
229
  healthScore: Math.max(
529
230
  0,
530
231
  100 -
531
- (issues.filter((i) => i.severity === 'error').length * 25 +
532
- issues.filter((i) => i.severity === 'warning').length * 10 +
533
- issues.filter((i) => i.severity === 'info').length * 2),
232
+ (issues.filter((i) => i.severity === "error").length * 25 +
233
+ issues.filter((i) => i.severity === "warning").length * 10 +
234
+ issues.filter((i) => i.severity === "info").length * 2),
534
235
  ),
535
236
  };
536
237
 
@@ -546,11 +247,11 @@ class PipelineDoctor {
546
247
  issues.forEach((issue) => {
547
248
  if (categories[issue.category]) {
548
249
  categories[issue.category].issues++;
549
- if (issue.severity === 'error') {
250
+ if (issue.severity === "error") {
550
251
  categories[issue.category].errors++;
551
- } else if (issue.severity === 'warning') {
252
+ } else if (issue.severity === "warning") {
552
253
  categories[issue.category].warnings++;
553
- } else if (issue.severity === 'info') {
254
+ } else if (issue.severity === "info") {
554
255
  categories[issue.category].info++;
555
256
  }
556
257
  }
@@ -571,36 +272,36 @@ class PipelineDoctor {
571
272
  async run() {
572
273
  const allIssues = [];
573
274
 
574
- const categoriesToRun = this.options.categories.includes('all')
275
+ const categoriesToRun = this.options.categories.includes("all")
575
276
  ? Object.values(DIAGNOSTIC_CATEGORIES)
576
277
  : this.options.categories;
577
278
 
578
- if (categoriesToRun.includes('configuration')) {
279
+ if (categoriesToRun.includes("configuration")) {
579
280
  const configIssues = await this.checkConfiguration();
580
281
  allIssues.push(...configIssues);
581
282
  }
582
283
 
583
- if (categoriesToRun.includes('plugins')) {
284
+ if (categoriesToRun.includes("plugins")) {
584
285
  const pluginIssues = await this.checkPlugins();
585
286
  allIssues.push(...pluginIssues);
586
287
  }
587
288
 
588
- if (categoriesToRun.includes('dependencies')) {
289
+ if (categoriesToRun.includes("dependencies")) {
589
290
  const depIssues = await this.checkDependencies();
590
291
  allIssues.push(...depIssues);
591
292
  }
592
293
 
593
- if (categoriesToRun.includes('performance')) {
294
+ if (categoriesToRun.includes("performance")) {
594
295
  const perfIssues = await this.checkPerformance();
595
296
  allIssues.push(...perfIssues);
596
297
  }
597
298
 
598
- if (categoriesToRun.includes('security')) {
299
+ if (categoriesToRun.includes("security")) {
599
300
  const secIssues = await this.checkSecurity();
600
301
  allIssues.push(...secIssues);
601
302
  }
602
303
 
603
- if (categoriesToRun.includes('environment')) {
304
+ if (categoriesToRun.includes("environment")) {
604
305
  const envIssues = await this.checkEnvironment();
605
306
  allIssues.push(...envIssues);
606
307
  }