hybard-agent 0.1.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/LICENSE +21 -0
- package/README.md +41 -0
- package/bin/.cmd +0 -0
- package/bin/agent.js +673 -0
- package/bin/cli.js +326 -0
- package/bin/hybard.cmd +2 -0
- package/knowledge/BENGALI_GUIDE.md +436 -0
- package/knowledge/CAPABILITIES.md +448 -0
- package/knowledge/INDEX.md +204 -0
- package/knowledge/KNOWLEDGE_BASE.md +1174 -0
- package/knowledge/README.md +97 -0
- package/knowledge/SYSTEM_PROMPT.md +310 -0
- package/lib/agent.js +730 -0
- package/lib/analyzer.js +330 -0
- package/lib/coding-agent.js +87 -0
- package/lib/coding-model.js +585 -0
- package/lib/engine.js +591 -0
- package/lib/hybard-agent.js +1063 -0
- package/lib/main.dart +32 -0
- package/lib/models.js +357 -0
- package/lib/online.js +654 -0
- package/lib/server.js +278 -0
- package/lib/ui.js +96 -0
- package/package.json +50 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybard Coding Model — LLM-powered code generation with context understanding.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* User Request → Tokenization → Context Building → LLM → Code Generation
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Multi-language support (Python, JS, TS, Dart, SQL, etc.)
|
|
9
|
+
* - Framework-aware code generation
|
|
10
|
+
* - Project context understanding
|
|
11
|
+
* - Error-aware code fixing
|
|
12
|
+
* - Bengali/English natural language to code
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { HybardAI } = require('./online');
|
|
18
|
+
const { ProjectDetector, CodebaseSearch } = require('./hybard-agent');
|
|
19
|
+
|
|
20
|
+
// ─── Language Configurations ────────────────────────────
|
|
21
|
+
|
|
22
|
+
const LANGUAGE_CONFIG = {
|
|
23
|
+
python: {
|
|
24
|
+
extensions: ['.py'],
|
|
25
|
+
frameworks: ['Django', 'Flask', 'FastAPI', 'PyTorch', 'TensorFlow'],
|
|
26
|
+
entryPoints: ['main.py', 'app.py', 'manage.py'],
|
|
27
|
+
fileTemplates: {
|
|
28
|
+
main: (name) => `def main():
|
|
29
|
+
print("Hello from ${name}")
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
main()
|
|
33
|
+
`,
|
|
34
|
+
test: (name) => `import pytest
|
|
35
|
+
|
|
36
|
+
def test_main():
|
|
37
|
+
assert True
|
|
38
|
+
`,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
javascript: {
|
|
42
|
+
extensions: ['.js', '.jsx'],
|
|
43
|
+
frameworks: ['React', 'Next.js', 'Express', 'Vue', 'Angular'],
|
|
44
|
+
entryPoints: ['index.js', 'src/index.js', 'src/main.js'],
|
|
45
|
+
fileTemplates: {
|
|
46
|
+
main: (name) => `console.log("Hello from ${name}");
|
|
47
|
+
`,
|
|
48
|
+
test: (name) => `describe('${name}', () => {
|
|
49
|
+
it('should work', () => {
|
|
50
|
+
expect(true).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
`,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
typescript: {
|
|
57
|
+
extensions: ['.ts', '.tsx'],
|
|
58
|
+
frameworks: ['React', 'Next.js', 'NestJS', 'Express'],
|
|
59
|
+
entryPoints: ['index.ts', 'src/index.ts', 'src/main.ts'],
|
|
60
|
+
fileTemplates: {
|
|
61
|
+
main: (name) => `console.log("Hello from ${name}");
|
|
62
|
+
`,
|
|
63
|
+
test: (name) => `import { describe, it, expect } from 'vitest';
|
|
64
|
+
|
|
65
|
+
describe('${name}', () => {
|
|
66
|
+
it('should work', () => {
|
|
67
|
+
expect(true).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
`,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
dart: {
|
|
74
|
+
extensions: ['.dart'],
|
|
75
|
+
frameworks: ['Flutter'],
|
|
76
|
+
entryPoints: ['lib/main.dart'],
|
|
77
|
+
fileTemplates: {
|
|
78
|
+
main: (name) => `import 'package:flutter/material.dart';
|
|
79
|
+
|
|
80
|
+
void main() {
|
|
81
|
+
runApp(const MyApp());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class MyApp extends StatelessWidget {
|
|
85
|
+
const MyApp({super.key});
|
|
86
|
+
|
|
87
|
+
@override
|
|
88
|
+
Widget build(BuildContext context) {
|
|
89
|
+
return MaterialApp(
|
|
90
|
+
title: '${name}',
|
|
91
|
+
theme: ThemeData(primarySwatch: Colors.blue),
|
|
92
|
+
home: const HomeScreen(),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
class HomeScreen extends StatelessWidget {
|
|
98
|
+
const HomeScreen({super.key});
|
|
99
|
+
|
|
100
|
+
@override
|
|
101
|
+
Widget build(BuildContext context) {
|
|
102
|
+
return Scaffold(
|
|
103
|
+
appBar: AppBar(title: const Text('${name}')),
|
|
104
|
+
body: const Center(
|
|
105
|
+
child: Text('Hello from ${name}'),
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
sql: {
|
|
114
|
+
extensions: ['.sql'],
|
|
115
|
+
frameworks: ['PostgreSQL', 'MySQL', 'SQLite'],
|
|
116
|
+
entryPoints: ['schema.sql', 'migrations/'],
|
|
117
|
+
fileTemplates: {
|
|
118
|
+
main: (name) => `-- ${name} Database Schema
|
|
119
|
+
CREATE TABLE users (
|
|
120
|
+
id SERIAL PRIMARY KEY,
|
|
121
|
+
username VARCHAR(50) UNIQUE NOT NULL,
|
|
122
|
+
email VARCHAR(100) UNIQUE NOT NULL,
|
|
123
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
124
|
+
);
|
|
125
|
+
`,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
html: {
|
|
129
|
+
extensions: ['.html'],
|
|
130
|
+
frameworks: ['Tailwind CSS', 'Bootstrap'],
|
|
131
|
+
entryPoints: ['index.html'],
|
|
132
|
+
fileTemplates: {
|
|
133
|
+
main: (name) => `<!DOCTYPE html>
|
|
134
|
+
<html lang="en">
|
|
135
|
+
<head>
|
|
136
|
+
<meta charset="UTF-8">
|
|
137
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
138
|
+
<title>${name}</title>
|
|
139
|
+
</head>
|
|
140
|
+
<body>
|
|
141
|
+
<h1>Hello from ${name}</h1>
|
|
142
|
+
</body>
|
|
143
|
+
</html>
|
|
144
|
+
`,
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
css: {
|
|
148
|
+
extensions: ['.css'],
|
|
149
|
+
frameworks: ['Tailwind CSS', 'Bootstrap'],
|
|
150
|
+
entryPoints: ['style.css'],
|
|
151
|
+
fileTemplates: {
|
|
152
|
+
main: (name) => `/* ${name} Styles */
|
|
153
|
+
* {
|
|
154
|
+
margin: 0;
|
|
155
|
+
padding: 0;
|
|
156
|
+
box-sizing: border-box;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
body {
|
|
160
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
161
|
+
}
|
|
162
|
+
`,
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// ─── Context Builder ────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
class ContextBuilder {
|
|
170
|
+
constructor(rootDir = process.cwd()) {
|
|
171
|
+
this.rootDir = rootDir;
|
|
172
|
+
this.detector = new ProjectDetector(rootDir);
|
|
173
|
+
this.searcher = new CodebaseSearch(rootDir);
|
|
174
|
+
this.projectInfo = null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
buildContext(userRequest) {
|
|
178
|
+
this.projectInfo = this.detector.detect();
|
|
179
|
+
|
|
180
|
+
let context = '';
|
|
181
|
+
|
|
182
|
+
// 1. Project Context
|
|
183
|
+
context += this.buildProjectContext();
|
|
184
|
+
|
|
185
|
+
// 2. Relevant Files (based on user request)
|
|
186
|
+
context += this.buildRelevantFilesContext(userRequest);
|
|
187
|
+
|
|
188
|
+
// 3. Framework Context
|
|
189
|
+
context += this.buildFrameworkContext();
|
|
190
|
+
|
|
191
|
+
// 4. Dependencies Context
|
|
192
|
+
context += this.buildDependenciesContext();
|
|
193
|
+
|
|
194
|
+
// 5. Documentation Context
|
|
195
|
+
context += this.buildDocumentationContext(userRequest);
|
|
196
|
+
|
|
197
|
+
return context;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
buildProjectContext() {
|
|
201
|
+
if (!this.projectInfo) return '';
|
|
202
|
+
|
|
203
|
+
let ctx = '\n=== PROJECT CONTEXT ===\n';
|
|
204
|
+
ctx += `Type: ${this.projectInfo.type}\n`;
|
|
205
|
+
ctx += `Languages: ${this.projectInfo.languages.join(', ')}\n`;
|
|
206
|
+
ctx += `Frameworks: ${this.projectInfo.frameworks.join(', ')}\n`;
|
|
207
|
+
ctx += `Entry Points: ${this.projectInfo.entryPoints.join(', ')}\n`;
|
|
208
|
+
ctx += `Config Files: ${this.projectInfo.configFiles.join(', ')}\n`;
|
|
209
|
+
return ctx;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
buildRelevantFilesContext(userRequest) {
|
|
213
|
+
const searchTerms = this.extractSearchTerms(userRequest);
|
|
214
|
+
if (searchTerms.length === 0) return '';
|
|
215
|
+
|
|
216
|
+
let ctx = '\n=== RELEVANT FILES ===\n';
|
|
217
|
+
for (const term of searchTerms.slice(0, 3)) {
|
|
218
|
+
const results = this.searcher.searchCode(term);
|
|
219
|
+
if (results.length > 0) {
|
|
220
|
+
ctx += `\nSearch "${term}":\n`;
|
|
221
|
+
for (const result of results.slice(0, 3)) {
|
|
222
|
+
ctx += ` ${result.file}:\n`;
|
|
223
|
+
for (const match of result.matches.slice(0, 2)) {
|
|
224
|
+
ctx += ` Line ${match.line}: ${match.content}\n`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return ctx;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
buildFrameworkContext() {
|
|
233
|
+
if (!this.projectInfo || this.projectInfo.frameworks.length === 0) return '';
|
|
234
|
+
|
|
235
|
+
let ctx = '\n=== FRAMEWORK CONTEXT ===\n';
|
|
236
|
+
for (const framework of this.projectInfo.frameworks) {
|
|
237
|
+
ctx += `Framework: ${framework}\n`;
|
|
238
|
+
ctx += ` - Use ${framework} patterns and conventions\n`;
|
|
239
|
+
ctx += ` - Follow ${framework} best practices\n`;
|
|
240
|
+
}
|
|
241
|
+
return ctx;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
buildDependenciesContext() {
|
|
245
|
+
if (!this.projectInfo) return '';
|
|
246
|
+
|
|
247
|
+
let ctx = '\n=== DEPENDENCIES ===\n';
|
|
248
|
+
const deps = this.projectInfo.dependencies;
|
|
249
|
+
|
|
250
|
+
if (deps.npm) {
|
|
251
|
+
ctx += 'npm packages:\n';
|
|
252
|
+
ctx += ` ${deps.npm.dependencies.slice(0, 10).join(', ')}\n`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (deps.pip) {
|
|
256
|
+
ctx += 'pip packages:\n';
|
|
257
|
+
ctx += ` ${deps.pip.slice(0, 10).join(', ')}\n`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return ctx;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
buildDocumentationContext(userRequest) {
|
|
264
|
+
const lower = userRequest.toLowerCase();
|
|
265
|
+
let ctx = '\n=== DOCUMENTATION CONTEXT ===\n';
|
|
266
|
+
|
|
267
|
+
// Add relevant documentation hints
|
|
268
|
+
if (lower.includes('flutter') || lower.includes('dart')) {
|
|
269
|
+
ctx += 'Flutter: Use Material Design, StatefulWidget for state, StatelessWidget for static UI.\n';
|
|
270
|
+
}
|
|
271
|
+
if (lower.includes('react') || lower.includes('next')) {
|
|
272
|
+
ctx += 'React: Use functional components with hooks, JSX syntax.\n';
|
|
273
|
+
}
|
|
274
|
+
if (lower.includes('fastapi') || lower.includes('python api')) {
|
|
275
|
+
ctx += 'FastAPI: Use async def, Pydantic models, dependency injection.\n';
|
|
276
|
+
}
|
|
277
|
+
if (lower.includes('express') || lower.includes('node')) {
|
|
278
|
+
ctx += 'Express: Use middleware pattern, req/res objects, router modules.\n';
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return ctx;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
extractSearchTerms(userRequest) {
|
|
285
|
+
const terms = [];
|
|
286
|
+
const words = userRequest.toLowerCase().split(/\s+/);
|
|
287
|
+
|
|
288
|
+
// Extract meaningful terms
|
|
289
|
+
const meaningfulWords = words.filter(w => w.length > 3 && !['this', 'that', 'with', 'from', 'have', 'will', 'should', 'would', 'could'].includes(w));
|
|
290
|
+
terms.push(...meaningfulWords.slice(0, 5));
|
|
291
|
+
|
|
292
|
+
return terms;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ─── Code Generator ─────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
class CodeGenerator {
|
|
299
|
+
constructor(ai) {
|
|
300
|
+
this.ai = ai;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async generate(userRequest, context = '', language = null) {
|
|
304
|
+
const detectedLanguage = language || this.detectLanguage(userRequest);
|
|
305
|
+
const langConfig = LANGUAGE_CONFIG[detectedLanguage] || LANGUAGE_CONFIG.javascript;
|
|
306
|
+
|
|
307
|
+
const systemPrompt = this.buildSystemPrompt(detectedLanguage, langConfig);
|
|
308
|
+
const fullPrompt = this.buildFullPrompt(userRequest, context, detectedLanguage);
|
|
309
|
+
|
|
310
|
+
const response = await this.ai.chat(fullPrompt, { system: systemPrompt });
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
response,
|
|
314
|
+
language: detectedLanguage,
|
|
315
|
+
codeBlocks: this.extractCodeBlocks(response),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
buildSystemPrompt(language, langConfig) {
|
|
320
|
+
return `You are Hybard AI Coding Model — an expert ${language} programmer.
|
|
321
|
+
|
|
322
|
+
LANGUAGE: ${language}
|
|
323
|
+
FRAMEWORKS: ${langConfig.frameworks.join(', ')}
|
|
324
|
+
|
|
325
|
+
RULES:
|
|
326
|
+
1. Generate clean, working, production-ready code
|
|
327
|
+
2. Follow ${language} best practices and conventions
|
|
328
|
+
3. Use proper error handling
|
|
329
|
+
4. Add comments only when necessary
|
|
330
|
+
5. Use meaningful variable and function names
|
|
331
|
+
6. Include type annotations where applicable
|
|
332
|
+
7. Follow the existing project structure and patterns
|
|
333
|
+
|
|
334
|
+
CODE FORMAT:
|
|
335
|
+
- Return code in markdown code blocks with language tag
|
|
336
|
+
- Use \`\`\`${language} for code blocks
|
|
337
|
+
- Include file paths when creating multiple files
|
|
338
|
+
|
|
339
|
+
EXAMPLE:
|
|
340
|
+
\`\`\`${language}
|
|
341
|
+
// code here
|
|
342
|
+
\`\`\`
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
buildFullPrompt(userRequest, context, language) {
|
|
347
|
+
let prompt = '';
|
|
348
|
+
|
|
349
|
+
if (context) {
|
|
350
|
+
prompt += context + '\n\n';
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
prompt += `USER REQUEST: ${userRequest}\n\n`;
|
|
354
|
+
prompt += `Generate complete, working ${language} code for this request. `;
|
|
355
|
+
prompt += `Follow the project context and framework patterns shown above.`;
|
|
356
|
+
|
|
357
|
+
return prompt;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
detectLanguage(userRequest) {
|
|
361
|
+
const lower = userRequest.toLowerCase();
|
|
362
|
+
|
|
363
|
+
if (lower.includes('python') || lower.includes('django') || lower.includes('flask') || lower.includes('fastapi')) return 'python';
|
|
364
|
+
if (lower.includes('typescript') || lower.includes('ts')) return 'typescript';
|
|
365
|
+
if (lower.includes('react') || lower.includes('next.js') || lower.includes('nextjs')) return 'javascript';
|
|
366
|
+
if (lower.includes('flutter') || lower.includes('dart')) return 'dart';
|
|
367
|
+
if (lower.includes('sql') || lower.includes('database') || lower.includes('query')) return 'sql';
|
|
368
|
+
if (lower.includes('html') || lower.includes('web page') || lower.includes('landing')) return 'html';
|
|
369
|
+
if (lower.includes('css') || lower.includes('style')) return 'css';
|
|
370
|
+
|
|
371
|
+
return 'javascript'; // default
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
extractCodeBlocks(response) {
|
|
375
|
+
const blocks = [];
|
|
376
|
+
const regex = /```(\w*)\n([\s\S]*?)```/g;
|
|
377
|
+
let match;
|
|
378
|
+
|
|
379
|
+
while ((match = regex.exec(response)) !== null) {
|
|
380
|
+
const lang = match[1] || 'text';
|
|
381
|
+
const code = match[2].trim();
|
|
382
|
+
|
|
383
|
+
// Try to extract filename from code comments or headers
|
|
384
|
+
const filename = this.extractFilename(code, lang);
|
|
385
|
+
|
|
386
|
+
blocks.push({
|
|
387
|
+
language: lang,
|
|
388
|
+
code,
|
|
389
|
+
filename,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return blocks;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
extractFilename(code, language) {
|
|
397
|
+
// Look for filename in comments
|
|
398
|
+
const filenamePatterns = [
|
|
399
|
+
/(?:file|filename|path):\s*(.+\.\w+)/i,
|
|
400
|
+
/\/\/\s*(.+\.\w+)/,
|
|
401
|
+
/#\s*(.+\.\w+)/,
|
|
402
|
+
/\/\/\s* Filename:\s*(.+)/i,
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
for (const pattern of filenamePatterns) {
|
|
406
|
+
const match = code.match(pattern);
|
|
407
|
+
if (match) return match[1].trim();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Generate default filename
|
|
411
|
+
const ext = LANGUAGE_CONFIG[language]?.extensions[0] || '.txt';
|
|
412
|
+
return `generated${ext}`;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ─── Code Fixer ─────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
class CodeFixer {
|
|
419
|
+
constructor(ai) {
|
|
420
|
+
this.ai = ai;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async fix(code, error = '', language = null) {
|
|
424
|
+
const detectedLanguage = language || this.detectLanguage(code);
|
|
425
|
+
|
|
426
|
+
const systemPrompt = `You are a debugging expert for ${detectedLanguage}.
|
|
427
|
+
Fix the given code and return ONLY the corrected code in a markdown code block.
|
|
428
|
+
Do not include explanations unless specifically asked.`;
|
|
429
|
+
|
|
430
|
+
const prompt = error
|
|
431
|
+
? `Fix this ${detectedLanguage} code. Error:\n${error}\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``
|
|
432
|
+
: `Fix any issues in this ${detectedLanguage} code:\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``;
|
|
433
|
+
|
|
434
|
+
const response = await this.ai.chat(prompt, { system: systemPrompt });
|
|
435
|
+
|
|
436
|
+
return {
|
|
437
|
+
response,
|
|
438
|
+
language: detectedLanguage,
|
|
439
|
+
codeBlocks: this.extractCodeBlocks(response),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
detectLanguage(code) {
|
|
444
|
+
if (code.includes('def ') || code.includes('import ')) return 'python';
|
|
445
|
+
if (code.includes('function ') || code.includes('const ') || code.includes('=>')) return 'javascript';
|
|
446
|
+
if (code.includes('interface ') || code.includes(': string')) return 'typescript';
|
|
447
|
+
if (code.includes('Widget') || code.includes('StatelessWidget')) return 'dart';
|
|
448
|
+
if (code.includes('SELECT ') || code.includes('CREATE TABLE')) return 'sql';
|
|
449
|
+
return 'javascript';
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
extractCodeBlocks(response) {
|
|
453
|
+
const blocks = [];
|
|
454
|
+
const regex = /```(\w*)\n([\s\S]*?)```/g;
|
|
455
|
+
let match;
|
|
456
|
+
|
|
457
|
+
while ((match = regex.exec(response)) !== null) {
|
|
458
|
+
blocks.push({
|
|
459
|
+
language: match[1] || 'text',
|
|
460
|
+
code: match[2].trim(),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return blocks;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// ─── Main Coding Model ──────────────────────────────────
|
|
469
|
+
|
|
470
|
+
class CodingModel {
|
|
471
|
+
constructor(options = {}) {
|
|
472
|
+
this.ai = new HybardAI(options);
|
|
473
|
+
this.contextBuilder = new ContextBuilder(options.rootDir || process.cwd());
|
|
474
|
+
this.generator = new CodeGenerator(this.ai);
|
|
475
|
+
this.fixer = new CodeFixer(this.ai);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async generateCode(userRequest, options = {}) {
|
|
479
|
+
console.log(`[CodingModel] Generating code for: "${userRequest}"`);
|
|
480
|
+
|
|
481
|
+
// 1. Build context
|
|
482
|
+
console.log('[CodingModel] Building context...');
|
|
483
|
+
const context = this.contextBuilder.buildContext(userRequest);
|
|
484
|
+
|
|
485
|
+
// 2. Generate code
|
|
486
|
+
console.log('[CodingModel] Generating code...');
|
|
487
|
+
const result = await this.generator.generate(userRequest, context, options.language);
|
|
488
|
+
|
|
489
|
+
// 3. Extract and organize code blocks
|
|
490
|
+
const codeBlocks = result.codeBlocks;
|
|
491
|
+
|
|
492
|
+
console.log(`[CodingModel] Generated ${codeBlocks.length} code block(s)`);
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
...result,
|
|
496
|
+
context,
|
|
497
|
+
codeBlocks,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async fixCode(code, error = '', options = {}) {
|
|
502
|
+
console.log(`[CodingModel] Fixing code...`);
|
|
503
|
+
|
|
504
|
+
const result = await this.fixer.fix(code, error, options.language);
|
|
505
|
+
|
|
506
|
+
console.log(`[CodingModel] Fixed ${result.codeBlocks.length} code block(s)`);
|
|
507
|
+
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async explainCode(code, language = null) {
|
|
512
|
+
const detectedLanguage = language || this.fixer.detectLanguage(code);
|
|
513
|
+
|
|
514
|
+
const systemPrompt = `You are a code analysis expert for ${detectedLanguage}.
|
|
515
|
+
Explain the given code clearly and concisely.
|
|
516
|
+
Cover: what it does, how it works, key patterns, and potential issues.`;
|
|
517
|
+
|
|
518
|
+
const prompt = `Explain this ${detectedLanguage} code:\n\n\`\`\`${detectedLanguage}\n${code}\n\`\`\``;
|
|
519
|
+
|
|
520
|
+
return this.ai.chat(prompt, { system: systemPrompt });
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async generateProject(goal, options = {}) {
|
|
524
|
+
console.log(`[CodingModel] Generating project: "${goal}"`);
|
|
525
|
+
|
|
526
|
+
const systemPrompt = `You are a project scaffolding expert.
|
|
527
|
+
Create a complete project structure for the given goal.
|
|
528
|
+
Return each file in this format:
|
|
529
|
+
|
|
530
|
+
## filename.ext
|
|
531
|
+
\`\`\`language
|
|
532
|
+
file content here
|
|
533
|
+
\`\`\`
|
|
534
|
+
|
|
535
|
+
Include all necessary files:
|
|
536
|
+
- Main code files
|
|
537
|
+
- Configuration files
|
|
538
|
+
- Package manifests
|
|
539
|
+
- README
|
|
540
|
+
- Tests (if applicable)`;
|
|
541
|
+
|
|
542
|
+
const context = this.contextBuilder.buildContext(goal);
|
|
543
|
+
const prompt = context + '\n\nCreate a project scaffold for: ' + goal;
|
|
544
|
+
|
|
545
|
+
const response = await this.ai.chat(prompt, { system: systemPrompt });
|
|
546
|
+
const codeBlocks = this.generator.extractCodeBlocks(response);
|
|
547
|
+
|
|
548
|
+
console.log(`[CodingModel] Generated ${codeBlocks.length} files`);
|
|
549
|
+
|
|
550
|
+
return {
|
|
551
|
+
response,
|
|
552
|
+
codeBlocks,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
async writeCodeToFiles(codeBlocks, targetDir = null) {
|
|
557
|
+
const dir = targetDir || process.cwd();
|
|
558
|
+
const written = [];
|
|
559
|
+
|
|
560
|
+
for (const block of codeBlocks) {
|
|
561
|
+
const filePath = path.join(dir, block.filename);
|
|
562
|
+
const fileDir = path.dirname(filePath);
|
|
563
|
+
|
|
564
|
+
if (!fs.existsSync(fileDir)) {
|
|
565
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
fs.writeFileSync(filePath, block.code, 'utf8');
|
|
569
|
+
written.push(filePath);
|
|
570
|
+
console.log(`[CodingModel] Written: ${filePath}`);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return written;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
getProjectInfo() {
|
|
577
|
+
return this.contextBuilder.detector.detect();
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
searchCode(query) {
|
|
581
|
+
return this.contextBuilder.searcher.searchCode(query);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
module.exports = { CodingModel, ContextBuilder, CodeGenerator, CodeFixer, LANGUAGE_CONFIG };
|