UNPKG

automagik-genie

Version:

Self-evolving AI agent orchestration framework with Model Context Protocol support

170 lines (167 loc) 7.29 kB
"use strict"; /** * Install Flow Helpers - Genie orchestration for fresh installations * * Architecture: * 1. CLI launches GENIE task with simple prompt: "Run explorer to acquire context, when it ends run the install workflow" * 2. Genie orchestrates: explore → interview → spawn installers → completion * 3. User monitors progress in Forge dashboard via shortened URL */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.printBox = printBox; exports.launchMasterGenie = launchMasterGenie; exports.runInstallFlow = runInstallFlow; const service_config_js_1 = require("./service-config.js"); const gradient_string_1 = __importDefault(require("gradient-string")); const child_process_1 = require("child_process"); // Import ForgeExecutor for workspace project management const forge_executor_js_1 = require("./forge-executor.js"); const FORGE_URL = process.env.FORGE_BASE_URL || (0, service_config_js_1.getForgeConfig)().baseUrl; // Import from compiled MCP dist (will be available after build) let shortenUrl; let getApiKeyFromEnv; try { const urlShortener = require('../../mcp/dist/lib/url-shortener.js'); shortenUrl = urlShortener.shortenUrl; getApiKeyFromEnv = urlShortener.getApiKeyFromEnv; } catch { // Fallback if MCP not built yet shortenUrl = async (url) => ({ success: false, fullUrl: url }); getApiKeyFromEnv = () => undefined; } /** * Print a gradient box to console */ function printBox(title, content) { const border = '═'.repeat(60); console.log(gradient_string_1.default.pastel(`╔${border}╗`)); console.log(gradient_string_1.default.pastel(`║ ${title.padEnd(58)} ║`)); console.log(gradient_string_1.default.pastel(`╠${border}╣`)); console.log(content); console.log(gradient_string_1.default.pastel(`╚${border}╝`)); } /** * Launch Genie orchestrator for installation */ async function launchMasterGenie(config) { const FORGE_URL = process.env.FORGE_BASE_URL || (0, service_config_js_1.getForgeConfig)().baseUrl; console.log(''); printBox('🧞 GENIE AWAKENING', 'Starting installation orchestration...'); console.log(''); // Get or create workspace-specific Forge project const forgeExecutor = (0, forge_executor_js_1.createForgeExecutor)({ forgeBaseUrl: FORGE_URL }); const projectId = await forgeExecutor.getOrCreateGenieProject(); // Get or create master agent (uses forge_agents table) const masterResponse = await fetch(`${FORGE_URL}/api/forge/agents?project_id=${projectId}&agent_type=master`); if (!masterResponse.ok) { throw new Error(`Failed to query master agent: ${masterResponse.status}`); } const { data: agents } = await masterResponse.json(); let masterAgent = agents?.[0]; if (!masterAgent) { console.log(gradient_string_1.default.pastel('Creating Genie agent...')); const createResponse = await fetch(`${FORGE_URL}/api/forge/agents`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ project_id: projectId, agent_type: 'master' }) }); if (!createResponse.ok) { throw new Error(`Failed to create master agent: ${createResponse.status}`); } const { data } = await createResponse.json(); masterAgent = data; } // Build simple orchestration prompt const templates = config.templates?.join(', ') || 'code'; const prompt = `Run explorer to acquire context, when it ends run the install workflow. Templates to install: ${templates} See @.genie/spells/install-genie.md for detailed instructions.`; // Get genie agent definition from registry let genieVariant = 'GENIE'; // Fallback let genieExecutor = config.executor?.toUpperCase() || 'CLAUDE_CODE'; try { const { getAgentRegistry } = await import('./agent-registry.js'); const registry = await getAgentRegistry(); // Lookup genie neuron by workflow name // Neurons are registered as "neuron/genie" without collective const genieAgentDef = registry.getAgent('genie'); if (genieAgentDef) { // Derive forge_profile_name: use explicit or derive from neuron name genieVariant = genieAgentDef.forge_profile_name || (genieAgentDef.type === 'neuron' ? genieAgentDef.name.toUpperCase() : 'GENIE'); genieExecutor = genieAgentDef.genie?.executor || genieExecutor; } } catch (error) { // Use fallback GENIE if registry unavailable console.warn('Failed to load genie agent definition, using fallback variant'); } // Create attempt with genie variant from registry console.log(gradient_string_1.default.pastel('Creating orchestration attempt...')); const attemptResponse = await fetch(`${FORGE_URL}/api/task-attempts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ task_id: masterAgent.task_id, executor_profile_id: { executor: genieExecutor, variant: genieVariant }, base_branch: getCurrentBranch() }) }); if (!attemptResponse.ok) { throw new Error(`Failed to create attempt: ${attemptResponse.status}`); } const { data: attempt } = await attemptResponse.json(); // Send installation prompt as follow-up message const followUpResponse = await fetch(`${FORGE_URL}/api/task-attempts/${attempt.id}/follow-up`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt }) }); if (!followUpResponse.ok) { throw new Error(`Failed to send installation prompt: ${followUpResponse.status}`); } console.log(''); console.log(gradient_string_1.default.pastel('✨ Genie orchestrating installation...')); console.log(''); const fullUrl = `${FORGE_URL}/projects/${projectId}/tasks/${masterAgent.task_id}/attempts/${attempt.id}?view=diffs`; // Shorten URL const { shortUrl: shortened } = await shortenUrl(fullUrl, { apiKey: getApiKeyFromEnv() }); return shortened || fullUrl; } /** * Main install flow orchestrator */ async function runInstallFlow(config) { const forgeExecutor = (0, forge_executor_js_1.createForgeExecutor)({ forgeBaseUrl: FORGE_URL }); // NOTE: Agent profile sync removed - Forge discovers .genie folders natively // Step 1: Launch Genie orchestrator (handles explore → install workflow) const shortUrl = await launchMasterGenie(config); return shortUrl; } /** * Get current git branch (suppresses stderr to avoid scary errors in new repos) */ function getCurrentBranch() { try { return (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] // Suppress stderr }).trim(); } catch { // Return 'main' for brand new repos (no commits yet) or non-git directories return 'main'; } }