UNPKG

hataraku

Version:

An autonomous coding agent for building AI-powered development tools. The name "Hataraku" (働く) means "to work" in Japanese.

236 lines 9.28 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.AgentManager = void 0; const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const config_paths_1 = require("./config-paths"); const agent_config_1 = require("./agent-config"); const ToolManager_1 = require("./ToolManager"); const tools_1 = require("../core/tools"); /** * Manager for agent configurations * Handles CRUD operations for agent configurations stored in the agents directory */ class AgentManager { agentsDir; toolManager; constructor() { // Ensure config directories exist (0, config_paths_1.createConfigDirectories)(); const paths = (0, config_paths_1.getConfigPaths)(); this.agentsDir = paths.agentsDir; this.toolManager = new ToolManager_1.ToolManager(); } /** * List all available agent configurations * @returns Array of agent configuration names */ async listAgents() { try { const files = await fs.readdir(this.agentsDir); return files .filter(file => file.endsWith('.json')) .map(file => path.basename(file, '.json')); } catch (error) { // If directory doesn't exist or can't be read, return empty array return []; } } /** * Get a specific agent configuration * @param name Agent configuration name * @returns Agent configuration object * @throws Error if agent configuration not found or invalid */ async getAgent(name) { const filePath = path.join(this.agentsDir, `${name}.json`); try { const data = await fs.readFile(filePath, 'utf-8'); const config = JSON.parse(data); return agent_config_1.AgentConfigSchema.parse(config); } catch (error) { throw new Error(`Agent configuration '${name}' not found or invalid: ${error.message}`); } } /** * Create a new agent configuration * @param name Agent configuration name * @param config Agent configuration object * @throws Error if agent configuration already exists or is invalid */ async createAgent(name, config) { const filePath = path.join(this.agentsDir, `${name}.json`); try { // Check if file already exists await fs.access(filePath); // If we get here, the file exists, so throw an error throw new Error(`Agent configuration '${name}' already exists`); } catch (error) { // Only proceed if error is that file doesn't exist (ENOENT) if (error.code !== 'ENOENT') { // If this is our own error about the file already existing, rethrow it if (error instanceof Error && error.message.includes('already exists')) { throw error; } // Otherwise throw an unexpected error throw error; } // Validate configuration agent_config_1.AgentConfigSchema.parse(config); // Validate tool references if (config.tools && config.tools.length > 0) { await this.validateToolReferences(config.tools); } // Write configuration to file await fs.writeFile(filePath, JSON.stringify(config, null, 2)); } } /** * Update an existing agent configuration * @param name Agent configuration name * @param updates Agent configuration updates * @throws Error if agent configuration not found or is invalid */ async updateAgent(name, updates) { const filePath = path.join(this.agentsDir, `${name}.json`); try { // Check if file exists and get current config const currentConfig = await this.getAgent(name); // Update config with new values const updatedConfig = { ...currentConfig, ...updates }; // Validate the updated configuration agent_config_1.AgentConfigSchema.parse(updatedConfig); // Validate tool references if (updatedConfig.tools && updatedConfig.tools.length > 0) { await this.validateToolReferences(updatedConfig.tools); } // Write updated configuration to file await fs.writeFile(filePath, JSON.stringify(updatedConfig, null, 2)); } catch (error) { if (error instanceof Error && error.message.includes('not found')) { throw error; } throw new Error(`Failed to update agent '${name}': ${error.message}`); } } /** * Delete an agent configuration * @param name Agent configuration name * @throws Error if agent configuration not found */ async deleteAgent(name) { const filePath = path.join(this.agentsDir, `${name}.json`); try { await fs.unlink(filePath); } catch (error) { if (error.code === 'ENOENT') { throw new Error(`Agent configuration '${name}' not found`); } // Only re-throw known errors, convert unknown errors to a standard message throw error instanceof Error ? error : new Error(`Unknown error occurred: ${error}`); } } /** * Validate tool references in an agent configuration * @param tools Array of tool names * @throws Error if a referenced tool doesn't exist (except for 'hataraku') */ async validateToolReferences(tools) { const availableTools = await this.toolManager.listTools(); for (const tool of tools) { // Skip validation for built-in tools if (tool === 'hataraku') continue; if (!availableTools.includes(tool)) { throw new Error(`Referenced tool '${tool}' not found`); } } } /** * Initialize default agent configurations * Creates default agent configurations if they don't exist */ async initializeDefaults() { const agents = await this.listAgents(); // Create default code assistant if not exists if (!agents.includes('code-assistant')) { await this.createAgent('code-assistant', agent_config_1.DEFAULT_CODE_ASSISTANT); } // Create default code reviewer if not exists if (!agents.includes('code-reviewer')) { await this.createAgent('code-reviewer', agent_config_1.DEFAULT_CODE_REVIEWER); } } /** * Resolve tool references for an agent * Converts tool references to actual tool configurations * @param name Agent name * @returns Agent with resolved tool configurations * @throws Error if agent configuration not found */ async resolveAgentTools(name) { const agent = await this.getAgent(name); const resolvedTools = []; if (agent.tools && agent.tools.length > 0) { for (const tool of agent.tools) { if (tool === 'hataraku') { // Add built-in Hataraku tools from ALL_TOOLS // Convert underscore-based tool names to hyphen-based names resolvedTools.push(...Object.keys(tools_1.ALL_TOOLS).map(toolName => toolName.replace(/_/g, '-'))); } else { // For other tools, add the tool name as-is // Actual tool resolution will happen when the agent is created resolvedTools.push(tool); } } } return { ...agent, resolvedTools }; } } exports.AgentManager = AgentManager; //# sourceMappingURL=agent-manager.js.map