agdi 2.5.0 → 2.6.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 CHANGED
@@ -19,7 +19,7 @@
19
19
  [![Node.js](https://img.shields.io/badge/Node.js-18+-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org/)
20
20
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.4-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
21
21
 
22
- **Build full-stack apps from natural language • AI-powered Git workflow • Enterprise-grade security**
22
+ **Build full-stack apps from natural language • Multi-Agent AI Codebase RAG • Enterprise Security**
23
23
 
24
24
  [Website](https://agdi-dev.vercel.app) · [npm](https://www.npmjs.com/package/agdi) · [GitHub](https://github.com/anassagd432/Agdi-dev)
25
25
 
@@ -27,6 +27,71 @@
27
27
 
28
28
  ---
29
29
 
30
+ ## 🚀 What's New in v2.6
31
+
32
+ <table>
33
+ <tr>
34
+ <td width="50%">
35
+
36
+ ### 🤖 Multi-Agent System
37
+ Planner → Coder → Reviewer pipeline. Your code is reviewed by AI before delivery.
38
+
39
+ ```bash
40
+ → /agent
41
+ 🤖 Multi-agent mode: ON
42
+ Planner → Coder → Reviewer pipeline enabled
43
+ ```
44
+
45
+ </td>
46
+ <td width="50%">
47
+
48
+ ### 🔍 Codebase RAG
49
+ Index and search your entire project semantically. The AI understands your code.
50
+
51
+ ```bash
52
+ → /index
53
+ ✓ Indexed 47 files, 312 chunks
54
+
55
+ → /search authentication
56
+ 🔍 src/auth/login.ts:15 (0.87)
57
+ ```
58
+
59
+ </td>
60
+ </tr>
61
+ <tr>
62
+ <td width="50%">
63
+
64
+ ### 🔧 MCP Tool Integration
65
+ Model Context Protocol for standardized AI tool calls.
66
+
67
+ ```bash
68
+ → /tools
69
+ 🔧 Available Tools
70
+ read_file [filesystem]
71
+ list_dir [filesystem]
72
+ search_code [code]
73
+ ```
74
+
75
+ </td>
76
+ <td width="50%">
77
+
78
+ ### 🧠 Persistent Memory
79
+ AI remembers your preferences and project context across sessions.
80
+
81
+ ```bash
82
+ → /memory
83
+ 🧠 Memory Stats
84
+ Total entries: 12
85
+ Projects: 3
86
+ Preferences: 5
87
+ ```
88
+
89
+ </td>
90
+ </tr>
91
+ </table>
92
+
93
+ ---
94
+
30
95
  ## ⚡ Quick Start
31
96
 
32
97
  ```bash
@@ -50,13 +115,25 @@ $ agdi
50
115
 
51
116
  Model: gemini-2.5-flash
52
117
  Workspace: ~/projects/my-app
53
- Commands: /status, /diff, /commit, /build, /clear, /history, /model, /help, /exit
118
+ Commands: /status, /diff, /commit, /build, /index, /search, /agent, /help, /exit
54
119
 
55
120
  ──────────────────────────────────────────────────
56
121
 
122
+ → /agent
123
+ 🤖 Multi-agent mode: ON
124
+
57
125
  → create a todo app with dark mode and local storage
58
126
 
59
- Generating action plan...
127
+ 📋 Phase 1: Planning...
128
+ ✓ Plan created
129
+
130
+ 💻 Phase 2: Coding...
131
+ ✓ Code generated
132
+
133
+ 🔍 Phase 3: Review (iteration 1)...
134
+ ✓ Code approved!
135
+
136
+ ✅ Multi-Agent Pipeline Complete
60
137
 
61
138
  📋 Action Plan - todo-app
62
139
  ─────────────────────────
@@ -80,7 +157,8 @@ Generating action plan...
80
157
  ### 🤖 AI-Powered Development
81
158
  - **Natural language to code** — Describe what you want, get production-ready apps
82
159
  - **Conversation memory** — AI remembers context across messages
83
- - **Multi-turn chat** — Iterative development with full context
160
+ - **Multi-agent mode** — Planner, Coder, Reviewer pipeline
161
+ - **Codebase RAG** — AI understands your entire project
84
162
 
85
163
  </td>
86
164
  <td width="50%">
@@ -107,9 +185,10 @@ Generating action plan...
107
185
  ### 🌐 Multi-Provider AI
108
186
  - **Gemini** — Free tier, fast responses
109
187
  - **OpenRouter** — 400+ models, one API
110
- - **OpenAI** — GPT-4o, o1 reasoning
111
- - **Anthropic** — Claude 3.5 Sonnet
188
+ - **OpenAI** — GPT-4o, o3 reasoning
189
+ - **Anthropic** — Claude 4.5 Sonnet
112
190
  - **DeepSeek** — R1, V3 models
191
+ - **Puter** — 100% free, no key needed
113
192
 
114
193
  </td>
115
194
  </tr>
@@ -131,6 +210,11 @@ Inside the session:
131
210
  |---------|-------------|
132
211
  | `/build <prompt>` | Generate & execute an app from description |
133
212
  | `/edit <file>` | AI-powered surgical file editing |
213
+ | `/index` | 🆕 Index current project for RAG search |
214
+ | `/search <query>` | 🆕 Semantic code search |
215
+ | `/tools` | 🆕 List available MCP tools |
216
+ | `/agent` | 🆕 Toggle multi-agent mode |
217
+ | `/memory` | 🆕 View persistent memory stats |
134
218
  | `/status` | AI analysis of git status |
135
219
  | `/diff` | AI explanation of current changes |
136
220
  | `/commit` | Auto-generate & run git commit |
@@ -153,6 +237,70 @@ agdi run [dir] # Run a generated project
153
237
 
154
238
  ---
155
239
 
240
+ ## 🤖 Multi-Agent Architecture (v2.6)
241
+
242
+ Enable with `/agent` for higher quality code:
243
+
244
+ ```
245
+ ┌──────────────────────────────────────────────────────────┐
246
+ │ User Request │
247
+ └─────────────────────────┬────────────────────────────────┘
248
+
249
+ ┌──────────────────────────────────────────────────────────┐
250
+ │ 📋 PLANNER AGENT │
251
+ │ Analyzes request, creates step-by-step implementation │
252
+ │ plan, identifies files to create/modify │
253
+ └─────────────────────────┬────────────────────────────────┘
254
+
255
+ ┌──────────────────────────────────────────────────────────┐
256
+ │ 💻 CODER AGENT │
257
+ │ Writes production-ready TypeScript/React code │
258
+ │ following the plan │
259
+ └─────────────────────────┬────────────────────────────────┘
260
+
261
+ ┌──────────────────────────────────────────────────────────┐
262
+ │ 🔍 REVIEWER AGENT │
263
+ │ Reviews for: │
264
+ │ • Correctness • Security • Performance • Completeness │
265
+ │ │
266
+ │ → APPROVED: Code delivered to user │
267
+ │ → NEEDS_CHANGES: Sent back to CODER (max 3 loops) │
268
+ └─────────────────────────┬────────────────────────────────┘
269
+
270
+ ┌──────────────────────────────────────────────────────────┐
271
+ │ ✅ High-Quality, Reviewed Code │
272
+ └──────────────────────────────────────────────────────────┘
273
+ ```
274
+
275
+ ---
276
+
277
+ ## 🔍 Codebase RAG (v2.6)
278
+
279
+ Index your project so AI can understand all your code:
280
+
281
+ ```bash
282
+ # Index your project (creates searchable chunks)
283
+ → /index
284
+ ✓ Indexed 47 files, 312 chunks
285
+
286
+ # Semantic search
287
+ → /search user authentication
288
+ 🔍 Search Results
289
+ src/auth/login.ts:15 (0.87)
290
+ export async function authenticateUser...
291
+ src/middleware/auth.ts:1 (0.65)
292
+ import { verifyToken } from...
293
+ src/hooks/useAuth.ts:5 (0.52)
294
+ const AuthContext = createContext...
295
+ ```
296
+
297
+ **How it works:**
298
+ 1. **Indexer** walks your project, chunks code by functions/classes
299
+ 2. **Retriever** uses TF-IDF semantic search (no external vector DB)
300
+ 3. **Context** is automatically injected into AI prompts
301
+
302
+ ---
303
+
156
304
  ## 🛡️ Security Architecture
157
305
 
158
306
  Agdi includes **zero-trust security** designed for safe AI-assisted development:
@@ -195,7 +343,7 @@ Real-time scanning detects:
195
343
  - **22+ secret patterns** — AWS, GitHub, OpenAI, Anthropic, Stripe, etc.
196
344
  - **Shell injection** — Dangerous command patterns
197
345
  - **Prompt injection** — LLM manipulation attempts
198
- - **Supply chain risks** — Suspicious package references
346
+ - **Network exfiltration** — Suspicious external requests
199
347
 
200
348
  ### 📊 Audit Logging
201
349
 
@@ -220,7 +368,6 @@ All decisions logged to `~/.agdi/audit.jsonl`:
220
368
  | Kimi K2 | `moonshotai/kimi-k2:free` | General purpose |
221
369
  | Gemma 3N E2B | `google/gemma-3n-e2b-it:free` | Lightweight |
222
370
  | LFM Thinking | `liquid/lfm-2.5-1.2b-thinking:free` | Agentic tasks |
223
- | Devstral ⚠️ | `mistralai/devstral-2512:free` | Ends Jan 27 |
224
371
 
225
372
  ### Image Generation
226
373
 
@@ -243,9 +390,9 @@ All decisions logged to `~/.agdi/audit.jsonl`:
243
390
  <td>
244
391
 
245
392
  **OpenRouter** 🌐
246
- - Claude 3.5 Sonnet
247
- - GPT-4o / 4o Mini
248
- - Llama 3.3 70B
393
+ - Claude 4.5 Sonnet
394
+ - GPT-5 / GPT-4o
395
+ - Llama 4 Maverick
249
396
  - DeepSeek R1
250
397
  - 400+ more
251
398
 
@@ -253,10 +400,10 @@ All decisions logged to `~/.agdi/audit.jsonl`:
253
400
  <td>
254
401
 
255
402
  **OpenAI** 🧠
403
+ - GPT-5
256
404
  - GPT-4o
257
- - GPT-4o Mini
405
+ - o3
258
406
  - o1
259
- - o1-mini
260
407
 
261
408
  </td>
262
409
  </tr>
@@ -264,15 +411,15 @@ All decisions logged to `~/.agdi/audit.jsonl`:
264
411
  <td>
265
412
 
266
413
  **Anthropic** 💜
414
+ - Claude 4.5 Sonnet
415
+ - Claude 4.5 Opus
267
416
  - Claude 3.5 Sonnet
268
- - Claude 3.5 Haiku
269
- - Claude 3 Opus
270
417
 
271
418
  </td>
272
419
  <td>
273
420
 
274
421
  **DeepSeek** 🌊
275
- - DeepSeek V3
422
+ - DeepSeek V3.2
276
423
  - DeepSeek R1 (Reasoning)
277
424
 
278
425
  </td>
@@ -300,6 +447,9 @@ Config stored in `~/.agdi/`:
300
447
  ├── config.json # API keys & settings
301
448
  ├── rules.json # Permission rules
302
449
  ├── trusted-workspaces.json # Trusted directories
450
+ ├── memory/ # 🆕 Persistent memory
451
+ │ └── store.json
452
+ ├── indexes/ # 🆕 RAG indexes
303
453
  └── audit.jsonl # Audit log
304
454
  ```
305
455
 
@@ -325,10 +475,14 @@ agdi auth --status
325
475
  <p>TypeScript Errors</p>
326
476
  </td>
327
477
  <td align="center">
328
- <h3>100</h3>
478
+ <h3>60</h3>
329
479
  <p>Tests Passing</p>
330
480
  </td>
331
481
  <td align="center">
482
+ <h3>148 KB</h3>
483
+ <p>Build Size</p>
484
+ </td>
485
+ <td align="center">
332
486
  <h3>22+</h3>
333
487
  <p>Security Patterns</p>
334
488
  </td>
@@ -344,14 +498,20 @@ agdi auth --status
344
498
  ## 🚀 Examples
345
499
 
346
500
  ```bash
347
- # Create a full-stack app
348
- agdi build "Create a blog with authentication and markdown support"
501
+ # Create a full-stack app (multi-agent recommended)
502
+ agdi
503
+ → /agent
504
+ → Create a blog with authentication and markdown support
349
505
 
350
- # Create a dashboard
351
- agdi build "Build an analytics dashboard with charts using Recharts"
506
+ # Semantic search your codebase
507
+ agdi
508
+ → /index
509
+ → /search payment processing
352
510
 
353
- # Create an API
354
- agdi build "Create a REST API with Express, Prisma, and PostgreSQL"
511
+ # AI-powered file editing
512
+ agdi
513
+ → /edit src/components/Header.tsx
514
+ "Add a dark mode toggle button"
355
515
 
356
516
  # Interactive development
357
517
  agdi
@@ -371,6 +531,7 @@ agdi
371
531
  - **Styling**: Chalk, Ora
372
532
  - **Build**: tsup
373
533
  - **Testing**: Vitest
534
+ - **AI**: Multi-agent, RAG, Token Optimization
374
535
 
375
536
  ---
376
537
 
@@ -0,0 +1,349 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/core/rag/indexer.ts
9
+ import { readFileSync, writeFileSync, existsSync, readdirSync, statSync, mkdirSync } from "fs";
10
+ import { join, extname, relative } from "path";
11
+ import { homedir } from "os";
12
+ import { createHash } from "crypto";
13
+ var INDEX_DIR = join(homedir(), ".agdi", "indexes");
14
+ var CHUNK_SIZE = 50;
15
+ var OVERLAP = 10;
16
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
17
+ ".ts",
18
+ ".tsx",
19
+ ".js",
20
+ ".jsx",
21
+ ".mjs",
22
+ ".cjs",
23
+ ".py",
24
+ ".rb",
25
+ ".go",
26
+ ".rs",
27
+ ".java",
28
+ ".kt",
29
+ ".c",
30
+ ".cpp",
31
+ ".h",
32
+ ".hpp",
33
+ ".cs",
34
+ ".json",
35
+ ".yaml",
36
+ ".yml",
37
+ ".toml",
38
+ ".md",
39
+ ".txt",
40
+ ".css",
41
+ ".scss",
42
+ ".html"
43
+ ]);
44
+ var IGNORE_DIRS = /* @__PURE__ */ new Set([
45
+ "node_modules",
46
+ ".git",
47
+ "dist",
48
+ "build",
49
+ ".next",
50
+ "__pycache__",
51
+ ".venv",
52
+ "venv",
53
+ "target",
54
+ ".idea",
55
+ ".vscode",
56
+ "coverage",
57
+ ".nyc_output"
58
+ ]);
59
+ var IGNORE_FILES = /* @__PURE__ */ new Set([
60
+ "package-lock.json",
61
+ "yarn.lock",
62
+ "pnpm-lock.yaml",
63
+ ".DS_Store",
64
+ "Thumbs.db"
65
+ ]);
66
+ function getLanguage(ext) {
67
+ const langMap = {
68
+ ".ts": "typescript",
69
+ ".tsx": "typescript",
70
+ ".js": "javascript",
71
+ ".jsx": "javascript",
72
+ ".mjs": "javascript",
73
+ ".py": "python",
74
+ ".rb": "ruby",
75
+ ".go": "go",
76
+ ".rs": "rust",
77
+ ".java": "java",
78
+ ".kt": "kotlin",
79
+ ".c": "c",
80
+ ".cpp": "cpp",
81
+ ".cs": "csharp",
82
+ ".json": "json",
83
+ ".yaml": "yaml",
84
+ ".yml": "yaml",
85
+ ".md": "markdown",
86
+ ".css": "css",
87
+ ".html": "html"
88
+ };
89
+ return langMap[ext] || "text";
90
+ }
91
+ function generateId(filePath, startLine) {
92
+ const hash = createHash("md5").update(`${filePath}:${startLine}`).digest("hex").slice(0, 8);
93
+ return `chunk_${hash}`;
94
+ }
95
+ function hashContent(content) {
96
+ return createHash("md5").update(content).digest("hex").slice(0, 12);
97
+ }
98
+ function detectChunkType(content, language) {
99
+ const firstLine = content.split("\n")[0].trim();
100
+ if (language === "typescript" || language === "javascript") {
101
+ if (/^(export\s+)?(async\s+)?function\s/.test(firstLine)) return "function";
102
+ if (/^(export\s+)?(abstract\s+)?class\s/.test(firstLine)) return "class";
103
+ if (/^(import|from)\s/.test(firstLine)) return "import";
104
+ if (/^export\s/.test(firstLine)) return "export";
105
+ }
106
+ if (language === "python") {
107
+ if (/^(async\s+)?def\s/.test(firstLine)) return "function";
108
+ if (/^class\s/.test(firstLine)) return "class";
109
+ if (/^(from|import)\s/.test(firstLine)) return "import";
110
+ }
111
+ if (/^(\/\/|\/\*|#|""")/.test(firstLine)) return "comment";
112
+ return "other";
113
+ }
114
+ function* walkDirectory(dir, basePath) {
115
+ const entries = readdirSync(dir, { withFileTypes: true });
116
+ for (const entry of entries) {
117
+ const fullPath = join(dir, entry.name);
118
+ if (entry.isDirectory()) {
119
+ if (!IGNORE_DIRS.has(entry.name)) {
120
+ yield* walkDirectory(fullPath, basePath);
121
+ }
122
+ } else if (entry.isFile()) {
123
+ if (!IGNORE_FILES.has(entry.name)) {
124
+ const ext = extname(entry.name).toLowerCase();
125
+ if (SUPPORTED_EXTENSIONS.has(ext)) {
126
+ yield fullPath;
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ function chunkFile(filePath, basePath) {
133
+ const content = readFileSync(filePath, "utf-8");
134
+ const lines = content.split("\n");
135
+ const ext = extname(filePath).toLowerCase();
136
+ const language = getLanguage(ext);
137
+ const relativePath = relative(basePath, filePath);
138
+ const chunks = [];
139
+ for (let i = 0; i < lines.length; i += CHUNK_SIZE - OVERLAP) {
140
+ const chunkLines = lines.slice(i, i + CHUNK_SIZE);
141
+ const chunkContent = chunkLines.join("\n");
142
+ if (chunkContent.trim().length === 0) continue;
143
+ chunks.push({
144
+ id: generateId(filePath, i),
145
+ filePath,
146
+ relativePath,
147
+ content: chunkContent,
148
+ startLine: i + 1,
149
+ endLine: Math.min(i + CHUNK_SIZE, lines.length),
150
+ type: detectChunkType(chunkContent, language),
151
+ language,
152
+ hash: hashContent(chunkContent)
153
+ });
154
+ }
155
+ return chunks;
156
+ }
157
+ function indexProject(projectPath) {
158
+ const startTime = Date.now();
159
+ const allChunks = [];
160
+ let fileCount = 0;
161
+ for (const filePath of walkDirectory(projectPath, projectPath)) {
162
+ try {
163
+ const stat = statSync(filePath);
164
+ if (stat.size > 1024 * 1024) continue;
165
+ const chunks = chunkFile(filePath, projectPath);
166
+ allChunks.push(...chunks);
167
+ fileCount++;
168
+ } catch {
169
+ }
170
+ }
171
+ const index = {
172
+ version: 1,
173
+ projectPath,
174
+ indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
175
+ fileCount,
176
+ chunkCount: allChunks.length,
177
+ chunks: allChunks
178
+ };
179
+ saveIndex(projectPath, index);
180
+ console.log(`Indexed ${fileCount} files, ${allChunks.length} chunks in ${Date.now() - startTime}ms`);
181
+ return index;
182
+ }
183
+ function getIndexPath(projectPath) {
184
+ const hash = createHash("md5").update(projectPath).digest("hex").slice(0, 12);
185
+ return join(INDEX_DIR, `${hash}.json`);
186
+ }
187
+ function saveIndex(projectPath, index) {
188
+ if (!existsSync(INDEX_DIR)) {
189
+ mkdirSync(INDEX_DIR, { recursive: true });
190
+ }
191
+ writeFileSync(getIndexPath(projectPath), JSON.stringify(index));
192
+ }
193
+ function loadIndex(projectPath) {
194
+ const indexPath = getIndexPath(projectPath);
195
+ if (!existsSync(indexPath)) return null;
196
+ try {
197
+ const data = readFileSync(indexPath, "utf-8");
198
+ return JSON.parse(data);
199
+ } catch {
200
+ return null;
201
+ }
202
+ }
203
+ function isIndexStale(index) {
204
+ const indexedAt = new Date(index.indexedAt).getTime();
205
+ const hourAgo = Date.now() - 60 * 60 * 1e3;
206
+ return indexedAt < hourAgo;
207
+ }
208
+
209
+ // src/core/rag/retriever.ts
210
+ function tokenize(text) {
211
+ return text.toLowerCase().replace(/[^a-z0-9_]/g, " ").split(/\s+/).filter((t) => t.length > 2);
212
+ }
213
+ function calculateTF(tokens) {
214
+ const tf = /* @__PURE__ */ new Map();
215
+ for (const token of tokens) {
216
+ tf.set(token, (tf.get(token) || 0) + 1);
217
+ }
218
+ const max = Math.max(...tf.values());
219
+ for (const [token, count] of tf) {
220
+ tf.set(token, count / max);
221
+ }
222
+ return tf;
223
+ }
224
+ function scoreChunk(chunk, queryTokens, queryTF) {
225
+ const chunkTokens = tokenize(chunk.content);
226
+ const chunkTF = calculateTF(chunkTokens);
227
+ let score = 0;
228
+ const matchedTokens = /* @__PURE__ */ new Set();
229
+ for (const queryToken of queryTokens) {
230
+ if (chunkTF.has(queryToken)) {
231
+ score += chunkTF.get(queryToken) * (queryTF.get(queryToken) || 1);
232
+ matchedTokens.add(queryToken);
233
+ }
234
+ for (const chunkToken of chunkTokens) {
235
+ if (chunkToken.startsWith(queryToken) || queryToken.startsWith(chunkToken)) {
236
+ if (!matchedTokens.has(queryToken)) {
237
+ score += 0.5 * (queryTF.get(queryToken) || 1);
238
+ matchedTokens.add(queryToken);
239
+ }
240
+ }
241
+ }
242
+ }
243
+ const pathTokens = tokenize(chunk.relativePath);
244
+ for (const queryToken of queryTokens) {
245
+ if (pathTokens.includes(queryToken)) {
246
+ score += 0.5;
247
+ }
248
+ }
249
+ if (chunk.type === "function" || chunk.type === "class") {
250
+ score *= 1.2;
251
+ }
252
+ score = score / Math.sqrt(queryTokens.length);
253
+ return score;
254
+ }
255
+ function extractHighlights(chunk, queryTokens) {
256
+ const lines = chunk.content.split("\n");
257
+ const highlights = [];
258
+ for (const line of lines) {
259
+ const lineLower = line.toLowerCase();
260
+ for (const token of queryTokens) {
261
+ if (lineLower.includes(token)) {
262
+ const trimmed = line.trim();
263
+ if (trimmed.length > 0 && !highlights.includes(trimmed)) {
264
+ highlights.push(trimmed.slice(0, 100));
265
+ break;
266
+ }
267
+ }
268
+ }
269
+ if (highlights.length >= 3) break;
270
+ }
271
+ return highlights;
272
+ }
273
+ function searchCodebase(projectPath, query, options = {}) {
274
+ const limit = options.limit ?? 10;
275
+ const minScore = options.minScore ?? 0.1;
276
+ const index = loadIndex(projectPath);
277
+ if (!index) {
278
+ console.warn("No index found. Run /index first.");
279
+ return [];
280
+ }
281
+ const queryTokens = tokenize(query);
282
+ if (queryTokens.length === 0) {
283
+ return [];
284
+ }
285
+ const queryTF = calculateTF(queryTokens);
286
+ const results = [];
287
+ for (const chunk of index.chunks) {
288
+ if (options.fileTypes && !options.fileTypes.includes(chunk.language)) {
289
+ continue;
290
+ }
291
+ if (options.chunkTypes && !options.chunkTypes.includes(chunk.type)) {
292
+ continue;
293
+ }
294
+ const score = scoreChunk(chunk, queryTokens, queryTF);
295
+ if (score >= minScore) {
296
+ results.push({
297
+ chunk,
298
+ score,
299
+ highlights: extractHighlights(chunk, queryTokens)
300
+ });
301
+ }
302
+ }
303
+ results.sort((a, b) => b.score - a.score);
304
+ return results.slice(0, limit);
305
+ }
306
+ function getRelevantContext(projectPath, prompt, maxChunks = 5) {
307
+ const results = searchCodebase(projectPath, prompt, { limit: maxChunks });
308
+ if (results.length === 0) {
309
+ return "";
310
+ }
311
+ const parts = ["[Relevant Code Context]"];
312
+ for (const result of results) {
313
+ parts.push(`
314
+ // ${result.chunk.relativePath}:${result.chunk.startLine}-${result.chunk.endLine}`);
315
+ parts.push("```" + result.chunk.language);
316
+ parts.push(result.chunk.content.slice(0, 500));
317
+ if (result.chunk.content.length > 500) {
318
+ parts.push("// ... (truncated)");
319
+ }
320
+ parts.push("```");
321
+ }
322
+ parts.push("[/Relevant Code Context]\n");
323
+ return parts.join("\n");
324
+ }
325
+ function findFiles(projectPath, pattern) {
326
+ const index = loadIndex(projectPath);
327
+ if (!index) return [];
328
+ const patternLower = pattern.toLowerCase();
329
+ const seen = /* @__PURE__ */ new Set();
330
+ const results = [];
331
+ for (const chunk of index.chunks) {
332
+ if (seen.has(chunk.filePath)) continue;
333
+ if (chunk.relativePath.toLowerCase().includes(patternLower)) {
334
+ seen.add(chunk.filePath);
335
+ results.push(chunk);
336
+ }
337
+ }
338
+ return results;
339
+ }
340
+
341
+ export {
342
+ __require,
343
+ indexProject,
344
+ loadIndex,
345
+ isIndexStale,
346
+ searchCodebase,
347
+ getRelevantContext,
348
+ findFiles
349
+ };
package/dist/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env node
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
2
+ import {
3
+ __require,
4
+ indexProject,
5
+ searchCodebase
6
+ } from "./chunk-NVMD3WL3.js";
8
7
 
9
8
  // src/index.ts
10
9
  import { Command } from "commander";
@@ -3915,7 +3914,174 @@ Generate the unified diff to make this change.`;
3915
3914
  }
3916
3915
  }
3917
3916
 
3917
+ // src/core/mcp/tools.ts
3918
+ var tools = /* @__PURE__ */ new Map();
3919
+ function registerTool(tool) {
3920
+ tools.set(tool.name, tool);
3921
+ }
3922
+ function listTools() {
3923
+ return Array.from(tools.values());
3924
+ }
3925
+ registerTool({
3926
+ name: "read_file",
3927
+ description: "Read the contents of a file",
3928
+ category: "filesystem",
3929
+ parameters: [
3930
+ { name: "path", type: "string", description: "File path to read", required: true }
3931
+ ],
3932
+ execute: async (params) => {
3933
+ const { readFileSync: readFileSync8 } = await import("fs");
3934
+ const { resolve: resolve5 } = await import("path");
3935
+ try {
3936
+ const filePath = resolve5(process.cwd(), params.path);
3937
+ const content = readFileSync8(filePath, "utf-8");
3938
+ return {
3939
+ success: true,
3940
+ data: content,
3941
+ display: `Read ${content.split("\n").length} lines from ${params.path}`
3942
+ };
3943
+ } catch (error) {
3944
+ return {
3945
+ success: false,
3946
+ error: `Failed to read file: ${error}`
3947
+ };
3948
+ }
3949
+ }
3950
+ });
3951
+ registerTool({
3952
+ name: "list_dir",
3953
+ description: "List files in a directory",
3954
+ category: "filesystem",
3955
+ parameters: [
3956
+ { name: "path", type: "string", description: "Directory path", required: false, default: "." }
3957
+ ],
3958
+ execute: async (params) => {
3959
+ const { readdirSync: readdirSync2, statSync: statSync2 } = await import("fs");
3960
+ const { resolve: resolve5, join: join8 } = await import("path");
3961
+ try {
3962
+ const dirPath = resolve5(process.cwd(), params.path || ".");
3963
+ const entries = readdirSync2(dirPath);
3964
+ const files = [];
3965
+ const dirs = [];
3966
+ for (const entry of entries) {
3967
+ try {
3968
+ const stat = statSync2(join8(dirPath, entry));
3969
+ if (stat.isDirectory()) {
3970
+ dirs.push(entry + "/");
3971
+ } else {
3972
+ files.push(entry);
3973
+ }
3974
+ } catch {
3975
+ files.push(entry);
3976
+ }
3977
+ }
3978
+ return {
3979
+ success: true,
3980
+ data: { dirs, files },
3981
+ display: `${dirs.length} directories, ${files.length} files`
3982
+ };
3983
+ } catch (error) {
3984
+ return {
3985
+ success: false,
3986
+ error: `Failed to list directory: ${error}`
3987
+ };
3988
+ }
3989
+ }
3990
+ });
3991
+ registerTool({
3992
+ name: "search_code",
3993
+ description: "Search for code in the current project",
3994
+ category: "code",
3995
+ parameters: [
3996
+ { name: "query", type: "string", description: "Search query", required: true },
3997
+ { name: "limit", type: "number", description: "Max results", required: false, default: 5 }
3998
+ ],
3999
+ execute: async (params) => {
4000
+ const { searchCodebase: searchCodebase2 } = await import("./rag-6HO4ZLBN.js");
4001
+ const results = searchCodebase2(
4002
+ process.cwd(),
4003
+ params.query,
4004
+ { limit: params.limit || 5 }
4005
+ );
4006
+ if (results.length === 0) {
4007
+ return {
4008
+ success: true,
4009
+ data: [],
4010
+ display: "No results found"
4011
+ };
4012
+ }
4013
+ const display = results.map(
4014
+ (r) => `${r.chunk.relativePath}:${r.chunk.startLine} (score: ${r.score.toFixed(2)})`
4015
+ ).join("\n");
4016
+ return {
4017
+ success: true,
4018
+ data: results.map((r) => ({
4019
+ file: r.chunk.relativePath,
4020
+ line: r.chunk.startLine,
4021
+ content: r.chunk.content.slice(0, 200)
4022
+ })),
4023
+ display
4024
+ };
4025
+ }
4026
+ });
4027
+ registerTool({
4028
+ name: "run_command",
4029
+ description: "Run a shell command (requires user approval)",
4030
+ category: "system",
4031
+ parameters: [
4032
+ { name: "command", type: "string", description: "Command to run", required: true }
4033
+ ],
4034
+ execute: async (params) => {
4035
+ return {
4036
+ success: false,
4037
+ error: "Shell commands require explicit user approval. Use /build or /exec instead."
4038
+ };
4039
+ }
4040
+ });
4041
+
4042
+ // src/core/memory-store.ts
4043
+ import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
4044
+ import { join as join7 } from "path";
4045
+ import { homedir as homedir6 } from "os";
4046
+ var MEMORY_DIR = join7(homedir6(), ".agdi", "memory");
4047
+ var MEMORY_FILE = join7(MEMORY_DIR, "store.json");
4048
+ function ensureMemoryDir() {
4049
+ if (!existsSync10(MEMORY_DIR)) {
4050
+ mkdirSync5(MEMORY_DIR, { recursive: true });
4051
+ }
4052
+ }
4053
+ function loadMemoryStore() {
4054
+ ensureMemoryDir();
4055
+ if (existsSync10(MEMORY_FILE)) {
4056
+ try {
4057
+ const data = readFileSync7(MEMORY_FILE, "utf-8");
4058
+ return JSON.parse(data);
4059
+ } catch {
4060
+ }
4061
+ }
4062
+ return {
4063
+ version: 1,
4064
+ entries: [],
4065
+ userPreferences: {},
4066
+ projectContexts: {}
4067
+ };
4068
+ }
4069
+ function getMemoryStats() {
4070
+ const store = loadMemoryStore();
4071
+ const byType = {};
4072
+ for (const entry of store.entries) {
4073
+ byType[entry.type] = (byType[entry.type] || 0) + 1;
4074
+ }
4075
+ return {
4076
+ totalEntries: store.entries.length,
4077
+ byType,
4078
+ projectCount: Object.keys(store.projectContexts).length,
4079
+ preferenceCount: Object.keys(store.userPreferences).length
4080
+ };
4081
+ }
4082
+
3918
4083
  // src/commands/agdi-dev.ts
4084
+ var multiAgentMode = false;
3919
4085
  var BASE_CHAT_PROMPT = `You are Agdi dev, an elite AI coding assistant. You help developers write code, debug issues, and build applications.
3920
4086
 
3921
4087
  ## Your Capabilities
@@ -4091,6 +4257,69 @@ async function startCodingMode() {
4091
4257
  }
4092
4258
  continue;
4093
4259
  }
