arcadia-suite-sv/server/autonomous/tools/filesystem/WriteFileTool.ts

89 lines
3.1 KiB
TypeScript

/**
* Arcadia Suite - Write File Tool
* Usa guardrails do BlackboardService para validação
*/
import { BaseTool, type ToolParameter, type ToolResult } from "../BaseTool";
import * as fs from "fs/promises";
import * as path from "path";
import { blackboardService } from "../../../blackboard/service";
const BLOCKED_FILES = ['package.json', 'package-lock.json', '.env', 'drizzle.config.ts'];
// Arquivos críticos que NÃO podem ser sobrescritos pelos agentes
const PROTECTED_PATHS = [
'server/routes.ts',
'shared/schema.ts',
'client/src/App.tsx',
'client/src/main.tsx',
'server/index.ts',
'server/storage.ts',
'db/index.ts',
];
export class WriteFileTool extends BaseTool {
name = "write_file";
description = "Escreve ou cria um arquivo no projeto";
category = "Filesystem";
parameters: ToolParameter[] = [
{ name: "path", type: "string", description: "Caminho do arquivo relativo à raiz", required: true },
{ name: "content", type: "string", description: "Conteúdo a ser escrito", required: true },
{ name: "createDirs", type: "boolean", description: "Criar diretórios se não existirem", required: false, default: true },
];
async execute(params: Record<string, any>): Promise<ToolResult> {
const filePath = params.path as string;
const content = params.content as string;
const createDirs = params.createDirs !== false;
// Usar guardrails do BlackboardService para validação de path
const pathValidation = blackboardService.validateFilePath(filePath);
if (!pathValidation.valid) {
return this.formatError(`Path inválido: ${pathValidation.error}`);
}
// Usar guardrails do BlackboardService para validação de conteúdo
const contentValidation = blackboardService.validateContent(content);
if (!contentValidation.valid) {
return this.formatError(`Conteúdo inválido: ${contentValidation.error}`);
}
const fileName = path.basename(filePath);
if (BLOCKED_FILES.includes(fileName)) {
return this.formatError(`Arquivo protegido: ${fileName}`);
}
// Bloquear sobrescrita de arquivos críticos do sistema
if (PROTECTED_PATHS.includes(filePath)) {
return this.formatError(`Arquivo crítico protegido - não pode ser sobrescrito: ${filePath}`);
}
try {
const absolutePath = path.resolve(process.cwd(), filePath);
if (!absolutePath.startsWith(process.cwd())) {
return this.formatError("Tentativa de escrita fora do projeto");
}
if (createDirs) {
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
}
const existed = await fs.access(absolutePath).then(() => true).catch(() => false);
await fs.writeFile(absolutePath, content, "utf-8");
return this.formatSuccess(
existed ? `Arquivo atualizado: ${filePath}` : `Arquivo criado: ${filePath}`,
{
path: filePath,
action: existed ? "updated" : "created",
size: content.length,
}
);
} catch (error: any) {
return this.formatError(`Erro ao escrever arquivo: ${error.message}`);
}
}
}