UNPKG

agent-files-watcher

Version:

A comprehensive CLI tool and MCP server for synchronizing AI agent documentation using a partials-to-templates architecture

316 lines (315 loc) 12 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.toolImplementations = exports.toolSchemas = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const yaml = __importStar(require("js-yaml")); const child_process_1 = require("child_process"); const builder_1 = require("./builder"); const zod_1 = require("zod"); // Simplified schema for tools - we only need the directory paths const ToolsConfigSchema = zod_1.z.object({ partialsDir: zod_1.z.string(), templatesDir: zod_1.z.string(), }); // Global state for watcher process let watcherProcess = null; // Function to get config paths function getConfigPaths() { const rootDir = process.cwd(); const configPath = path.join(rootDir, ".agent-instructions.yaml"); if (!fs.existsSync(configPath)) { // Fallback to default if config doesn't exist console.warn("Warning: .agent-instructions.yaml not found. Using default 'docs' directory."); return { partialsDir: path.join(rootDir, "docs/agent-partials"), templatesDir: path.join(rootDir, "docs/agent-templates"), }; } try { const config = yaml.load(fs.readFileSync(configPath, "utf8")); const validatedConfig = ToolsConfigSchema.parse(config); return { partialsDir: path.join(rootDir, validatedConfig.partialsDir), templatesDir: path.join(rootDir, validatedConfig.templatesDir), }; } catch (error) { console.warn(`Warning: Error reading config file: ${error instanceof Error ? error.message : "Unknown error"}. Using default 'docs' directory.`); return { partialsDir: path.join(rootDir, "docs/agent-partials"), templatesDir: path.join(rootDir, "docs/agent-templates"), }; } } exports.toolSchemas = [ { name: "list_partials", description: "Lists all available content partials.", inputSchema: { type: "object", properties: {} }, }, { name: "read_partial", description: "Reads the content of a specific partial.", inputSchema: { type: "object", properties: { partial_name: { type: "string", description: "The name of the partial to read.", }, }, required: ["partial_name"], }, }, { name: "update_partial", description: "Overwrites the content of a specific partial file.", inputSchema: { type: "object", properties: { partial_name: { type: "string", description: "The name of the partial to update.", }, new_content: { type: "string", description: "The new, complete content for the partial.", }, }, required: ["partial_name", "new_content"], }, }, { name: "build_context_files", description: "Triggers the build process to regenerate all physical agent files from the partials.", inputSchema: { type: "object", properties: {} }, }, { name: "create_new_partial", description: "Creates a new partial file.", inputSchema: { type: "object", properties: { partial_name: { type: "string", description: "The name of the partial to create.", }, content: { type: "string", description: "The content of the partial to create.", }, }, required: ["partial_name", "content"], }, }, { name: "list_templates", description: "Lists all available templates.", inputSchema: { type: "object", properties: {} }, }, { name: "read_template", description: "Reads the content of a specific template.", inputSchema: { type: "object", properties: { template_name: { type: "string", description: "The name of the template to read.", }, }, required: ["template_name"], }, }, { name: "update_template", description: "Overwrites the content of a specific template file.", inputSchema: { type: "object", properties: { template_name: { type: "string", description: "The name of the template to update.", }, new_content: { type: "string", description: "The new, complete content for the template.", }, }, required: ["template_name", "new_content"], }, }, { name: "start_watcher", description: "Starts the agent-context watcher to monitor file changes and auto-rebuild context files.", inputSchema: { type: "object", properties: {} }, }, { name: "stop_watcher", description: "Stops the currently running agent-context watcher process.", inputSchema: { type: "object", properties: {} }, }, ]; exports.toolImplementations = { list_partials: () => { const { partialsDir } = getConfigPaths(); return fs.readdirSync(partialsDir); }, read_partial: ({ partial_name }) => { const { partialsDir } = getConfigPaths(); const partialPath = path.join(partialsDir, partial_name); return fs.readFileSync(partialPath, "utf8"); }, update_partial: ({ partial_name, new_content, }) => { const { partialsDir } = getConfigPaths(); const partialPath = path.join(partialsDir, partial_name); fs.writeFileSync(partialPath, new_content); return { success: true }; }, build_context_files: async () => { // Run build in current working directory await (0, builder_1.runBuild)(); return { success: true }; }, create_new_partial: ({ partial_name, content, }) => { const { partialsDir } = getConfigPaths(); const partialPath = path.join(partialsDir, partial_name); fs.writeFileSync(partialPath, content); return { success: true }; }, list_templates: () => { const { templatesDir } = getConfigPaths(); return fs.readdirSync(templatesDir); }, read_template: ({ template_name }) => { const { templatesDir } = getConfigPaths(); const templatePath = path.join(templatesDir, template_name); return fs.readFileSync(templatePath, "utf8"); }, update_template: ({ template_name, new_content, }) => { const { templatesDir } = getConfigPaths(); const templatePath = path.join(templatesDir, template_name); fs.writeFileSync(templatePath, new_content); return { success: true }; }, start_watcher: () => { if (watcherProcess && !watcherProcess.killed) { return { success: false, message: "Watcher is already running" }; } try { // Get the path to the current binary const executablePath = process.execPath; // Path to node const scriptPath = path.resolve(__dirname, "../index.js"); // Check if compiled version exists, otherwise use ts-node for development const isBuilt = fs.existsSync(scriptPath); if (isBuilt) { // Use the built version watcherProcess = (0, child_process_1.spawn)(executablePath, [scriptPath, "watch"], { stdio: "pipe", detached: false, }); } else { // Use ts-node for development const tsNodePath = path.resolve(process.cwd(), "node_modules/.bin/ts-node"); const srcScriptPath = path.resolve(__dirname, "../index.ts"); if (fs.existsSync(tsNodePath)) { watcherProcess = (0, child_process_1.spawn)(tsNodePath, [srcScriptPath, "watch"], { stdio: "pipe", detached: false, }); } else { // Fallback to npx ts-node watcherProcess = (0, child_process_1.spawn)("npx", ["ts-node", srcScriptPath, "watch"], { stdio: "pipe", detached: false, }); } } watcherProcess.stdout?.on("data", (data) => { console.log(`Watcher: ${data}`); }); watcherProcess.stderr?.on("data", (data) => { console.error(`Watcher: ${data}`); }); watcherProcess.on("close", (code) => { console.error(`Watcher process exited with code ${code}`); watcherProcess = null; }); watcherProcess.on("error", (error) => { console.error(`Watcher process error: ${error.message}`); watcherProcess = null; }); return { success: true, message: "Watcher started successfully", pid: watcherProcess.pid, }; } catch (error) { return { success: false, message: `Failed to start watcher: ${error instanceof Error ? error.message : "Unknown error"}`, }; } }, stop_watcher: () => { if (!watcherProcess || watcherProcess.killed) { return { success: false, message: "No watcher process is currently running", }; } try { watcherProcess.kill("SIGTERM"); // Give it a moment to gracefully shutdown, then force kill if needed setTimeout(() => { if (watcherProcess && !watcherProcess.killed) { watcherProcess.kill("SIGKILL"); } }, 5000); return { success: true, message: "Watcher stop signal sent" }; } catch (error) { return { success: false, message: `Failed to stop watcher: ${error instanceof Error ? error.message : "Unknown error"}`, }; } } };