import { z } from "zod";
import fs from 'fs/promises';
import path from 'path';
/**
* Template Tools - Access static code templates
*/
// ============================================
// Get Template Tool
// ============================================
export const getTemplateSchema = {
name: "get_template",
description: "Retrieves a specific code template from the library",
inputSchema: z.object({
category: z.enum([
"auth", "configs", "database", "discord-bot", "django", "express",
"fastapi", "go", "graphql", "hono", "interaction", "mobile",
"nestjs", "nextjs", "react", "rust", "svelte", "testing", "trpc",
"vue", "websocket", "infrastructure", "ci-cd"
]).describe("Template category"),
templateName: z.string().optional().describe("Specific template file name (lists available if empty)")
})
};
export async function getTemplateHandler(args: { category: string; templateName?: string }) {
const { category, templateName } = args;
// In a real deployed environment, we need to know where the templates are.
// Assuming they are copied to dist/data/templates or src/data/templates is accessible.
// For this environment:
const basePath = path.join(process.cwd(), 'src', 'data', 'templates');
const categoryPath = path.join(basePath, category);
try {
// Check if category exists
try {
await fs.access(categoryPath);
} catch {
return {
content: [{
type: "text",
text: `Category '${category}' not found. Available categories: auth, database, react, vue, etc.`
}],
isError: true
};
}
// If no template name, list files
if (!templateName) {
const files = await fs.readdir(categoryPath);
return {
content: [{
type: "text",
text: `# Templates in '${category}'\n\n${files.map(f => `- ${f}`).join('\n')}\n\nUsage: get_template(category: "${category}", templateName: "${files[0]}")`
}]
};
}
// Search for file (fuzzy match or direct)
// We'll search recursively for the file if it's not in the root of the category
async function findFile(dir: string, name: string): Promise<string | null> {
const entries = await fs.readdir(dir, { withFileTypes: true });
// Direct match
const match = entries.find(e => e.name === name || e.name === name + '.md' || e.name === name + '.ts' || e.name === name + '.js');
if (match && match.isFile()) return path.join(dir, match.name);
// Fuzzy match (contains)
const fuzzy = entries.find(e => e.isFile() && e.name.includes(name));
if (fuzzy) return path.join(dir, fuzzy.name);
// Recursive search
for (const entry of entries) {
if (entry.isDirectory()) {
const found = await findFile(path.join(dir, entry.name), name);
if (found) return found;
}
}
return null;
}
const filePath = await findFile(categoryPath, templateName);
if (!filePath) {
return {
content: [{
type: "text",
text: `Template '${templateName}' not found in category '${category}'.`
}],
isError: true
};
}
const content = await fs.readFile(filePath, 'utf-8');
return {
content: [{
type: "text",
text: `# Template: ${category}/${path.basename(filePath)}\n\n\`\`\`${path.extname(filePath).slice(1) || 'text'}\n${content}\n\`\`\``
}]
};
} catch (error) {
return {
content: [{ type: "text", text: `Error accessing templates: ${(error as Error).message}` }],
isError: true
};
}
}
export const templateTools = {
getTemplateSchema, getTemplateHandler
};