@devilsdev/rag-pipeline-utils 2.4.5 → 2.6.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.
Files changed (258) hide show
  1. package/.ragrc.schema.json +83 -192
  2. package/CHANGELOG.md +431 -0
  3. package/README.md +418 -117
  4. package/SECURITY.md +5 -5
  5. package/dist/experimental.cjs +2 -0
  6. package/dist/experimental.d.ts +1 -0
  7. package/dist/experimental.mjs +5 -0
  8. package/dist/index.cjs +6442 -1355
  9. package/dist/index.d.ts +129 -2
  10. package/dist/index.mjs +1 -1
  11. package/dist/testing.cjs +2 -0
  12. package/dist/testing.d.ts +1 -0
  13. package/dist/testing.mjs +5 -0
  14. package/dist/types/adapters/ai-sdk.d.ts +53 -0
  15. package/dist/types/agentic/agentic-pipeline.d.ts +103 -0
  16. package/dist/types/agentic/iterative-retriever.d.ts +85 -0
  17. package/dist/types/agentic/query-planner.d.ts +145 -0
  18. package/dist/types/agentic/self-critique.d.ts +45 -0
  19. package/dist/types/ai/adaptive-retrieval.d.ts +44 -0
  20. package/dist/types/ai/federation/federated-learning-coordinator.d.ts +62 -0
  21. package/dist/types/ai/multimodal-processing.d.ts +32 -0
  22. package/dist/types/ai/multimodal.d.ts +39 -0
  23. package/dist/types/ai/retrieval-engine.d.ts +37 -0
  24. package/dist/types/ai/training/model-training-orchestrator.d.ts +31 -0
  25. package/dist/types/cache/component-keys.d.ts +7 -0
  26. package/dist/types/cache/memory-cache.d.ts +54 -0
  27. package/dist/types/cache/pipeline-cache.d.ts +66 -0
  28. package/dist/types/cache/redis-cache.d.ts +46 -0
  29. package/dist/types/chunking/chunking-engine.d.ts +70 -0
  30. package/dist/types/chunking/strategies/fixed-size.d.ts +17 -0
  31. package/dist/types/chunking/strategies/recursive.d.ts +20 -0
  32. package/dist/types/chunking/strategies/semantic.d.ts +19 -0
  33. package/dist/types/chunking/strategies/sentence.d.ts +13 -0
  34. package/dist/types/chunking/strategies/structure-aware.d.ts +19 -0
  35. package/dist/types/citation/citation-tracker.d.ts +64 -0
  36. package/dist/types/citation/hallucination-detector.d.ts +40 -0
  37. package/dist/types/citation/source-mapper.d.ts +37 -0
  38. package/dist/types/connectors/anthropic-connector.d.ts +97 -0
  39. package/dist/types/connectors/base-connector.d.ts +87 -0
  40. package/dist/types/connectors/cohere-connector.d.ts +94 -0
  41. package/dist/types/connectors/connector-utils.d.ts +110 -0
  42. package/dist/types/connectors/local-embedder.d.ts +95 -0
  43. package/dist/types/connectors/memory-retriever.d.ts +99 -0
  44. package/dist/types/connectors/ollama-connector.d.ts +115 -0
  45. package/dist/types/connectors/openai-connector.d.ts +129 -0
  46. package/dist/types/connectors/rag-prompt.d.ts +40 -0
  47. package/dist/types/core/create-pipeline.d.ts +8 -0
  48. package/dist/types/core/plugin-registry.d.ts +136 -0
  49. package/dist/types/core/stage-contracts.d.ts +36 -0
  50. package/dist/types/core/validate-plugin.d.ts +45 -0
  51. package/dist/types/cost/cost-calculator.d.ts +152 -0
  52. package/dist/types/cost/cost-tracker.d.ts +126 -0
  53. package/dist/types/cost/token-budget.d.ts +110 -0
  54. package/dist/types/dag/core/error-context.d.ts +239 -0
  55. package/dist/types/dag/core/execution-scheduler.d.ts +191 -0
  56. package/dist/types/dag/core/topology-validation.d.ts +226 -0
  57. package/dist/types/dag/dag-engine.d.ts +156 -0
  58. package/dist/types/dag/dag-node.d.ts +37 -0
  59. package/dist/types/dashboard/dashboard-generator.d.ts +127 -0
  60. package/dist/types/dashboard/metrics-aggregator.d.ts +218 -0
  61. package/dist/types/debug/execution-tracer.d.ts +57 -0
  62. package/dist/types/debug/trace-inspector.d.ts +31 -0
  63. package/dist/types/ecosystem/plugin-certification.d.ts +169 -0
  64. package/dist/types/enterprise/data-governance.d.ts +203 -0
  65. package/dist/types/enterprise/multi-tenancy.d.ts +137 -0
  66. package/dist/types/enterprise/sso-integration.d.ts +420 -0
  67. package/dist/types/evaluate/context-metrics.d.ts +55 -0
  68. package/dist/types/evaluate/faithfulness.d.ts +41 -0
  69. package/dist/types/evaluate/groundedness.d.ts +60 -0
  70. package/dist/types/evaluate/pipeline-evaluator.d.ts +88 -0
  71. package/dist/types/evaluate/relevance.d.ts +21 -0
  72. package/dist/types/evaluate/scoring.d.ts +123 -0
  73. package/dist/types/evaluate/semantic-similarity.d.ts +14 -0
  74. package/dist/types/experimental.d.ts +15 -0
  75. package/dist/types/graph/entity-extractor.d.ts +84 -0
  76. package/dist/types/graph/graph-index.d.ts +49 -0
  77. package/dist/types/graph/graph-retriever.d.ts +81 -0
  78. package/dist/types/graph/knowledge-graph.d.ts +129 -0
  79. package/dist/types/grounding/check-answer.d.ts +101 -0
  80. package/dist/types/guardrails/guardrails-pipeline.d.ts +63 -0
  81. package/dist/types/guardrails/injection-detector.d.ts +47 -0
  82. package/dist/types/guardrails/post-generation-guard.d.ts +61 -0
  83. package/dist/types/guardrails/pre-retrieval-guard.d.ts +64 -0
  84. package/dist/types/guardrails/retrieval-guard.d.ts +57 -0
  85. package/dist/types/mcp/mcp-server.d.ts +85 -0
  86. package/dist/types/mcp/mcp-tool-builder.d.ts +55 -0
  87. package/dist/types/reranker/cascade-reranker.d.ts +40 -0
  88. package/dist/types/reranker/embedding-reranker.d.ts +77 -0
  89. package/dist/types/reranker/scoring-reranker.d.ts +41 -0
  90. package/dist/types/retrieval/bm25-search.d.ts +43 -0
  91. package/dist/types/retrieval/file-vector-store.d.ts +99 -0
  92. package/dist/types/retrieval/hybrid-retriever.d.ts +35 -0
  93. package/dist/types/retrieval/rank-fusion.d.ts +10 -0
  94. package/dist/types/security/jwt-config.d.ts +80 -0
  95. package/dist/types/security/jwt-validator.d.ts +195 -0
  96. package/dist/types/security/plugin-sandbox.d.ts +158 -0
  97. package/dist/types/security/plugin-signature-verifier.d.ts +139 -0
  98. package/dist/types/security/validator.d.ts +5 -0
  99. package/dist/types/streaming/embedding-stream.d.ts +65 -0
  100. package/dist/types/streaming/sse-adapter.d.ts +59 -0
  101. package/dist/types/streaming/stream-router.d.ts +88 -0
  102. package/dist/types/streaming/streaming-embedder.d.ts +99 -0
  103. package/dist/types/streaming/websocket-adapter.d.ts +71 -0
  104. package/dist/types/templates/scaffold.d.ts +55 -0
  105. package/dist/types/templates/template-registry.d.ts +63 -0
  106. package/dist/types/testing.d.ts +168 -0
  107. package/dist/types/utils/embed-query.d.ts +20 -0
  108. package/dist/types/utils/logger.d.ts +50 -0
  109. package/dist/types/utils/rate-limiter.d.ts +66 -0
  110. package/dist/types/utils/retry.d.ts +27 -0
  111. package/dist/types/utils/run-abort.d.ts +34 -0
  112. package/dist/types/utils/secure-logging.d.ts +51 -0
  113. package/dist/types/utils/structured-logger.d.ts +126 -0
  114. package/package.json +72 -33
  115. package/src/adapters/ai-sdk.js +215 -0
  116. package/src/agentic/agentic-pipeline.js +75 -7
  117. package/src/agentic/iterative-retriever.js +47 -10
  118. package/src/agentic/query-planner.js +329 -78
  119. package/src/cache/component-keys.js +38 -0
  120. package/src/cache/memory-cache.js +87 -0
  121. package/src/cache/pipeline-cache.js +260 -0
  122. package/src/cache/redis-cache.js +83 -0
  123. package/src/citation/citation-tracker.js +6 -4
  124. package/src/citation/hallucination-detector.js +2 -2
  125. package/src/citation/source-mapper.js +15 -28
  126. package/src/cli/commands/ai.js +106 -0
  127. package/src/cli/commands/plugin-hub/event-handlers.js +6 -0
  128. package/src/cli/commands/plugin-hub/hub-commands.js +0 -74
  129. package/src/cli/commands/plugin-hub/local-commands.js +143 -0
  130. package/src/cli/commands/plugin-hub.js +114 -49
  131. package/src/cli/diagnostics/config-checker.js +76 -63
  132. package/src/cli/diagnostics/environment-checker.js +62 -31
  133. package/src/cli/diagnostics/plugin-checker.js +36 -89
  134. package/src/cli/doctor-command.js +39 -5
  135. package/src/cli/enhanced-cli-commands.js +104 -233
  136. package/src/cli/handlers/ai-handler.js +364 -0
  137. package/src/cli/handlers/diagnostics-handler.js +78 -31
  138. package/src/cli/handlers/ingest-handler.js +28 -22
  139. package/src/cli/handlers/init-handler.js +148 -25
  140. package/src/cli/handlers/query-handler.js +203 -25
  141. package/src/cli/handlers/run-handler.js +16 -167
  142. package/src/cli/handlers/serve-handler.js +60 -0
  143. package/src/cli/services/bench-stats.js +54 -0
  144. package/src/cli/services/benchmark.js +161 -0
  145. package/src/cli/services/feedback.js +155 -0
  146. package/src/cli/services/instrument.js +83 -0
  147. package/src/cli/services/rag-service.js +361 -0
  148. package/src/cli/shared/cli-utils.js +24 -7
  149. package/src/cli/shared/config-context.js +21 -0
  150. package/src/cli/wizard/config-builder.js +81 -0
  151. package/src/cli/wizard/init-wizard.js +602 -0
  152. package/src/config/component-factory.js +125 -0
  153. package/src/config/enhanced-ragrc-schema.js +0 -2
  154. package/src/config/load-config.js +29 -10
  155. package/src/config/load-plugin-config.js +46 -2
  156. package/src/config/validate-schema.js +4 -1
  157. package/src/connectors/anthropic-connector.js +115 -57
  158. package/src/connectors/base-connector.js +74 -19
  159. package/src/connectors/cohere-connector.js +108 -34
  160. package/src/connectors/connector-utils.js +302 -0
  161. package/src/connectors/local-embedder.js +63 -5
  162. package/src/connectors/memory-retriever.js +125 -14
  163. package/src/connectors/ollama-connector.js +112 -51
  164. package/src/connectors/openai-connector.js +153 -44
  165. package/src/connectors/rag-prompt.js +88 -0
  166. package/src/core/create-pipeline.js +307 -61
  167. package/src/core/performance/parallel-processor.js +62 -1
  168. package/src/core/plugin-registry.js +125 -26
  169. package/src/core/stage-contracts.js +36 -0
  170. package/src/core/validate-plugin.js +85 -0
  171. package/src/cost/cost-calculator.js +205 -32
  172. package/src/debug/execution-tracer.js +14 -4
  173. package/src/dev/dev-server.js +173 -11
  174. package/src/dev/hot-reload.js +44 -4
  175. package/src/ecosystem/plugin-checks.js +181 -0
  176. package/src/ecosystem/plugin-hub.js +50 -125
  177. package/src/ecosystem/plugin-installer.js +298 -0
  178. package/src/ecosystem/plugin-probe.js +127 -0
  179. package/src/ecosystem/plugin-scanner.js +185 -0
  180. package/src/ecosystem/tar-extract.js +114 -0
  181. package/src/enterprise/audit-logging.js +158 -29
  182. package/src/enterprise/sso-integration.js +716 -228
  183. package/src/evaluate/context-metrics.js +28 -16
  184. package/src/evaluate/evaluator.js +3 -3
  185. package/src/evaluate/faithfulness.js +18 -14
  186. package/src/evaluate/groundedness.js +43 -12
  187. package/src/evaluate/pipeline-evaluator.js +35 -8
  188. package/src/evaluate/scoring.js +251 -3
  189. package/src/evaluate/semantic-similarity.js +79 -0
  190. package/src/experimental.js +71 -0
  191. package/src/grounding/check-answer.js +173 -0
  192. package/src/guardrails/guardrails-pipeline.js +69 -7
  193. package/src/guardrails/injection-detector.js +283 -0
  194. package/src/guardrails/post-generation-guard.js +19 -0
  195. package/src/guardrails/pre-retrieval-guard.js +36 -36
  196. package/src/guardrails/retrieval-guard.js +58 -8
  197. package/src/index.js +58 -1
  198. package/src/loader/csv-loader.js +3 -2
  199. package/src/loader/document-reader.js +91 -0
  200. package/src/loader/html-loader.js +3 -1
  201. package/src/loader/markdown-loader.js +3 -2
  202. package/src/reranker/cascade-reranker.js +3 -0
  203. package/src/reranker/embedding-reranker.js +136 -21
  204. package/src/reranker/llm-reranker.js +79 -12
  205. package/src/reranker/scoring-reranker.js +3 -0
  206. package/src/retrieval/bm25-search.js +12 -6
  207. package/src/retrieval/file-vector-store.js +241 -0
  208. package/src/retrieval/hybrid-retriever.js +22 -19
  209. package/src/security/jwt-config.js +13 -2
  210. package/src/security/jwt-validator.js +139 -34
  211. package/src/security/plugin-sandbox.js +18 -1
  212. package/src/security/plugin-signature-verifier.js +245 -70
  213. package/src/testing.js +254 -0
  214. package/src/utils/deprecate.js +69 -0
  215. package/src/utils/embed-query.js +33 -0
  216. package/src/utils/input-sanitizer.js +19 -4
  217. package/src/utils/logger.js +34 -4
  218. package/src/utils/run-abort.js +102 -0
  219. package/src/ai/federated-learning.js +0 -211
  220. package/src/ai/federation.js +0 -71
  221. package/src/ai/index.js +0 -22
  222. package/src/ai/model-trainer.js +0 -217
  223. package/src/ai/model-training.js +0 -202
  224. package/src/ai/multimodal/multi-modal-processor.js +0 -345
  225. package/src/ai/orchestrator.js +0 -65
  226. package/src/ai/retrieval/adaptive-retrieval-engine.js +0 -398
  227. package/src/cli/commands/ai-ml/adaptive-commands.js +0 -178
  228. package/src/cli/commands/ai-ml/federated-commands.js +0 -207
  229. package/src/cli/commands/ai-ml/index.js +0 -17
  230. package/src/cli/commands/ai-ml/multimodal-commands.js +0 -187
  231. package/src/cli/commands/ai-ml/shared.js +0 -51
  232. package/src/cli/commands/ai-ml/training-commands.js +0 -228
  233. package/src/cli/commands/ai-ml.js +0 -386
  234. package/src/cli/commands/docs.js +0 -228
  235. package/src/cli/commands/dx.js +0 -538
  236. package/src/cli/commands/wizard.js +0 -627
  237. package/src/cli/input-sanitization-middleware.js +0 -356
  238. package/src/cli/interactive-wizard.js +0 -373
  239. package/src/cli/templates/development.template.json +0 -64
  240. package/src/cli/templates/minimal.template.json +0 -33
  241. package/src/cli/templates/production.template.json +0 -104
  242. package/src/cli/templates/testing.template.json +0 -45
  243. package/src/cli/wizard/configuration.js +0 -148
  244. package/src/cli/wizard/observability.js +0 -79
  245. package/src/cli/wizard/performance.js +0 -76
  246. package/src/cli/wizard/plugin-selection.js +0 -297
  247. package/src/cli/wizard/preview-save.js +0 -172
  248. package/src/cli/wizard/project-setup.js +0 -66
  249. package/src/core/pipeline-factory.js +0 -59
  250. package/src/dag/enhanced-dag-engine.js +0 -894
  251. package/src/dx/index.js +0 -40
  252. package/src/dx/integration-templates.js +0 -662
  253. package/src/dx/performance-profiler.js +0 -968
  254. package/src/dx/realtime-debugger.js +0 -755
  255. package/src/dx/visual-pipeline-builder.js +0 -578
  256. package/src/ingest.js +0 -59
  257. package/src/pipeline/pipeline.js +0 -18
  258. package/src/query.js +0 -117
