UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

246 lines (216 loc) 8.18 kB
#!/usr/bin/env node /** * Generates deployment files from config.json * * Usage: * node scripts/generate-config.js [config-path] * * Outputs: * - chat-ui/dotenv-local.txt (baked into Docker image) * - mcp-bridge/index.js (updated with custom tools/endpoints) * - chat-ui/cloudbuild.yaml (with project-specific values) * - mcp-bridge/cloudbuild.yaml (with project-specific values) */ import { readFileSync, writeFileSync, existsSync } from "fs"; import { resolve, dirname } from "path"; import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, ".."); const configPath = process.argv[2] || resolve(ROOT, "config/config.json"); if (!existsSync(configPath)) { console.error(`Config not found: ${configPath}`); console.error("Copy config/config.example.json to config/config.json and fill in your values."); process.exit(1); } const config = JSON.parse(readFileSync(configPath, "utf-8")); // ---- Provider endpoints ---- const PROVIDER_ENDPOINTS = { gemini: { type: "openai", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", }, openai: { type: "openai", baseURL: "https://api.openai.com/v1", }, openrouter: { type: "openai", baseURL: "https://openrouter.ai/api/v1", }, }; // ---- Build MCP bridge URL ---- const mcpBridgeService = config.gcp.serviceName?.mcpBridge || "mcp-bridge"; // For Docker Compose: use internal Docker network URL. // For Cloud Run: deploy.sh replaces this with the real HTTPS URL after deployment. const bridgeURL = process.env.MCP_BRIDGE_URL || `http://${mcpBridgeService}:3001`; // ---- Build MODELS array ---- // All models route through the MCP bridge's /chat/completions proxy. // The bridge resolves the correct upstream provider (OpenAI, Gemini, OpenRouter) // from the model name and uses server-side API keys. No keys in the client config. const models = (config.models || []).map((m) => { return { name: m.name, displayName: m.displayName || m.name, description: m.description || "", supportsTools: m.supportsTools !== false, ...(m.multimodal ? { multimodal: true } : {}), parameters: m.parameters || {}, preprompt: config.systemPrompt || `You are ${config.brand.name}, a helpful AI assistant.`, endpoints: [{ type: "openai", baseURL: bridgeURL }], }; }); // ---- Generate dotenv-local.txt ---- const chatService = config.gcp.serviceName?.chatUi || "chat-ui"; let dotenv = `MONGODB_URL=mongodb://localhost:27017 MONGODB_DB_NAME=${chatService}-db PUBLIC_APP_NAME=${config.brand.name} PUBLIC_ORIGIN=https://${config.brand.domain} PUBLIC_APP_DESCRIPTION="${config.brand.description}" LLM_SUMMARIZATION=true ENABLE_DATA_EXPORT=true ALLOW_IFRAME=false USE_LOCAL_WEBSEARCH=true OPENAI_BASE_URL=${bridgeURL}`; // MCP_SERVERS: Each tool group is a separate MCP server (toggle-able in Chat UI). // RVF security patch allows HTTP for admin-configured MCP_SERVERS // on the private container network (not exposed to internet). // For Cloud Run, deploy.sh replaces ${bridgeURL} with HTTPS URL. const mcpGroups = config.mcpGroups || { core: true, intelligence: true, agents: true, memory: true, devtools: true, security: false, browser: false, neural: false, "agentic-flow": false, "claude-code": false, gemini: false, codex: false, }; const groupDisplayNames = { core: "Core Tools", intelligence: "Intelligence & Learning", agents: "Agents & Orchestration", memory: "Memory & Knowledge", devtools: "Dev Tools & Analysis", security: "Security & Safety", browser: "Browser Automation", neural: "Neural & DAA", "agentic-flow": "Agentic Flow", "claude-code": "Claude Code", gemini: "Gemini", codex: "Codex", }; const mcpServers = Object.entries(mcpGroups) .filter(([, enabled]) => enabled) .map(([name]) => ({ name: groupDisplayNames[name] || name, url: `${bridgeURL}/mcp/${name}`, })); dotenv += `\nMCP_SERVERS=\`${JSON.stringify(mcpServers)}\``; // Auth if (config.auth?.enabled) { dotenv += ` OPENID_PROVIDER_URL=https://accounts.google.com OPENID_CLIENT_ID=${config.auth.clientId} OPENID_SCOPES=${config.auth.scopes || "openid profile email"} OPENID_NAME_CLAIM=${config.auth.nameClaim || "name"} COOKIE_SECURE=true COOKIE_SAMESITE=lax COOKIE_MAX_AGE=604800`; } // Models dotenv += `\nMODELS=\`${JSON.stringify(models)}\``; writeFileSync(resolve(ROOT, "chat-ui/dotenv-local.txt"), dotenv); console.log("Generated: chat-ui/dotenv-local.txt"); // ---- Generate chat-ui/cloudbuild.yaml ---- const chatCloudbuild = `steps: # Build custom image with branded assets - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', 'gcr.io/\${PROJECT_ID}/${chatService}:\${_VERSION}', '-f', 'chat-ui/Dockerfile', 'chat-ui' ] # Push versioned tag - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/\${PROJECT_ID}/${chatService}:\${_VERSION}'] # Tag and push latest - name: 'gcr.io/cloud-builders/docker' args: [ 'tag', 'gcr.io/\${PROJECT_ID}/${chatService}:\${_VERSION}', 'gcr.io/\${PROJECT_ID}/${chatService}:latest' ] - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/\${PROJECT_ID}/${chatService}:latest'] # Deploy to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: [ 'run', 'deploy', '${chatService}', '--image', 'gcr.io/\${PROJECT_ID}/${chatService}:\${_VERSION}', '--platform', 'managed', '--region', '${config.gcp.region}', '--port', '3000', '--memory', '2Gi', '--cpu', '2', '--min-instances', '1', '--max-instances', '10', '--timeout', '300',${config.gcp.vpcConnector ? `\n '--vpc-connector', '${config.gcp.vpcConnector}',` : ""} '--allow-unauthenticated', '--set-secrets', '${config.auth?.enabled ? `OPENID_CLIENT_SECRET=${config.auth.clientSecretName || "google-client-secret"}:latest` : ""}' ] substitutions: _VERSION: 'v1' options: logging: CLOUD_LOGGING_ONLY timeout: 1200s `; writeFileSync(resolve(ROOT, "chat-ui/cloudbuild.yaml"), chatCloudbuild); console.log("Generated: chat-ui/cloudbuild.yaml"); // ---- Generate mcp-bridge/cloudbuild.yaml ---- const bridgeCloudbuild = `steps: # Build Docker image - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:\${_VERSION}', '-f', 'mcp-bridge/Dockerfile', 'mcp-bridge' ] # Push versioned tag - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:\${_VERSION}'] # Tag and push latest - name: 'gcr.io/cloud-builders/docker' args: [ 'tag', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:\${_VERSION}', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:latest' ] - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:latest'] # Deploy to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: [ 'run', 'deploy', '${mcpBridgeService}', '--image', 'gcr.io/\${PROJECT_ID}/${mcpBridgeService}:\${_VERSION}', '--platform', 'managed', '--region', '${config.gcp.region}', '--port', '3001', '--memory', '512Mi', '--cpu', '1', '--min-instances', '0', '--max-instances', '5', '--timeout', '300',${config.gcp.vpcConnector ? `\n '--vpc-connector', '${config.gcp.vpcConnector}',` : ""} '--allow-unauthenticated', '--set-env-vars', 'NODE_ENV=production', '--set-secrets', '${Object.entries(config.secrets || {}).map(([k, v]) => `${k.replace(/([A-Z])/g, "_$1").toUpperCase()}=${v}:latest`).join(",")}' ] substitutions: _VERSION: 'v1' options: logging: CLOUD_LOGGING_ONLY timeout: 600s `; writeFileSync(resolve(ROOT, "mcp-bridge/cloudbuild.yaml"), bridgeCloudbuild); console.log("Generated: mcp-bridge/cloudbuild.yaml"); console.log("\nDone! Next steps:"); console.log(" 1. Edit mcp-bridge/index.js to add your custom tools"); console.log(" 2. Run: bash scripts/deploy.sh");