179 lines
5.5 KiB
TypeScript
179 lines
5.5 KiB
TypeScript
/**
|
|
* Arcadia Suite - Executor Agent
|
|
*
|
|
* Agente responsável por preparar código para staging (preview).
|
|
* NÃO aplica código diretamente - envia para área de staging
|
|
* onde o usuário pode revisar e aprovar antes de publicar.
|
|
*
|
|
* @author Arcadia Development Team
|
|
* @version 3.0.0 - Staging Flow
|
|
*/
|
|
|
|
import { BaseBlackboardAgent, type AgentConfig } from "../BaseBlackboardAgent";
|
|
import { blackboardService } from "../service";
|
|
import { type BlackboardTask } from "@shared/schema";
|
|
|
|
const SYSTEM_PROMPT = `Você é o Agente Executor do Arcadia Suite.
|
|
|
|
## Seu Papel
|
|
Você prepara código validado para staging (preview), onde o usuário pode revisar antes de publicar.
|
|
|
|
## Processo de Staging
|
|
1. Verificar se validação passou
|
|
2. Validar caminhos dos arquivos
|
|
3. Marcar tarefa como "staged" (pronta para preview)
|
|
4. Aguardar aprovação do usuário para publicar
|
|
|
|
## IMPORTANTE
|
|
- NÃO aplique código diretamente ao projeto
|
|
- O código vai para STAGING primeiro
|
|
- O usuário decide quando publicar`;
|
|
|
|
const PROTECTED_FILES = [
|
|
"server/routes.ts",
|
|
"server/index.ts",
|
|
"server/storage.ts",
|
|
"server/db.ts",
|
|
"shared/schema.ts",
|
|
"client/src/App.tsx",
|
|
"client/src/main.tsx",
|
|
"client/src/pages/Cockpit.tsx",
|
|
"client/src/pages/Agent.tsx",
|
|
"client/src/pages/ProcessCompass.tsx",
|
|
"client/src/pages/DevCenter.tsx",
|
|
"package.json",
|
|
"tsconfig.json",
|
|
"vite.config.ts",
|
|
"drizzle.config.ts",
|
|
];
|
|
|
|
export class ExecutorAgent extends BaseBlackboardAgent {
|
|
constructor() {
|
|
const config: AgentConfig = {
|
|
name: "executor",
|
|
displayName: "Agente Executor",
|
|
description: "Prepara código para staging e publicação",
|
|
systemPrompt: SYSTEM_PROMPT,
|
|
capabilities: [
|
|
"Preparar código para staging",
|
|
"Validar caminhos de arquivos",
|
|
"Bloquear arquivos protegidos",
|
|
"Preparar para publicação"
|
|
],
|
|
pollInterval: 2000
|
|
};
|
|
super(config);
|
|
}
|
|
|
|
canHandle(task: BlackboardTask): boolean {
|
|
const context = task.context as any;
|
|
return context?.phase === "deploy" || task.assignedAgent === "executor";
|
|
}
|
|
|
|
async process(task: BlackboardTask): Promise<void> {
|
|
await this.log(task.id, "thinking", "Preparando para staging...");
|
|
|
|
const codeArtifacts = await blackboardService.getArtifactsForTask(task.id, "code");
|
|
|
|
const allDocs = await blackboardService.getArtifactsForTask(task.id, "doc");
|
|
const validationArtifact = allDocs.find(a => a.name === "validation-report.json");
|
|
|
|
if (codeArtifacts.length === 0) {
|
|
await blackboardService.failTask(task.id, "executor", "Nenhum código para aplicar");
|
|
return;
|
|
}
|
|
|
|
let validation: any = { valid: false, score: 0 };
|
|
if (validationArtifact?.content) {
|
|
try {
|
|
validation = JSON.parse(validationArtifact.content);
|
|
} catch {}
|
|
}
|
|
|
|
if (!validation.valid || validation.score < 60) {
|
|
await this.log(task.id, "blocked", `Validação falhou (score: ${validation.score}, valid: ${validation.valid})`);
|
|
await blackboardService.failTask(task.id, "executor", `Código não aprovado (score: ${validation.score}) - staging bloqueado`);
|
|
return;
|
|
}
|
|
|
|
await this.log(task.id, "executing", `Preparando ${codeArtifacts.length} arquivos para staging...`);
|
|
|
|
const stagedFiles: string[] = [];
|
|
const blockedFiles: string[] = [];
|
|
const errors: string[] = [];
|
|
|
|
for (const artifact of codeArtifacts) {
|
|
const filePath = artifact.name;
|
|
const content = artifact.content;
|
|
|
|
if (!content) {
|
|
errors.push(`${filePath}: conteúdo vazio`);
|
|
continue;
|
|
}
|
|
|
|
if (PROTECTED_FILES.includes(filePath)) {
|
|
blockedFiles.push(filePath);
|
|
await this.log(task.id, "blocked", `Arquivo protegido: ${filePath} - não será incluído no staging`);
|
|
continue;
|
|
}
|
|
|
|
const isValidPath = filePath.startsWith("client/src") ||
|
|
filePath.startsWith("server/") ||
|
|
filePath.startsWith("shared/");
|
|
|
|
if (!isValidPath) {
|
|
await this.log(task.id, "skipped", `Arquivo fora dos diretórios permitidos: ${filePath}`);
|
|
continue;
|
|
}
|
|
|
|
stagedFiles.push(filePath);
|
|
}
|
|
|
|
if (stagedFiles.length === 0) {
|
|
await blackboardService.failTask(task.id, "executor", `Nenhum arquivo válido para staging. Bloqueados: ${blockedFiles.join(", ")}. Erros: ${errors.join("; ")}`);
|
|
return;
|
|
}
|
|
|
|
const mainTask = await blackboardService.getMainTask(task.id);
|
|
|
|
const stagingReport = {
|
|
action: "staging",
|
|
status: "awaiting_approval",
|
|
stagedFiles,
|
|
blockedFiles,
|
|
errors: errors.length > 0 ? errors : undefined,
|
|
validationScore: validation.score,
|
|
taskId: task.id,
|
|
mainTaskId: mainTask?.id,
|
|
title: mainTask?.title || task.title,
|
|
stagedAt: new Date().toISOString(),
|
|
};
|
|
|
|
await blackboardService.addArtifact(
|
|
task.id,
|
|
"doc",
|
|
"staging-report.json",
|
|
JSON.stringify(stagingReport, null, 2),
|
|
"executor"
|
|
);
|
|
|
|
await this.log(task.id, "completed", `Staging pronto: ${stagedFiles.length} arquivos aguardando aprovação no Preview`);
|
|
|
|
if (mainTask) {
|
|
await blackboardService.createSubtask(
|
|
mainTask.id,
|
|
"Registrar aprendizado",
|
|
"Armazenar padrões aprendidos para evolução",
|
|
"evolution",
|
|
[task.id],
|
|
{ phase: "evolution" }
|
|
);
|
|
}
|
|
|
|
await blackboardService.completeTask(task.id, "executor", stagingReport);
|
|
}
|
|
}
|
|
|
|
export { PROTECTED_FILES };
|
|
export const executorAgent = new ExecutorAgent();
|