UNPKG

remcode

Version:

Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.

304 lines (303 loc) 13.8 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.WorkflowGenerator = exports.WorkflowTemplateType = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const logger_1 = require("../utils/logger"); const logger = (0, logger_1.getLogger)('WorkflowGenerator'); /** * GitHub Actions workflow template types */ var WorkflowTemplateType; (function (WorkflowTemplateType) { WorkflowTemplateType["BASIC"] = "basic"; WorkflowTemplateType["ADVANCED"] = "advanced"; WorkflowTemplateType["ENTERPRISE"] = "enterprise"; })(WorkflowTemplateType || (exports.WorkflowTemplateType = WorkflowTemplateType = {})); /** * Class for generating GitHub Actions workflows for Remcode */ class WorkflowGenerator { /** * Constructor * @param repoPath Path to the repository */ constructor(repoPath = process.cwd()) { this.currentVersion = '0.2.0'; this.repoPath = repoPath; } /** * Generate a GitHub Actions workflow for Remcode * @param options Workflow template options * @param templateType Type of workflow template to generate * @returns Workflow generation result */ async generateWorkflow(options, templateType = WorkflowTemplateType.BASIC) { logger.info(`Generating GitHub Actions workflow using ${templateType} template`); try { // Create .github/workflows directory if it doesn't exist const workflowsDir = path.join(this.repoPath, '.github', 'workflows'); await this.ensureDirectoryExists(workflowsDir); // Generate workflow content based on template type const workflowContent = this.generateWorkflowContent(options, templateType); // Write workflow to file const workflowPath = path.join(workflowsDir, 'remcode.yml'); fs.writeFileSync(workflowPath, workflowContent, 'utf8'); logger.info(`Workflow generated successfully at ${workflowPath}`); return { success: true, filePath: workflowPath, workflowContent, workflowVersion: this.currentVersion }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to generate workflow: ${errorMessage}`); return { success: false, error: errorMessage, workflowVersion: this.currentVersion }; } } /** * Ensure directory exists, creating it if necessary * @param dir Directory path */ async ensureDirectoryExists(dir) { try { // Create directory recursively if it doesn't exist if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); logger.debug(`Created directory: ${dir}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to create directory ${dir}: ${errorMessage}`); throw error; } } /** * Generate workflow content based on template type and options * @param options Workflow template options * @param templateType Type of workflow template * @returns Workflow content as string */ generateWorkflowContent(options, templateType) { // Default values const { repoName, owner = 'unknown', branches = ['main', 'master', 'develop'], nodeVersion = '18', embeddingModel = 'microsoft/graphcodebert-base', cronSchedule = '0 0 * * 1', // Weekly on Monday at midnight includeSchedule = true, customSecrets = {} } = options; // Version comment const versionComment = `# Remcode workflow version: ${this.currentVersion}\n# Generated on: ${new Date().toISOString()}\n`; // Base workflow content let workflowContent = `${versionComment}name: Remcode Code Indexing\n\n`; // Add triggers workflowContent += 'on:\n'; workflowContent += ' push:\n'; workflowContent += ` branches: [ ${branches.join(', ')} ]\n`; // Add schedule if enabled if (includeSchedule) { workflowContent += ' schedule:\n'; workflowContent += ` - cron: '${cronSchedule}'\n`; } // Add manual trigger workflowContent += ' workflow_dispatch:\n'; workflowContent += '\n'; // Add jobs section based on template type switch (templateType) { case WorkflowTemplateType.ENTERPRISE: workflowContent += this.generateEnterpriseWorkflow(repoName, nodeVersion, embeddingModel, customSecrets); break; case WorkflowTemplateType.ADVANCED: workflowContent += this.generateAdvancedWorkflow(repoName, nodeVersion, embeddingModel, customSecrets); break; case WorkflowTemplateType.BASIC: default: workflowContent += this.generateBasicWorkflow(repoName, nodeVersion, embeddingModel, customSecrets); break; } return workflowContent; } /** * Generate a basic workflow for Remcode */ generateBasicWorkflow(repoName, nodeVersion, embeddingModel, customSecrets) { let content = 'jobs:\n'; content += ' process:\n'; content += ' runs-on: ubuntu-latest\n'; content += ' steps:\n'; content += ' - uses: actions/checkout@v4\n'; content += ' with:\n'; content += ' fetch-depth: 0\n'; content += ' - name: Setup Node.js\n'; content += ' uses: actions/setup-node@v4\n'; content += ' with:\n'; content += ` node-version: '${nodeVersion}'\n`; content += ' - name: Process with Remcode\n'; content += ' run: npx remcode process\n'; content += ' env:\n'; content += ' PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}\n'; content += ' HUGGINGFACE_TOKEN: ${{ secrets.HUGGINGFACE_TOKEN }}\n'; content += ` EMBEDDING_MODEL: ${embeddingModel}\n`; // Add custom secrets if provided Object.entries(customSecrets).forEach(([key, value]) => { content += ` ${key}: ${value}\n`; }); return content; } /** * Generate an advanced workflow with caching and metrics */ generateAdvancedWorkflow(repoName, nodeVersion, embeddingModel, customSecrets) { let content = 'jobs:\n'; content += ' process:\n'; content += ' runs-on: ubuntu-latest\n'; content += ' steps:\n'; content += ' - uses: actions/checkout@v4\n'; content += ' with:\n'; content += ' fetch-depth: 0\n'; content += ' - name: Setup Node.js\n'; content += ' uses: actions/setup-node@v4\n'; content += ' with:\n'; content += ` node-version: '${nodeVersion}'\n`; content += ' cache: "npm"\n'; content += ' - name: Install Dependencies\n'; content += ' run: npm ci\n'; content += ' - name: Process with Remcode\n'; content += ' id: remcode\n'; content += ' run: npx remcode process --detailed-output --metrics\n'; content += ' env:\n'; content += ' PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}\n'; content += ' HUGGINGFACE_TOKEN: ${{ secrets.HUGGINGFACE_TOKEN }}\n'; content += ` EMBEDDING_MODEL: ${embeddingModel}\n`; // Add custom secrets if provided Object.entries(customSecrets).forEach(([key, value]) => { content += ` ${key}: ${value}\n`; }); // Add post-processing steps content += ' - name: Upload Processing Metrics\n'; content += ' if: always()\n'; content += ' uses: actions/upload-artifact@v3\n'; content += ' with:\n'; content += ` name: remcode-metrics-${repoName}\n`; content += ' path: .remcode-metrics.json\n'; content += ' retention-days: 90\n'; return content; } /** * Generate an enterprise workflow with multiple jobs and notifications */ generateEnterpriseWorkflow(repoName, nodeVersion, embeddingModel, customSecrets) { let content = 'jobs:\n'; // Preparation job content += ' prepare:\n'; content += ' runs-on: ubuntu-latest\n'; content += ' outputs:\n'; content += ' cache_key: ${{ steps.cache_key.outputs.key }}\n'; content += ' steps:\n'; content += ' - uses: actions/checkout@v4\n'; content += ' with:\n'; content += ' fetch-depth: 0\n'; content += ' - name: Generate cache key\n'; content += ' id: cache_key\n'; content += ' run: echo "key=remcode-${{ github.repository }}-${{ hashFiles(\'**/*.{js,ts,jsx,tsx,md,json}\') }}" >> $GITHUB_OUTPUT\n'; // Processing job content += ' process:\n'; content += ' needs: prepare\n'; content += ' runs-on: ubuntu-latest\n'; content += ' steps:\n'; content += ' - uses: actions/checkout@v4\n'; content += ' with:\n'; content += ' fetch-depth: 0\n'; content += ' - name: Setup Node.js\n'; content += ' uses: actions/setup-node@v4\n'; content += ' with:\n'; content += ` node-version: '${nodeVersion}'\n`; content += ' cache: "npm"\n'; content += ' - name: Restore cache\n'; content += ' uses: actions/cache@v3\n'; content += ' with:\n'; content += ' path: |\n'; content += ' .remcode-cache\n'; content += ' .remcode-temp\n'; content += ' key: ${{ needs.prepare.outputs.cache_key }}\n'; content += ' - name: Install Dependencies\n'; content += ' run: npm ci\n'; content += ' - name: Process with Remcode\n'; content += ' id: remcode\n'; content += ' run: npx remcode process --detailed-output --metrics --cache\n'; content += ' env:\n'; content += ' PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}\n'; content += ' HUGGINGFACE_TOKEN: ${{ secrets.HUGGINGFACE_TOKEN }}\n'; content += ` EMBEDDING_MODEL: ${embeddingModel}\n`; // Add custom secrets if provided Object.entries(customSecrets).forEach(([key, value]) => { content += ` ${key}: ${value}\n`; }); // Add post-processing steps content += ' - name: Upload Processing Metrics\n'; content += ' if: always()\n'; content += ' uses: actions/upload-artifact@v3\n'; content += ' with:\n'; content += ` name: remcode-metrics-${repoName}\n`; content += ' path: .remcode-metrics.json\n'; content += ' retention-days: 90\n'; // Notification job content += ' notify:\n'; content += ' needs: process\n'; content += ' if: always()\n'; content += ' runs-on: ubuntu-latest\n'; content += ' steps:\n'; content += ' - name: Send Notification\n'; content += ' if: always()\n'; content += ' uses: slackapi/slack-github-action@v1.24.0\n'; content += ' with:\n'; content += ' payload: |\n'; content += ' {\n'; content += ` "repository": "${repoName}",\n`; content += ' "status": "${{ needs.process.result }}",\n'; content += ' "run_id": "${{ github.run_id }}",\n'; content += ' "run_number": "${{ github.run_number }}"\n'; content += ' }\n'; content += ' env:\n'; content += ' SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}\n'; content += ' SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK\n'; return content; } } exports.WorkflowGenerator = WorkflowGenerator;