@dastbal/nestjs-ai-agent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # Meet the NestJS Code Alchemist 🧙‍♂️
2
+
3
+ ![NestJS Logo](https://nestjs.com/img/logo-small.svg)
4
+
5
+
6
+ # @dastbal/nestjs-ai-agent 🤖
7
+
8
+ Autonomous AI Agent acting as a **Principal Software Engineer** for NestJS projects.
9
+
10
+ ## Features
11
+ - **The Surgeon Rule**: Reads and analyzes files before writing code.
12
+ - **RAG Powered**: Uses your codebase as context for precise implementations.
13
+ - **SQLite Persistence**: Remembers conversation history between sessions.
14
+ - **Self-Correcting**: Automatically runs integrity checks and fixes compilation errors.
15
+
16
+ ## Installation
17
+ ```bash
18
+ npm install @dastbal/nestjs-ai-agent
19
+
20
+ npx gen "Create a new Payments service with DDD and its corresponding test"
21
+
22
+
23
+ 🔐 Configuration & Authentication
24
+ This agent uses Google Vertex AI. To allow the agent to operate, you must provide your Google Cloud credentials.
25
+
26
+ Create your credentials file: Place your Google Service Account JSON file in the root of your project and name it exactly: credentials_vertex.json
27
+
28
+ Setup your environment: Create a .env file in your project root and point to that file:
29
+
30
+ Code snippet
31
+ GOOGLE_APPLICATION_CREDENTIALS="./credentials_vertex.json"
32
+ # Optional: specify your project and location
33
+ GCP_PROJECT_ID="your-project-id"
34
+ GCP_LOCATION="us-central1"
35
+ ⚠️ Important Security Note: Never commit your credentials_vertex.json or .env files to version control. Add them to your .gitignore.
36
+
37
+ ## Introduction
38
+
39
+ I am a specialized AI, a Principal Software Engineer, crafted to assist you in your NestJS projects. I operate directly on the project's local file system, enabling me to read, understand, and modify your codebase with precision and efficiency. My goal is to help you write clean, well-documented, and testable code, adhering to the best practices of NestJS and Domain-Driven Design (DDD).
40
+
41
+ ## Core Functionality
42
+
43
+ Here's a breakdown of how I work:
44
+
45
+ 1. **Understanding Your Needs:** I start by carefully interpreting your requests. I clarify any ambiguities and break down complex tasks into manageable steps.
46
+
47
+ 2. **Code Exploration (🔍 `ask_codebase`):**
48
+ * Before making any changes, I use the `ask_codebase` tool. This is my primary research instrument.
49
+ * It allows me to perform semantic searches and analyze the project's dependency graph.
50
+ * I use it to find relevant code snippets, understand how different parts of the system interact, and locate the exact file paths I need.
51
+
52
+ 3. **Code Comprehension (📖 `safe_read_file`):**
53
+ * When I need to modify a file, I *always* read its contents first using `safe_read_file`.
54
+ * This ensures I understand the existing code, its structure, and any existing documentation (TSDocs).
55
+ * This is crucial for avoiding regressions and maintaining code quality.
56
+
57
+ 4. **Code Generation & Modification (✍️):**
58
+ * Based on your instructions and my understanding of the code, I generate or modify code.
59
+ * I adhere to strict TypeScript typing, DDD principles, and NestJS best practices.
60
+ * I also create corresponding tests to ensure code reliability.
61
+
62
+ 5. **Code Writing (💾 `safe_write_file`):**
63
+ * I write the generated or modified code to the file system using `safe_write_file`.
64
+ * This tool automatically creates a backup of the original file, providing a safety net.
65
+
66
+ 6. **Integrity Validation (✅ `run_integrity_check`):**
67
+ * Immediately after writing or modifying code, I run `run_integrity_check`.
68
+ * This is a critical step. It uses the TypeScript compiler to ensure that the code is type-safe and compiles without errors.
69
+ * This helps catch any mistakes I might have made.
70
+
71
+ 7. **Self-Correction (🛠️):**
72
+ * If the integrity check fails, I analyze the error messages and attempt to fix the code myself.
73
+ * I will retry up to three times. If I cannot fix the error, I will ask for human assistance.
74
+
75
+ 8. **Iteration and Refinement (🔄):**
76
+ * I repeat these steps as needed, refining the code and ensuring it meets your requirements.
77
+
78
+ 9. **Documentation (📝):**
79
+ * I always strive to maintain and improve code documentation (TSDocs).
80
+
81
+ 10. **Learning and Adaptation (🧠):**
82
+ * I learn from your feedback. If you correct a style preference, I store it in `/memories/style-guide.txt` to improve future responses.
83
+
84
+ ## Tools and Technologies
85
+
86
+ I am built upon a foundation of powerful tools and technologies:
87
+
88
+ * **Language Model:** I leverage a large language model (LLM) from Google, enabling me to understand and generate human-like text.
89
+ * **Retrieval-Augmented Generation (RAG):** I utilize a live RAG system. This means I can dynamically access and process information from your codebase to provide accurate and relevant responses. This allows me to understand the context of your project and generate code that fits seamlessly.
90
+ * **NestJS Expertise:** I have been specifically trained on NestJS best practices, DDD, and related concepts.
91
+ * **TypeScript:** I am fluent in TypeScript and adhere to strict typing.
92
+ * **Libraries:** I utilize a suite of libraries for code analysis, generation, and validation.
93
+ * **File System Access:** I have secure access to the project's local file system, allowing me to directly modify your code.
94
+
95
+ ## Safety and Quality
96
+
97
+ * **Strict Typing:** I enforce strict TypeScript typing to prevent common errors.
98
+ * **Comprehensive Testing:** I create tests alongside the code to ensure its reliability.
99
+ * **Error Handling:** I use standard NestJS HTTP exceptions and avoid swallowing errors silently.
100
+ * **Code Reviews:** I am designed to be used in conjunction with human code reviews to ensure the highest quality.
101
+
102
+ ## How to Interact with Me
103
+
104
+ Simply provide me with clear instructions, and I will do my best to assist you. For example:
105
+
106
+ * "Add a new DTO for the User entity."
107
+ * "Create a service to handle authentication."
108
+ * "Write a unit test for the UserService."
109
+
110
+ I will guide you through the process, providing feedback and ensuring the code meets your requirements.
111
+
112
+ ## Disclaimer
113
+
114
+ I am an AI assistant and should be used responsibly. Always review the code I generate before deploying it to production. I am constantly learning and improving, but I am not perfect. Please report any issues or suggestions.
115
+
116
+ ## Let's Build Something Amazing! ✨
@@ -0,0 +1,2 @@
1
+ export declare class AiAgentModule {
2
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AiAgentModule = void 0;
10
+ // src/ai-agent.module.ts
11
+ const common_1 = require("@nestjs/common");
12
+ const factory_1 = require("./core/agent/factory");
13
+ let AiAgentModule = class AiAgentModule {
14
+ };
15
+ exports.AiAgentModule = AiAgentModule;
16
+ exports.AiAgentModule = AiAgentModule = __decorate([
17
+ (0, common_1.Global)(),
18
+ (0, common_1.Module)({
19
+ providers: [
20
+ {
21
+ provide: "AI_AGENT",
22
+ useFactory: async () => {
23
+ // Aquí usamos tu lógica actual
24
+ return await factory_1.AgentFactory.create("nestjs-instance");
25
+ },
26
+ },
27
+ ],
28
+ exports: ["AI_AGENT"],
29
+ })
30
+ ], AiAgentModule);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const dotenv = __importStar(require("dotenv"));
41
+ dotenv.config(); // Carga las variables del .env si existen
42
+ const commander_1 = require("commander");
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const factory_1 = require("../core/agent/factory");
45
+ const program = new commander_1.Command();
46
+ // Logs con estilo (Chalk 4 syntax)
47
+ const log = {
48
+ ai: (msg) => console.log(chalk_1.default.blue("🤖 [AI]: ") + msg),
49
+ sys: (msg) => console.log(chalk_1.default.gray("⚙️ [SYS]: ") + msg),
50
+ error: (msg) => console.log(chalk_1.default.red("❌ [ERR]: ") + msg),
51
+ };
52
+ program
53
+ .name("gen")
54
+ .description("Agente Autónomo de Ingeniería NestJS")
55
+ .argument("<instruction>", "La instrucción técnica para el agente")
56
+ .action(async (instruction) => {
57
+ try {
58
+ if (!instruction || instruction.trim().length === 0) {
59
+ log.error("Proporciona una instrucción válida.");
60
+ return;
61
+ }
62
+ log.sys("Inicializando Agente en modo CLI...");
63
+ // El threadId puede ser fijo para sesiones de CLI o dinámico
64
+ const threadId = "cli-user-session";
65
+ const agent = await factory_1.AgentFactory.create(threadId);
66
+ log.ai(`Procesando: "${instruction}"`);
67
+ const response = await agent.invoke({ messages: [{ role: "user", content: instruction }] }, { configurable: { thread_id: threadId } });
68
+ const lastMessage = response.messages[response.messages.length - 1];
69
+ if (lastMessage && lastMessage.content) {
70
+ console.log("\n" + chalk_1.default.green("--- RESPUESTA DEL AGENTE ---"));
71
+ console.log(lastMessage.content);
72
+ console.log(chalk_1.default.green("----------------------------\n"));
73
+ }
74
+ log.sys("Tarea completada.");
75
+ }
76
+ catch (error) {
77
+ log.error("Error en el agente:");
78
+ log.error(error?.message || "Error desconocido");
79
+ }
80
+ });
81
+ program.parse(process.argv);
@@ -0,0 +1,24 @@
1
+ export declare class AgentFactory {
2
+ static create(threadId?: string): Promise<import("langchain").ReactAgent<import("langchain").AgentTypeConfig<import("langchain").ResponseFormatUndefined, undefined, import("langchain").AnyAnnotationRoot, readonly import("langchain").AgentMiddleware<any, any, any, readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[]>[], readonly [import("langchain").DynamicStructuredTool<import("zod").ZodObject<{
3
+ query: import("zod").ZodString;
4
+ }, import("zod/v4/core").$strip>, {
5
+ query: string;
6
+ }, {
7
+ query: string;
8
+ }, string, "ask_codebase">, import("langchain").DynamicStructuredTool<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, Record<string, never>, Record<string, never>, string, "run_integrity_check">, import("langchain").DynamicStructuredTool<import("zod").ZodObject<{
9
+ filePath: import("zod").ZodString;
10
+ content: import("zod").ZodString;
11
+ }, import("zod/v4/core").$strip>, {
12
+ filePath: string;
13
+ content: string;
14
+ }, {
15
+ filePath: string;
16
+ content: string;
17
+ }, string, "safe_write_file">, import("langchain").DynamicStructuredTool<import("zod").ZodObject<{
18
+ filePath: import("zod").ZodString;
19
+ }, import("zod/v4/core").$strip>, {
20
+ filePath: string;
21
+ }, {
22
+ filePath: string;
23
+ }, string, "safe_read_file">, import("langchain").DynamicStructuredTool<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, Record<string, never>, Record<string, never>, string, "refresh_project_index">]>>>;
24
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AgentFactory = void 0;
37
+ const langchain_1 = require("langchain"); // Usamos la versión estándar
38
+ const langgraph_checkpoint_sqlite_1 = require("@langchain/langgraph-checkpoint-sqlite");
39
+ const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
40
+ const provider_1 = require("../llm/provider");
41
+ const tools_1 = require("../tools/tools");
42
+ const path = __importStar(require("path"));
43
+ const fs = __importStar(require("fs"));
44
+ class AgentFactory {
45
+ static async create(threadId = 'cli-session') {
46
+ const rootDir = process.cwd();
47
+ // Configuración de directorios
48
+ const agentDir = path.join(rootDir, '.agent');
49
+ if (!fs.existsSync(agentDir))
50
+ fs.mkdirSync(agentDir, { recursive: true });
51
+ // 1. Persistencia (Checkpointer)
52
+ const dbPath = path.join(agentDir, 'history.db');
53
+ const checkpointer = langgraph_checkpoint_sqlite_1.SqliteSaver.fromConnString(dbPath);
54
+ // 2. Store (Opcional en createAgent, pero lo mantenemos por si lo usas en el runtime)
55
+ const memoryStore = new langgraph_checkpoint_1.InMemoryStore();
56
+ /**
57
+ * NOTA: 'createAgent' de LangChain NO utiliza el parámetro 'backend' ni 'subagents'
58
+ * de la misma manera que 'createDeepAgent'.
59
+ * Esto evita que se cree automáticamente el canal "files" que causa el error.
60
+ */
61
+ const mainSystemPrompt = `
62
+ You are a Principal Software Engineer specialized in NestJS (Node.js). You are operating directly on the local file system of a live, real-world project.
63
+
64
+ 💎 QUALITY STANDARDS (UNBREAKABLE):
65
+
66
+ Architecture: Follow DDD (Domain-Driven Design) and NestJS Best Practices.
67
+
68
+ Use strict DTOs with class-validator and class-transformer.
69
+
70
+ Always document with TSDocs (prefer technical English).
71
+
72
+ Testing (TDD): DO NOT write code without its corresponding test.
73
+
74
+ Create the .spec.ts file alongside the implementation.
75
+
76
+ Ensure all tests pass.
77
+
78
+ Error Handling:
79
+
80
+ Use standard NestJS HTTP exceptions (NotFoundException, BadRequestException).
81
+
82
+ Never swallow errors silently (no empty catch blocks).
83
+
84
+ Typing: Strict TypeScript. The use of any is FORBIDDEN.
85
+
86
+ ⚙️ EXECUTION PROTOCOL:
87
+
88
+
89
+ RESEARCH (ask_codebase): BEFORE touching anything, search for existing patterns in the project.
90
+
91
+ Example: "Search for UserEntity before creating a related DTO."
92
+
93
+ IMPLEMENT (Safe Write): Write the files.
94
+
95
+ Reminder: You have an active backup system; work with confidence but caution.
96
+
97
+ VALIDATE (run_integrity_check): MANDATORY.
98
+
99
+ After writing code, run the integrity check immediately.
100
+
101
+ If it fails, SELF-CORRECT. Do not ask the user; fix the compilation/test error yourself.
102
+ if afeter 3 tries you cannot fix an error ask for human help
103
+ LEARN: If the user corrects a style preference, save it to /memories/style-guide.txt.
104
+ use the ttools provided first to read and write file
105
+ 🚨 SAFETY RULES:
106
+
107
+ Never perform mass file deletions.
108
+
109
+ If modifying core files (such as app.module.ts), double-check your imports.
110
+ NOTE ON INDEXING:
111
+ - The codebase is indexed. Use 'ask_codebase' to search.
112
+ - After you write files, they are automatically re-indexed.
113
+ - If 'ask_codebase' fails to find recent changes, use 'refresh_project_index'.
114
+
115
+ Wait for human approval. If rejected, propose a different solution.
116
+ FILE SYSTEM CONFIGURATION:
117
+ - Real project files are located under: /project/
118
+ - Long-term memories are located under: /memories/
119
+ - The root (/) is for transient scratchpad files only.
120
+
121
+ ALWAYS use the '/project/' prefix when reading or writing source code.
122
+ Example: write_file('/project/src/app.service.ts', '...')
123
+ 🔍 CODE REFINEMENT & INTEGRITY (THE SURGEON'S RULE):
124
+
125
+ 1. Read-Before-Write: NEVER overwrite a file without reading it first using 'safe_read_file'. You must understand the existing logic, TSDocs, and dependencies before making any changes.
126
+
127
+ 2. Preservation First: Do not delete existing documentation (TSDocs), helpful comments, or business logic unrelated to your current task. Your goal is to AUGMENT and REFINE, not to destroy.
128
+
129
+ 3. Differential Analysis: Before proposing a 'safe_write_file', mentally compare your new version with the existing one.
130
+ - Ask yourself: Does this change preserve all existing functionality?
131
+ - Does it maintain the established TSDoc standards?
132
+ - Is this strictly better than the previous version?
133
+
134
+ 4. Anti-Regression: If you are refactoring, ensure that you are not losing edge-case handling that the previous author implemented. If you don't understand why a piece of code is there, RESEARCH it before removing it.
135
+
136
+ 5. Focus vs. Context: While focusing on your specific task, maintain the "big picture" of the file. Do not break the file's internal consistency (naming conventions, patterns, or architecture).
137
+ `;
138
+ return (0, langchain_1.createAgent)({
139
+ model: provider_1.LLMProvider.getModel(),
140
+ checkpointer: checkpointer, // Para persistencia de memoria de corto plazo
141
+ // Añadimos solo las herramientas necesarias
142
+ tools: [
143
+ tools_1.askCodebaseTool,
144
+ tools_1.integrityCheckTool,
145
+ tools_1.safeWriteFileTool,
146
+ tools_1.safeReadFileTool,
147
+ tools_1.refreshIndexTool,
148
+ ],
149
+ // En createAgent, el prompt se pasa generalmente como 'prompt' o 'systemPrompt'
150
+ // dependiendo de la versión de la librería.
151
+ systemPrompt: mainSystemPrompt,
152
+ });
153
+ }
154
+ }
155
+ exports.AgentFactory = AgentFactory;
@@ -0,0 +1,46 @@
1
+ import { FilesystemBackend } from 'deepagents';
2
+ /**
3
+ * 🛡️ SAFE BACKEND
4
+ * * Extiende el backend de sistema de archivos nativo de DeepAgents para interceptar
5
+ * operaciones destructivas (escritura/edición) y crear copias de seguridad automáticas.
6
+ * * @example
7
+ * ```ts
8
+ * const backend = new SafeFilesystemBackend("/usuario/proyectos/mi-app");
9
+ * // Ahora cada write_file o edit_file creará un backup en .agent/backups
10
+ * ```
11
+ */
12
+ export declare class SafeFilesystemBackend extends FilesystemBackend {
13
+ /** Directorio donde se almacenarán los backups */
14
+ private backupDir;
15
+ /** * Referencia local al directorio raíz para poder resolver rutas absolutas.
16
+ * Fue necesario agregar esto porque la clase padre no expone `this.rootDir`.
17
+ */
18
+ private readonly rootDir;
19
+ /**
20
+ * Crea una instancia del backend seguro.
21
+ * @param rootDir - La ruta absoluta del directorio de trabajo del agente.
22
+ */
23
+ constructor(rootDir: string);
24
+ /**
25
+ * Sobrescribe la escritura nativa para inyectar el backup antes de modificar el archivo.
26
+ * * @param filePath - Ruta relativa del archivo a escribir.
27
+ * @param content - Nuevo contenido del archivo.
28
+ * @returns El resultado de la operación de escritura original.
29
+ */
30
+ write(filePath: string, content: string): Promise<import("deepagents").WriteResult>;
31
+ /**
32
+ * Sobrescribe la edición nativa para inyectar el backup antes de reemplazar texto.
33
+ * * @param filePath - Ruta relativa del archivo.
34
+ * @param oldString - Texto a buscar.
35
+ * @param newString - Texto de reemplazo.
36
+ * @param replaceAll - Si se deben reemplazar todas las ocurrencias.
37
+ * @returns El resultado de la operación de edición original.
38
+ */
39
+ edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<import("deepagents").EditResult>;
40
+ /**
41
+ * Genera una copia del archivo original con timestamp antes de ser modificado.
42
+ * Si el archivo no existe (es nuevo), no hace nada.
43
+ * * @param virtualPath - Ruta virtual (desde el punto de vista del agente) del archivo.
44
+ */
45
+ private createBackup;
46
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SafeFilesystemBackend = void 0;
37
+ const deepagents_1 = require("deepagents");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ /**
41
+ * 🛡️ SAFE BACKEND
42
+ * * Extiende el backend de sistema de archivos nativo de DeepAgents para interceptar
43
+ * operaciones destructivas (escritura/edición) y crear copias de seguridad automáticas.
44
+ * * @example
45
+ * ```ts
46
+ * const backend = new SafeFilesystemBackend("/usuario/proyectos/mi-app");
47
+ * // Ahora cada write_file o edit_file creará un backup en .agent/backups
48
+ * ```
49
+ */
50
+ class SafeFilesystemBackend extends deepagents_1.FilesystemBackend {
51
+ /**
52
+ * Crea una instancia del backend seguro.
53
+ * @param rootDir - La ruta absoluta del directorio de trabajo del agente.
54
+ */
55
+ constructor(rootDir) {
56
+ // virtualMode: true asegura que el agente no pueda salir de rootDir (Sandbox)
57
+ super({ rootDir, virtualMode: true });
58
+ // 1. AQUI AGREGAMOS LA ASIGNACIÓN QUE FALTABA
59
+ this.rootDir = rootDir;
60
+ this.backupDir = path.join(rootDir, '.agent', 'backups');
61
+ if (!fs.existsSync(this.backupDir)) {
62
+ fs.mkdirSync(this.backupDir, { recursive: true });
63
+ }
64
+ }
65
+ /**
66
+ * Sobrescribe la escritura nativa para inyectar el backup antes de modificar el archivo.
67
+ * * @param filePath - Ruta relativa del archivo a escribir.
68
+ * @param content - Nuevo contenido del archivo.
69
+ * @returns El resultado de la operación de escritura original.
70
+ */
71
+ async write(filePath, content) {
72
+ this.createBackup(filePath);
73
+ return super.write(filePath, content);
74
+ }
75
+ /**
76
+ * Sobrescribe la edición nativa para inyectar el backup antes de reemplazar texto.
77
+ * * @param filePath - Ruta relativa del archivo.
78
+ * @param oldString - Texto a buscar.
79
+ * @param newString - Texto de reemplazo.
80
+ * @param replaceAll - Si se deben reemplazar todas las ocurrencias.
81
+ * @returns El resultado de la operación de edición original.
82
+ */
83
+ async edit(filePath, oldString, newString, replaceAll = false) {
84
+ this.createBackup(filePath);
85
+ return super.edit(filePath, oldString, newString, replaceAll);
86
+ }
87
+ /**
88
+ * Genera una copia del archivo original con timestamp antes de ser modificado.
89
+ * Si el archivo no existe (es nuevo), no hace nada.
90
+ * * @param virtualPath - Ruta virtual (desde el punto de vista del agente) del archivo.
91
+ */
92
+ createBackup(virtualPath) {
93
+ try {
94
+ // Convertir ruta virtual (/src/...) a ruta real del sistema
95
+ const relativePath = virtualPath.startsWith('/')
96
+ ? virtualPath.slice(1)
97
+ : virtualPath;
98
+ // 2. AQUI AHORA FUNCIONA PORQUE YA DEFINIMOS this.rootDir
99
+ const realPath = path.join(this.rootDir, relativePath);
100
+ if (fs.existsSync(realPath)) {
101
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
102
+ const filename = path.basename(realPath);
103
+ const backupPath = path.join(this.backupDir, `${timestamp}_${filename}.bak`);
104
+ fs.copyFileSync(realPath, backupPath);
105
+ console.log(`💾 [SafeBackend] Backup creado: .agent/backups/${path.basename(backupPath)}`);
106
+ }
107
+ }
108
+ catch (error) {
109
+ console.error(`⚠️ [SafeBackend] Falló el backup (continuando escritura):`, error);
110
+ }
111
+ }
112
+ }
113
+ exports.SafeFilesystemBackend = SafeFilesystemBackend;
@@ -0,0 +1,8 @@
1
+ import { ChatVertexAI, VertexAIEmbeddings } from '@langchain/google-vertexai';
2
+ export declare class LLMProvider {
3
+ private static instance;
4
+ private constructor();
5
+ static getModel(): ChatVertexAI;
6
+ private static embeddingsInstance;
7
+ static getEmbeddingsModel(): VertexAIEmbeddings;
8
+ }