@lucasdoreac/mcp-continuity-server
Version:
Um servidor MCP para gerenciamento de continuidade e estado em projetos
175 lines (154 loc) • 7.26 kB
JavaScript
import fs from 'fs-extra';
import path from 'path';
import { StateManager } from './stateManager.js';
import { RepositoryTools } from './repositoryTools.js';
export class AutoSetup {
constructor() {
this.stateManager = new StateManager();
this.repoTools = new RepositoryTools();
}
/**
* Configura e inicializa o project-status.json automaticamente
* @param {string} repositoryUrl - URL ou identificador do repositório
* @param {string} workingDirectory - Diretório de trabalho opcional (ex: 'src', 'frontend/src')
* @returns {Promise<Object>} - Estado do projeto configurado
*/
async setupProjectState(repositoryUrl, workingDirectory = '') {
console.log(`[INICIANDO] Configurando ambiente para o repositório: ${repositoryUrl}${workingDirectory ? ` (diretório: ${workingDirectory})` : ''}`);
// Extrai informações do repositório a partir da URL
const repoPath = repositoryUrl.split('/').slice(-2).join('/').replace('.git', '');
const repoName = repoPath.split('/')[1] || repositoryUrl.split('/').pop() || 'project';
// Determina o caminho para o project-status.json
const projectStatusPath = workingDirectory
? path.join(workingDirectory, 'project-status.json')
: 'project-status.json';
// Verifica se o diretório de trabalho existe, caso especificado
if (workingDirectory) {
try {
await fs.ensureDir(workingDirectory);
console.log(`[OK] Diretório ${workingDirectory} está disponível`);
} catch (error) {
console.log(`[AVISO] Diretório ${workingDirectory} não encontrado. Tentando criar...`);
try {
// Tenta criar o diretório de trabalho
await fs.ensureDir(workingDirectory);
console.log(`[OK] Diretório ${workingDirectory} criado`);
} catch (dirError) {
console.error(`[ERRO] Erro ao criar diretório de trabalho: ${dirError}`);
console.log('[AVISO] Usando diretório raiz como alternativa.');
workingDirectory = '';
}
}
}
// Verifica se o state já existe
let projectState;
try {
// Tenta carregar o estado existente
projectState = await this.stateManager.loadProjectState(projectStatusPath);
console.log('[OK] project-status.json encontrado para ' + repoName);
} catch (error) {
console.log('[AVISO] project-status.json não encontrado. Criando um novo com dados do repositório...');
// Coleta informações do repositório para preencher dinamicamente o template
let mainFiles = [];
try {
// Define o diretório para listar arquivos
const listDir = workingDirectory || '.';
// Lista os arquivos disponíveis para identificar arquivos principais
const files = await fs.readdir(listDir);
mainFiles = files.filter(f =>
f.endsWith('.js') || f.endsWith('.py') || f.endsWith('.html') ||
f.endsWith('.jsx') || f.endsWith('.ts') || f.endsWith('.tsx')
);
} catch (e) {
console.log('Não foi possível listar arquivos:', e);
}
// Define arquivo inicial baseado em convenções comuns
const defaultMainFile = mainFiles.find(f =>
['index.js', 'main.js', 'app.js', 'index.jsx', 'index.ts', 'app.py'].includes(f)
) || (mainFiles.length > 0 ? mainFiles[0] : 'main.js');
// Prepara o caminho do arquivo principal
const mainFilePath = workingDirectory
? path.join(workingDirectory, defaultMainFile)
: defaultMainFile;
// Cria um template preenchido com informações do repositório
const template = {
projectInfo: {
name: repoName,
repository: repositoryUrl,
workingDirectory: workingDirectory || null,
lastUpdated: new Date().toISOString()
},
development: {
currentFile: mainFilePath,
currentComponent: repoName + "Component",
inProgress: {
type: "feature",
description: "Configuração inicial do projeto " + repoName,
remainingTasks: ["Análise de requisitos", "Planejamento da arquitetura", "Implementação de funcionalidades core"]
}
},
components: {
completed: [],
inProgress: [{name: "Sistema de Configuração", priority: "high"}],
pending: [{name: "Interface de Usuário", priority: "medium"}, {name: "Testes", priority: "high"}]
},
context: {
lastThought: "Iniciar o desenvolvimento com foco na arquitetura principal do " + repoName,
nextSteps: ["Estruturar diretórios", "Definir interfaces principais", "Configurar ferramentas de build"],
dependencies: []
},
mcpTools: {
lastUsed: {
repl: null,
artifacts: [],
searchResults: []
},
cacheFiles: [],
tempStorage: []
}
};
// Salva o template com informações reais
await this.stateManager.saveProjectState(template, projectStatusPath);
projectState = template;
console.log('[OK] Novo project-status.json criado com dados do repositório ' + repoName);
}
return projectState;
}
/**
* Inicializa o ambiente completo para o repositório
* @param {string} repositoryUrl - URL ou identificador do repositório
* @param {string} workingDirectory - Diretório de trabalho opcional
* @returns {Promise<Object>} - Informações do ambiente inicializado
*/
async initializeEnvironment(repositoryUrl, workingDirectory = '') {
try {
console.log('[PROCESSANDO] Inicializando ambiente MCP...');
// Configura o estado do projeto
const projectState = await this.setupProjectState(repositoryUrl, workingDirectory);
// Analisa o repositório
const repoAnalysis = await this.repoTools.analyzeRepository(workingDirectory);
// Gera prompt de continuidade
const continuityPrompt = this.stateManager.generateContinuityPrompt(projectState);
// Exibe informações de resumo
console.log('\n[RESUMO] Resumo do Ambiente:');
console.log(`- Projeto: ${projectState.projectInfo.name}`);
console.log(`- Repositório: ${projectState.projectInfo.repository}`);
if (workingDirectory) {
console.log(`- Diretório de trabalho: ${workingDirectory}`);
}
console.log(`- Arquivo atual: ${projectState.development.currentFile}`);
console.log(`- Tarefa em progresso: ${projectState.development.inProgress.description}`);
console.log(`- Total de arquivos: ${repoAnalysis.fileCount}`);
console.log('\n[PROCESSANDO] Prompt de continuidade para próximas sessões:');
console.log(continuityPrompt);
return {
projectState,
repoAnalysis,
continuityPrompt
};
} catch (error) {
console.error('[ERRO] Erro ao inicializar ambiente:', error);
throw error;
}
}
}