zignet
Version:
MCP server for Zig â AI-powered code analysis, validation, and documentation with fine-tuned LLM
430 lines (414 loc) âĸ 14.2 kB
JavaScript
const require_chunk = require('./chunk-DWy1uDak.cjs');
const require_config = require('./config-C2ufArDU.cjs');
require('./executor-ON2Rt60w.cjs');
const require_analyze = require('./analyze-CKCU4PaJ.cjs');
const require_compile = require('./compile-F5XWbjXn.cjs');
const require_model_downloader = require('./model-downloader-ioH3AphD.cjs');
let __modelcontextprotocol_sdk_server_index_js = require("@modelcontextprotocol/sdk/server/index.js");
__modelcontextprotocol_sdk_server_index_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_index_js);
let __modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
__modelcontextprotocol_sdk_server_stdio_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_stdio_js);
let __modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
__modelcontextprotocol_sdk_types_js = require_chunk.__toESM(__modelcontextprotocol_sdk_types_js);
let node_llama_cpp = require("node-llama-cpp");
node_llama_cpp = require_chunk.__toESM(node_llama_cpp);
//#region src/llm/session.ts
var ZigNetLLM = class {
model = null;
context = null;
session = null;
config;
constructor(config = {}) {
this.config = {
modelPath: config.modelPath || "",
gpuDevice: config.gpuDevice,
gpuLayers: config.gpuLayers ?? 35,
contextSize: config.contextSize ?? 4096,
temperature: config.temperature ?? .7,
topP: config.topP ?? .9
};
}
/**
* Initialize the LLM model and session
*/
async initialize() {
if (this.session) {
console.log("âšī¸ LLM already initialized");
return;
}
console.log("đ Initializing ZigNet LLM...");
if (this.config.gpuDevice !== void 0) {
process.env.CUDA_VISIBLE_DEVICES = this.config.gpuDevice;
console.log(`đ¯ GPU device selection: ${this.config.gpuDevice}`);
}
const modelPath = this.config.modelPath || await require_model_downloader.modelDownloader.ensureModel((progress) => {
if (progress.percent % 10 < 1) console.log(`đĨ Downloading model: ${progress.percent.toFixed(1)}%`);
});
console.log(`đĻ Loading model: ${modelPath}`);
console.log(`đŽ GPU layers: ${this.config.gpuLayers}`);
this.model = await (await (0, node_llama_cpp.getLlama)()).loadModel({
modelPath,
gpuLayers: this.config.gpuLayers
});
this.context = await this.model.createContext({ contextSize: this.config.contextSize });
this.session = new node_llama_cpp.LlamaChatSession({
contextSequence: this.context.getSequence(),
systemPrompt: `You are ZigNet, an AI assistant specialized in Zig programming language (v0.13-0.15).
Your expertise includes:
- Explaining Zig syntax, features, and idioms
- Understanding comptime, generics, and error handling
- Providing code examples and fixes
- Referencing official Zig documentation
Always:
- Generate idiomatic Zig code
- Explain Zig-specific concepts clearly
- Suggest best practices
- Validate syntax mentally before responding
When unsure, reference official Zig docs or suggest using 'zig ast-check'.`
});
console.log("â
LLM initialized successfully!");
}
/**
* Query the LLM with a prompt
*/
async query(prompt) {
if (!this.session) await this.initialize();
if (!this.session) throw new Error("Failed to initialize LLM session");
console.log(`đ¤ Querying LLM: ${prompt.substring(0, 50)}...`);
return await this.session.prompt(prompt, {
temperature: this.config.temperature,
topP: this.config.topP
});
}
/**
* Dispose resources
*/
dispose() {
if (this.context) {
this.context.dispose();
this.context = null;
}
if (this.model) {
this.model.dispose();
this.model = null;
}
this.session = null;
console.log("đī¸ LLM resources disposed");
}
};
/**
* Singleton instance
*/
let globalLLM = null;
/**
* Get or create the global LLM instance
*/
async function getLLM(config) {
if (!globalLLM) {
if (!config) {
const { MODEL_PATH, GPU_DEVICE, GPU_LAYERS, CONTEXT_SIZE, TEMPERATURE, TOP_P } = await Promise.resolve().then(() => require("./config.cjs"));
config = {
modelPath: MODEL_PATH,
gpuDevice: GPU_DEVICE,
gpuLayers: GPU_LAYERS,
contextSize: CONTEXT_SIZE,
temperature: TEMPERATURE,
topP: TOP_P
};
}
globalLLM = new ZigNetLLM(config);
await globalLLM.initialize();
}
return globalLLM;
}
//#endregion
//#region src/tools/docs.ts
/**
* Get Zig documentation for a specific topic
*/
async function getZigDocs(args) {
const { topic, detail_level = "intermediate" } = args;
console.log(`đ Getting Zig docs for: ${topic} (${detail_level})`);
const prompt = `Explain the following Zig programming concept: "${topic}"
${{
basic: "Provide a brief, beginner-friendly explanation.",
intermediate: "Provide a detailed explanation with practical examples.",
advanced: "Provide an in-depth explanation covering edge cases, best practices, and advanced patterns."
}[detail_level]}
Format your response as:
1. A clear definition/explanation
2. One or more code examples
3. Key points to remember
Be specific to Zig versions 0.13-0.15.`;
try {
const response = await (await getLLM()).query(prompt);
const examples = extractCodeBlocks(response);
return {
topic,
documentation: response,
examples: examples.length > 0 ? examples : void 0
};
} catch (error) {
throw new Error(`Failed to get Zig docs: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Extract code blocks from markdown text
*/
function extractCodeBlocks(text) {
const codeBlockRegex = /```(?:zig)?\n([\s\S]*?)```/g;
const blocks = [];
let match;
while ((match = codeBlockRegex.exec(text)) !== null) blocks.push(match[1].trim());
return blocks;
}
//#endregion
//#region src/tools/suggest.ts
/**
* Suggest fixes for Zig compilation errors
*/
async function suggestFix(args) {
const { error_message, code_context, error_type = "semantic" } = args;
console.log(`đĄ Suggesting fix for: ${error_message.substring(0, 50)}...`);
const prompt = `You are analyzing a Zig compilation error. Help fix it.
Error Message:
\`\`\`
${error_message}
\`\`\`
${code_context ? `Code Context:\n\`\`\`zig\n${code_context}\n\`\`\`\n` : ""}
Error Type: ${error_type}
Provide:
1. A brief summary of what's wrong
2. 1-3 concrete fix suggestions with code examples
3. Explanation of why each fix works
Format your response clearly with code blocks for fixes.`;
try {
const response = await (await getLLM()).query(prompt);
const fixes = parseFixes(response);
return {
error_summary: extractErrorSummary(response),
suggested_fixes: fixes,
explanation: response
};
} catch (error) {
throw new Error(`Failed to suggest fix: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Extract error summary from LLM response
*/
function extractErrorSummary(response) {
return response.split("\n").filter((line) => line.trim())[0] || "Error analysis";
}
/**
* Parse fix suggestions from LLM response
*/
function parseFixes(response) {
const fixes = [];
const codeBlockRegex = /```(?:zig)?\n([\s\S]*?)```/g;
const codeBlocks = [];
let match;
while ((match = codeBlockRegex.exec(response)) !== null) codeBlocks.push(match[1].trim());
const fixPattern = /(?:Fix|Option|Solution)\s*\d*[:.]\s*([^\n]+)/gi;
const descriptions = [];
while ((match = fixPattern.exec(response)) !== null) descriptions.push(match[1].trim());
for (let i = 0; i < Math.max(descriptions.length, codeBlocks.length); i++) fixes.push({
description: descriptions[i] || `Fix option ${i + 1}`,
code_after: codeBlocks[i] || "// See explanation above",
rationale: `Addresses the ${extractErrorSummary(response)}`
});
if (fixes.length === 0) fixes.push({
description: "Suggested fix",
code_after: codeBlocks[0] || "// See detailed explanation",
rationale: "Based on error analysis"
});
return fixes;
}
//#endregion
//#region src/mcp-server.ts
/**
* Create and configure the MCP server
*/
function createServer() {
const server = new __modelcontextprotocol_sdk_server_index_js.Server({
name: "zignet",
version: "0.15.2-h"
}, { capabilities: { tools: {} } });
/**
* Handler for listing available tools
*/
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.ListToolsRequestSchema, async () => {
return { tools: [
{
name: "analyze_zig",
description: "Analyze Zig code for syntax errors, type mismatches, and semantic issues using the official Zig compiler",
inputSchema: {
type: "object",
properties: {
code: {
type: "string",
description: "Zig source code to analyze"
},
zig_version: {
type: "string",
enum: require_config.SUPPORTED_ZIG_VERSIONS,
description: `Zig version to use for validation (default: ${require_config.DEFAULT_ZIG_VERSION})`
}
},
required: ["code"]
}
},
{
name: "compile_zig",
description: "Format Zig code using the official Zig formatter",
inputSchema: {
type: "object",
properties: {
code: {
type: "string",
description: "Zig source code to format"
},
zig_version: {
type: "string",
enum: require_config.SUPPORTED_ZIG_VERSIONS,
description: `Zig version to use for formatting (default: ${require_config.DEFAULT_ZIG_VERSION})`
}
},
required: ["code"]
}
},
{
name: "get_zig_docs",
description: "Retrieve Zig documentation for specific topics",
inputSchema: {
type: "object",
properties: { topic: {
type: "string",
description: "Topic to get documentation for (e.g., 'comptime', 'generics')"
} },
required: ["topic"]
}
},
{
name: "suggest_fix",
description: "Get intelligent suggestions for fixing Zig code errors",
inputSchema: {
type: "object",
properties: {
error: {
type: "string",
description: "Error message to get fix suggestions for"
},
code: {
type: "string",
description: "Code context where the error occurred"
}
},
required: ["error", "code"]
}
}
] };
});
/**
* Handler for tool execution
*/
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.CallToolRequestSchema, async (request) => {
const { name, arguments: args = {} } = request.params;
switch (name) {
case "analyze_zig": {
const code = args.code;
const zig_version = args.zig_version;
if (!code) throw new Error("Missing required argument: code");
return { content: [{
type: "text",
text: require_analyze.formatAnalyzeResult(await require_analyze.analyzeZig({
code,
zig_version
}))
}] };
}
case "compile_zig": {
const compileArgs = args;
if (!compileArgs.code) throw new Error("Missing required argument: code");
return { content: [{
type: "text",
text: require_compile.formatCompileResult(await require_compile.compileZig({
code: compileArgs.code,
zig_version: compileArgs.zig_version
}))
}] };
}
case "get_zig_docs": {
const docsArgs = args;
if (!docsArgs.topic) throw new Error("Missing required argument: topic");
const result = await getZigDocs({
topic: docsArgs.topic,
detail_level: docsArgs.detail_level
});
return { content: [{
type: "text",
text: `# Zig Documentation: ${result.topic}\n\n${result.documentation}`
}] };
}
case "suggest_fix": {
const fixArgs = args;
if (!fixArgs.error_message) throw new Error("Missing required argument: error_message");
const result = await suggestFix({
error_message: fixArgs.error_message,
code_context: fixArgs.code_context,
error_type: fixArgs.error_type
});
const fixesText = result.suggested_fixes.map((fix, i) => `## Fix ${i + 1}: ${fix.description}\n\n\`\`\`zig\n${fix.code_after}\n\`\`\`\n\n**Rationale**: ${fix.rationale}`).join("\n\n");
return { content: [{
type: "text",
text: `# Error Fix Suggestions\n\n**Error**: ${result.error_summary}\n\n${fixesText}\n\n## Full Analysis\n\n${result.explanation}`
}] };
}
default: throw new Error(`Unknown tool: ${name}`);
}
});
return server;
}
/**
* Main entry point
*/
async function main() {
console.error("đ ZigNet MCP Server starting...");
console.error(`đ Configuration:`);
console.error(` - Zig versions: ${require_config.SUPPORTED_ZIG_VERSIONS.join(", ")}`);
console.error(` - Default version: ${require_config.DEFAULT_ZIG_VERSION}`);
const { modelDownloader: modelDownloader$1 } = await Promise.resolve().then(() => require("./model-downloader-CID2GL8m.cjs"));
const modelAvailable = modelDownloader$1.isModelAvailable();
console.error(`đ¤ Model status:`);
if (modelAvailable) console.error(` â
Model ready: ${modelDownloader$1.getModelPath()}`);
else {
console.error(` đĨ Model not found - downloading now...`);
console.error(` đ Target: ${modelDownloader$1.getModelPath()}`);
try {
let lastLoggedPercent = -1;
await modelDownloader$1.ensureModel((progress) => {
const currentMilestone = Math.floor(progress.percent / 5) * 5;
if (currentMilestone > lastLoggedPercent && currentMilestone % 5 === 0) {
console.error(` đĻ Download progress: ${currentMilestone}% (${(progress.downloaded / 1024 / 1024).toFixed(0)}MB / ${(progress.total / 1024 / 1024).toFixed(0)}MB)`);
lastLoggedPercent = currentMilestone;
}
});
console.error(` â
Model downloaded successfully!`);
} catch (error) {
console.error(` â ī¸ Model download failed: ${error}`);
console.error(` âšī¸ LLM tools (get_zig_docs, suggest_fix) will not be available`);
console.error(` âšī¸ Deterministic tools (analyze_zig, compile_zig) will still work`);
}
}
const server = createServer();
const transport = new __modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
await server.connect(transport);
console.error("â
ZigNet MCP Server running on stdio");
console.error("đĄ Available tools: analyze_zig, compile_zig, get_zig_docs, suggest_fix");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
//#endregion
//# sourceMappingURL=mcp-server.cjs.map