@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
@@ -0,0 +1,143 @@
1
+ /**
2
+ * `hub install` and `hub certify submit|check`: real plugin installation and
3
+ * automated certification checks (see src/ecosystem/plugin-installer.js and
4
+ * plugin-checks.js).
5
+ */
6
+
7
+ const fs = require("fs/promises");
8
+ const { resolveConfigPath } = require("../../../config/load-config.js");
9
+
10
+ const ICONS = { high: "❌", medium: "⚠️ ", low: "ℹ️ " };
11
+
12
+ function printFindings(findings) {
13
+ for (const f of findings) {
14
+ const where = f.line ? `${f.file}:${f.line}` : f.file;
15
+ console.log(
16
+ ` ${ICONS[f.severity] || "-"} ${f.severity}: ${f.message} (${where})`,
17
+ );
18
+ }
19
+ }
20
+
21
+ /**
22
+ * @param {string} source - Registry id, path, .tgz, .js or npm:<spec>
23
+ * @param {object} options - { stage, name, force, allowRisky, version }
24
+ * @param {object} globals - Includes the root --config option
25
+ * @param {Function} getHub - Returns a PluginHub, or null when no registry is set
26
+ */
27
+ async function installFromSource(source, options, globals, getHub) {
28
+ try {
29
+ const { installPlugin } = require("../../../ecosystem/plugin-installer.js");
30
+ const result = await installPlugin({
31
+ source,
32
+ configPath: resolveConfigPath(globals.config || ".ragrc.json"),
33
+ stage: options.stage,
34
+ name: options.name,
35
+ force: options.force,
36
+ allowRisky: options.allowRisky,
37
+ version: options.version,
38
+ hub: getHub(),
39
+ onProgress: (step) => console.log(`… ${step}`),
40
+ });
41
+
42
+ if (result.scan.findings.length > 0) {
43
+ console.log("Security scan findings:");
44
+ printFindings(result.scan.findings);
45
+ }
46
+ console.log(
47
+ `✅ Installed ${result.stage} plugin "${result.name}"` +
48
+ `${result.version ? ` ${result.version}` : ""} (${result.source}) at ${result.entry}`,
49
+ );
50
+ console.log(` Methods: ${result.methods.join(", ")}`);
51
+ if (!result.inPipeline) {
52
+ console.log(
53
+ ` To use it, add { "stage": "${result.stage}", "name": "${result.name}" } to "pipeline" in your config.`,
54
+ );
55
+ }
56
+ } catch (error) {
57
+ console.error(`❌ Install failed: ${error.message}`);
58
+ if (error.scan) printFindings(error.scan.findings);
59
+ process.exitCode = 1;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param {string} pluginPath - Local plugin directory or .js file
65
+ * @param {object} options - { stage, json, output }
66
+ */
67
+ async function certifyLocal(pluginPath, options) {
68
+ try {
69
+ const { runPluginChecks } = require("../../../ecosystem/plugin-checks.js");
70
+ const report = await runPluginChecks(pluginPath, { stage: options.stage });
71
+
72
+ if (options.output) {
73
+ await fs.writeFile(options.output, JSON.stringify(report, null, 2));
74
+ }
75
+ if (options.json) {
76
+ console.log(JSON.stringify(report, null, 2));
77
+ } else {
78
+ console.log(`Certification checks: ${report.plugin} (${report.stage})\n`);
79
+ for (const check of report.checks) {
80
+ console.log(
81
+ `${check.label}: ${check.score}/100 (weight ${check.weight})`,
82
+ );
83
+ check.details.forEach((d) => console.log(` - ${d}`));
84
+ }
85
+ console.log(`\nScore: ${report.score}/100`);
86
+ if (report.level) {
87
+ console.log(
88
+ `Meets the automated threshold for ${report.level}` +
89
+ (report.pendingReview
90
+ ? ` (also requires ${report.pendingReview})`
91
+ : ""),
92
+ );
93
+ } else {
94
+ console.log(
95
+ "Does not meet the BASIC threshold (60, with a passing contract).",
96
+ );
97
+ }
98
+ if (report.nextLevel) {
99
+ console.log(
100
+ `Next level: ${report.nextLevel.level} at ${report.nextLevel.score}`,
101
+ );
102
+ }
103
+ if (options.output) console.log(`Report saved to ${options.output}`);
104
+ }
105
+ if (!report.level) process.exitCode = 1;
106
+ } catch (error) {
107
+ console.error(`❌ Certification checks failed: ${error.message}`);
108
+ process.exitCode = 1;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * @param {object} globals - Includes the root --config option
114
+ * @param {object} options - { json }
115
+ */
116
+ function listPlugins(globals, options) {
117
+ const {
118
+ listInstalledPlugins,
119
+ } = require("../../../ecosystem/plugin-installer.js");
120
+ const plugins = listInstalledPlugins(
121
+ resolveConfigPath(globals.config || ".ragrc.json"),
122
+ );
123
+ if (options.json) {
124
+ console.log(JSON.stringify(plugins, null, 2));
125
+ return;
126
+ }
127
+ if (plugins.length === 0) {
128
+ console.log('No plugins registered under "plugins" in the config.');
129
+ return;
130
+ }
131
+ for (const p of plugins) {
132
+ const flags = [
133
+ p.installed
134
+ ? `installed${p.version ? ` ${p.version}` : ""}`
135
+ : "local path",
136
+ p.inPipeline ? "in pipeline" : "not in pipeline",
137
+ p.exists ? null : "FILE MISSING",
138
+ ].filter(Boolean);
139
+ console.log(`${p.stage}/${p.name} ${p.entry} (${flags.join(", ")})`);
140
+ }
141
+ }
142
+
143
+ module.exports = { installFromSource, certifyLocal, listPlugins };
@@ -7,21 +7,89 @@ const { Command } = require("commander");
7
7
  const { PluginHub } = require("../../ecosystem/plugin-hub");
8
8
  const { PluginCertification } = require("../../ecosystem/plugin-certification");
9
9
 
10
- const hubCommands = require("./plugin-hub/hub-commands");
11
- const certificationCommands = require("./plugin-hub/certification-commands");
12
- const reviewCommands = require("./plugin-hub/review-commands");
10
+ // Command modules (and inquirer, ora, cli-table3) load when a hub command
11
+ // runs, not when the CLI starts.
12
+ /* eslint-disable global-require */
13
+ const hubCommands = () => require("./plugin-hub/hub-commands");
14
+ const certificationCommands = () =>
15
+ require("./plugin-hub/certification-commands");
16
+ const reviewCommands = () => require("./plugin-hub/review-commands");
17
+ /* eslint-enable global-require */
13
18
  const { setupEventListeners } = require("./plugin-hub/event-handlers");
19
+ const {
20
+ installFromSource,
21
+ certifyLocal,
22
+ listPlugins,
23
+ } = require("./plugin-hub/local-commands");
14
24
 
15
25
  class PluginHubCLI {
16
- constructor() {
17
- this.hub = new PluginHub();
18
- this.certification = new PluginCertification();
19
- setupEventListeners(this.hub, this.certification);
26
+ /**
27
+ * @param {object} [options]
28
+ * @param {string} [options.registryUrl] - Overrides --registry / RAG_PLUGIN_REGISTRY
29
+ */
30
+ constructor(options = {}) {
31
+ this.registryUrl = options.registryUrl;
32
+ }
33
+
34
+ /**
35
+ * There is no public registry: the old default (registry.rag-pipeline.dev)
36
+ * does not resolve. Commands that talk to a registry need one configured.
37
+ */
38
+ _resolveRegistryUrl() {
39
+ const url = this.registryUrl || process.env.RAG_PLUGIN_REGISTRY;
40
+ if (!url) {
41
+ throw new Error(
42
+ "No plugin registry configured. Pass --registry <url> or set RAG_PLUGIN_REGISTRY.",
43
+ );
44
+ }
45
+ return url;
46
+ }
47
+
48
+ _init() {
49
+ if (!this._hub) {
50
+ const registryUrl = this._resolveRegistryUrl();
51
+ this._hub = new PluginHub({ registryUrl });
52
+ this._certification = new PluginCertification({ registryUrl });
53
+ setupEventListeners(this._hub, this._certification);
54
+ }
55
+ }
56
+
57
+ get hub() {
58
+ this._init();
59
+ return this._hub;
60
+ }
61
+
62
+ get certification() {
63
+ this._init();
64
+ return this._certification;
20
65
  }
21
66
 
22
67
  createCommands() {
23
68
  const program = new Command("hub");
24
- program.description("Community plugin hub operations");
69
+ program
70
+ .alias("plugin")
71
+ .description("Plugin registry operations (requires --registry <url>)")
72
+ .option(
73
+ "--registry <url>",
74
+ "Plugin registry URL (or RAG_PLUGIN_REGISTRY)",
75
+ )
76
+ .hook("preAction", (_hubCommand, actionCommand) => {
77
+ // Local commands: requirements and submit never need a registry; install
78
+ // needs one only for registry ids and checks that itself.
79
+ if (
80
+ ["requirements", "install", "submit", "list"].includes(
81
+ actionCommand.name(),
82
+ )
83
+ )
84
+ return;
85
+ this.registryUrl = this.registryUrl || program.opts().registry;
86
+ try {
87
+ this._resolveRegistryUrl();
88
+ } catch (error) {
89
+ console.error(`❌ ${error.message}`);
90
+ process.exit(1);
91
+ }
92
+ });
25
93
 
26
94
  // Search command
27
95
  program
@@ -39,24 +107,25 @@ class PluginHubCLI {
39
107
  "relevance",
40
108
  )
41
109
  .action(async (query, _options) => {
42
- await hubCommands.searchPlugins(this.hub, query, _options);
110
+ await hubCommands().searchPlugins(this.hub, query, _options);
43
111
  });
44
112
 
45
- // Install command
46
113
  program
47
- .command("install <plugin>")
48
- .description("Install a plugin from the hub")
49
- .option("-v, --version <version>", "Plugin version", "latest")
50
- .option("--no-security-scan", "Skip security scan")
51
- .option("--require-certified", "Only install certified plugins")
52
- .option(
53
- "--sandbox-timeout <timeout>",
54
- "Sandbox timeout in ms",
55
- parseInt,
56
- 30000,
114
+ .command("install <source>")
115
+ .description(
116
+ "Install a plugin from a local path, .tgz, .js, npm:<package> or the registry",
57
117
  )
58
- .action(async (plugin, _options) => {
59
- await hubCommands.installPlugin(this.hub, plugin, _options);
118
+ .option("--stage <stage>", "loader, embedder, retriever, llm or reranker")
119
+ .option("--name <name>", "Name to register the plugin under")
120
+ .option("-v, --version <version>", "Registry version", "latest")
121
+ .option("--force", "Replace an installed plugin with the same stage/name")
122
+ .option("--allow-risky", "Install despite high-risk security findings")
123
+ .action(async (source, _options, command) => {
124
+ const globals = command.optsWithGlobals();
125
+ this.registryUrl = this.registryUrl || globals.registry;
126
+ const getHub = () =>
127
+ this.registryUrl || process.env.RAG_PLUGIN_REGISTRY ? this.hub : null;
128
+ await installFromSource(source, _options, globals, getHub);
60
129
  });
61
130
 
62
131
  // Info command
@@ -64,17 +133,17 @@ class PluginHubCLI {
64
133
  .command("info <plugin>")
65
134
  .description("Get detailed information about a plugin")
66
135
  .action(async (plugin) => {
67
- await hubCommands.getPluginInfo(this.hub, plugin);
136
+ await hubCommands().getPluginInfo(this.hub, plugin);
68
137
  });
69
138
 
70
139
  // List installed command
71
140
  program
72
141
  .command("list")
73
142
  .alias("ls")
74
- .description("List installed plugins")
75
- .option("--format <format>", "Output format: table, json", "table")
76
- .action(async (_options) => {
77
- await hubCommands.listInstalledPlugins(this.hub, _options);
143
+ .description("List plugins registered in the config")
144
+ .option("--json", "Print as JSON")
145
+ .action(async (_options, command) => {
146
+ listPlugins(command.optsWithGlobals(), _options);
78
147
  });
79
148
 
80
149
  // Publish command
@@ -84,7 +153,7 @@ class PluginHubCLI {
84
153
  .option("--dry-run", "Validate without publishing")
85
154
  .option("--tag <tag>", "Release tag")
86
155
  .action(async (pluginPath, _options) => {
87
- await hubCommands.publishPlugin(
156
+ await hubCommands().publishPlugin(
88
157
  this.hub,
89
158
  pluginPath || process.cwd(),
90
159
  _options,
@@ -97,7 +166,7 @@ class PluginHubCLI {
97
166
  .description("Rate a plugin (1-5 stars)")
98
167
  .option("-r, --review <review>", "Written review")
99
168
  .action(async (plugin, rating, _options) => {
100
- await reviewCommands.ratePlugin(
169
+ await reviewCommands().ratePlugin(
101
170
  this.hub,
102
171
  plugin,
103
172
  parseInt(rating),
@@ -112,7 +181,7 @@ class PluginHubCLI {
112
181
  .option("-l, --limit <limit>", "Number of reviews", parseInt, 10)
113
182
  .option("--sort <sort>", "Sort by: helpful, recent, rating", "helpful")
114
183
  .action(async (plugin, _options) => {
115
- await reviewCommands.getPluginReviews(this.hub, plugin, _options);
184
+ await reviewCommands().getPluginReviews(this.hub, plugin, _options);
116
185
  });
117
186
 
118
187
  // Trending command
@@ -123,7 +192,7 @@ class PluginHubCLI {
123
192
  .option("-c, --category <category>", "Filter by category")
124
193
  .option("-l, --limit <limit>", "Number of results", parseInt, 20)
125
194
  .action(async (_options) => {
126
- await hubCommands.getTrendingPlugins(this.hub, _options);
195
+ await hubCommands().getTrendingPlugins(this.hub, _options);
127
196
  });
128
197
 
129
198
  // Certification commands
@@ -132,26 +201,21 @@ class PluginHubCLI {
132
201
  .description("Plugin certification operations");
133
202
 
134
203
  certifyCmd
135
- .command("submit <plugin>")
136
- .description("Submit plugin for certification")
137
- .option(
138
- "-l, --level <level>",
139
- "Certification level: BASIC, VERIFIED, ENTERPRISE",
140
- "BASIC",
141
- )
142
- .action(async (plugin, _options) => {
143
- await certificationCommands.submitForCertification(
144
- this.certification,
145
- plugin,
146
- _options,
147
- );
204
+ .command("submit <path>")
205
+ .alias("check")
206
+ .description("Run automated certification checks on a local plugin")
207
+ .option("--stage <stage>", "loader, embedder, retriever, llm or reranker")
208
+ .option("--json", "Print the report as JSON")
209
+ .option("--output <file>", "Save the report as JSON")
210
+ .action(async (pluginPath, _options) => {
211
+ await certifyLocal(pluginPath, _options);
148
212
  });
149
213
 
150
214
  certifyCmd
151
215
  .command("verify <plugin> <certificationId>")
152
216
  .description("Verify plugin certification")
153
217
  .action(async (plugin, certificationId) => {
154
- await certificationCommands.verifyCertification(
218
+ await certificationCommands().verifyCertification(
155
219
  this.certification,
156
220
  plugin,
157
221
  certificationId,
@@ -162,8 +226,9 @@ class PluginHubCLI {
162
226
  .command("requirements [level]")
163
227
  .description("Show certification requirements")
164
228
  .action(async (level) => {
165
- await certificationCommands.showCertificationRequirements(
166
- this.certification,
229
+ // Requirements are a static list; no registry is contacted.
230
+ await certificationCommands().showCertificationRequirements(
231
+ new PluginCertification(),
167
232
  level,
168
233
  );
169
234
  });
@@ -177,7 +242,7 @@ class PluginHubCLI {
177
242
  .command("status [publisherId]")
178
243
  .description("Check publisher verification status")
179
244
  .action(async (publisherId) => {
180
- await certificationCommands.getPublisherStatus(
245
+ await certificationCommands().getPublisherStatus(
181
246
  this.certification,
182
247
  publisherId,
183
248
  );
@@ -187,7 +252,7 @@ class PluginHubCLI {
187
252
  .command("apply")
188
253
  .description("Apply for publisher verification")
189
254
  .action(async () => {
190
- await certificationCommands.applyForPublisherVerification(
255
+ await certificationCommands().applyForPublisherVerification(
191
256
  this.certification,
192
257
  );
193
258
  });
@@ -1,78 +1,91 @@
1
1
  /**
2
- * Configuration checker for RAG Pipeline Diagnostics
3
- * Checks configuration file existence, validity, and schema compliance
2
+ * Configuration diagnostics: the file exists, parses, validates, and every
3
+ * pipeline entry resolves to a component.
4
4
  */
5
5
 
6
- const fs = require("fs/promises");
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+
9
+ function issue(severity, code, message, fix) {
10
+ return {
11
+ category: "configuration",
12
+ severity,
13
+ code,
14
+ message,
15
+ fix,
16
+ autoFixable: false,
17
+ };
18
+ }
7
19
 
8
- /**
9
- * Check configuration issues
10
- * @param {object} options - Doctor options (must include configPath)
11
- * @returns {Promise<Array>} Array of configuration issues
12
- */
13
20
  async function checkConfiguration(options) {
14
- const issues = [];
21
+ const { loadRagConfig } = require("../../config/load-config.js");
22
+ const { buildComponents } = require("../../config/component-factory.js");
23
+ const configPath = path.resolve(options.configPath);
15
24
 
16
- try {
17
- await fs.access(options.configPath);
18
- } catch (error) {
19
- issues.push({
20
- category: "configuration",
21
- severity: "error",
22
- code: "CONFIG_MISSING",
23
- message: `Configuration file not found: ${options.configPath}`,
24
- fix: 'Run "rag-pipeline init" to create a configuration file',
25
- autoFixable: false,
26
- });
27
- return issues;
25
+ if (!fs.existsSync(configPath)) {
26
+ return [
27
+ issue(
28
+ "error",
29
+ "CONFIG_MISSING",
30
+ `Configuration file not found: ${options.configPath}`,
31
+ 'Run "rag-pipeline init" to create a configuration file',
32
+ ),
33
+ ];
28
34
  }
29
35
 
36
+ let config;
30
37
  try {
31
- const configContent = await fs.readFile(options.configPath, "utf8");
32
- const config = JSON.parse(configContent);
38
+ config = loadRagConfig(configPath);
39
+ } catch (error) {
40
+ const invalidJson = /Invalid JSON/.test(error.message);
41
+ return [
42
+ issue(
43
+ "error",
44
+ invalidJson ? "CONFIG_INVALID_JSON" : "CONFIG_SCHEMA_ERROR",
45
+ error.message,
46
+ invalidJson
47
+ ? `Fix JSON syntax errors in ${options.configPath}`
48
+ : "Fix the reported configuration errors",
49
+ ),
50
+ ];
51
+ }
33
52
 
34
- // Check if config is empty
35
- if (Object.keys(config).length === 0 || !config.plugins) {
36
- issues.push({
37
- category: "configuration",
38
- severity: "warning",
39
- code: "CONFIG_EMPTY",
40
- message: "Configuration file is empty or missing required sections",
41
- fix: "Add plugin configurations and pipeline settings",
42
- autoFixable: false,
43
- });
53
+ const issues = [];
54
+ const stages = new Set(config.pipeline.map((entry) => entry.stage));
55
+ for (const stage of ["embedder", "retriever"]) {
56
+ if (!stages.has(stage)) {
57
+ issues.push(
58
+ issue(
59
+ "error",
60
+ "CONFIG_STAGE_MISSING",
61
+ `Pipeline has no ${stage} stage`,
62
+ `Add { "stage": "${stage}", "name": ... } to the pipeline (see rag-pipeline init)`,
63
+ ),
64
+ );
44
65
  }
66
+ }
67
+ if (!stages.has("llm")) {
68
+ issues.push(
69
+ issue(
70
+ "info",
71
+ "CONFIG_NO_LLM",
72
+ "Pipeline has no llm stage; query prints retrieved passages only",
73
+ 'Add { "stage": "llm", "name": "openai" } (or anthropic, ollama) to generate answers',
74
+ ),
75
+ );
76
+ }
45
77
 
46
- // Validate schema if available
47
- try {
48
- const {
49
- validateEnhancedRagrcSchema,
50
- } = require("../../config/enhanced-ragrc-schema.js");
51
- const validation = validateEnhancedRagrcSchema(config);
52
- if (!validation.valid && validation.errors) {
53
- validation.errors.forEach((error) => {
54
- issues.push({
55
- category: "configuration",
56
- severity: "error",
57
- code: "CONFIG_SCHEMA_ERROR",
58
- message: `Schema validation failed: ${error.instancePath} ${error.message}`,
59
- fix: "Fix configuration schema errors",
60
- autoFixable: false,
61
- });
62
- });
63
- }
64
- } catch (schemaError) {
65
- // Schema validation not available, skip
66
- }
67
- } catch (parseError) {
68
- issues.push({
69
- category: "configuration",
70
- severity: "error",
71
- code: "CONFIG_INVALID_JSON",
72
- message: "Configuration file contains invalid JSON syntax",
73
- fix: `Fix JSON syntax errors in ${options.configPath}`,
74
- autoFixable: false,
75
- });
78
+ try {
79
+ buildComponents(config, { configDir: path.dirname(configPath) });
80
+ } catch (error) {
81
+ issues.push(
82
+ issue(
83
+ "error",
84
+ "CONFIG_COMPONENT_UNKNOWN",
85
+ error.message,
86
+ 'Use a built-in name or register the plugin under "plugins"',
87
+ ),
88
+ );
76
89
  }
77
90
 
78
91
  return issues;
@@ -1,44 +1,75 @@
1
1
  /**
2
- * Environment checker for RAG Pipeline Diagnostics
3
- * Checks for missing environment variables referenced in configuration
2
+ * Environment diagnostics: API keys the configured providers need, ${VAR}
3
+ * references in the config, and whether the file-store index exists yet.
4
4
  */
5
5
 
6
- const fs = require("fs/promises");
6
+ const fs = require("fs");
7
+ const path = require("path");
7
8
 
8
- /**
9
- * Check environment issues
10
- * @param {object} options - Doctor options (must include configPath)
11
- * @returns {Promise<Array>} Array of environment issues
12
- */
13
- async function checkEnvironment(options) {
14
- const issues = [];
9
+ const PROVIDER_KEYS = {
10
+ openai: "OPENAI_API_KEY",
11
+ anthropic: "ANTHROPIC_API_KEY",
12
+ cohere: "COHERE_API_KEY",
13
+ };
14
+
15
+ function missingVar(envVar, reason) {
16
+ return {
17
+ category: "environment",
18
+ severity: "error",
19
+ code: "ENV_VAR_MISSING",
20
+ message: `Required environment variable missing: ${envVar}${reason ? ` (${reason})` : ""}`,
21
+ fix: `Set environment variable: export ${envVar}=your_key`,
22
+ autoFixable: false,
23
+ };
24
+ }
15
25
 
26
+ async function checkEnvironment(options) {
27
+ const configPath = path.resolve(options.configPath);
28
+ let config;
16
29
  try {
17
- const configContent = await fs.readFile(options.configPath, "utf8");
18
- const config = JSON.parse(configContent);
30
+ config = JSON.parse(fs.readFileSync(configPath, "utf8"));
31
+ } catch {
32
+ return []; // reported by the configuration checker
33
+ }
19
34
 
20
- // Check for missing environment variables
21
- const configStr = JSON.stringify(config);
22
- const envVarMatches = configStr.match(/\$\{([^}]+)\}/g);
23
- if (envVarMatches) {
24
- envVarMatches.forEach((match) => {
25
- const envVar = match.slice(2, -1);
26
- if (!process.env[envVar]) {
27
- issues.push({
28
- category: "environment",
29
- severity: "error",
30
- code: "ENV_VAR_MISSING",
31
- message: `Required environment variable missing: ${envVar}`,
32
- fix: `Set environment variable: export ${envVar}=your_key`,
33
- autoFixable: false,
34
- });
35
- }
36
- });
35
+ const issues = [];
36
+ const seen = new Set();
37
+ for (const entry of Array.isArray(config.pipeline) ? config.pipeline : []) {
38
+ const envVar = PROVIDER_KEYS[entry?.name];
39
+ if (
40
+ envVar &&
41
+ !entry.config?.apiKey &&
42
+ !process.env[envVar] &&
43
+ !seen.has(envVar)
44
+ ) {
45
+ seen.add(envVar);
46
+ issues.push(missingVar(envVar, `used by ${entry.stage} "${entry.name}"`));
47
+ }
48
+ if (entry?.stage === "retriever" && entry.name === "file-store") {
49
+ const indexPath = path.resolve(
50
+ path.dirname(configPath),
51
+ entry.config?.path || ".rag/index.json",
52
+ );
53
+ if (!fs.existsSync(indexPath)) {
54
+ issues.push({
55
+ category: "environment",
56
+ severity: "info",
57
+ code: "INDEX_MISSING",
58
+ message: `No index yet at ${path.relative(process.cwd(), indexPath)}`,
59
+ fix: "Run: rag-pipeline ingest <file-or-directory>",
60
+ autoFixable: false,
61
+ });
62
+ }
37
63
  }
38
- } catch (error) {
39
- // Config issues handled elsewhere
40
64
  }
41
65
 
66
+ for (const match of JSON.stringify(config).match(/\$\{([^}]+)\}/g) || []) {
67
+ const envVar = match.slice(2, -1);
68
+ if (!process.env[envVar] && !seen.has(envVar)) {
69
+ seen.add(envVar);
70
+ issues.push(missingVar(envVar, "referenced in the config"));
71
+ }
72
+ }
42
73
  return issues;
43
74
  }
44
75