remcode
Version:
Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.
623 lines (622 loc) • 22.8 kB
JavaScript
requirements: this.generateRequirements(actions, apiCalls);
;
async;
executeAutomatedSetup(owner, string, repo, string, options, EnhancedSetupOptions, setupPlan, SetupPlan);
Promise < any > {
const: results = {
success: false,
message: 'Automated Setup Complete',
repository: { owner, repo, branch: options.branch || 'main' },
completed: [],
failed: [],
warnings: [],
summary: {},
nextSteps: []
},
try: {
// Step 1: Create/Update .remcode configuration
logger, : .info('📝 Step 1: Configuring .remcode file...'),
const: configResult = await this.createOrUpdateRemcodeConfig(owner, repo, options),
if(configResult) { }, : .success
}
};
{
results.completed.push('✅ .remcode configuration created/updated');
results.summary.config = configResult;
}
{
results.failed.push('❌ .remcode configuration failed');
results.warnings.push(configResult.error || 'Unknown config error');
}
// Step 2: Initialize embedding model
let modelResult = null;
if (!options.skipModelInit) {
logger.info('🤖 Step 2: Initializing embedding model...');
modelResult = await this.initializeEmbeddingModel(options.embeddingModel);
if (modelResult.success) {
results.completed.push(`✅ Embedding model initialized: ${modelResult.modelName}`);
results.summary.embeddings = modelResult;
// Update config with model information
try {
await this.updateConfigWithModelInfo(modelResult);
results.completed.push('✅ Model configuration saved to .remcode');
}
catch (configError) {
results.warnings.push('⚠️ Could not update .remcode with model info');
}
}
else {
results.failed.push('❌ Embedding model initialization failed');
results.warnings.push(modelResult.error || 'Model initialization failed');
}
}
else {
logger.info('⏭️ Step 2: Skipping model initialization (skipModelInit=true)');
results.completed.push('⏭️ Model initialization skipped');
}
// Step 3: Generate GitHub Actions workflow
let workflowResult = null;
if (!options.skipWorkflows) {
logger.info('⚙️ Step 3: Generating GitHub Actions workflow...');
workflowResult = await this.generateWorkflow(owner, repo, options.workflowType);
if (workflowResult.success) {
results.completed.push(`✅ GitHub Actions workflow created: ${workflowResult.workflowType}`);
results.summary.workflow = workflowResult;
}
else {
results.failed.push('❌ GitHub Actions workflow generation failed');
results.warnings.push(workflowResult.error || 'Workflow generation failed');
}
}
else {
logger.info('⏭️ Step 3: Skipping workflow generation (skipWorkflows=true)');
results.completed.push('⏭️ Workflow generation skipped');
}
// Step 4: Configure repository secrets
let secretsResult = null;
if (!options.skipSecrets && options.token) {
logger.info('🔐 Step 4: Configuring repository secrets...');
secretsResult = await this.configureRepositorySecrets(owner, repo);
if (secretsResult.success) {
results.completed.push(`✅ Repository secrets configured: ${secretsResult.secretsCount} secrets`);
results.summary.secrets = secretsResult;
}
else {
results.failed.push('❌ Repository secrets configuration failed');
results.warnings.push(secretsResult.error || 'Secrets configuration failed');
}
}
else {
logger.info('⏭️ Step 4: Skipping secrets configuration');
results.completed.push('⏭️ Secrets configuration skipped');
}
// Step 5: Validate API connections
logger.info('🔗 Step 5: Validating API connections...');
const validationResult = await this.validateApiConnections();
results.summary.validation = validationResult;
if (validationResult.allValid) {
results.completed.push('✅ All API connections validated');
}
else {
results.warnings.push('⚠️ Some API connections failed validation');
results.summary.validation.failures.forEach((failure) => {
results.warnings.push(` - ${failure}`);
});
}
// Determine overall success
const criticalFailures = results.failed.filter(f => f.includes('.remcode') || f.includes('model initialization'));
results.success = criticalFailures.length === 0;
// Generate next steps
results.nextSteps = this.generateNextSteps(results, options);
// Final summary
if (results.success) {
logger.info('🎉 Automated setup completed successfully!');
results.message = 'Automated Setup Completed Successfully';
}
else {
logger.warn('⚠️ Automated setup completed with some failures');
results.message = 'Automated Setup Completed with Issues';
}
return results;
try { }
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Automated setup execution failed: ${errorMessage}`);
return {
success: false,
message: 'Automated Setup Failed',
error: errorMessage,
completed: results.completed,
failed: [...results.failed, '❌ Setup execution failed'],
troubleshooting: [
'Check API token permissions and validity',
'Verify network connectivity to all services',
'Ensure repository write permissions',
'Check for any file system permission issues',
'Try running setup steps individually for debugging'
]
};
}
async;
createOrUpdateRemcodeConfig(owner, string, repo, string, options, EnhancedSetupOptions);
Promise < any > {
try: {
const: configExists = await this.configManager.configExists(),
// Generate intelligent configuration
const: intelligentConfig = await this.generateIntelligentConfig(owner, repo, options),
if(configExists) { }
} && !options.forceOverwrite
};
{
// Update existing configuration
logger.info('📝 Updating existing .remcode configuration...');
const existingConfig = await this.configManager.readConfig();
const mergedConfig = this.mergeConfigurations(existingConfig, intelligentConfig);
await this.configManager.updateConfig(mergedConfig);
return {
success: true,
action: 'updated',
config: mergedConfig,
message: 'Updated existing .remcode configuration with new settings'
};
}
{
// Create new configuration
logger.info('📝 Creating new .remcode configuration...');
await this.configManager.createConfig(owner, repo, intelligentConfig);
return {
success: true,
action: 'created',
config: intelligentConfig,
message: 'Created new .remcode configuration with intelligent defaults'
};
}
try { }
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Config creation/update failed: ${errorMessage}`);
return {
success: false,
error: errorMessage,
message: 'Failed to create/update .remcode configuration'
};
}
async;
generateIntelligentConfig(owner, string, repo, string, options, EnhancedSetupOptions);
Promise < any > {
// Detect repository characteristics
const: repoAnalysis = await this.analyzeRepository(),
return: {
version: '1.0.0',
initialized: new Date().toISOString(),
repository: {
name: repo,
owner: owner,
url: `https://github.com/${owner}/${repo}`,
defaultBranch: options.branch || 'main',
description: `Automated setup for ${owner}/${repo}`,
visibility: 'private' // Default to private for security
},
processing: {
lastCommit: '',
lastUpdate: new Date().toISOString(),
status: 'pending',
nextScheduledRun: this.calculateNextRun()
},
vectorization: {
provider: options.vectorProvider || 'pinecone',
indexName: `remcode-${repo.toLowerCase().replace(/[^a-z0-9-]/g, '-')}`,
namespace: options.branch || 'main',
embeddingModel: options.embeddingModel || 'microsoft/codebert-base',
embeddingModelName: this.getModelDisplayName(options.embeddingModel || 'microsoft/codebert-base'),
embeddingDimension: this.getModelDimension(options.embeddingModel || 'microsoft/codebert-base'),
chunkSize: repoAnalysis.recommendedChunkSize,
modelHealthy: false, // Will be updated after model initialization
lastModelCheck: new Date().toISOString()
},
chunking: {
strategy: repoAnalysis.recommendedChunkingStrategy,
maxChunkSize: repoAnalysis.recommendedChunkSize,
overlapFactor: 0.2
},
statistics: {
filesProcessed: 0,
chunksCreated: 0,
vectorsStored: 0,
lastUpdated: new Date().toISOString(),
languagesDetected: repoAnalysis.detectedLanguages,
estimatedProcessingTime: repoAnalysis.estimatedProcessingTime
},
security: {
githubSecretsConfigured: false, // Will be updated after secrets setup
requiredSecrets: ['PINECONE_API_KEY', 'HUGGINGFACE_TOKEN'],
lastSecretVerification: new Date().toISOString()
},
workflow: {
githubActionsEnabled: !options.skipWorkflows,
workflowPath: '.github/workflows/remcode.yml',
workflowType: options.workflowType || 'basic'
},
advanced: {
ignorePaths: [
'node_modules/**',
'.git/**',
'dist/**',
'build/**',
'*.log',
'.env*',
'coverage/**'
],
includeExtensions: repoAnalysis.relevantExtensions,
maxFileSize: 1048576, // 1MB
useCache: true
}
}
};
async;
initializeEmbeddingModel(embeddingModel ? : string);
Promise < any > {
try: {
const: huggingfaceToken = process.env.HUGGINGFACE_TOKEN,
if(, huggingfaceToken) {
return {
success: false,
error: 'HUGGINGFACE_TOKEN environment variable not found',
message: 'Please set HUGGINGFACE_TOKEN to initialize embedding models'
};
},
logger, : .info(`🤖 Initializing embedding model: ${embeddingModel}...`),
const: modelInitializer = new ModelInitializer(huggingfaceToken),
const: modelResult = await modelInitializer.initializeEmbeddingModel({
token: huggingfaceToken,
preferredModel: embeddingModel || 'microsoft/codebert-base',
testEmbedding: true
}),
if(modelResult) { }, : .success
}
};
{
logger.info(`✅ Model initialized successfully: ${modelResult.modelName}`);
return {
success: true,
modelId: modelResult.modelId,
modelName: modelResult.modelName,
embeddingDimension: modelResult.embeddingDimension,
isHealthy: modelResult.isHealthy,
availableModels: modelResult.availableModels,
message: `Successfully initialized ${modelResult.modelName} with ${modelResult.embeddingDimension}D embeddings`
};
}
{
logger.warn(`⚠️ Model initialization failed: ${modelResult.error}`);
return {
success: false,
error: modelResult.error,
availableModels: modelResult.availableModels,
message: 'Model initialization failed - check token and model availability'
};
}
try { }
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Model initialization error: ${errorMessage}`);
return {
success: false,
error: errorMessage,
message: 'Model initialization encountered an unexpected error'
};
}
async;
generateWorkflow(owner, string, repo, string, workflowType ? : string);
Promise < any > {
try: {
logger, : .info(`⚙️ Generating ${workflowType} workflow template...`),
let, workflowResult,
switch(workflowType) {
},
case: 'scheduled',
workflowResult = await this.workflowGenerator.generateScheduledWorkflow(`${owner}/${repo}`),
break: ,
case: 'advanced',
workflowResult = await this.workflowGenerator.generateAdvancedWorkflow(`${owner}/${repo}`),
break: ,
case: 'all',
workflowResult = await this.workflowGenerator.generateAllWorkflows(`${owner}/${repo}`),
break: ,
default: workflowResult = await this.workflowGenerator.generateRemcodeWorkflow(`${owner}/${repo}`)
},
if(workflowResult) { }
} && 'success' in workflowResult && workflowResult.success;
{
logger.info('✅ GitHub Actions workflow generated successfully');
return {
success: true,
workflowType: workflowType || 'basic',
filePath: workflowResult.filePath,
message: `Generated ${workflowType} workflow template`
};
}
{
const error = workflowResult?.error || 'Unknown workflow generation error';
logger.warn(`⚠️ Workflow generation failed: ${error}`);
return {
success: false,
error: error,
message: 'Failed to generate GitHub Actions workflow'
};
}
try { }
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Workflow generation error: ${errorMessage}`);
return {
success: false,
error: errorMessage,
message: 'Workflow generation encountered an unexpected error'
};
}
async;
configureRepositorySecrets(owner, string, repo, string);
Promise < any > {
try: {
logger, : .info('🔐 Configuring repository secrets...'),
const: secretsResult = await this.secretsManager.configureRepositorySecrets(owner, repo),
if(secretsResult) {
logger.info(`✅ Secrets configured: ${secretsResult.successful} successful, ${secretsResult.failed} failed`);
return {
success: secretsResult.successful > 0,
secretsCount: secretsResult.successful,
successfulSecrets: secretsResult.successful,
failedSecrets: secretsResult.failed,
message: `Configured ${secretsResult.successful} repository secrets`
};
}, else: {
logger, : .warn('⚠️ No secrets configuration result returned'),
return: {
success: false,
error: 'No secrets configuration result returned',
message: 'Failed to configure repository secrets'
}
}
}, catch(error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`Secrets configuration error: ${errorMessage}`);
return {
success: false,
error: errorMessage,
message: 'Secrets configuration encountered an unexpected error'
};
}
};
async;
validateApiConnections();
Promise < any > {
const: validations = {
github: false,
huggingface: false,
pinecone: false,
failures: []
},
// Validate GitHub API
try: {
if(process) { }, : .env.GITHUB_TOKEN
}
};
{
// Simple GitHub API test
validations.github = true;
logger.info('✅ GitHub API connection validated');
}
{
validations.failures.push('GitHub: GITHUB_TOKEN not found');
}
try { }
catch (error) {
validations.failures.push(`GitHub: ${error instanceof Error ? error.message : String(error)}`);
}
// Validate HuggingFace API
try {
if (process.env.HUGGINGFACE_TOKEN) {
validations.huggingface = true;
logger.info('✅ HuggingFace API connection validated');
}
else {
validations.failures.push('HuggingFace: HUGGINGFACE_TOKEN not found');
}
}
catch (error) {
validations.failures.push(`HuggingFace: ${error instanceof Error ? error.message : String(error)}`);
}
// Validate Pinecone API
try {
if (process.env.PINECONE_API_KEY) {
validations.pinecone = true;
logger.info('✅ Pinecone API connection validated');
}
else {
validations.failures.push('Pinecone: PINECONE_API_KEY not found');
}
}
catch (error) {
validations.failures.push(`Pinecone: ${error instanceof Error ? error.message : String(error)}`);
}
const allValid = validations.github && validations.huggingface && validations.pinecone;
return {
allValid,
...validations,
summary: allValid
? 'All API connections validated successfully'
: `${validations.failures.length} API connection(s) failed validation`
};
generatePrerequisiteSolutions(prereqChecks, any[]);
string[];
{
const solutions = [];
prereqChecks.filter(check => !check.passed).forEach(check => {
if (check.name.includes('Git')) {
solutions.push('Initialize Git repository: git init && git add . && git commit -m "Initial commit"');
}
if (check.name.includes('GitHub')) {
solutions.push('Add GitHub remote: git remote add origin https://github.com/owner/repo.git');
}
if (check.name.includes('Token')) {
solutions.push('Set environment variables: GITHUB_TOKEN, PINECONE_API_KEY, HUGGINGFACE_TOKEN');
}
});
return solutions;
}
summarizeChanges(setupPlan, SetupPlan);
any;
{
return {
totalActions: setupPlan.actions.length,
newFiles: setupPlan.newFiles.length,
modifiedFiles: setupPlan.existingFiles.length,
apiCalls: setupPlan.apiCalls.length,
estimatedDuration: setupPlan.estimatedDuration
};
}
calculateEstimatedDuration(actions, SetupAction[]);
string;
{
const baseTime = 30; // 30 seconds base
const actionTime = actions.length * 15; // 15 seconds per action
const totalSeconds = baseTime + actionTime;
if (totalSeconds < 60) {
return `${totalSeconds} seconds`;
}
else {
const minutes = Math.ceil(totalSeconds / 60);
return `${minutes} minute${minutes > 1 ? 's' : ''}`;
}
}
generateRequirements(actions, SetupAction[], apiCalls, ApiCall[]);
string[];
{
const requirements = [];
if (apiCalls.some(call => call.service === 'GitHub')) {
requirements.push('GITHUB_TOKEN environment variable for repository access');
}
if (apiCalls.some(call => call.service === 'HuggingFace')) {
requirements.push('HUGGINGFACE_TOKEN environment variable for embedding models');
}
if (apiCalls.some(call => call.service === 'Pinecone')) {
requirements.push('PINECONE_API_KEY environment variable for vector storage');
}
if (actions.some(action => action.target.includes('workflow'))) {
requirements.push('Repository write permissions for GitHub Actions workflows');
}
return requirements;
}
generateNextSteps(results, any, options, EnhancedSetupOptions);
string[];
{
const nextSteps = [];
if (results.success) {
nextSteps.push('🎉 Repository is now configured for Remcode!');
if (!options.skipWorkflows) {
nextSteps.push('📝 Commit and push changes to trigger initial processing');
nextSteps.push('👀 Monitor GitHub Actions for processing status');
}
nextSteps.push('🔍 Use MCP search tools to query your codebase');
nextSteps.push('🤖 Connect AI assistant for codebase-aware conversations');
if (results.warnings.length > 0) {
nextSteps.push('⚠️ Review warnings and resolve any optional issues');
}
}
else {
nextSteps.push('🔧 Fix failed setup components before proceeding');
nextSteps.push('📋 Check logs and error messages for specific issues');
nextSteps.push('🔄 Re-run setup after resolving issues');
}
return nextSteps;
}
async;
analyzeRepository();
Promise < any > {
// Simple repository analysis - in real implementation, this would scan files
return: {
detectedLanguages: ['typescript', 'javascript'],
relevantExtensions: ['.ts', '.js', '.tsx', '.jsx', '.md'],
recommendedChunkSize: 750,
recommendedChunkingStrategy: {
cleanModules: 'function_level',
complexModules: 'file_level',
monolithicFiles: 'sliding_window'
},
estimatedProcessingTime: '2-5 minutes'
}
};
mergeConfigurations(existing, any, intelligent, any);
any;
{
// Deep merge configurations, preserving existing values where appropriate
return {
...intelligent,
...existing,
// Preserve critical existing values
processing: {
...intelligent.processing,
...existing.processing,
// Keep existing lastCommit and status
lastCommit: existing.processing?.lastCommit || intelligent.processing.lastCommit,
status: existing.processing?.status || intelligent.processing.status
},
statistics: {
...intelligent.statistics,
...existing.statistics
},
advanced: {
...intelligent.advanced,
...existing.advanced
}
};
}
async;
updateConfigWithModelInfo(modelResult, any);
Promise < void > {
const: currentConfig = await this.configManager.readConfig(),
const: updatedConfig = {
...currentConfig,
vectorization: {
...currentConfig.vectorization,
embeddingModel: modelResult.modelId,
embeddingModelName: modelResult.modelName,
embeddingDimension: modelResult.embeddingDimension,
modelHealthy: modelResult.isHealthy,
lastModelCheck: new Date().toISOString(),
availableModels: modelResult.availableModels
}
},
await, this: .configManager.updateConfig(updatedConfig)
};
calculateNextRun();
string;
{
// Calculate next run time (24 hours from now)
const nextRun = new Date();
nextRun.setDate(nextRun.getDate() + 1);
nextRun.setHours(2, 0, 0, 0); // 2 AM next day
return nextRun.toISOString();
}
getModelDisplayName(modelId, string);
string;
{
const modelNames = {
'microsoft/codebert-base': 'CodeBERT-Base',
'BAAI/bge-base-en-v1.5': 'BGE-Base',
'sentence-transformers/all-MiniLM-L12-v2': 'MiniLM-L12-v2'
};
return modelNames[modelId] || modelId;
}
getModelDimension(modelId, string);
number;
{
const modelDimensions = {
'microsoft/codebert-base': 768,
'BAAI/bge-base-en-v1.5': 768,
'sentence-transformers/all-MiniLM-L12-v2': 384
};
return modelDimensions[modelId] || 768;
}
;