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
package/bin/agent.js
ADDED
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hybard CLI — Professional autonomous coding assistant.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* hybard Interactive chat
|
|
8
|
+
* hybard "prompt" Single message
|
|
9
|
+
* hybard code "prompt" Generate and optionally save code
|
|
10
|
+
* hybard fix <file> Fix a file
|
|
11
|
+
* hybard explain <file> Explain code
|
|
12
|
+
* hybard search <query> Search codebase
|
|
13
|
+
* hybard project Show project info
|
|
14
|
+
* hybard network Show network status
|
|
15
|
+
* hybard help Show help
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
const readline = require('readline');
|
|
22
|
+
const { Engine, Git, Security, Production, Evaluator } = require('../lib/engine');
|
|
23
|
+
const { detectLocalIP, discoverHybardServer } = require('../lib/online');
|
|
24
|
+
|
|
25
|
+
const engine = new Engine();
|
|
26
|
+
|
|
27
|
+
// ─── Status Printer ──────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
function status(msg) {
|
|
30
|
+
process.stdout.write(`\x1b[90m ${msg}\x1b[0m`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function success(msg) {
|
|
34
|
+
console.log(`\x1b[32m ${msg}\x1b[0m`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function info(msg) {
|
|
38
|
+
console.log(`\x1b[36m ${msg}\x1b[0m`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function header(title) {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(`\x1b[1m${title}\x1b[0m`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── Interactive Chat ────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
async function interactiveChat() {
|
|
49
|
+
const rl = readline.createInterface({
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stdout,
|
|
52
|
+
prompt: '\x1b[1mhybard\x1b[0m › ',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
console.log();
|
|
56
|
+
console.log('\x1b[1m Hybard\x1b[0m \x1b[90mAutonomous Coding Assistant\x1b[0m');
|
|
57
|
+
console.log('\x1b[90m Type your request, or /help for commands.\x1b[0m');
|
|
58
|
+
console.log();
|
|
59
|
+
|
|
60
|
+
rl.prompt();
|
|
61
|
+
|
|
62
|
+
rl.on('line', async (line) => {
|
|
63
|
+
const input = line.trim();
|
|
64
|
+
if (!input) { rl.prompt(); return; }
|
|
65
|
+
|
|
66
|
+
// Slash commands
|
|
67
|
+
if (input === '/quit' || input === '/exit') {
|
|
68
|
+
console.log('\n\x1b[90m Goodbye.\x1b[0m\n');
|
|
69
|
+
rl.close();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (input === '/help') {
|
|
74
|
+
printChatHelp();
|
|
75
|
+
rl.prompt();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (input === '/clear') {
|
|
80
|
+
console.clear();
|
|
81
|
+
rl.prompt();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (input === '/project') {
|
|
86
|
+
printProjectInfo();
|
|
87
|
+
rl.prompt();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (input === '/network') {
|
|
92
|
+
await printNetworkInfo();
|
|
93
|
+
rl.prompt();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (input.startsWith('/search ')) {
|
|
98
|
+
const query = input.slice(8);
|
|
99
|
+
printSearchResults(query);
|
|
100
|
+
rl.prompt();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Normal message — autonomous processing
|
|
105
|
+
status('Thinking...');
|
|
106
|
+
try {
|
|
107
|
+
const response = await engine.process(input);
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(response);
|
|
110
|
+
console.log();
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.log(`\n\x1b[31m Error: ${err.message}\x1b[0m\n`);
|
|
113
|
+
}
|
|
114
|
+
rl.prompt();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
rl.on('close', () => process.exit(0));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── Single-Shot Commands ────────────────────────────────
|
|
121
|
+
|
|
122
|
+
async function singleShot(prompt) {
|
|
123
|
+
status('Processing...');
|
|
124
|
+
try {
|
|
125
|
+
const response = await engine.process(prompt);
|
|
126
|
+
console.log();
|
|
127
|
+
console.log(response);
|
|
128
|
+
console.log();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error(`\n\x1b[31m Error: ${err.message}\x1b[0m\n`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function generateCode(prompt) {
|
|
136
|
+
status('Generating code...');
|
|
137
|
+
|
|
138
|
+
const system = `You are an expert programmer. Generate clean, working code.
|
|
139
|
+
Return ONLY the code in markdown code blocks with language tags.
|
|
140
|
+
Include filename as a comment at the top of each file.`;
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const response = await engine.ai.chat(prompt, { system });
|
|
144
|
+
console.log();
|
|
145
|
+
console.log(response);
|
|
146
|
+
console.log();
|
|
147
|
+
|
|
148
|
+
// Extract code blocks and offer to save
|
|
149
|
+
const blocks = extractCodeBlocks(response);
|
|
150
|
+
if (blocks.length > 0) {
|
|
151
|
+
console.log(`\x1b[90m Found ${blocks.length} code block(s)\x1b[0m`);
|
|
152
|
+
for (const b of blocks) {
|
|
153
|
+
console.log(` → ${b.filename} (${b.language})`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
157
|
+
rl.question('\n Save to files? (y/n) ', async (answer) => {
|
|
158
|
+
if (answer.toLowerCase() === 'y') {
|
|
159
|
+
for (const block of blocks) {
|
|
160
|
+
const abs = path.resolve(block.filename);
|
|
161
|
+
const dir = path.dirname(abs);
|
|
162
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
163
|
+
fs.writeFileSync(abs, block.code, 'utf8');
|
|
164
|
+
success(`Created ${block.filename}`);
|
|
165
|
+
}
|
|
166
|
+
console.log();
|
|
167
|
+
}
|
|
168
|
+
rl.close();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.error(`\n\x1b[31m Error: ${err.message}\x1b[0m\n`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function fixFile(filePath) {
|
|
178
|
+
const abs = path.resolve(filePath);
|
|
179
|
+
if (!fs.existsSync(abs)) {
|
|
180
|
+
console.error(`\n\x1b[31m File not found: ${filePath}\x1b[0m\n`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const content = fs.readFileSync(abs, 'utf8');
|
|
185
|
+
status(`Fixing ${filePath}...`);
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const system = `You are a debugging expert. Fix the given code.
|
|
189
|
+
Return ONLY the corrected code in a markdown code block.
|
|
190
|
+
Do not include explanations.`;
|
|
191
|
+
|
|
192
|
+
const response = await engine.ai.chat(
|
|
193
|
+
`Fix any issues in this code:\n\n\`\`\`\n${content}\n\`\`\``,
|
|
194
|
+
{ system }
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const blocks = extractCodeBlocks(response);
|
|
198
|
+
if (blocks.length > 0) {
|
|
199
|
+
// Backup original
|
|
200
|
+
fs.writeFileSync(abs + '.bak', content, 'utf8');
|
|
201
|
+
fs.writeFileSync(abs, blocks[0].code, 'utf8');
|
|
202
|
+
success(`Fixed ${filePath} (backup: ${filePath}.bak)`);
|
|
203
|
+
} else {
|
|
204
|
+
console.log('\n\x1b[33m No changes needed — file looks good.\x1b[0m\n');
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.error(`\n\x1b[31m Error: ${err.message}\x1b[0m\n`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function explainFile(filePath) {
|
|
213
|
+
const abs = path.resolve(filePath);
|
|
214
|
+
if (!fs.existsSync(abs)) {
|
|
215
|
+
console.error(`\n\x1b[31m File not found: ${filePath}\x1b[0m\n`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const content = fs.readFileSync(abs, 'utf8');
|
|
220
|
+
status(`Analyzing ${filePath}...`);
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const system = `You are a code analyst. Explain the given code clearly.
|
|
224
|
+
Cover: what it does, how it works, key patterns, and potential issues.
|
|
225
|
+
Be concise but thorough.`;
|
|
226
|
+
|
|
227
|
+
const response = await engine.ai.chat(
|
|
228
|
+
`Explain this code:\n\n\`\`\`\n${content}\n\`\`\``,
|
|
229
|
+
{ system }
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
console.log();
|
|
233
|
+
console.log(response);
|
|
234
|
+
console.log();
|
|
235
|
+
} catch (err) {
|
|
236
|
+
console.error(`\n\x1b[31m Error: ${err.message}\x1b[0m\n`);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function searchCodebase(query) {
|
|
242
|
+
status(`Searching for "${query}"...`);
|
|
243
|
+
const result = engine.executeTool('search_code', { query });
|
|
244
|
+
|
|
245
|
+
if (!result.ok || result.count === 0) {
|
|
246
|
+
console.log('\n\x1b[90m No results found.\x1b[0m\n');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
console.log();
|
|
251
|
+
console.log(` Found ${result.count} match(es) in ${result.results.length} file(s):\n`);
|
|
252
|
+
for (const r of result.results.slice(0, 10)) {
|
|
253
|
+
console.log(` \x1b[36m${r.file}\x1b[0m`);
|
|
254
|
+
for (const m of r.matches.slice(0, 3)) {
|
|
255
|
+
console.log(` L${m.line}: ${m.content.slice(0, 100)}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
console.log();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function printProjectInfo() {
|
|
262
|
+
const result = engine.executeTool('detect_project', {});
|
|
263
|
+
if (!result.ok) {
|
|
264
|
+
console.log('\n\x1b[90m No project detected.\x1b[0m\n');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
console.log();
|
|
268
|
+
console.log(' \x1b[1mProject Info\x1b[0m');
|
|
269
|
+
console.log(` Type: ${result.type}`);
|
|
270
|
+
console.log(` Languages: ${result.languages.join(', ') || 'Unknown'}`);
|
|
271
|
+
console.log(` Frameworks: ${result.frameworks.join(', ') || 'None'}`);
|
|
272
|
+
console.log(` Entry: ${result.entryPoints.join(', ') || 'None'}`);
|
|
273
|
+
console.log(` Config: ${result.configFiles.join(', ') || 'None'}`);
|
|
274
|
+
console.log();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async function printNetworkInfo() {
|
|
278
|
+
const localIP = detectLocalIP();
|
|
279
|
+
console.log();
|
|
280
|
+
console.log(' \x1b[1mNetwork Status\x1b[0m');
|
|
281
|
+
console.log(` Local IP: ${localIP}`);
|
|
282
|
+
console.log(` Server: http://${localIP}:8000`);
|
|
283
|
+
console.log(` Endpoint: http://${localIP}:8000/v1/chat/completions`);
|
|
284
|
+
console.log(` Health: http://${localIP}:8000/health`);
|
|
285
|
+
console.log(` Platform: ${os.platform()} ${os.arch()}`);
|
|
286
|
+
console.log(` CPU: ${os.cpus().length} cores`);
|
|
287
|
+
console.log(` RAM: ${(os.totalmem() / (1024 ** 3)).toFixed(1)} GB`);
|
|
288
|
+
try {
|
|
289
|
+
const server = await discoverHybardServer();
|
|
290
|
+
console.log(` Status: ${server ? '\x1b[32mONLINE\x1b[0m' : '\x1b[31mOFFLINE\x1b[0m'}`);
|
|
291
|
+
} catch (e) {
|
|
292
|
+
console.log(' Status: \x1b[33mUNKNOWN\x1b[0m');
|
|
293
|
+
}
|
|
294
|
+
console.log();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function printSearchResults(query) {
|
|
298
|
+
searchCodebase(query);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ─── Helpers ─────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
function extractCodeBlocks(text) {
|
|
304
|
+
const blocks = [];
|
|
305
|
+
const regex = /```(\w*)\n([\s\S]*?)```/g;
|
|
306
|
+
let match;
|
|
307
|
+
while ((match = regex.exec(text)) !== null) {
|
|
308
|
+
const lang = match[1] || 'txt';
|
|
309
|
+
const code = match[2].trim();
|
|
310
|
+
// Try to extract filename from code comment
|
|
311
|
+
const fileMatch = code.match(/(?:#|\/\/|\/\*+|<!--)\s*(?:filename|file|path)[:\s]+(.+\.\w+)/i);
|
|
312
|
+
const filename = fileMatch ? fileMatch[1].trim() : `generated.${extMap[lang] || 'txt'}`;
|
|
313
|
+
blocks.push({ language: lang, code, filename });
|
|
314
|
+
}
|
|
315
|
+
return blocks;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const extMap = {
|
|
319
|
+
python: 'py', javascript: 'js', typescript: 'ts', dart: 'dart',
|
|
320
|
+
html: 'html', css: 'css', sql: 'sql', bash: 'sh', json: 'json',
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
function printChatHelp() {
|
|
324
|
+
console.log(`
|
|
325
|
+
\x1b[1mCommands:\x1b[0m
|
|
326
|
+
/help Show this help
|
|
327
|
+
/project Show project info
|
|
328
|
+
/network Show network status
|
|
329
|
+
/search <q> Search codebase
|
|
330
|
+
/clear Clear screen
|
|
331
|
+
/quit Exit
|
|
332
|
+
|
|
333
|
+
\x1b[1mTips:\x1b[0m
|
|
334
|
+
Just type naturally — the agent understands context.
|
|
335
|
+
Example: "Add a login page to my React app"
|
|
336
|
+
Example: "একটা Python calculator বানাও"
|
|
337
|
+
Example: "Fix the bug in src/utils.js"
|
|
338
|
+
`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ─── Git Commands ─────────────────────────────────────────
|
|
342
|
+
|
|
343
|
+
function printGitStatus() {
|
|
344
|
+
const s = Git.statusSummary();
|
|
345
|
+
if (!s.isRepo) {
|
|
346
|
+
console.log('\n\x1b[90m Not a git repository.\x1b[0m\n');
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
console.log();
|
|
350
|
+
console.log(' \x1b[1mGit Status\x1b[0m');
|
|
351
|
+
console.log(` Branch: ${s.branch}`);
|
|
352
|
+
console.log(` Modified: ${s.modified.length ? s.modified.join(', ') : 'none'}`);
|
|
353
|
+
console.log(` Added: ${s.added.length ? s.added.join(', ') : 'none'}`);
|
|
354
|
+
console.log(` Deleted: ${s.deleted.length ? s.deleted.join(', ') : 'none'}`);
|
|
355
|
+
console.log();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function printGitDiff(file) {
|
|
359
|
+
const result = file ? Git.diffFile(file) : Git.diff();
|
|
360
|
+
if (!result.ok || !result.stdout) {
|
|
361
|
+
console.log('\n\x1b[90m No changes.\x1b[0m\n');
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
console.log();
|
|
365
|
+
console.log(result.stdout);
|
|
366
|
+
console.log();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function printGitLog(n) {
|
|
370
|
+
const result = Git.log(n);
|
|
371
|
+
if (!result.ok) {
|
|
372
|
+
console.log('\n\x1b[90m No git history.\x1b[0m\n');
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
console.log();
|
|
376
|
+
console.log(' \x1b[1mRecent Commits\x1b[0m');
|
|
377
|
+
result.stdout.split('\n').forEach(line => console.log(` ${line}`));
|
|
378
|
+
console.log();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function gitCommit(message) {
|
|
382
|
+
status('Committing...');
|
|
383
|
+
const result = Git.commit(message);
|
|
384
|
+
if (result.ok) {
|
|
385
|
+
success(`Committed: ${message}`);
|
|
386
|
+
} else {
|
|
387
|
+
console.log(`\n\x1b[31m Commit failed: ${result.stderr}\x1b[0m\n`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function printGitBranches() {
|
|
392
|
+
const result = Git.branches();
|
|
393
|
+
if (!result.ok) {
|
|
394
|
+
console.log('\n\x1b[90m No branches.\x1b[0m\n');
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
console.log();
|
|
398
|
+
result.stdout.split('\n').forEach(line => {
|
|
399
|
+
const trimmed = line.trim();
|
|
400
|
+
if (trimmed.startsWith('*')) {
|
|
401
|
+
console.log(` \x1b[32m${trimmed}\x1b[0m`);
|
|
402
|
+
} else if (trimmed) {
|
|
403
|
+
console.log(` ${trimmed}`);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
console.log();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function gitRollback(n) {
|
|
410
|
+
status(`Rolling back ${n} commit(s)...`);
|
|
411
|
+
const result = Git.rollback(n);
|
|
412
|
+
if (result.ok) {
|
|
413
|
+
success(`Rolled back ${n} commit(s)`);
|
|
414
|
+
} else {
|
|
415
|
+
console.log(`\n\x1b[31m Rollback failed: ${result.stderr}\x1b[0m\n`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ─── Security Commands ───────────────────────────────────
|
|
420
|
+
|
|
421
|
+
function securityScan(filePath) {
|
|
422
|
+
status(`Scanning ${filePath}...`);
|
|
423
|
+
const abs = path.resolve(filePath);
|
|
424
|
+
if (fs.existsSync(abs) && fs.statSync(abs).isFile()) {
|
|
425
|
+
const result = engine.executeTool('security_scan', { path: filePath });
|
|
426
|
+
console.log();
|
|
427
|
+
if (result.hasIssues) {
|
|
428
|
+
console.log(' \x1b[31mSecurity Issues Found:\x1b[0m');
|
|
429
|
+
result.secrets.forEach(s => console.log(` ⚠ ${s}`));
|
|
430
|
+
} else {
|
|
431
|
+
console.log(' \x1b[32mNo security issues found.\x1b[0m');
|
|
432
|
+
}
|
|
433
|
+
console.log();
|
|
434
|
+
} else {
|
|
435
|
+
// Scan all files in directory
|
|
436
|
+
const searcher = new (require('../lib/hybard-agent').CodebaseSearch)(process.cwd());
|
|
437
|
+
const files = searcher.findFiles('.').slice(0, 20);
|
|
438
|
+
let totalIssues = 0;
|
|
439
|
+
console.log();
|
|
440
|
+
for (const f of files) {
|
|
441
|
+
const result = engine.executeTool('security_scan', { path: f });
|
|
442
|
+
if (result.hasIssues) {
|
|
443
|
+
console.log(` \x1b[31m${f}:\x1b[0m`);
|
|
444
|
+
result.secrets.forEach(s => console.log(` ⚠ ${s}`));
|
|
445
|
+
totalIssues += result.secrets.length;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (totalIssues === 0) {
|
|
449
|
+
console.log(' \x1b[32mNo security issues found in project.\x1b[0m');
|
|
450
|
+
} else {
|
|
451
|
+
console.log(`\n \x1b[31m${totalIssues} issue(s) found.\x1b[0m`);
|
|
452
|
+
}
|
|
453
|
+
console.log();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function securityValidate(input) {
|
|
458
|
+
const result = Security.validateInput(input);
|
|
459
|
+
console.log();
|
|
460
|
+
if (result.ok) {
|
|
461
|
+
console.log(' \x1b[32mInput is safe.\x1b[0m');
|
|
462
|
+
} else {
|
|
463
|
+
console.log(` \x1b[31m${result.reason}\x1b[0m`);
|
|
464
|
+
}
|
|
465
|
+
console.log();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// ─── Production Commands ─────────────────────────────────
|
|
469
|
+
|
|
470
|
+
function printSystemHealth() {
|
|
471
|
+
const health = Production.healthCheck();
|
|
472
|
+
const info = Production.getSystemInfo();
|
|
473
|
+
console.log();
|
|
474
|
+
console.log(' \x1b[1mSystem Health\x1b[0m');
|
|
475
|
+
const statusColor = health.status === 'healthy' ? '\x1b[32m' : health.status === 'warning' ? '\x1b[33m' : '\x1b[31m';
|
|
476
|
+
console.log(` Status: ${statusColor}${health.status.toUpperCase()}\x1b[0m`);
|
|
477
|
+
console.log(` Memory: ${health.memory}`);
|
|
478
|
+
console.log(` CPU: ${health.cpu}`);
|
|
479
|
+
console.log(` Uptime: ${health.uptime}`);
|
|
480
|
+
console.log(` Platform: ${info.platform} ${info.arch}`);
|
|
481
|
+
console.log(` Node: ${info.nodeVersion}`);
|
|
482
|
+
console.log(` Hostname: ${info.hostname}`);
|
|
483
|
+
console.log();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ─── Evaluation Commands ─────────────────────────────────
|
|
487
|
+
|
|
488
|
+
function evalCode(filePath) {
|
|
489
|
+
const abs = path.resolve(filePath);
|
|
490
|
+
if (!fs.existsSync(abs)) {
|
|
491
|
+
console.error(`\n\x1b[31m File not found: ${filePath}\x1b[0m\n`);
|
|
492
|
+
process.exit(1);
|
|
493
|
+
}
|
|
494
|
+
const content = fs.readFileSync(abs, 'utf8');
|
|
495
|
+
const ext = path.extname(filePath).slice(1);
|
|
496
|
+
const langMap = { py: 'python', js: 'javascript', ts: 'typescript', dart: 'dart', sql: 'sql' };
|
|
497
|
+
const lang = langMap[ext] || 'python';
|
|
498
|
+
|
|
499
|
+
const result = Evaluator.evaluateCode(content, lang);
|
|
500
|
+
console.log();
|
|
501
|
+
console.log(' \x1b[1mCode Evaluation\x1b[0m');
|
|
502
|
+
const scoreColor = result.score >= 80 ? '\x1b[32m' : result.score >= 50 ? '\x1b[33m' : '\x1b[31m';
|
|
503
|
+
console.log(` Score: ${scoreColor}${result.score}/100\x1b[0m`);
|
|
504
|
+
console.log(` Lines: ${result.metrics.lines}`);
|
|
505
|
+
console.log(` Comments: ${result.metrics.commentRatio}`);
|
|
506
|
+
console.log(` Docstring: ${result.metrics.hasDocstring ? 'Yes' : 'No'}`);
|
|
507
|
+
console.log(` Type Hints: ${result.metrics.hasTypeHints ? 'Yes' : 'No'}`);
|
|
508
|
+
if (result.issues.length > 0) {
|
|
509
|
+
console.log(' Issues:');
|
|
510
|
+
result.issues.forEach(i => console.log(` ⚠ ${i}`));
|
|
511
|
+
} else {
|
|
512
|
+
console.log(' \x1b[32mNo issues found.\x1b[0m');
|
|
513
|
+
}
|
|
514
|
+
console.log();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ─── Main ────────────────────────────────────────────────
|
|
518
|
+
|
|
519
|
+
async function main() {
|
|
520
|
+
const args = process.argv.slice(2);
|
|
521
|
+
|
|
522
|
+
if (args.length === 0) {
|
|
523
|
+
await interactiveChat();
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const cmd = args[0].toLowerCase();
|
|
528
|
+
const rest = args.slice(1).join(' ');
|
|
529
|
+
|
|
530
|
+
switch (cmd) {
|
|
531
|
+
case 'help': case '--help': case '-h':
|
|
532
|
+
printFullHelp();
|
|
533
|
+
break;
|
|
534
|
+
case 'code': case 'generate':
|
|
535
|
+
if (!rest) { console.error('\n Usage: hybard code "description"\n'); process.exit(1); }
|
|
536
|
+
await generateCode(rest);
|
|
537
|
+
break;
|
|
538
|
+
case 'fix':
|
|
539
|
+
if (!rest) { console.error('\n Usage: hybard fix <file>\n'); process.exit(1); }
|
|
540
|
+
await fixFile(rest);
|
|
541
|
+
break;
|
|
542
|
+
case 'explain':
|
|
543
|
+
if (!rest) { console.error('\n Usage: hybard explain <file>\n'); process.exit(1); }
|
|
544
|
+
await explainFile(rest);
|
|
545
|
+
break;
|
|
546
|
+
case 'search': case 'find':
|
|
547
|
+
if (!rest) { console.error('\n Usage: hybard search <query>\n'); process.exit(1); }
|
|
548
|
+
searchCodebase(rest);
|
|
549
|
+
break;
|
|
550
|
+
case 'project': case 'info':
|
|
551
|
+
printProjectInfo();
|
|
552
|
+
break;
|
|
553
|
+
case 'network': case 'server': case 'status':
|
|
554
|
+
await printNetworkInfo();
|
|
555
|
+
break;
|
|
556
|
+
case 'run':
|
|
557
|
+
if (!rest) { console.error('\n Usage: hybard run <command>\n'); process.exit(1); }
|
|
558
|
+
const result = engine.executeTool('run_command', { command: rest });
|
|
559
|
+
if (result.ok) console.log(result.stdout);
|
|
560
|
+
else console.error(result.stderr || result.error);
|
|
561
|
+
break;
|
|
562
|
+
|
|
563
|
+
case 'git':
|
|
564
|
+
case 'g':
|
|
565
|
+
{
|
|
566
|
+
const sub = (args[1] || 'status').toLowerCase();
|
|
567
|
+
switch (sub) {
|
|
568
|
+
case 'status': case 'st':
|
|
569
|
+
printGitStatus();
|
|
570
|
+
break;
|
|
571
|
+
case 'diff': case 'd':
|
|
572
|
+
printGitDiff(args[2]);
|
|
573
|
+
break;
|
|
574
|
+
case 'log':
|
|
575
|
+
printGitLog(parseInt(args[2]) || 10);
|
|
576
|
+
break;
|
|
577
|
+
case 'commit': case 'ci':
|
|
578
|
+
if (!args[2]) { console.error('\n Usage: hybard git commit "message"\n'); process.exit(1); }
|
|
579
|
+
gitCommit(args.slice(2).join(' '));
|
|
580
|
+
break;
|
|
581
|
+
case 'branch': case 'b':
|
|
582
|
+
printGitBranches();
|
|
583
|
+
break;
|
|
584
|
+
case 'rollback': case 'rb':
|
|
585
|
+
gitRollback(parseInt(args[2]) || 1);
|
|
586
|
+
break;
|
|
587
|
+
default:
|
|
588
|
+
printGitStatus();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
break;
|
|
592
|
+
|
|
593
|
+
case 'security': case 'sec':
|
|
594
|
+
{
|
|
595
|
+
const sub = (args[1] || 'scan').toLowerCase();
|
|
596
|
+
switch (sub) {
|
|
597
|
+
case 'scan':
|
|
598
|
+
if (!args[2]) { console.error('\n Usage: hybard security scan <file>\n'); process.exit(1); }
|
|
599
|
+
securityScan(args[2]);
|
|
600
|
+
break;
|
|
601
|
+
case 'validate':
|
|
602
|
+
if (!args[2]) { console.error('\n Usage: hybard security validate "input"\n'); process.exit(1); }
|
|
603
|
+
securityValidate(args.slice(2).join(' '));
|
|
604
|
+
break;
|
|
605
|
+
default:
|
|
606
|
+
securityScan(args[2] || '.');
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
break;
|
|
610
|
+
|
|
611
|
+
case 'health': case 'sys':
|
|
612
|
+
printSystemHealth();
|
|
613
|
+
break;
|
|
614
|
+
|
|
615
|
+
case 'eval':
|
|
616
|
+
if (!rest) { console.error('\n Usage: hybard eval <file>\n'); process.exit(1); }
|
|
617
|
+
evalCode(rest);
|
|
618
|
+
break;
|
|
619
|
+
|
|
620
|
+
default:
|
|
621
|
+
await singleShot(args.join(' '));
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function printFullHelp() {
|
|
627
|
+
console.log(`
|
|
628
|
+
\x1b[1mHybard\x1b[0m \x1b[90mAutonomous Coding Assistant\x1b[0m
|
|
629
|
+
|
|
630
|
+
\x1b[1mUsage:\x1b[0m
|
|
631
|
+
hybard Interactive chat
|
|
632
|
+
hybard "prompt" Single message
|
|
633
|
+
hybard code "prompt" Generate code
|
|
634
|
+
hybard fix <file> Fix a file
|
|
635
|
+
hybard explain <file> Explain code
|
|
636
|
+
hybard search <query> Search codebase
|
|
637
|
+
hybard project Project info
|
|
638
|
+
hybard network Network status
|
|
639
|
+
hybard run <command> Run shell command
|
|
640
|
+
|
|
641
|
+
\x1b[1mGit:\x1b[0m
|
|
642
|
+
hybard git status Show git status
|
|
643
|
+
hybard git diff [file] Show changes
|
|
644
|
+
hybard git log [n] Show recent commits
|
|
645
|
+
hybard git commit "msg" Stage all & commit
|
|
646
|
+
hybard git branch List branches
|
|
647
|
+
hybard git rollback [n] Rollback N commits
|
|
648
|
+
|
|
649
|
+
\x1b[1mSecurity:\x1b[0m
|
|
650
|
+
hybard security scan <f> Scan for secrets/vulnerabilities
|
|
651
|
+
hybard security validate "input" Check for prompt injection
|
|
652
|
+
|
|
653
|
+
\x1b[1mProduction:\x1b[0m
|
|
654
|
+
hybard health System health check
|
|
655
|
+
|
|
656
|
+
\x1b[1mEvaluation:\x1b[0m
|
|
657
|
+
hybard eval <file> Evaluate code quality
|
|
658
|
+
|
|
659
|
+
\x1b[1mExamples:\x1b[0m
|
|
660
|
+
hybard code "create a Python login page"
|
|
661
|
+
hybard code "একটা Flutter app বানাও"
|
|
662
|
+
hybard git status
|
|
663
|
+
hybard git commit "add login feature"
|
|
664
|
+
hybard security scan src/auth.py
|
|
665
|
+
hybard health
|
|
666
|
+
hybard eval lib/engine.js
|
|
667
|
+
`);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
main().catch(err => {
|
|
671
|
+
console.error(`\n\x1b[31m Fatal: ${err.message}\x1b[0m\n`);
|
|
672
|
+
process.exit(1);
|
|
673
|
+
});
|