@devilsdev/rag-pipeline-utils 2.3.1 → 2.4.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/README.md +293 -369
- package/contracts/loader-contract.json +11 -6
- package/contracts/reranker-contract.json +18 -26
- package/dist/index.cjs +21190 -47
- package/dist/index.d.ts +298 -68
- package/dist/index.mjs +9 -76
- package/package.json +20 -8
- package/src/agentic/agentic-pipeline.js +235 -0
- package/src/agentic/iterative-retriever.js +213 -0
- package/src/agentic/query-planner.js +208 -0
- package/src/agentic/self-critique.js +102 -0
- package/src/ai/adaptive-retrieval.js +0 -3
- package/src/ai/federated-learning.js +0 -3
- package/src/ai/federation.js +1 -6
- package/src/ai/index.js +9 -20
- package/src/ai/model-training.js +0 -3
- package/src/ai/multimodal-processing.js +0 -3
- package/src/ai/multimodal.js +1 -6
- package/src/ai/orchestrator.js +1 -6
- package/src/ai/retrieval-engine.js +1 -6
- package/src/chunking/chunking-engine.js +142 -0
- package/src/chunking/strategies/fixed-size.js +54 -0
- package/src/chunking/strategies/recursive.js +127 -0
- package/src/chunking/strategies/semantic.js +128 -0
- package/src/chunking/strategies/sentence.js +32 -0
- package/src/chunking/strategies/structure-aware.js +138 -0
- package/src/citation/citation-tracker.js +161 -0
- package/src/citation/hallucination-detector.js +74 -0
- package/src/citation/source-mapper.js +95 -0
- package/src/cli/commands/ai-ml/adaptive-commands.js +178 -0
- package/src/cli/commands/ai-ml/federated-commands.js +207 -0
- package/src/cli/commands/ai-ml/index.js +17 -0
- package/src/cli/commands/ai-ml/multimodal-commands.js +187 -0
- package/src/cli/commands/ai-ml/shared.js +51 -0
- package/src/cli/commands/ai-ml/training-commands.js +228 -0
- package/src/cli/commands/ai-ml.js +176 -757
- package/src/cli/commands/plugin-hub/certification-commands.js +221 -0
- package/src/cli/commands/plugin-hub/event-handlers.js +64 -0
- package/src/cli/commands/plugin-hub/hub-commands.js +290 -0
- package/src/cli/commands/plugin-hub/review-commands.js +78 -0
- package/src/cli/commands/plugin-hub.js +106 -782
- package/src/cli/diagnostics/config-checker.js +81 -0
- package/src/cli/diagnostics/dependency-checker.js +69 -0
- package/src/cli/diagnostics/environment-checker.js +45 -0
- package/src/cli/diagnostics/performance-checker.js +51 -0
- package/src/cli/diagnostics/plugin-checker.js +106 -0
- package/src/cli/diagnostics/security-checker.js +61 -0
- package/src/cli/doctor-command.js +70 -369
- package/src/cli/enhanced-cli-commands.js +162 -706
- package/src/cli/handlers/config-handler.js +126 -0
- package/src/cli/handlers/diagnostics-handler.js +113 -0
- package/src/cli/handlers/ingest-handler.js +42 -0
- package/src/cli/handlers/init-handler.js +51 -0
- package/src/cli/handlers/query-handler.js +45 -0
- package/src/cli/handlers/run-handler.js +181 -0
- package/src/cli/interactive-wizard.js +99 -723
- package/src/cli/shared/cli-utils.js +89 -0
- package/src/cli/wizard/configuration.js +148 -0
- package/src/cli/wizard/observability.js +79 -0
- package/src/cli/wizard/performance.js +76 -0
- package/src/cli/wizard/plugin-selection.js +297 -0
- package/src/cli/wizard/preview-save.js +172 -0
- package/src/cli/wizard/project-setup.js +66 -0
- package/src/config/memory-optimization.js +3 -3
- package/src/connectors/anthropic-connector.js +179 -0
- package/src/connectors/base-connector.js +94 -0
- package/src/connectors/cohere-connector.js +143 -0
- package/src/connectors/local-embedder.js +171 -0
- package/src/connectors/memory-retriever.js +150 -0
- package/src/connectors/ollama-connector.js +205 -0
- package/src/connectors/openai-connector.js +173 -0
- package/src/core/create-pipeline.js +21 -1
- package/src/core/observability/tracing.js +2 -1
- package/src/core/pipeline-factory.js +0 -1
- package/src/core/plugin-registry.js +14 -14
- package/src/cost/cost-calculator.js +146 -0
- package/src/cost/cost-tracker.js +260 -0
- package/src/cost/token-budget.js +245 -0
- package/src/dag/core/execution-scheduler.js +2 -1
- package/src/dag/core/topology-validation.js +0 -3
- package/src/dag/dag-engine.js +3 -5
- package/src/dag/dag-node.js +0 -1
- package/src/dag/enhanced-dag-engine.js +171 -99
- package/src/dashboard/dashboard-generator.js +642 -0
- package/src/dashboard/metrics-aggregator.js +409 -0
- package/src/debug/execution-tracer.js +210 -0
- package/src/debug/trace-inspector.js +281 -0
- package/src/dev/dev-server.js +5 -5
- package/src/dev/hot-reload.js +3 -2
- package/src/dx/integration-templates.js +0 -3
- package/src/ecosystem/plugin-analytics-dashboard.js +2 -2
- package/src/ecosystem/plugin-hub.js +2 -2
- package/src/enterprise/audit-logging.js +2 -2
- package/src/enterprise/sso-integration.js +52 -32
- package/src/evaluate/context-metrics.js +127 -0
- package/src/evaluate/evaluator.js +4 -2
- package/src/evaluate/faithfulness.js +117 -0
- package/src/evaluate/groundedness.js +60 -0
- package/src/evaluate/pipeline-evaluator.js +156 -0
- package/src/evaluate/relevance.js +129 -0
- package/src/evaluate/scoring.js +27 -0
- package/src/graph/entity-extractor.js +183 -0
- package/src/graph/graph-index.js +113 -0
- package/src/graph/graph-retriever.js +244 -0
- package/src/graph/knowledge-graph.js +256 -0
- package/src/guardrails/guardrails-pipeline.js +136 -0
- package/src/guardrails/post-generation-guard.js +170 -0
- package/src/guardrails/pre-retrieval-guard.js +161 -0
- package/src/guardrails/retrieval-guard.js +126 -0
- package/src/index.js +255 -9
- package/src/loader/html-loader.js +4 -15
- package/src/loader/markdown-loader.js +4 -15
- package/src/mcp/mcp-server.js +199 -0
- package/src/mcp/mcp-tool-builder.js +121 -0
- package/src/observability/audit-logger.js +0 -2
- package/src/observability/event-logger.js +2 -1
- package/src/observability/security-monitor.js +0 -2
- package/src/observability/telemetry.js +0 -2
- package/src/reranker/cascade-reranker.js +79 -0
- package/src/reranker/embedding-reranker.js +124 -0
- package/src/reranker/llm-reranker.js +6 -3
- package/src/reranker/scoring-reranker.js +123 -0
- package/src/retrieval/bm25-search.js +157 -0
- package/src/retrieval/hybrid-retriever.js +111 -0
- package/src/retrieval/rank-fusion.js +62 -0
- package/src/security/jwt-config.js +4 -3
- package/src/security/jwt-validator.js +2 -1
- package/src/security/plugin-sandbox.js +0 -3
- package/src/security/plugin-signature-verifier.js +4 -6
- package/src/security/validator.js +0 -2
- package/src/streaming/embedding-stream.js +197 -0
- package/src/streaming/sse-adapter.js +168 -0
- package/src/streaming/stream-router.js +210 -0
- package/src/streaming/streaming-embedder.js +231 -0
- package/src/streaming/websocket-adapter.js +171 -0
- package/src/templates/scaffold.js +147 -0
- package/src/templates/template-registry.js +272 -0
- package/src/utils/contract-validator.js +2 -1
- package/src/utils/input-sanitizer.js +80 -99
- package/src/utils/performance-monitor.js +0 -3
- package/src/utils/plugin-scaffolder.js +9 -16
- package/src/utils/rate-limiter.js +0 -1
- package/src/utils/retry-policy.js +0 -3
- package/src/utils/safe-expression-evaluator.js +0 -3
- package/src/utils/secure-logger-config.js +2 -4
- package/src/utils/secure-logging.js +0 -3
- package/src/utils/structured-logger.js +0 -3
- package/src/ai/index-fixed.js +0 -509
- package/src/ai/module-template.js +0 -37
- package/src/ci/workflow-analyzer.js +0 -71
- package/src/cli/plugin-marketplace-commands.js +0 -869
- package/src/dev/README.md +0 -126
- package/src/dev/examples/hot-reload-usage.js +0 -355
- package/src/mocks/openai-embedder.js +0 -119
- package/src/mocks/openai-llm.js +0 -77
- package/src/mocks/pdf-loader.js +0 -21
- package/src/mocks/pinecone-retriever.js +0 -106
- package/src/scripts/script-utilities.js +0 -36
- package/src/utils/ci/diagnostic-reporter.js +0 -57
- 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(
|
|
7
|
-
const path = require(
|
|
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:
|
|
14
|
-
PLUGINS:
|
|
15
|
-
DEPENDENCIES:
|
|
16
|
-
PERFORMANCE:
|
|
17
|
-
SECURITY:
|
|
18
|
-
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:
|
|
26
|
-
WARNING:
|
|
27
|
-
INFO:
|
|
28
|
-
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 ||
|
|
47
|
+
configPath: _options.configPath || ".ragrc.json",
|
|
38
48
|
verbose: _options.verbose || false,
|
|
39
49
|
autoFix: _options.autoFix || false,
|
|
40
|
-
categories: _options.categories || [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
411
|
-
const { promisify } = require(
|
|
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 = [
|
|
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 !==
|
|
423
|
-
throw new Error(
|
|
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:
|
|
149
|
+
message: "Issue is not auto-fixable",
|
|
449
150
|
};
|
|
450
151
|
}
|
|
451
152
|
|
|
452
153
|
try {
|
|
453
|
-
if (issue.code ===
|
|
154
|
+
if (issue.code === "NPM_DEPENDENCY_MISSING") {
|
|
454
155
|
// Use execSafe with validated command and args
|
|
455
|
-
const result = await this.execSafe(
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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 ||
|
|
163
|
+
message: result.stdout || "Dependencies installed",
|
|
463
164
|
};
|
|
464
165
|
}
|
|
465
166
|
|
|
466
|
-
if (issue.code ===
|
|
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(
|
|
172
|
+
throw new Error("Config path outside project directory");
|
|
472
173
|
}
|
|
473
174
|
|
|
474
175
|
// Check if running on Windows
|
|
475
|
-
if (process.platform ===
|
|
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(
|
|
179
|
+
await this.execSafe("icacls", [
|
|
479
180
|
configPath,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
`${require(
|
|
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(
|
|
197
|
+
await this.execSafe("chmod", ["600", configPath]);
|
|
497
198
|
}
|
|
498
199
|
|
|
499
200
|
return {
|
|
500
201
|
success: true,
|
|
501
|
-
message:
|
|
202
|
+
message: "Permissions updated",
|
|
502
203
|
};
|
|
503
204
|
}
|
|
504
205
|
|
|
505
206
|
return {
|
|
506
207
|
success: false,
|
|
507
|
-
message:
|
|
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 ===
|
|
526
|
-
warnings: issues.filter((i) => i.severity ===
|
|
527
|
-
info: issues.filter((i) => i.severity ===
|
|
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 ===
|
|
532
|
-
issues.filter((i) => i.severity ===
|
|
533
|
-
issues.filter((i) => i.severity ===
|
|
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 ===
|
|
250
|
+
if (issue.severity === "error") {
|
|
550
251
|
categories[issue.category].errors++;
|
|
551
|
-
} else if (issue.severity ===
|
|
252
|
+
} else if (issue.severity === "warning") {
|
|
552
253
|
categories[issue.category].warnings++;
|
|
553
|
-
} else if (issue.severity ===
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
304
|
+
if (categoriesToRun.includes("environment")) {
|
|
604
305
|
const envIssues = await this.checkEnvironment();
|
|
605
306
|
allIssues.push(...envIssues);
|
|
606
307
|
}
|