@chainlink/mcp-server
Version:
Prototype MCP Server for CLL
114 lines • 4.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadCreCliCommandDocs = loadCreCliCommandDocs;
exports.searchCreCliDocs = searchCreCliDocs;
const fs_1 = require("fs");
const path_1 = require("path");
const logger_1 = require("../../../utils/logger");
function getCreCliDocsDir() {
// __dirname: src/tools/products/cre
return (0, path_1.join)(__dirname, "..", "..", "..", "..", "external", "cre-cli", "docs");
}
function extractFirstHeading(content) {
const m = content.match(/^##\s+(.+)$/m);
const captured = m && m[1] ? m[1].trim() : undefined;
return captured;
}
function extractSectionCodeBlock(content, heading) {
// Find heading like `### Options` and capture the next fenced code block
const escapedHeading = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const patternSource = "^###\\s+" +
escapedHeading +
"\\s*\\n[\\s\\S]*?^\\x60{3}[\\s\\S]*?\\n([\\s\\S]*?)\\n\\x60{3}";
const pattern = new RegExp(patternSource, "m");
const m = content.match(pattern);
const captured = m && m[1] ? m[1] : undefined;
return captured;
}
function extractSynopsis(content) {
const pattern = /^###\s+Synopsis\s*\n[\s\S]*?^```[\s\S]*?\n([\s\S]*?)\n```/m;
const m = content.match(pattern);
const captured = m && m[1] ? m[1].trim() : undefined;
return captured;
}
function parseOptionsBlock(block) {
if (!block)
return [];
const lines = block
.split(/\r?\n/)
.map((l) => l.trimEnd())
.filter((l) => l.trim().length > 0);
const opts = [];
for (const line of lines) {
// Split by two or more spaces between flag and description
const parts = line.split(/\s{2,}/);
const flag = (parts[0] || line).trim();
const description = (parts.slice(1).join(" ") || "").trim();
opts.push({ flag, description });
}
return opts;
}
async function loadCreCliCommandDocs() {
try {
const dir = getCreCliDocsDir();
if (!(0, fs_1.existsSync)(dir)) {
logger_1.Logger.debug(`CRE CLI docs directory not found: ${dir}`);
return [];
}
const files = (0, fs_1.readdirSync)(dir)
.filter((f) => f.toLowerCase().endsWith(".md"))
.map((f) => (0, path_1.join)(dir, f));
const results = [];
for (const file of files) {
try {
const content = (0, fs_1.readFileSync)(file, "utf8");
if (!content || content.trim().length < 20)
continue;
const name = extractFirstHeading(content) || "unknown";
const synopsis = extractSynopsis(content) || "";
const optionsBlock = extractSectionCodeBlock(content, "Options");
const inheritedBlock = extractSectionCodeBlock(content, "Options inherited from parent commands");
results.push({
name,
synopsis,
options: parseOptionsBlock(optionsBlock),
inheritedOptions: parseOptionsBlock(inheritedBlock),
filepath: file,
});
}
catch (e) {
// Continue on per-file errors
}
}
return results;
}
catch (error) {
logger_1.Logger.log("warn", `Failed to load CRE CLI docs: ${error}`);
return [];
}
}
async function searchCreCliDocs(query) {
const docs = await loadCreCliCommandDocs();
if (!docs.length)
return [];
const q = query.toLowerCase();
const score = (d) => {
let s = 0;
const hay = [d.name, d.synopsis || "", ...d.options.map((o) => o.flag)]
.join(" \n ")
.toLowerCase();
if (hay.includes(q))
s += 150;
for (const w of q.split(/\s+/))
if (w.length > 2 && hay.includes(w))
s += 30;
return s;
};
return docs
.map((d) => ({ d, s: score(d) }))
.filter((x) => x.s > 0)
.sort((a, b) => b.s - a.s)
.slice(0, 30)
.map((x) => x.d);
}
//# sourceMappingURL=cli.js.map