@dastbal/nestjs-ai-agent 1.0.1 → 1.0.3

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 CHANGED
@@ -1,116 +1,79 @@
1
- # Meet the NestJS Code Alchemist 🧙‍♂️
1
+ # @dastbal/nestjs-ai-agent 🧙‍♂️
2
+ ### Autonomous Principal Software Engineer for NestJS
2
3
 
3
- ![NestJS Logo](https://nestjs.com/img/logo-small.svg)
4
+ [![npm version](https://img.shields.io/npm/v/@dastbal/nestjs-ai-agent.svg)](https://www.npmjs.com/package/@dastbal/nestjs-ai-agent)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
 
7
+ Transform your NestJS development with an agent that doesn't just "chat", but **operates** directly on your codebase with Senior-level precision.
5
8
 
6
- # @dastbal/nestjs-ai-agent 🤖
9
+ ---
7
10
 
8
- Autonomous AI Agent acting as a **Principal Software Engineer** for NestJS projects.
11
+ ## 🚀 Quick Start
9
12
 
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
13
  ```bash
14
+ # Install the agent
18
15
  npm install @dastbal/nestjs-ai-agent
19
16
 
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.
17
+ # Run your first command
18
+ npx gen "Create a new Payments service with DDD patterns"
19
+ ```
51
20
 
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.
21
+ ---
56
22
 
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.
23
+ ## 💎 Key Features
61
24
 
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.
25
+ This agent operates with a strict set of principles and advanced capabilities:
65
26
 
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.
27
+ * **🔍 RAG Search:** Performs semantic search across your entire codebase before proposing changes, ensuring context-aware development.
28
+ * **🩺 The Surgeon Rule:** Never overwrites a file without reading and analyzing it first, preserving existing logic and intent.
29
+ * **✅ Self-Healing:** Runs integrity checks (TypeScript compiler) and attempts to auto-fix compilation errors (up to 3 retries).
30
+ * **💾 Safe Writes:** Automatically creates backups before any file modification, ensuring data safety.
31
+ * **🧠 SQLite Memory:** Remembers conversation threads and learned preferences across restarts using a local SQLite database.
32
+ * **🔐 Configuration:** Leverages Google Vertex AI. Requires a service account JSON file (`credentials_vertex.json`) in the root folder and specific environment variables.
70
33
 
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.
34
+ **Credentials File:** Place your Google Service Account JSON in the root folder and name it exactly `credentials_vertex.json`.
74
35
 
75
- 8. **Iteration and Refinement (🔄):**
76
- * I repeat these steps as needed, refining the code and ensuring it meets your requirements.
36
+ **Environment Variables:** Add the following to your `.env` file:
37
+ ```dotenv
38
+ GOOGLE_APPLICATION_CREDENTIALS="./credentials_vertex.json"
39
+ GCP_PROJECT_ID="your-project-id"
40
+ GCP_LOCATION="us-central1"
41
+ ```
42
+ **[CAUTION] Security First:** Always add `credentials_vertex.json` and `.env` to your `.gitignore` file to protect your credentials.
77
43
 
78
- 9. **Documentation (📝):**
79
- * I always strive to maintain and improve code documentation (TSDocs).
44
+ ---
80
45
 
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.
46
+ ## ⚙️ Internal Workflow
83
47
 
84
- ## Tools and Technologies
48
+ The agent follows a strict Principal Engineer protocol:
85
49
 
86
- I am built upon a foundation of powerful tools and technologies:
50
+ 1. **Research:** Uses `ask_codebase` to find existing patterns, logic, and dependencies.
51
+ 2. **Comprehension:** Reads existing code using `safe_read_file` to understand context and avoid regressions.
52
+ 3. **Implementation:** Writes new code adhering to DDD principles, strict TypeScript typing (no `any`), and TSDocs.
53
+ 4. **Validation:** Runs `run_integrity_check` (TypeScript compiler) immediately after implementation to ensure type safety.
54
+ 5. **Safety:** Creates backups before writing files using `safe_write_file`.
55
+ 6. **Human-in-the-loop:** Pauses for explicit approval before performing critical file operations or major changes.
87
56
 
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.
57
+ ---
94
58
 
95
- ## Safety and Quality
59
+ ## 💡 Usage Examples
96
60
 
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.
61
+ Try these commands to see the agent in action:
101
62
 
102
- ## How to Interact with Me
63
+ * **Scaffolding:** `"Create a UserEntity with email and password fields using TypeORM"`
64
+ * **Logic Implementation:** `"Add a validation pipe to the login DTO"`
65
+ * **Testing:** `"Write a unit test for the AuthService including mocks for the repository"`
66
+ * **Refactoring:** `"Standardize all HTTP exceptions in the users controller"`
67
+ * **Code Generation:** `"Generate a NestJS module for handling user authentication"`
103
68
 
104
- Simply provide me with clear instructions, and I will do my best to assist you. For example:
69
+ ---
105
70
 
106
- * "Add a new DTO for the User entity."
107
- * "Create a service to handle authentication."
108
- * "Write a unit test for the UserService."
71
+ ## 🧠 Learning & Adaptation
109
72
 
110
- I will guide you through the process, providing feedback and ensuring the code meets your requirements.
73
+ The agent learns from your feedback. If you provide a style correction or a new pattern, it stores this information in `.agent/memories/style-guide.txt` to ensure future code generation aligns with your preferences.
111
74
 
112
- ## Disclaimer
75
+ ---
113
76
 
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.
77
+ ## 📄 License
115
78
 
116
- ## Let's Build Something Amazing! ✨
79
+ This project is released under the MIT License. Build something amazing! ✨
package/dist/bin/cli.js CHANGED
@@ -61,10 +61,10 @@ program
61
61
  }
62
62
  log.sys("Inicializando Agente en modo CLI...");
63
63
  // El threadId puede ser fijo para sesiones de CLI o dinámico
64
- const threadId = "cli-user-session";
64
+ const threadId = "cli-user";
65
65
  const agent = await factory_1.AgentFactory.create(threadId);
66
66
  log.ai(`Procesando: "${instruction}"`);
67
- const response = await agent.invoke({ messages: [{ role: "user", content: instruction }] }, { configurable: { thread_id: threadId } });
67
+ const response = await agent.invoke({ messages: [{ role: "user", content: instruction }] }, { configurable: { thread_id: threadId }, recursionLimit: 50 });
68
68
  const lastMessage = response.messages[response.messages.length - 1];
69
69
  if (lastMessage && lastMessage.content) {
70
70
  console.log("\n" + chalk_1.default.green("--- RESPUESTA DEL AGENTE ---"));
@@ -42,14 +42,14 @@ const tools_1 = require("../tools/tools");
42
42
  const path = __importStar(require("path"));
43
43
  const fs = __importStar(require("fs"));
44
44
  class AgentFactory {
45
- static async create(threadId = 'cli-session') {
45
+ static async create(threadId = "cli-session") {
46
46
  const rootDir = process.cwd();
47
47
  // Configuración de directorios
48
- const agentDir = path.join(rootDir, '.agent');
48
+ const agentDir = path.join(rootDir, ".agent");
49
49
  if (!fs.existsSync(agentDir))
50
50
  fs.mkdirSync(agentDir, { recursive: true });
51
51
  // 1. Persistencia (Checkpointer)
52
- const dbPath = path.join(agentDir, 'history.db');
52
+ const dbPath = path.join(agentDir, "history.db");
53
53
  const checkpointer = langgraph_checkpoint_sqlite_1.SqliteSaver.fromConnString(dbPath);
54
54
  // 2. Store (Opcional en createAgent, pero lo mantenemos por si lo usas en el runtime)
55
55
  const memoryStore = new langgraph_checkpoint_1.InMemoryStore();
@@ -85,7 +85,7 @@ Typing: Strict TypeScript. The use of any is FORBIDDEN.
85
85
 
86
86
  ⚙️ EXECUTION PROTOCOL:
87
87
 
88
-
88
+ - You operate on a NestJS project. The root directory is: ${process.cwd()}
89
89
  RESEARCH (ask_codebase): BEFORE touching anything, search for existing patterns in the project.
90
90
 
91
91
  Example: "Search for UserEntity before creating a related DTO."
@@ -113,13 +113,14 @@ NOTE ON INDEXING:
113
113
  - If 'ask_codebase' fails to find recent changes, use 'refresh_project_index'.
114
114
 
115
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.
116
+ - Use RELATIVE PATHS for all file operations.
117
+ - All source code is inside the 'src' folder (e.g., 'src/app.module.ts').
118
+ - DO NOT use the '/project/' prefix anymore. Just use the path relative to the root.
119
+
120
+ 🔍 EXAMPLE:
121
+ - Correct: safe_write_file('src/calculator/calculator.controller.ts', '...')
122
+ - Incorrect: safe_write_file('/project/src/...', '...')
120
123
 
121
- ALWAYS use the '/project/' prefix when reading or writing source code.
122
- Example: write_file('/project/src/app.service.ts', '...')
123
124
  🔍 CODE REFINEMENT & INTEGRITY (THE SURGEON'S RULE):
124
125
 
125
126
  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.
@@ -1,4 +1,12 @@
1
1
  import { z } from 'zod';
2
+ /**
3
+ * Tool for safely writing content to a file on the real disk.
4
+ * It creates a backup before writing and then triggers a project re-indexing.
5
+ * @param {object} params - The parameters for the tool.
6
+ * @param {string} params.filePath - The relative path where the file should be saved.
7
+ * @param {string} params.content - The content to write to the file.
8
+ * @returns {Promise<string>} A message indicating success or failure.
9
+ */
2
10
  export declare const safeWriteFileTool: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
3
11
  filePath: z.ZodString;
4
12
  content: z.ZodString;
@@ -9,6 +17,12 @@ export declare const safeWriteFileTool: import("@langchain/core/tools").DynamicS
9
17
  filePath: string;
10
18
  content: string;
11
19
  }, string, "safe_write_file">;
20
+ /**
21
+ * Tool for safely reading the content of a file from the real disk.
22
+ * @param {object} params - The parameters for the tool.
23
+ * @param {string} params.filePath - The relative path of the file to read.
24
+ * @returns {Promise<string>} The content of the file, or an error message if reading fails.
25
+ */
12
26
  export declare const safeReadFileTool: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
13
27
  filePath: z.ZodString;
14
28
  }, z.core.$strip>, {
@@ -17,8 +31,11 @@ export declare const safeReadFileTool: import("@langchain/core/tools").DynamicSt
17
31
  filePath: string;
18
32
  }, string, "safe_read_file">;
19
33
  /**
20
- * 🔍 TOOL: Ask Codebase (Semantic & Graph Search)
21
- * This is the Agent's "Eyes". It retrieves code + context.
34
+ * Tool to query the codebase using semantic search and dependency graph analysis.
35
+ * It's the primary way for the agent to explore and understand the project structure and logic.
36
+ * @param {object} params - The parameters for the tool.
37
+ * @param {string} params.query - A natural language query describing the code or functionality to find.
38
+ * @returns {Promise<string>} A report containing relevant code snippets, file paths, and dependencies.
22
39
  */
23
40
  export declare const askCodebaseTool: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
24
41
  query: z.ZodString;
@@ -28,15 +45,15 @@ export declare const askCodebaseTool: import("@langchain/core/tools").DynamicStr
28
45
  query: string;
29
46
  }, string, "ask_codebase">;
30
47
  /**
31
- * TOOL: Integrity Check (Compiler)
32
- * Validates the project state using TypeScript compiler.
48
+ * Tool to run the TypeScript compiler (tsc) for type checking.
49
+ * This is crucial for maintaining code quality and catching errors early.
50
+ * @returns {Promise<string>} A message indicating whether the integrity check passed or failed, including compiler output on failure.
33
51
  */
34
52
  export declare const integrityCheckTool: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, z.core.$strip>, Record<string, never>, Record<string, never>, string, "run_integrity_check">;
35
53
  /**
36
- * Maintenance tool to update the vector knowledge base.
37
- * * This tool forces a re-read and vectorization of the project files.
38
- * It is useful for ensuring the LLM has access to the most recent code changes
39
- * that may not have been synchronized automatically.
40
- * * @returns {Promise<string>} A confirmation message or error details.
54
+ * Tool to refresh the project's index, forcing a re-scan and re-vectorization of all files.
55
+ * This is useful when the agent needs to be absolutely sure it's working with the latest code,
56
+ * especially after significant changes or if the automatic indexing seems to be lagging.
57
+ * @returns {Promise<string>} A confirmation message or details about any errors encountered during indexing.
41
58
  */
42
59
  export declare const refreshIndexTool: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, z.core.$strip>, Record<string, never>, Record<string, never>, string, "refresh_project_index">;
@@ -52,41 +52,79 @@ const log = {
52
52
  tool: (msg) => console.log(chalk_1.default.yellow('🛠️ [TOOL]: ') + msg),
53
53
  sys: (msg) => console.log(chalk_1.default.gray('⚙️ [SYS]: ') + msg),
54
54
  error: (msg) => console.log(chalk_1.default.red('❌ [ERR]: ') + msg),
55
+ debug: (msg) => console.log(chalk_1.default.magenta('🐛 [DEBUG]: ') + msg), // Added for debugging
55
56
  };
56
57
  /**
57
- * 💾 Genera un backup antes de modificar un archivo real.
58
+ * Creates a backup of a file before it is modified.
59
+ * The backup is stored in the .agent/backups directory with a timestamp.
60
+ * @param {string} filePath - The relative path of the file to back up.
58
61
  */
59
62
  const createBackup = (filePath) => {
63
+ log.debug(`Starting backup process for file: ${filePath}`);
60
64
  const rootDir = process.cwd();
61
65
  const backupDir = path.join(rootDir, '.agent', 'backups');
62
- if (!fs.existsSync(backupDir))
66
+ log.debug(`Backup directory resolved to: ${backupDir}`);
67
+ if (!fs.existsSync(backupDir)) {
68
+ log.debug(`Backup directory does not exist. Creating: ${backupDir}`);
63
69
  fs.mkdirSync(backupDir, { recursive: true });
70
+ }
64
71
  const realPath = path.resolve(rootDir, filePath);
72
+ log.debug(`Resolved real path for backup: ${realPath}`);
65
73
  if (fs.existsSync(realPath)) {
66
74
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
67
75
  const filename = path.basename(realPath);
68
76
  const backupPath = path.join(backupDir, `${timestamp}_${filename}.bak`);
77
+ log.debug(`Attempting to copy ${realPath} to ${backupPath}`);
69
78
  fs.copyFileSync(realPath, backupPath);
79
+ log.sys(`Backup created for ${filePath} at ${backupPath}`);
80
+ }
81
+ else {
82
+ log.debug(`File does not exist, no backup needed: ${realPath}`);
70
83
  }
71
84
  };
85
+ /**
86
+ * Tool for safely writing content to a file on the real disk.
87
+ * It creates a backup before writing and then triggers a project re-indexing.
88
+ * @param {object} params - The parameters for the tool.
89
+ * @param {string} params.filePath - The relative path where the file should be saved.
90
+ * @param {string} params.content - The content to write to the file.
91
+ * @returns {Promise<string>} A message indicating success or failure.
92
+ */
72
93
  exports.safeWriteFileTool = (0, tools_1.tool)(async ({ filePath, content }) => {
94
+ log.debug(`safe_write_file called with filePath: ${filePath}`);
73
95
  try {
74
96
  const rootDir = process.cwd();
97
+ log.debug(`Current working directory: ${rootDir}`);
75
98
  const targetPath = path.resolve(rootDir, filePath);
76
- if (!targetPath.startsWith(rootDir))
77
- return '❌ Error: Access denied.';
99
+ log.debug(`Resolved target path: ${targetPath}`);
100
+ // Security check: Ensure the path is within the project root
101
+ if (!targetPath.startsWith(rootDir)) {
102
+ log.error(`Attempted write outside root directory: ${filePath}. Resolved path: ${targetPath}`);
103
+ return '❌ Error: Access denied. Cannot write outside the project root.';
104
+ }
78
105
  const dir = path.dirname(targetPath);
79
- if (!fs.existsSync(dir))
106
+ log.debug(`Directory for target path: ${dir}`);
107
+ if (!fs.existsSync(dir)) {
108
+ log.debug(`Directory does not exist. Creating: ${dir}`);
80
109
  fs.mkdirSync(dir, { recursive: true });
81
- createBackup(filePath); // Tu lógica de backup
110
+ log.sys(`Created directory: ${dir}`);
111
+ }
112
+ createBackup(filePath); // Create backup before writing
113
+ log.debug(`Writing content to file: ${targetPath}`);
82
114
  fs.writeFileSync(targetPath, content, 'utf-8');
83
- log.sys(`Indexando cambio en: ${filePath}`);
115
+ log.sys(`File saved to REAL DISK: ${filePath}`);
116
+ // Trigger re-indexing after a successful write
117
+ log.sys(`Initiating re-index for: ${filePath}`);
84
118
  const indexer = new indexer_1.IndexerService();
85
- indexer.indexProject().catch((err) => log.error(` ${err.message}`));
119
+ // Run indexing asynchronously, log errors but don't block the write confirmation
120
+ indexer.indexProject().catch((err) => {
121
+ log.error(`Failed to re-index after write for ${filePath}: ${err.message}`);
122
+ });
86
123
  return `✅ File saved to REAL DISK: ${filePath}`;
87
124
  }
88
125
  catch (error) {
89
- return `❌ Error: ${error.message}`;
126
+ log.error(`Failed to write file ${filePath}: ${error.message}`);
127
+ return `❌ Error writing file: ${error.message}`;
90
128
  }
91
129
  }, {
92
130
  name: 'safe_write_file',
@@ -96,17 +134,36 @@ exports.safeWriteFileTool = (0, tools_1.tool)(async ({ filePath, content }) => {
96
134
  content: zod_1.z.string().describe('Full file content'),
97
135
  }),
98
136
  });
99
- // --- TOOL 2: READ FILE (Manual) ---
137
+ /**
138
+ * Tool for safely reading the content of a file from the real disk.
139
+ * @param {object} params - The parameters for the tool.
140
+ * @param {string} params.filePath - The relative path of the file to read.
141
+ * @returns {Promise<string>} The content of the file, or an error message if reading fails.
142
+ */
100
143
  exports.safeReadFileTool = (0, tools_1.tool)(async ({ filePath }) => {
144
+ log.debug(`safe_read_file called with filePath: ${filePath}`);
101
145
  try {
102
146
  const rootDir = process.cwd();
147
+ log.debug(`Current working directory: ${rootDir}`);
103
148
  const targetPath = path.resolve(rootDir, filePath);
104
- if (!fs.existsSync(targetPath))
105
- return '❌ File not found.';
106
- return fs.readFileSync(targetPath, 'utf-8');
149
+ log.debug(`Resolved target path: ${targetPath}`);
150
+ // Security check: Ensure the path is within the project root
151
+ if (!fs.existsSync(targetPath)) {
152
+ log.error(`File not found for reading: ${filePath}. Resolved path: ${targetPath}`);
153
+ return `❌ File not found: ${filePath}`;
154
+ }
155
+ if (!targetPath.startsWith(rootDir)) {
156
+ log.error(`Attempted read outside root directory: ${filePath}. Resolved path: ${targetPath}`);
157
+ return '❌ Error: Access denied. Cannot read outside the project root.';
158
+ }
159
+ log.debug(`Reading file content from: ${targetPath}`);
160
+ const content = fs.readFileSync(targetPath, 'utf-8');
161
+ log.sys(`File read successfully: ${filePath}`);
162
+ return content;
107
163
  }
108
164
  catch (e) {
109
- return `Error: ${e.message}`;
165
+ log.error(`Failed to read file ${filePath}: ${e.message}`);
166
+ return `❌ Error reading file: ${e.message}`;
110
167
  }
111
168
  }, {
112
169
  name: 'safe_read_file',
@@ -114,18 +171,27 @@ exports.safeReadFileTool = (0, tools_1.tool)(async ({ filePath }) => {
114
171
  schema: zod_1.z.object({ filePath: zod_1.z.string() }),
115
172
  });
116
173
  /**
117
- * 🔍 TOOL: Ask Codebase (Semantic & Graph Search)
118
- * This is the Agent's "Eyes". It retrieves code + context.
174
+ * Tool to query the codebase using semantic search and dependency graph analysis.
175
+ * It's the primary way for the agent to explore and understand the project structure and logic.
176
+ * @param {object} params - The parameters for the tool.
177
+ * @param {string} params.query - A natural language query describing the code or functionality to find.
178
+ * @returns {Promise<string>} A report containing relevant code snippets, file paths, and dependencies.
119
179
  */
120
180
  exports.askCodebaseTool = (0, tools_1.tool)(async ({ query }) => {
181
+ log.debug(`ask_codebase called with query: "${query}"`);
121
182
  try {
122
- // We assume the streaming UI handles the 'Thinking...' log via the framework events
183
+ log.tool(`Querying codebase: "${query}"`);
123
184
  const retriever = new retriever_1.RetrieverService();
185
+ log.debug('RetrieverService instantiated.');
124
186
  const context = await retriever.getContextForLLM(query);
187
+ log.tool(`Codebase query complete for: "${query}"`);
188
+ log.debug(`Context retrieved for query "${query}".`);
125
189
  return context;
126
190
  }
127
191
  catch (error) {
128
- return `❌ Error querying codebase: ${error}`;
192
+ const errorMessage = error instanceof Error ? error.message : String(error);
193
+ log.error(`Error during codebase query "${query}": ${errorMessage}`);
194
+ return `❌ Error querying codebase: ${errorMessage}`;
129
195
  }
130
196
  }, {
131
197
  name: 'ask_codebase',
@@ -141,20 +207,32 @@ exports.askCodebaseTool = (0, tools_1.tool)(async ({ query }) => {
141
207
  }),
142
208
  });
143
209
  /**
144
- * TOOL: Integrity Check (Compiler)
145
- * Validates the project state using TypeScript compiler.
210
+ * Tool to run the TypeScript compiler (tsc) for type checking.
211
+ * This is crucial for maintaining code quality and catching errors early.
212
+ * @returns {Promise<string>} A message indicating whether the integrity check passed or failed, including compiler output on failure.
146
213
  */
147
214
  exports.integrityCheckTool = (0, tools_1.tool)(async () => {
215
+ const rootDir = process.cwd();
216
+ log.tool('Running TypeScript integrity check...');
217
+ log.debug(`Integrity check running in directory: ${rootDir}`);
148
218
  try {
149
- const rootDir = process.cwd();
150
- // 'tsc --noEmit' checks types without generating JS files. Fast and safe.
151
- const { stdout } = await execAsync('npx tsc --noEmit', { cwd: rootDir });
152
- console.log('INTEGRITY CHECK PASSED.', rootDir, stdout);
219
+ // 'tsc --noEmit' checks types without generating JS files. It's fast and safe.
220
+ log.debug('Executing command: npx tsc --noEmit');
221
+ const { stdout, stderr } = await execAsync('npx tsc --noEmit', { cwd: rootDir });
222
+ if (stderr) {
223
+ // Log stderr as an error even if stdout indicates success, as tsc might output warnings here
224
+ log.error(`TypeScript integrity check produced stderr output:\n${stderr}`);
225
+ }
226
+ log.tool('TypeScript integrity check PASSED.');
227
+ log.debug(`Integrity check stdout:\n${stdout}`);
228
+ // Include stdout in the success message for completeness, though it's usually empty on success.
153
229
  return `✅ INTEGRITY CHECK PASSED. The codebase is strictly typed and compiles correctly.\n${stdout}`;
154
230
  }
155
231
  catch (error) {
156
- // Return the exact compiler error so the agent can fix it
157
- return `❌ INTEGRITY CHECK FAILED. You must fix these TypeScript errors before finishing:\n${error.stdout || error.message}`;
232
+ // Return the exact compiler error output so the agent can attempt to fix it
233
+ const errorMessage = error.stdout || error.stderr || error.message || 'Unknown error';
234
+ log.error(`TypeScript integrity check FAILED.\n${errorMessage}`);
235
+ return `❌ INTEGRITY CHECK FAILED. You must fix these TypeScript errors before finishing:\n${errorMessage}`;
158
236
  }
159
237
  }, {
160
238
  name: 'run_integrity_check',
@@ -163,30 +241,31 @@ exports.integrityCheckTool = (0, tools_1.tool)(async () => {
163
241
  schema: zod_1.z.object({}),
164
242
  });
165
243
  /**
166
- * Maintenance tool to update the vector knowledge base.
167
- * * This tool forces a re-read and vectorization of the project files.
168
- * It is useful for ensuring the LLM has access to the most recent code changes
169
- * that may not have been synchronized automatically.
170
- * * @returns {Promise<string>} A confirmation message or error details.
244
+ * Tool to refresh the project's index, forcing a re-scan and re-vectorization of all files.
245
+ * This is useful when the agent needs to be absolutely sure it's working with the latest code,
246
+ * especially after significant changes or if the automatic indexing seems to be lagging.
247
+ * @returns {Promise<string>} A confirmation message or details about any errors encountered during indexing.
171
248
  */
172
249
  exports.refreshIndexTool = (0, tools_1.tool)(async () => {
173
250
  log.sys('🔄 Starting full project re-indexing...');
174
251
  try {
175
- // Start the expensive operation
176
252
  const indexer = new indexer_1.IndexerService();
177
- indexer.indexProject().catch((err) => log.error(` ${err.message}`));
253
+ log.debug('IndexerService instantiated.');
254
+ // Execute the indexing process.
255
+ await indexer.indexProject(); // Await the completion of the indexing process
178
256
  log.sys('✅ Re-indexing completed successfully.');
257
+ log.debug('Project re-indexing process finished.');
179
258
  return '✅ Index successfully updated. I now have access to the latest code version.';
180
259
  }
181
260
  catch (error) {
182
- // Safe error handling in TypeScript
261
+ // Provide a detailed error message if indexing fails.
183
262
  const errorMessage = error instanceof Error ? error.message : String(error);
184
263
  log.error(`❌ Indexing failed: ${errorMessage}`);
264
+ log.debug(`Error details during indexing: ${errorMessage}`);
185
265
  return `❌ Critical error while attempting to index the project: ${errorMessage}. Please try again or check the logs.`;
186
266
  }
187
267
  }, {
188
268
  name: 'refresh_project_index',
189
- // CRITICAL IMPROVEMENT: Instruction-oriented description for the LLM
190
269
  description: 'Triggers a forced, full re-indexing of the project codebase. That fucntion is optimazed only index changes comparing hash' +
191
270
  'USE THIS TOOL ONLY WHEN: ' +
192
271
  '1) The user explicitly states that files have changed. ' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dastbal/nestjs-ai-agent",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Autonomous AI Agent for NestJS - Principal Software Engineer Level with RAG and SQLite persistence",
5
5
  "author": "David Balladares",
6
6
  "license": "MIT",