@devilsdev/rag-pipeline-utils 2.4.5 → 2.5.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/.ragrc.schema.json +83 -192
- package/CHANGELOG.md +345 -0
- package/README.md +418 -117
- package/SECURITY.md +5 -5
- package/dist/experimental.cjs +2 -0
- package/dist/experimental.d.ts +1 -0
- package/dist/experimental.mjs +5 -0
- package/dist/index.cjs +4992 -1242
- package/dist/index.d.ts +80 -2
- package/dist/index.mjs +1 -1
- package/dist/types/agentic/agentic-pipeline.d.ts +103 -0
- package/dist/types/agentic/iterative-retriever.d.ts +85 -0
- package/dist/types/agentic/query-planner.d.ts +145 -0
- package/dist/types/agentic/self-critique.d.ts +45 -0
- package/dist/types/ai/adaptive-retrieval.d.ts +44 -0
- package/dist/types/ai/federation/federated-learning-coordinator.d.ts +62 -0
- package/dist/types/ai/multimodal-processing.d.ts +32 -0
- package/dist/types/ai/multimodal.d.ts +39 -0
- package/dist/types/ai/retrieval-engine.d.ts +37 -0
- package/dist/types/ai/training/model-training-orchestrator.d.ts +31 -0
- package/dist/types/chunking/chunking-engine.d.ts +70 -0
- package/dist/types/chunking/strategies/fixed-size.d.ts +17 -0
- package/dist/types/chunking/strategies/recursive.d.ts +20 -0
- package/dist/types/chunking/strategies/semantic.d.ts +19 -0
- package/dist/types/chunking/strategies/sentence.d.ts +13 -0
- package/dist/types/chunking/strategies/structure-aware.d.ts +19 -0
- package/dist/types/citation/citation-tracker.d.ts +64 -0
- package/dist/types/citation/hallucination-detector.d.ts +40 -0
- package/dist/types/citation/source-mapper.d.ts +37 -0
- package/dist/types/connectors/anthropic-connector.d.ts +92 -0
- package/dist/types/connectors/base-connector.d.ts +87 -0
- package/dist/types/connectors/cohere-connector.d.ts +89 -0
- package/dist/types/connectors/connector-utils.d.ts +110 -0
- package/dist/types/connectors/local-embedder.d.ts +86 -0
- package/dist/types/connectors/memory-retriever.d.ts +91 -0
- package/dist/types/connectors/ollama-connector.d.ts +110 -0
- package/dist/types/connectors/openai-connector.d.ts +114 -0
- package/dist/types/connectors/rag-prompt.d.ts +40 -0
- package/dist/types/cost/cost-calculator.d.ts +152 -0
- package/dist/types/cost/cost-tracker.d.ts +126 -0
- package/dist/types/cost/token-budget.d.ts +110 -0
- package/dist/types/dag/core/error-context.d.ts +239 -0
- package/dist/types/dag/core/execution-scheduler.d.ts +191 -0
- package/dist/types/dag/core/topology-validation.d.ts +226 -0
- package/dist/types/dag/dag-engine.d.ts +156 -0
- package/dist/types/dag/dag-node.d.ts +37 -0
- package/dist/types/dashboard/dashboard-generator.d.ts +127 -0
- package/dist/types/dashboard/metrics-aggregator.d.ts +218 -0
- package/dist/types/debug/execution-tracer.d.ts +57 -0
- package/dist/types/debug/trace-inspector.d.ts +31 -0
- package/dist/types/ecosystem/plugin-certification.d.ts +169 -0
- package/dist/types/enterprise/data-governance.d.ts +203 -0
- package/dist/types/enterprise/multi-tenancy.d.ts +137 -0
- package/dist/types/enterprise/sso-integration.d.ts +420 -0
- package/dist/types/evaluate/context-metrics.d.ts +55 -0
- package/dist/types/evaluate/faithfulness.d.ts +41 -0
- package/dist/types/evaluate/groundedness.d.ts +60 -0
- package/dist/types/evaluate/pipeline-evaluator.d.ts +88 -0
- package/dist/types/evaluate/relevance.d.ts +21 -0
- package/dist/types/evaluate/scoring.d.ts +123 -0
- package/dist/types/experimental.d.ts +15 -0
- package/dist/types/graph/entity-extractor.d.ts +84 -0
- package/dist/types/graph/graph-index.d.ts +49 -0
- package/dist/types/graph/graph-retriever.d.ts +81 -0
- package/dist/types/graph/knowledge-graph.d.ts +129 -0
- package/dist/types/guardrails/guardrails-pipeline.d.ts +63 -0
- package/dist/types/guardrails/injection-detector.d.ts +47 -0
- package/dist/types/guardrails/post-generation-guard.d.ts +61 -0
- package/dist/types/guardrails/pre-retrieval-guard.d.ts +64 -0
- package/dist/types/guardrails/retrieval-guard.d.ts +57 -0
- package/dist/types/mcp/mcp-server.d.ts +85 -0
- package/dist/types/mcp/mcp-tool-builder.d.ts +55 -0
- package/dist/types/reranker/cascade-reranker.d.ts +40 -0
- package/dist/types/reranker/embedding-reranker.d.ts +77 -0
- package/dist/types/reranker/scoring-reranker.d.ts +41 -0
- package/dist/types/retrieval/bm25-search.d.ts +43 -0
- package/dist/types/retrieval/file-vector-store.d.ts +87 -0
- package/dist/types/retrieval/hybrid-retriever.d.ts +35 -0
- package/dist/types/retrieval/rank-fusion.d.ts +10 -0
- package/dist/types/security/jwt-config.d.ts +80 -0
- package/dist/types/security/jwt-validator.d.ts +195 -0
- package/dist/types/security/plugin-sandbox.d.ts +158 -0
- package/dist/types/security/plugin-signature-verifier.d.ts +139 -0
- package/dist/types/security/validator.d.ts +5 -0
- package/dist/types/streaming/embedding-stream.d.ts +65 -0
- package/dist/types/streaming/sse-adapter.d.ts +59 -0
- package/dist/types/streaming/stream-router.d.ts +88 -0
- package/dist/types/streaming/streaming-embedder.d.ts +99 -0
- package/dist/types/streaming/websocket-adapter.d.ts +71 -0
- package/dist/types/templates/scaffold.d.ts +55 -0
- package/dist/types/templates/template-registry.d.ts +63 -0
- package/dist/types/utils/embed-query.d.ts +20 -0
- package/dist/types/utils/logger.d.ts +50 -0
- package/dist/types/utils/rate-limiter.d.ts +66 -0
- package/dist/types/utils/retry.d.ts +27 -0
- package/dist/types/utils/run-abort.d.ts +34 -0
- package/dist/types/utils/secure-logging.d.ts +51 -0
- package/dist/types/utils/structured-logger.d.ts +126 -0
- package/package.json +53 -29
- package/src/agentic/agentic-pipeline.js +75 -7
- package/src/agentic/iterative-retriever.js +47 -10
- package/src/agentic/query-planner.js +329 -78
- package/src/citation/citation-tracker.js +6 -4
- package/src/citation/hallucination-detector.js +2 -2
- package/src/citation/source-mapper.js +15 -28
- package/src/cli/commands/ai.js +101 -0
- package/src/cli/commands/plugin-hub/event-handlers.js +6 -0
- package/src/cli/commands/plugin-hub/hub-commands.js +0 -74
- package/src/cli/commands/plugin-hub/local-commands.js +143 -0
- package/src/cli/commands/plugin-hub.js +96 -36
- package/src/cli/diagnostics/config-checker.js +76 -63
- package/src/cli/diagnostics/environment-checker.js +62 -31
- package/src/cli/diagnostics/plugin-checker.js +36 -89
- package/src/cli/doctor-command.js +39 -5
- package/src/cli/enhanced-cli-commands.js +72 -217
- package/src/cli/handlers/ai-handler.js +364 -0
- package/src/cli/handlers/diagnostics-handler.js +78 -31
- package/src/cli/handlers/ingest-handler.js +28 -22
- package/src/cli/handlers/init-handler.js +148 -25
- package/src/cli/handlers/query-handler.js +41 -26
- package/src/cli/handlers/run-handler.js +16 -167
- package/src/cli/handlers/serve-handler.js +60 -0
- package/src/cli/services/bench-stats.js +54 -0
- package/src/cli/services/benchmark.js +161 -0
- package/src/cli/services/feedback.js +155 -0
- package/src/cli/services/rag-service.js +322 -0
- package/src/cli/shared/cli-utils.js +24 -7
- package/src/cli/shared/config-context.js +21 -0
- package/src/cli/wizard/config-builder.js +81 -0
- package/src/cli/wizard/init-wizard.js +617 -0
- package/src/config/component-factory.js +125 -0
- package/src/config/load-config.js +29 -10
- package/src/config/load-plugin-config.js +46 -2
- package/src/connectors/anthropic-connector.js +93 -55
- package/src/connectors/base-connector.js +74 -19
- package/src/connectors/cohere-connector.js +88 -32
- package/src/connectors/connector-utils.js +302 -0
- package/src/connectors/local-embedder.js +43 -5
- package/src/connectors/memory-retriever.js +108 -15
- package/src/connectors/ollama-connector.js +83 -49
- package/src/connectors/openai-connector.js +108 -44
- package/src/connectors/rag-prompt.js +88 -0
- package/src/core/create-pipeline.js +209 -60
- package/src/core/plugin-registry.js +87 -11
- package/src/cost/cost-calculator.js +205 -32
- package/src/dev/dev-server.js +166 -11
- package/src/dev/hot-reload.js +40 -1
- package/src/ecosystem/plugin-checks.js +181 -0
- package/src/ecosystem/plugin-hub.js +50 -125
- package/src/ecosystem/plugin-installer.js +298 -0
- package/src/ecosystem/plugin-probe.js +127 -0
- package/src/ecosystem/plugin-scanner.js +185 -0
- package/src/ecosystem/tar-extract.js +114 -0
- package/src/enterprise/audit-logging.js +158 -29
- package/src/enterprise/sso-integration.js +715 -228
- package/src/evaluate/context-metrics.js +28 -16
- package/src/evaluate/evaluator.js +3 -3
- package/src/evaluate/faithfulness.js +18 -14
- package/src/evaluate/groundedness.js +43 -12
- package/src/evaluate/pipeline-evaluator.js +35 -8
- package/src/evaluate/scoring.js +251 -3
- package/src/experimental.js +71 -0
- package/src/guardrails/guardrails-pipeline.js +69 -7
- package/src/guardrails/injection-detector.js +283 -0
- package/src/guardrails/post-generation-guard.js +19 -0
- package/src/guardrails/pre-retrieval-guard.js +36 -36
- package/src/guardrails/retrieval-guard.js +58 -8
- package/src/index.js +36 -1
- package/src/loader/document-reader.js +91 -0
- package/src/reranker/cascade-reranker.js +3 -0
- package/src/reranker/embedding-reranker.js +136 -21
- package/src/reranker/llm-reranker.js +79 -12
- package/src/reranker/scoring-reranker.js +3 -0
- package/src/retrieval/bm25-search.js +12 -6
- package/src/retrieval/file-vector-store.js +212 -0
- package/src/retrieval/hybrid-retriever.js +22 -19
- package/src/security/jwt-config.js +13 -2
- package/src/security/jwt-validator.js +134 -30
- package/src/security/plugin-sandbox.js +18 -1
- package/src/security/plugin-signature-verifier.js +245 -70
- package/src/utils/deprecate.js +69 -0
- package/src/utils/embed-query.js +33 -0
- package/src/utils/input-sanitizer.js +19 -4
- package/src/utils/logger.js +34 -4
- package/src/utils/run-abort.js +102 -0
- package/src/ai/federated-learning.js +0 -211
- package/src/ai/federation.js +0 -71
- package/src/ai/index.js +0 -22
- package/src/ai/model-trainer.js +0 -217
- package/src/ai/model-training.js +0 -202
- package/src/ai/multimodal/multi-modal-processor.js +0 -345
- package/src/ai/orchestrator.js +0 -65
- package/src/ai/retrieval/adaptive-retrieval-engine.js +0 -398
- package/src/cli/commands/ai-ml/adaptive-commands.js +0 -178
- package/src/cli/commands/ai-ml/federated-commands.js +0 -207
- package/src/cli/commands/ai-ml/index.js +0 -17
- package/src/cli/commands/ai-ml/multimodal-commands.js +0 -187
- package/src/cli/commands/ai-ml/shared.js +0 -51
- package/src/cli/commands/ai-ml/training-commands.js +0 -228
- package/src/cli/commands/ai-ml.js +0 -386
- package/src/cli/commands/docs.js +0 -228
- package/src/cli/commands/dx.js +0 -538
- package/src/cli/commands/wizard.js +0 -627
- package/src/cli/input-sanitization-middleware.js +0 -356
- package/src/cli/interactive-wizard.js +0 -373
- package/src/cli/templates/development.template.json +0 -64
- package/src/cli/templates/minimal.template.json +0 -33
- package/src/cli/templates/production.template.json +0 -104
- package/src/cli/templates/testing.template.json +0 -45
- package/src/cli/wizard/configuration.js +0 -148
- package/src/cli/wizard/observability.js +0 -79
- package/src/cli/wizard/performance.js +0 -76
- package/src/cli/wizard/plugin-selection.js +0 -297
- package/src/cli/wizard/preview-save.js +0 -172
- package/src/cli/wizard/project-setup.js +0 -66
- package/src/core/pipeline-factory.js +0 -59
- package/src/dag/enhanced-dag-engine.js +0 -894
- package/src/dx/index.js +0 -40
- package/src/dx/integration-templates.js +0 -662
- package/src/dx/performance-profiler.js +0 -968
- package/src/dx/realtime-debugger.js +0 -755
- package/src/dx/visual-pipeline-builder.js +0 -578
- package/src/ingest.js +0 -59
- package/src/pipeline/pipeline.js +0 -18
- package/src/query.js +0 -117
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `rag-pipeline ai ...`: training, benchmarking, relevance feedback and file
|
|
5
|
+
* inspection built on the real pipeline components (.ragrc.json + index).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { Command, Option } = require("commander");
|
|
9
|
+
const { parsePositiveInteger } = require("../shared/cli-utils.js");
|
|
10
|
+
const {
|
|
11
|
+
handleTrainEmbedding,
|
|
12
|
+
handleBenchmark,
|
|
13
|
+
handleFeedback,
|
|
14
|
+
handleSearch,
|
|
15
|
+
handleMultimodalProcess,
|
|
16
|
+
} = require("../handlers/ai-handler.js");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {() => object} getGlobalOptions - Returns program.opts()
|
|
20
|
+
* @returns {Command}
|
|
21
|
+
*/
|
|
22
|
+
function createAiCommand(getGlobalOptions) {
|
|
23
|
+
const ai = new Command("ai").description(
|
|
24
|
+
"Train the local embedder, benchmark queries, relevance feedback, file inspection",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const train = ai
|
|
28
|
+
.command("train")
|
|
29
|
+
.description("Fit corpus-trained components");
|
|
30
|
+
train
|
|
31
|
+
.command("embedding")
|
|
32
|
+
.description(
|
|
33
|
+
"Refit the local TF-IDF embedder (on the index, or on [path]) and re-embed the index",
|
|
34
|
+
)
|
|
35
|
+
.argument(
|
|
36
|
+
"[path]",
|
|
37
|
+
"Train on documents from this file or directory instead",
|
|
38
|
+
)
|
|
39
|
+
.action(async (inputPath) => {
|
|
40
|
+
await handleTrainEmbedding(getGlobalOptions(), inputPath);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
ai.command("benchmark")
|
|
44
|
+
.description(
|
|
45
|
+
"Measure query latency against the configured pipeline and index",
|
|
46
|
+
)
|
|
47
|
+
.option(
|
|
48
|
+
"--queries <file>",
|
|
49
|
+
"Queries file: JSON array of strings or one per line (default: sampled from the index)",
|
|
50
|
+
)
|
|
51
|
+
.option("--runs <n>", "Passes over the query set", parsePositiveInteger, 3)
|
|
52
|
+
.option("--top-k <n>", "Passages to retrieve", parsePositiveInteger, 3)
|
|
53
|
+
.option("--json", "Print the measurements as JSON")
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
await handleBenchmark(getGlobalOptions(), options);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
ai.command("feedback")
|
|
59
|
+
.description(
|
|
60
|
+
"Record whether an indexed chunk was a good result for a question",
|
|
61
|
+
)
|
|
62
|
+
.argument("<question>", "Question the chunk was returned for")
|
|
63
|
+
.argument("<docId>", "Chunk id as shown by `ai search` (e.g. docs/a.md#0)")
|
|
64
|
+
.addOption(
|
|
65
|
+
new Option("--rating <rating>", "Relevance vote")
|
|
66
|
+
.choices(["up", "down"])
|
|
67
|
+
.makeOptionMandatory(),
|
|
68
|
+
)
|
|
69
|
+
.action(async (question, docId, options) => {
|
|
70
|
+
await handleFeedback(getGlobalOptions(), question, docId, options);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
ai.command("search")
|
|
74
|
+
.description(
|
|
75
|
+
"Retrieve passages re-scored with stored feedback (retrieval only)",
|
|
76
|
+
)
|
|
77
|
+
.argument("<question>", "Question text")
|
|
78
|
+
.option("--top-k <n>", "Passages to return", parsePositiveInteger, 3)
|
|
79
|
+
.option("--json", "Print the results as JSON")
|
|
80
|
+
.action(async (question, options) => {
|
|
81
|
+
await handleSearch(getGlobalOptions(), question, options);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const multimodal = ai
|
|
85
|
+
.command("multimodal")
|
|
86
|
+
.description("Inspect files before ingesting");
|
|
87
|
+
multimodal
|
|
88
|
+
.command("process")
|
|
89
|
+
.description(
|
|
90
|
+
"Report type, characters and chunks for text files (images need a vision model)",
|
|
91
|
+
)
|
|
92
|
+
.argument("<path>", "File or directory")
|
|
93
|
+
.option("--json", "Print the report as JSON")
|
|
94
|
+
.action(async (inputPath, options) => {
|
|
95
|
+
await handleMultimodalProcess(getGlobalOptions(), inputPath, options);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return ai;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { createAiCommand };
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
const chalk = require("chalk");
|
|
7
7
|
|
|
8
8
|
function setupEventListeners(hub, certification) {
|
|
9
|
+
// The hub emits 'error' and then throws a descriptive error that each
|
|
10
|
+
// command reports. Without a listener, EventEmitter would throw its own
|
|
11
|
+
// "Unhandled error" first and hide that message.
|
|
12
|
+
hub.on("error", () => {});
|
|
13
|
+
certification.on("error", () => {});
|
|
14
|
+
|
|
9
15
|
// Hub events
|
|
10
16
|
hub.on("install_start", (data) => {
|
|
11
17
|
console.log(
|
|
@@ -69,34 +69,6 @@ async function searchPlugins(hub, query, _options) {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
async function installPlugin(hub, plugin, _options) {
|
|
73
|
-
try {
|
|
74
|
-
const installOptions = {
|
|
75
|
-
securityScan: _options.securityScan,
|
|
76
|
-
requireCertified: _options.requireCertified,
|
|
77
|
-
sandboxTimeout: _options.sandboxTimeout,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const result = await hub.installPlugin(
|
|
81
|
-
plugin,
|
|
82
|
-
_options.version,
|
|
83
|
-
installOptions,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
console.log(chalk.green("\n✅ Installation completed successfully!")); // eslint-disable-line no-console
|
|
87
|
-
console.log(chalk.blue(`Plugin: ${result.pluginInfo.name}`)); // eslint-disable-line no-console
|
|
88
|
-
console.log(chalk.blue(`Version: ${result.version}`)); // eslint-disable-line no-console
|
|
89
|
-
console.log(chalk.blue(`Install Path: ${result.installPath}`)); // eslint-disable-line no-console
|
|
90
|
-
|
|
91
|
-
if (result.pluginInfo.certified) {
|
|
92
|
-
console.log(chalk.green("🏆 This plugin is certified!")); // eslint-disable-line no-console
|
|
93
|
-
}
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error(chalk.red(`Installation failed: ${error.message}`)); // eslint-disable-line no-console
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
72
|
async function getPluginInfo(hub, plugin) {
|
|
101
73
|
const spinner = ora("Fetching plugin information...").start();
|
|
102
74
|
|
|
@@ -170,50 +142,6 @@ async function getPluginInfo(hub, plugin) {
|
|
|
170
142
|
}
|
|
171
143
|
}
|
|
172
144
|
|
|
173
|
-
async function listInstalledPlugins(hub, _options) {
|
|
174
|
-
const spinner = ora("Loading installed plugins...").start();
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const installed = await hub.getInstalledPlugins();
|
|
178
|
-
spinner.stop();
|
|
179
|
-
|
|
180
|
-
if (installed.length === 0) {
|
|
181
|
-
console.log(chalk.yellow("No plugins installed.")); // eslint-disable-line no-console
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (_options.format === "json") {
|
|
186
|
-
console.log(JSON.stringify(installed, null, 2)); // eslint-disable-line no-console
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
console.log(chalk.green(`${installed.length} plugins installed:\n`)); // eslint-disable-line no-console
|
|
191
|
-
|
|
192
|
-
const table = new Table({
|
|
193
|
-
head: ["Name", "Version", "Type", "Last Used", "Status"],
|
|
194
|
-
colWidths: [25, 12, 15, 15, 10],
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
for (const plugin of installed) {
|
|
198
|
-
const lastUsed = plugin.lastUsed
|
|
199
|
-
? new Date(plugin.lastUsed).toLocaleDateString()
|
|
200
|
-
: chalk.gray("Never");
|
|
201
|
-
|
|
202
|
-
const status = plugin.certified
|
|
203
|
-
? chalk.green("Certified")
|
|
204
|
-
: chalk.gray("Standard");
|
|
205
|
-
|
|
206
|
-
table.push([plugin.name, plugin.version, plugin._type, lastUsed, status]);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
console.log(table.toString()); // eslint-disable-line no-console
|
|
210
|
-
} catch (error) {
|
|
211
|
-
spinner.stop();
|
|
212
|
-
console.error(chalk.red(`Failed to list plugins: ${error.message}`)); // eslint-disable-line no-console
|
|
213
|
-
process.exit(1);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
145
|
async function publishPlugin(hub, pluginPath, _options) {
|
|
218
146
|
if (_options.dryRun) {
|
|
219
147
|
console.log(
|
|
@@ -282,9 +210,7 @@ async function getTrendingPlugins(hub, _options) {
|
|
|
282
210
|
|
|
283
211
|
module.exports = {
|
|
284
212
|
searchPlugins,
|
|
285
|
-
installPlugin,
|
|
286
213
|
getPluginInfo,
|
|
287
|
-
listInstalledPlugins,
|
|
288
214
|
publishPlugin,
|
|
289
215
|
getTrendingPlugins,
|
|
290
216
|
};
|
|
@@ -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 };
|
|
@@ -11,17 +11,80 @@ const hubCommands = require("./plugin-hub/hub-commands");
|
|
|
11
11
|
const certificationCommands = require("./plugin-hub/certification-commands");
|
|
12
12
|
const reviewCommands = require("./plugin-hub/review-commands");
|
|
13
13
|
const { setupEventListeners } = require("./plugin-hub/event-handlers");
|
|
14
|
+
const {
|
|
15
|
+
installFromSource,
|
|
16
|
+
certifyLocal,
|
|
17
|
+
listPlugins,
|
|
18
|
+
} = require("./plugin-hub/local-commands");
|
|
14
19
|
|
|
15
20
|
class PluginHubCLI {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
/**
|
|
22
|
+
* @param {object} [options]
|
|
23
|
+
* @param {string} [options.registryUrl] - Overrides --registry / RAG_PLUGIN_REGISTRY
|
|
24
|
+
*/
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
this.registryUrl = options.registryUrl;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* There is no public registry: the old default (registry.rag-pipeline.dev)
|
|
31
|
+
* does not resolve. Commands that talk to a registry need one configured.
|
|
32
|
+
*/
|
|
33
|
+
_resolveRegistryUrl() {
|
|
34
|
+
const url = this.registryUrl || process.env.RAG_PLUGIN_REGISTRY;
|
|
35
|
+
if (!url) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
"No plugin registry configured. Pass --registry <url> or set RAG_PLUGIN_REGISTRY.",
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return url;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_init() {
|
|
44
|
+
if (!this._hub) {
|
|
45
|
+
const registryUrl = this._resolveRegistryUrl();
|
|
46
|
+
this._hub = new PluginHub({ registryUrl });
|
|
47
|
+
this._certification = new PluginCertification({ registryUrl });
|
|
48
|
+
setupEventListeners(this._hub, this._certification);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get hub() {
|
|
53
|
+
this._init();
|
|
54
|
+
return this._hub;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get certification() {
|
|
58
|
+
this._init();
|
|
59
|
+
return this._certification;
|
|
20
60
|
}
|
|
21
61
|
|
|
22
62
|
createCommands() {
|
|
23
63
|
const program = new Command("hub");
|
|
24
|
-
program
|
|
64
|
+
program
|
|
65
|
+
.alias("plugin")
|
|
66
|
+
.description("Plugin registry operations (requires --registry <url>)")
|
|
67
|
+
.option(
|
|
68
|
+
"--registry <url>",
|
|
69
|
+
"Plugin registry URL (or RAG_PLUGIN_REGISTRY)",
|
|
70
|
+
)
|
|
71
|
+
.hook("preAction", (_hubCommand, actionCommand) => {
|
|
72
|
+
// Local commands: requirements and submit never need a registry; install
|
|
73
|
+
// needs one only for registry ids and checks that itself.
|
|
74
|
+
if (
|
|
75
|
+
["requirements", "install", "submit", "list"].includes(
|
|
76
|
+
actionCommand.name(),
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
return;
|
|
80
|
+
this.registryUrl = this.registryUrl || program.opts().registry;
|
|
81
|
+
try {
|
|
82
|
+
this._resolveRegistryUrl();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(`❌ ${error.message}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
25
88
|
|
|
26
89
|
// Search command
|
|
27
90
|
program
|
|
@@ -42,21 +105,22 @@ class PluginHubCLI {
|
|
|
42
105
|
await hubCommands.searchPlugins(this.hub, query, _options);
|
|
43
106
|
});
|
|
44
107
|
|
|
45
|
-
// Install command
|
|
46
108
|
program
|
|
47
|
-
.command("install <
|
|
48
|
-
.description(
|
|
49
|
-
|
|
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,
|
|
109
|
+
.command("install <source>")
|
|
110
|
+
.description(
|
|
111
|
+
"Install a plugin from a local path, .tgz, .js, npm:<package> or the registry",
|
|
57
112
|
)
|
|
58
|
-
.
|
|
59
|
-
|
|
113
|
+
.option("--stage <stage>", "loader, embedder, retriever, llm or reranker")
|
|
114
|
+
.option("--name <name>", "Name to register the plugin under")
|
|
115
|
+
.option("-v, --version <version>", "Registry version", "latest")
|
|
116
|
+
.option("--force", "Replace an installed plugin with the same stage/name")
|
|
117
|
+
.option("--allow-risky", "Install despite high-risk security findings")
|
|
118
|
+
.action(async (source, _options, command) => {
|
|
119
|
+
const globals = command.optsWithGlobals();
|
|
120
|
+
this.registryUrl = this.registryUrl || globals.registry;
|
|
121
|
+
const getHub = () =>
|
|
122
|
+
this.registryUrl || process.env.RAG_PLUGIN_REGISTRY ? this.hub : null;
|
|
123
|
+
await installFromSource(source, _options, globals, getHub);
|
|
60
124
|
});
|
|
61
125
|
|
|
62
126
|
// Info command
|
|
@@ -71,10 +135,10 @@ class PluginHubCLI {
|
|
|
71
135
|
program
|
|
72
136
|
.command("list")
|
|
73
137
|
.alias("ls")
|
|
74
|
-
.description("List
|
|
75
|
-
.option("--
|
|
76
|
-
.action(async (_options) => {
|
|
77
|
-
|
|
138
|
+
.description("List plugins registered in the config")
|
|
139
|
+
.option("--json", "Print as JSON")
|
|
140
|
+
.action(async (_options, command) => {
|
|
141
|
+
listPlugins(command.optsWithGlobals(), _options);
|
|
78
142
|
});
|
|
79
143
|
|
|
80
144
|
// Publish command
|
|
@@ -132,19 +196,14 @@ class PluginHubCLI {
|
|
|
132
196
|
.description("Plugin certification operations");
|
|
133
197
|
|
|
134
198
|
certifyCmd
|
|
135
|
-
.command("submit <
|
|
136
|
-
.
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
await certificationCommands.submitForCertification(
|
|
144
|
-
this.certification,
|
|
145
|
-
plugin,
|
|
146
|
-
_options,
|
|
147
|
-
);
|
|
199
|
+
.command("submit <path>")
|
|
200
|
+
.alias("check")
|
|
201
|
+
.description("Run automated certification checks on a local plugin")
|
|
202
|
+
.option("--stage <stage>", "loader, embedder, retriever, llm or reranker")
|
|
203
|
+
.option("--json", "Print the report as JSON")
|
|
204
|
+
.option("--output <file>", "Save the report as JSON")
|
|
205
|
+
.action(async (pluginPath, _options) => {
|
|
206
|
+
await certifyLocal(pluginPath, _options);
|
|
148
207
|
});
|
|
149
208
|
|
|
150
209
|
certifyCmd
|
|
@@ -162,8 +221,9 @@ class PluginHubCLI {
|
|
|
162
221
|
.command("requirements [level]")
|
|
163
222
|
.description("Show certification requirements")
|
|
164
223
|
.action(async (level) => {
|
|
224
|
+
// Requirements are a static list; no registry is contacted.
|
|
165
225
|
await certificationCommands.showCertificationRequirements(
|
|
166
|
-
|
|
226
|
+
new PluginCertification(),
|
|
167
227
|
level,
|
|
168
228
|
);
|
|
169
229
|
});
|
|
@@ -1,78 +1,91 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration
|
|
3
|
-
*
|
|
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
|
|
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
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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;
|