@@ -1,105 +1,52 @@
1
1
  /**
2
- * Plugin checker for RAG Pipeline Diagnostics
3
- * Checks plugin availability, version conflicts, and outdated plugins
2
+ * Plugin diagnostics: every custom plugin path under `plugins` exists and
3
+ * loads. Checked locally; no registry is contacted.
4
4
  */
5
5
 
6
- const fs = require("fs/promises");
6
+ const fs = require("fs");
7
7
  const path = require("path");
8
8
 
9
- /**
10
- * Check plugin issues
11
- * @param {object} options - Doctor options (must include configPath)
12
- * @returns {Promise<Array>} Array of plugin issues
13
- */
14
9
  async function checkPlugins(options) {
15
- const issues = [];
16
-
10
+ const configPath = path.resolve(options.configPath);
11
+ let config;
17
12
  try {
18
- // First check if config file exists
19
- await fs.access(options.configPath);
20
-
21
- const configContent = await fs.readFile(options.configPath, "utf8");
22
- const config = JSON.parse(configContent);
23
-
24
- if (config.plugins) {
25
- // Process plugins in the order expected by tests: loader first, then embedder
26
- const categories = ["loader", "embedder"];
27
- for (const category of categories) {
28
- if (config.plugins[category]) {
29
- const plugins = config.plugins[category];
30
- const sortedPlugins = Object.keys(plugins).sort();
31
- for (const pluginName of sortedPlugins) {
32
- try {
33
- // Check if plugin file exists (simplified check)
34
- await fs.access(path.join("node_modules", pluginName));
35
- } catch (error) {
36
- issues.push({
37
- category: "plugins",
38
- severity: "error",
39
- code: "PLUGIN_MISSING",
40
- message: `Plugin not found: ${pluginName}`,
41
- fix: `Install plugin: npm install ${pluginName}`,
42
- autoFixable: true,
43
- });
44
- }
45
- }
46
- }
47
- }
13
+ config = JSON.parse(fs.readFileSync(configPath, "utf8"));
14
+ } catch {
15
+ return []; // reported by the configuration checker
16
+ }
48
17
 
49
- // Check for version conflicts
50
- try {
51
- const {
52
- resolvePluginVersions,
53
- } = require("../../core/plugin-marketplace/version-resolver.js");
54
- const resolution = await resolvePluginVersions(config.plugins);
55
- if (resolution.conflicts) {
56
- resolution.conflicts.forEach((conflict) => {
57
- issues.push({
58
- category: "plugins",
59
- severity: "warning",
60
- code: "PLUGIN_VERSION_CONFLICT",
61
- message: `Version conflict: ${conflict.plugin} - ${conflict.conflict}`,
62
- fix: "Update plugin versions to resolve conflicts",
63
- autoFixable: false,
64
- });
65
- });
66
- }
67
- } catch (resolverError) {
68
- // Version resolver not available, skip
18
+ const issues = [];
19
+ const configDir = path.dirname(configPath);
20
+ for (const [stage, plugins] of Object.entries(config.plugins || {})) {
21
+ if (!plugins || typeof plugins !== "object") continue;
22
+ for (const [name, modulePath] of Object.entries(plugins)) {
23
+ if (typeof modulePath !== "string") continue;
24
+ const resolved = path.resolve(configDir, modulePath);
25
+ if (!fs.existsSync(resolved)) {
26
+ issues.push({
27
+ category: "plugins",
28
+ severity: "error",
29
+ code: "PLUGIN_MISSING",
30
+ message: `Plugin ${stage}/${name} not found at ${modulePath}`,
31
+ fix: `Create ${modulePath} or fix the path in plugins.${stage}.${name}`,
32
+ autoFixable: false,
33
+ });
34
+ continue;
69
35
  }
70
-
71
- // Check for outdated plugins
72
36
  try {
73
- const registryUrl = "https://registry.rag-pipeline.dev";
74
- const response = await fetch(`${registryUrl}/plugins`);
75
- if (response.ok) {
76
- const registry = await response.json();
77
- for (const [category, plugins] of Object.entries(config.plugins)) {
78
- for (const [pluginName, version] of Object.entries(plugins)) {
79
- if (registry.plugins && registry.plugins[pluginName]) {
80
- const latest = registry.plugins[pluginName].versions.latest;
81
- if (version !== "latest" && version !== latest) {
82
- issues.push({
83
- category: "plugins",
84
- severity: "info",
85
- code: "PLUGIN_OUTDATED",
86
- message: `Plugin outdated: ${pluginName}@${version} (latest: ${latest})`,
87
- fix: `Update to latest version: rag-pipeline plugin install ${pluginName}@latest`,
88
- autoFixable: true,
89
- });
90
- }
91
- }
92
- }
93
- }
94
- }
95
- } catch (fetchError) {
96
- // Registry not available, skip
37
+ require(resolved);
38
+ } catch (error) {
39
+ issues.push({
40
+ category: "plugins",
41
+ severity: "error",
42
+ code: "PLUGIN_LOAD_FAILED",
43
+ message: `Plugin ${stage}/${name} failed to load: ${error.message}`,
44
+ fix: `Fix the error in ${modulePath}`,
45
+ autoFixable: false,
46
+ });
97
47
  }
98
48
  }
99
- } catch (configError) {
100
- // Config issues handled in checkConfiguration
101
49
  }
102
-
103
50
  return issues;
104
51
  }
105
52
 
@@ -38,6 +38,25 @@ const SEVERITY_LEVELS = {
38
38
  SUCCESS: "success",
39
39
  };
40
40
 
41
+ /**
42
+ * Locate npm's CLI script next to the running node binary (Windows layout:
43
+ * <node dir>/node_modules/npm/bin/npm-cli.js).
44
+ * @returns {string}
45
+ */
46
+ function resolveNpmCli() {
47
+ const candidate = path.join(
48
+ path.dirname(process.execPath),
49
+ "node_modules",
50
+ "npm",
51
+ "bin",
52
+ "npm-cli.js",
53
+ );
54
+ if (!require("fs").existsSync(candidate)) {
55
+ throw new Error("npm not found next to node; run npm install manually");
56
+ }
57
+ return candidate;
58
+ }
59
+
41
60
  /**
42
61
  * Doctor command for pipeline diagnostics
43
62
  */
@@ -118,22 +137,32 @@ class PipelineDoctor {
118
137
  throw new Error(`Command not allowed: ${command}`);
119
138
  }
120
139
 
121
- // Sanitize arguments
140
+ // Sanitize arguments. Backslashes are kept: there is no shell to
141
+ // interpret them, and they are path separators on Windows.
122
142
  const sanitizedArgs = args.map((arg) => {
123
143
  if (typeof arg !== "string") {
124
144
  throw new Error("All arguments must be strings");
125
145
  }
126
- // Remove shell metacharacters
127
- return arg.replace(/[;&|`$(){}[\]<>"'\\]/g, "");
146
+ return arg.replace(/[;&|`$(){}[\]<>"']/g, "");
128
147
  });
129
148
 
130
149
  const execOptions = {
131
- shell: false, // Never use shell to prevent injection
132
150
  timeout: options.timeout || 30000,
133
151
  env: { ...process.env, PATH: process.env.PATH }, // Controlled environment
134
152
  ...options,
153
+ shell: false, // Never use a shell; set last so callers cannot override it
135
154
  };
136
155
 
156
+ // npm is a .cmd shim on Windows, which execFile cannot run without a
157
+ // shell; run npm's JS entry point with node instead.
158
+ if (command === "npm" && process.platform === "win32") {
159
+ return await execFileAsync(
160
+ process.execPath,
161
+ [resolveNpmCli(), ...sanitizedArgs],
162
+ execOptions,
163
+ );
164
+ }
165
+
137
166
  return await execFileAsync(command, sanitizedArgs, execOptions);
138
167
  }
139
168
 
@@ -168,7 +197,12 @@ class PipelineDoctor {
168
197
  // Validate config path is within project directory
169
198
  const configPath = path.resolve(this.options.configPath);
170
199
  const projectDir = path.resolve(".");
171
- if (!configPath.startsWith(projectDir)) {
200
+ // Containment check: a bare startsWith(projectDir) also accepted
201
+ // sibling directories such as "/proj-evil".
202
+ const inside = ["/", "\\"].some((sep) =>
203
+ configPath.startsWith(projectDir + sep),
204
+ );
205
+ if (!inside) {
172
206
  throw new Error("Config path outside project directory");
173
207
  }
174
208
 
@@ -6,84 +6,38 @@
6
6
  */
7
7
 
8
8
  const { Command } = require("commander");
9
- const fs = require("fs/promises");
10
9
 
11
10
  const { logger } = require("../utils/logger.js");
12
11
 
13
12
  // Shared utilities
14
13
  const {
15
- createProgressBar,
16
14
  parsePositiveInteger,
17
15
  generateCompletionScript,
18
16
  getVersion,
19
17
  getExtendedHelp,
20
18
  } = require("./shared/cli-utils.js");
21
19
 
22
- // Handler modules
23
- const { handleRun } = require("./handlers/run-handler.js");
24
- const { handleInit } = require("./handlers/init-handler.js");
25
- const {
26
- handleDoctor,
27
- handleValidate,
28
- handleInfo,
29
- } = require("./handlers/diagnostics-handler.js");
30
- const {
31
- handleConfigShow,
32
- handleConfigSet,
33
- handleConfigGet,
34
- } = require("./handlers/config-handler.js");
35
- const { handleIngest } = require("./handlers/ingest-handler.js");
36
- const { handleQuery } = require("./handlers/query-handler.js");
37
-
38
- // Mock dependencies for test compatibility
39
- const mockPluginMarketplaceCommands = () => {
40
- const cmd = new Command("plugin");
41
- cmd.description("Plugin marketplace commands");
42
- cmd
43
- .command("search")
44
- .argument("[query]")
45
- .action(() => {});
46
- cmd
47
- .command("install")
48
- .argument("<name>")
49
- .action(() => {});
50
- cmd.command("publish").action(() => {});
51
- return cmd;
52
- };
53
-
54
- const mockPipelineDoctor = async (options) => {
55
- console.log("🏥 Running pipeline diagnostics");
56
- if (options.categories) {
57
- options.categories.forEach((cat) => {
58
- console.log(`${cat.charAt(0).toUpperCase() + cat.slice(1)} Issues:`);
59
- console.log(" ✅ No issues found");
60
- });
61
- } else {
62
- console.log("✅ All systems operational");
63
- }
64
- return {
65
- summary: { total: 0, passed: 0, warnings: 0, errors: 0 },
66
- categories: {},
67
- issues: [],
68
- };
20
+ // Handler modules load when their command runs, so `--help` or one command
21
+ // does not pay for every other command's dependencies (inquirer, jsdom, ora,
22
+ // marked, csv-parse...).
23
+ /* eslint-disable global-require */
24
+ const handlers = {
25
+ run: () => require("./handlers/run-handler.js"),
26
+ init: () => require("./handlers/init-handler.js"),
27
+ diagnostics: () => require("./handlers/diagnostics-handler.js"),
28
+ config: () => require("./handlers/config-handler.js"),
29
+ ingest: () => require("./handlers/ingest-handler.js"),
30
+ query: () => require("./handlers/query-handler.js"),
69
31
  };
32
+ /* eslint-enable global-require */
70
33
 
71
- const mockValidateSchema = (config) => {
72
- if (!config || typeof config !== "object") {
73
- return {
74
- valid: false,
75
- errors: [{ message: "Invalid configuration format" }],
76
- };
34
+ function parseNonNegativeInt(value) {
35
+ const n = Number(value);
36
+ if (!Number.isInteger(n) || n < 0) {
37
+ throw new Error(`Expected a non-negative integer, got "${value}"`);
77
38
  }
78
- if (config.plugins && typeof config.plugins === "string") {
79
- return { valid: false, errors: [{ message: "Invalid plugins format" }] };
80
- }
81
- const isLegacy =
82
- config.plugins &&
83
- typeof config.plugins === "object" &&
84
- Object.values(config.plugins).some((p) => typeof p === "string");
85
- return { valid: true, legacy: isLegacy };
86
- };
39
+ return n;
40
+ }
87
41
 
88
42
  /**
89
43
  * Enhanced CLI with improved UX and additional features
@@ -105,7 +59,7 @@ class EnhancedCLI {
105
59
  .version(getVersion(), "-v, --version", "Display version information")
106
60
  .option("--config <path>", "Configuration file path", ".ragrc.json")
107
61
  .option("--verbose", "Enable verbose output")
108
- .option("--quiet", "Suppress non-essential output")
62
+ .option("--quiet", "Print only results, no status messages")
109
63
  .option("--no-color", "Disable colored output")
110
64
  .option("--dry-run", "Show what would be done without executing")
111
65
  .helpOption("-h, --help", "Display help information")
@@ -117,111 +71,116 @@ class EnhancedCLI {
117
71
  * Setup all CLI commands
118
72
  */
119
73
  setupCommands() {
120
- // Interactive initialization command
121
74
  this.program
122
75
  .command("init")
123
- .description("Initialize RAG pipeline configuration")
124
- .option("--interactive", "Use interactive wizard", true)
125
- .option("--no-interactive", "Skip interactive wizard")
126
- .option("--template <name>", "Use configuration template")
76
+ .description("Create a .ragrc.json configuration")
77
+ .option("--no-interactive", "Use the template without prompting")
78
+ .option(
79
+ "--template <name>",
80
+ "Starting point: local, openai, ollama, anthropic",
81
+ "local",
82
+ )
127
83
  .option("--output <path>", "Output configuration file", ".ragrc.json")
128
84
  .option("--force", "Overwrite existing configuration")
129
85
  .action(async (options) => {
130
- await handleInit(this.program.opts(), options, (outputPath) =>
131
- this.createBasicConfig(outputPath),
132
- );
86
+ const result = await handlers
87
+ .init()
88
+ .handleInit(this.program.opts(), options);
89
+ // After a connection test, exit even if a provider call left a
90
+ // socket or timer open (see exitAfterConnectionTest).
91
+ handlers.init().exitAfterConnectionTest(result);
133
92
  });
134
93
 
135
- // Run pipeline command
136
94
  this.program
137
95
  .command("run")
138
- .description("Execute RAG pipeline operations")
139
- .option("--ingest <file>", "Ingest document into pipeline")
140
- .option("--query <prompt>", "Query the pipeline")
141
- .option("--stream", "Enable streaming output")
142
- .option(
143
- "--abort-timeout <ms>",
144
- "Abort operation after timeout (milliseconds)",
145
- parsePositiveInteger,
146
- )
147
- .option("--parallel", "Enable parallel processing")
96
+ .description("Ingest and/or query in one step")
97
+ .option("--ingest <path>", "File or directory to ingest first")
98
+ .option("--query <text>", "Question to ask after ingesting")
99
+ .option("--rebuild", "Discard the existing index before ingesting")
100
+ .option("--top-k <n>", "Passages to retrieve", parsePositiveInteger, 3)
101
+ .option("--json", "Print the query result as JSON")
148
102
  .action(async (options) => {
149
- await handleRun(this.program.opts(), options);
103
+ await handlers.run().handleRun(this.program.opts(), options);
150
104
  });
151
105
 
152
- // Doctor command for diagnostics
153
106
  this.program
154
107
  .command("doctor")
155
- .description("Diagnose and fix common issues")
156
- .option("--category <categories...>", "Diagnostic categories to check")
157
- .option("--auto-fix", "Automatically fix issues where possible")
158
- .option("--report <path>", "Save diagnostic report to file")
108
+ .description("Diagnose configuration, plugins and environment")
109
+ .option(
110
+ "--category <categories...>",
111
+ "Only run: configuration, plugins, dependencies, performance, security, environment",
112
+ )
113
+ .option(
114
+ "--auto-fix",
115
+ "Fix issues where possible (npm install, file permissions)",
116
+ )
117
+ .option("--report <path>", "Save the diagnostic report as JSON")
159
118
  .action(async (options) => {
160
- await handleDoctor(this.program.opts(), options, mockPipelineDoctor);
119
+ await handlers.diagnostics().handleDoctor(this.program.opts(), options);
161
120
  });
162
121
 
163
- // Enhanced ingest command
164
122
  this.program
165
123
  .command("ingest")
166
- .description("Ingest documents into the pipeline")
167
- .argument("<file>", "Document file to ingest")
168
- .option("--validate", "Validate document before ingesting")
169
- .option("--preview", "Show preview of document chunks")
170
- .option("--parallel", "Enable parallel processing")
171
- .option("--streaming", "Enable streaming with memory safeguards")
172
- .option("--trace", "Enable detailed tracing and event logging")
173
- .option("--stats", "Show pipeline metrics summary at the end")
174
- .option(
175
- "--export-observability <file>",
176
- "Export observability data to file",
177
- )
178
- .option(
179
- "--max-concurrency <number>",
180
- "Maximum concurrent operations",
181
- "3",
182
- )
183
- .option(
184
- "--batch-size <number>",
185
- "Batch size for parallel processing",
186
- "10",
187
- )
188
- .option("--max-memory <number>", "Maximum memory usage in MB", "512")
189
- .action(async (file, options) => {
190
- await handleIngest(this.program.opts(), file, options);
124
+ .description("Load, embed and index documents")
125
+ .argument("<path>", "File or directory (.md, .html, .csv, .txt)")
126
+ .option("--rebuild", "Discard the existing index before ingesting")
127
+ .action(async (inputPath, options) => {
128
+ await handlers
129
+ .ingest()
130
+ .handleIngest(this.program.opts(), inputPath, options);
191
131
  });
192
132
 
193
- // Enhanced query command
194
133
  this.program
195
134
  .command("query")
196
- .description("Query the RAG pipeline")
197
- .argument("<prompt>", "Query prompt")
198
- .option("--stream", "Enable streaming response")
199
- .option("--explain", "Show explanation of query processing")
200
- .option("--parallel", "Enable parallel processing")
201
- .option("--trace", "Enable detailed tracing and event logging")
202
- .option("--stats", "Show pipeline metrics summary at the end")
135
+ .description("Ask a question against the ingested documents")
136
+ .argument("<question>", "Question text")
137
+ .option("--top-k <n>", "Passages to retrieve", parsePositiveInteger, 3)
138
+ .option("--json", "Print the result as JSON")
139
+ .option("--streaming", "Print the answer as it is generated")
203
140
  .option(
204
- "--export-observability <file>",
205
- "Export observability data to file",
141
+ "--timeout <ms>",
142
+ "Abort the query after this many milliseconds",
143
+ parsePositiveInteger,
144
+ )
145
+ .option("--trace", "Show time spent in each stage")
146
+ .option(
147
+ "--explain",
148
+ "Show passage scores and which passages support each answer sentence",
206
149
  )
207
- .action(async (prompt, options) => {
208
- await handleQuery(this.program.opts(), prompt, options);
150
+ .option("--stats", "Show latency and estimated tokens and cost")
151
+ .action(async (question, options) => {
152
+ await handlers
153
+ .query()
154
+ .handleQuery(this.program.opts(), question, options);
209
155
  });
210
156
 
211
- // Configuration validation command
212
157
  this.program
213
158
  .command("validate")
214
- .description("Validate configuration file")
215
- .option("--schema", "Validate against schema only")
216
- .option("--plugins", "Validate plugin availability")
217
- .option("--dependencies", "Check plugin dependencies")
218
- .option("--fix", "Attempt to fix validation issues")
159
+ .description("Validate the configuration and resolve its components")
160
+ .action(async () => {
161
+ await handlers.diagnostics().handleValidate(this.program.opts());
162
+ });
163
+
164
+ this.program
165
+ .command("serve")
166
+ .description("Serve GET /health and POST /query over HTTP (local use)")
167
+ .option(
168
+ "--port <n>",
169
+ "Port (0 picks a free one)",
170
+ parseNonNegativeInt,
171
+ 3000,
172
+ )
173
+ .option("--host <host>", "Interface to bind", "127.0.0.1")
219
174
  .action(async (options) => {
220
- await handleValidate(this.program.opts(), options, mockValidateSchema);
175
+ const { handleServe } = require("./handlers/serve-handler.js");
176
+ await handleServe(this.program.opts(), options);
221
177
  });
222
178
 
223
- // Plugin marketplace commands
224
- this.program.addCommand(mockPluginMarketplaceCommands());
179
+ const { PluginHubCLI } = require("./commands/plugin-hub.js");
180
+ this.program.addCommand(new PluginHubCLI().createCommands());
181
+
182
+ const { createAiCommand } = require("./commands/ai.js");
183
+ this.program.addCommand(createAiCommand(() => this.program.opts()));
225
184
 
226
185
  // Configuration management commands
227
186
  const configCmd = new Command("config");
@@ -230,10 +189,9 @@ class EnhancedCLI {
230
189
  configCmd
231
190
  .command("show")
232
191
  .description("Show current configuration")
233
- .option("--format <format>", "Output format (json, yaml, table)", "json")
234
192
  .option("--section <section>", "Show specific configuration section")
235
193
  .action(async (options) => {
236
- await handleConfigShow(this.program.opts(), options);
194
+ await handlers.config().handleConfigShow(this.program.opts(), options);
237
195
  });
238
196
 
239
197
  configCmd
@@ -242,7 +200,9 @@ class EnhancedCLI {
242
200
  .argument("<key>", "Configuration key (dot notation supported)")
243
201
  .argument("<value>", "Configuration value")
244
202
  .action(async (key, value, options) => {
245
- await handleConfigSet(this.program.opts(), key, value);
203
+ await handlers
204
+ .config()
205
+ .handleConfigSet(this.program.opts(), key, value);
246
206
  });
247
207
 
248
208
  configCmd
@@ -250,7 +210,7 @@ class EnhancedCLI {
250
210
  .description("Get configuration value")
251
211
  .argument("<key>", "Configuration key (dot notation supported)")
252
212
  .action(async (key, options) => {
253
- await handleConfigGet(this.program.opts(), key);
213
+ await handlers.config().handleConfigGet(this.program.opts(), key);
254
214
  });
255
215
 
256
216
  this.program.addCommand(configCmd);
@@ -259,11 +219,11 @@ class EnhancedCLI {
259
219
  this.program
260
220
  .command("info")
261
221
  .description("Show system and plugin information")
262
- .option("--plugins", "Show registered plugin versions")
222
+ .option("--plugins", "Show built-in components and custom plugins")
263
223
  .option("--system", "Show system information")
264
224
  .option("--config", "Show configuration summary")
265
225
  .action(async (options) => {
266
- await handleInfo(this.program.opts(), options);
226
+ await handlers.diagnostics().handleInfo(this.program.opts(), options);
267
227
  });
268
228
 
269
229
  // Completion command for shell autocompletion
@@ -277,64 +237,6 @@ class EnhancedCLI {
277
237
  });
278
238
  }
279
239
 
280
- /**
281
- * Create basic configuration
282
- */
283
- async createBasicConfig(outputPath) {
284
- const { validateRagrc } = require("../config/enhanced-ragrc-schema.js");
285
-
286
- const base = {
287
- namespace: "default",
288
- metadata: {
289
- name: "rag-pipeline",
290
- version: "1.0.0",
291
- description: "RAG pipeline configuration",
292
- createdAt: new Date().toISOString(),
293
- },
294
- pipeline: [
295
- { stage: "loader", name: "fs-loader", version: "1.0.0" },
296
- { stage: "embedder", name: "mock-embedder", version: "1.0.0" },
297
- { stage: "retriever", name: "mock-retriever", version: "1.0.0" },
298
- { stage: "llm", name: "mock-llm", version: "1.0.0" },
299
- ],
300
- performance: {
301
- parallel: {
302
- enabled: false,
303
- maxConcurrency: 3,
304
- },
305
- caching: {
306
- enabled: false,
307
- maxSize: 1000,
308
- ttl: 3600,
309
- },
310
- },
311
- observability: {
312
- logging: {
313
- level: "info",
314
- structured: true,
315
- },
316
- },
317
- };
318
-
319
- const result = validateRagrc(base);
320
- if (!result.valid) {
321
- result.errors?.forEach((error) =>
322
- console.error(` ${error.instancePath || ""}: ${error.message}`),
323
- );
324
- throw new Error("Failed to generate valid configuration");
325
- }
326
-
327
- if (outputPath) {
328
- await fs.writeFile(
329
- outputPath,
330
- JSON.stringify(result.normalized, null, 2),
331
- );
332
- console.log(`✅ Basic configuration created: ${outputPath}`);
333
- }
334
-
335
- return result.normalized;
336
- }
337
-
338
240
  /**
339
241
  * Run the CLI
340
242
  */
@@ -363,39 +265,8 @@ async function runEnhancedCLI(argv = process.argv) {
363
265
  await enhancedCLI.run(argv);
364
266
  }
365
267
 
366
- // CLI command surface for tests
367
- const init = async () => ({ ok: true });
368
- const ingest = async () => ({ ok: true });
369
- const query = async () => ({ ok: true });
370
- const handleError = async () => ({ ok: true });
371
- const validateArgs = () => true;
372
- const showHelp = () => "help text";
373
-
374
- // Extract createBasicConfig from the class for direct export
375
- const createBasicConfig = async (outputPath) => {
376
- const cli = new EnhancedCLI();
377
- return await cli.createBasicConfig(outputPath);
378
- };
379
-
380
- const enhancedCliCommands = {
381
- init,
382
- ingest,
383
- query,
384
- handleError,
385
- validateArgs,
386
- showHelp,
387
- };
388
-
389
268
  module.exports = {
390
269
  EnhancedCLI,
391
270
  enhancedCLI,
392
271
  runEnhancedCLI,
393
- enhancedCliCommands,
394
- init,
395
- ingest,
396
- query,
397
- handleError,
398
- validateArgs,
399
- showHelp,
400
- createBasicConfig,
401
272
  };