4260
+ if (trimmed === "/index") {
4261
+ const spinner2 = ora4("Indexing project...").start();
4262
+ try {
4263
+ const index = indexProject(process.cwd());
4264
+ spinner2.succeed(`Indexed ${index.fileCount} files, ${index.chunkCount} chunks`);
4265
+ } catch (error) {
4266
+ spinner2.fail("Indexing failed: " + (error instanceof Error ? error.message : String(error)));
4267
+ }
4268
+ continue;
4269
+ }
4270
+ if (trimmed.startsWith("/search ")) {
4271
+ const query = userInput.slice(8).trim();
4272
+ if (!query) {
4273
+ console.log(chalk12.yellow("\nUsage: /search <query>\n"));
4274
+ continue;
4275
+ }
4276
+ const results = searchCodebase(process.cwd(), query, { limit: 8 });
4277
+ if (results.length === 0) {
4278
+ console.log(chalk12.gray("\nNo results found. Try /index first.\n"));
4279
+ } else {
4280
+ console.log(chalk12.cyan.bold("\n\u{1F50D} Search Results\n"));
4281
+ for (const r of results) {
4282
+ console.log(chalk12.green(` ${r.chunk.relativePath}:${r.chunk.startLine}`) + chalk12.gray(` (${r.score.toFixed(2)})`));
4283
+ if (r.highlights.length > 0) {
4284
+ console.log(chalk12.gray(` ${r.highlights[0].slice(0, 60)}...`));
4285
+ }
4286
+ }
4287
+ console.log("");
4288
+ }
4289
+ continue;
4290
+ }
4291
+ if (trimmed === "/tools") {
4292
+ const tools2 = listTools();
4293
+ console.log(chalk12.cyan.bold("\n\u{1F527} Available Tools\n"));
4294
+ for (const tool of tools2) {
4295
+ console.log(chalk12.green(` ${tool.name}`) + chalk12.gray(` [${tool.category}]`));
4296
+ console.log(chalk12.gray(` ${tool.description}`));
4297
+ }
4298
+ console.log("");
4299
+ continue;
4300
+ }
4301
+ if (trimmed === "/agent") {
4302
+ multiAgentMode = !multiAgentMode;
4303
+ console.log(chalk12.cyan(`
4304
+ \u{1F916} Multi-agent mode: ${multiAgentMode ? chalk12.green("ON") : chalk12.gray("OFF")}
4305
+ `));
4306
+ if (multiAgentMode) {
4307
+ console.log(chalk12.gray(" Planner \u2192 Coder \u2192 Reviewer pipeline enabled\n"));
4308
+ }
4309
+ continue;
4310
+ }
4311
+ if (trimmed === "/memory") {
4312
+ const stats = getMemoryStats();
4313
+ console.log(chalk12.cyan.bold("\n\u{1F9E0} Memory Stats\n"));
4314
+ console.log(chalk12.gray(` Total entries: ${stats.totalEntries}`));
4315
+ console.log(chalk12.gray(` Projects: ${stats.projectCount}`));
4316
+ console.log(chalk12.gray(` Preferences: ${stats.preferenceCount}`));
4317
+ for (const [type, count] of Object.entries(stats.byType)) {
4318
+ console.log(chalk12.gray(` ${type}: ${count}`));
4319
+ }
4320
+ console.log("");
4321
+ continue;
4322
+ }
4094
4323
  if (trimmed.startsWith("/build ") || trimmed.startsWith("build ")) {
4095
4324
  const prompt = userInput.replace(/^\/?build\s+/i, "").trim();
4096
4325
  if (prompt) {
@@ -4302,6 +4531,15 @@ function showHelp() {
4302
4531
  console.log(chalk12.gray(" /build ") + "Generate and execute an application");
4303
4532
  console.log(chalk12.gray(" /edit ") + "AI-powered surgical file editing");
4304
4533
  console.log("");
4534
+ console.log(chalk12.cyan(" RAG Commands:"));
4535
+ console.log(chalk12.gray(" /index ") + "Index current project for search");
4536
+ console.log(chalk12.gray(" /search ") + "Semantic code search");
4537
+ console.log("");
4538
+ console.log(chalk12.cyan(" Advanced:"));
4539
+ console.log(chalk12.gray(" /tools ") + "List available MCP tools");
4540
+ console.log(chalk12.gray(" /agent ") + "Toggle multi-agent mode");
4541
+ console.log(chalk12.gray(" /memory ") + "Show memory stats");
4542
+ console.log("");
4305
4543
  console.log(chalk12.cyan(" Conversation:"));
4306
4544
  console.log(chalk12.gray(" /clear ") + "Clear conversation history");
4307
4545
  console.log(chalk12.gray(" /history ") + "Show recent conversation");
@@ -4312,7 +4550,6 @@ function showHelp() {
4312
4550
  console.log(chalk12.gray(" /help ") + "Show this help");
4313
4551
  console.log(chalk12.gray(" /exit ") + "Exit Agdi");
4314
4552
  console.log(chalk12.gray("\n Or just type your coding question!\n"));
4315
- console.log(chalk12.gray('Tip: "Create a todo app" will generate & write files.\n'));
4316
4553
  }
4317
4554
  function handleError(error) {
4318
4555
  const msg = error instanceof Error ? error.message : String(error);
@@ -0,0 +1,16 @@
1
+ import {
2
+ findFiles,
3
+ getRelevantContext,
4
+ indexProject,
5
+ isIndexStale,
6
+ loadIndex,
7
+ searchCodebase
8
+ } from "./chunk-NVMD3WL3.js";
9
+ export {
10
+ findFiles,
11
+ getRelevantContext,
12
+ indexProject,
13
+ isIndexStale,
14
+ loadIndex,
15
+ searchCodebase
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdi",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "AI-powered app generator - build full-stack apps from natural language in your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -62,4 +62,4 @@
62
62
  "jszip": "^3.10.0",
63
63
  "ora": "^8.0.0"
64
64
  }
65
- }
65
+ }