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/cli.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { runAgent } = require('../lib/agent');
|
|
4
|
+
const { HybardAI, startChat } = require('../lib/online');
|
|
5
|
+
const { CodingAgent } = require('../lib/coding-agent');
|
|
6
|
+
const { ProjectAnalyzer } = require('../lib/analyzer');
|
|
7
|
+
const { getLocalIP, getServerInfo } = require('../lib/server');
|
|
8
|
+
const ui = require('../lib/ui');
|
|
9
|
+
const readline = require('readline');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const command = args[0] || '';
|
|
15
|
+
const rest = args.slice(1).join(' ').trim();
|
|
16
|
+
|
|
17
|
+
// Config file
|
|
18
|
+
const CONFIG_DIR = path.join(require('os').homedir(), '.hybard');
|
|
19
|
+
const NETWORK_CONFIG = path.join(CONFIG_DIR, 'network.json');
|
|
20
|
+
|
|
21
|
+
function loadNetworkConfig() {
|
|
22
|
+
try {
|
|
23
|
+
if (fs.existsSync(NETWORK_CONFIG)) return JSON.parse(fs.readFileSync(NETWORK_CONFIG, 'utf8'));
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
return { ip: '', port: 7860, autoConnect: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function saveNetworkConfig(config) {
|
|
29
|
+
if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
30
|
+
fs.writeFileSync(NETWORK_CONFIG, JSON.stringify(config, null, 2));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parsePort() {
|
|
34
|
+
const idx = args.indexOf('--port');
|
|
35
|
+
if (idx !== -1 && args[idx + 1]) return parseInt(args[idx + 1], 10) || 7860;
|
|
36
|
+
return loadNetworkConfig().port || 7860;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Interactive Chat ──────────────────────────────────
|
|
40
|
+
function startChatMode() {
|
|
41
|
+
ui.printBanner();
|
|
42
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: '' });
|
|
43
|
+
console.log(ui.c(' Commands: help, config, models, project, create, exit', ui.C.dim));
|
|
44
|
+
console.log('');
|
|
45
|
+
|
|
46
|
+
function prompt() {
|
|
47
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (line) => handleChat(line, rl));
|
|
48
|
+
}
|
|
49
|
+
prompt();
|
|
50
|
+
rl.on('close', () => { console.log(ui.c('\n Goodbye!\n', ui.C.green)); process.exit(0); });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function handleChat(line, rl) {
|
|
54
|
+
const text = (line || '').trim();
|
|
55
|
+
if (!text) { rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl)); return; }
|
|
56
|
+
if (text === 'exit' || text === 'quit') { console.log(ui.c('\n Goodbye!\n', ui.C.green)); rl.close(); return; }
|
|
57
|
+
if (text === 'help') { ui.printHelp(); rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl)); return; }
|
|
58
|
+
|
|
59
|
+
if (text === 'config') {
|
|
60
|
+
const ai = new HybardAI();
|
|
61
|
+
ui.printTable(['Setting', 'Value'], [
|
|
62
|
+
['Provider', ai.config.provider],
|
|
63
|
+
['Model', ai.config.model],
|
|
64
|
+
['API Key', ai.getApiKey() ? '***' + ai.getApiKey().slice(-4) : 'NOT SET'],
|
|
65
|
+
['Online Mode', ai.getApiKey() ? 'YES' : 'NO (Offline)'],
|
|
66
|
+
]);
|
|
67
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (text.startsWith('config provider ')) {
|
|
72
|
+
const provider = text.slice(16).trim();
|
|
73
|
+
const ai = new HybardAI();
|
|
74
|
+
try { ai.setProvider(provider); ui.printSuccess('Switched to ' + provider); }
|
|
75
|
+
catch (err) { ui.printError(err.message); }
|
|
76
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (text === 'models') {
|
|
81
|
+
const { ModelRouter } = require('../lib/models');
|
|
82
|
+
const router = new ModelRouter();
|
|
83
|
+
for (const prov of router.listProviders()) {
|
|
84
|
+
const models = router.listModels(prov.id);
|
|
85
|
+
console.log(ui.c('\n ' + prov.name, ui.C.brightYellow, ui.C.bold));
|
|
86
|
+
ui.printTable(['Model', 'Name', 'Size'], models.map(m => [m.modelId, m.name, m.size]));
|
|
87
|
+
}
|
|
88
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (text === 'project') {
|
|
93
|
+
const analyzer = new ProjectAnalyzer();
|
|
94
|
+
const info = analyzer.analyze();
|
|
95
|
+
ui.printProjectFiles(analyzer.files.slice(0, 20), info.projectType);
|
|
96
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (text.startsWith('create ')) {
|
|
101
|
+
console.log('');
|
|
102
|
+
const stop = ui.startThinking('Creating project');
|
|
103
|
+
rl.pause();
|
|
104
|
+
try { await runAgent(['create ' + text.slice(7)]); stop(); ui.printSuccess('Project created!'); }
|
|
105
|
+
catch (err) { stop(); ui.printError(err.message); }
|
|
106
|
+
rl.resume();
|
|
107
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// AI Chat
|
|
112
|
+
console.log('');
|
|
113
|
+
ui.printUser(text);
|
|
114
|
+
const stop = ui.startThinking('Generating');
|
|
115
|
+
rl.pause();
|
|
116
|
+
try {
|
|
117
|
+
const agent = new CodingAgent();
|
|
118
|
+
agent.init();
|
|
119
|
+
const response = await agent.chat(text);
|
|
120
|
+
stop();
|
|
121
|
+
ui.printAI(response);
|
|
122
|
+
// Save code to files
|
|
123
|
+
const blocks = agent.extractCodeBlocks(response);
|
|
124
|
+
if (blocks.length > 0) {
|
|
125
|
+
console.log(ui.c('\n Files to save:', ui.C.brightGreen, ui.C.bold));
|
|
126
|
+
for (const b of blocks) console.log(ui.c(' - ' + b.filename, ui.C.green));
|
|
127
|
+
}
|
|
128
|
+
} catch (err) { stop(); ui.printError(err.message); }
|
|
129
|
+
rl.resume();
|
|
130
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleChat(l, rl));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── Coding Agent ──────────────────────────────────────
|
|
134
|
+
async function startAgentMode(initialPrompt) {
|
|
135
|
+
ui.printBanner();
|
|
136
|
+
const agent = new CodingAgent();
|
|
137
|
+
// Skip slow project analysis - just set basic info
|
|
138
|
+
agent.projectContext = { projectType: 'unknown', languages: [], frameworks: [], summary: 'Project loaded', fileCount: 0 };
|
|
139
|
+
const info = agent.getModelInfo();
|
|
140
|
+
ui.printStatus(info.provider, info.model, info.projectSummary);
|
|
141
|
+
console.log(ui.c('\n Type your request. Commands: /models, /switch, /info, exit', ui.C.dim));
|
|
142
|
+
console.log('');
|
|
143
|
+
|
|
144
|
+
if (initialPrompt) {
|
|
145
|
+
await processAgentPrompt(initialPrompt, agent);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: '' });
|
|
150
|
+
function prompt() { rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent)); }
|
|
151
|
+
prompt();
|
|
152
|
+
rl.on('close', () => { console.log(ui.c('\n Goodbye!\n', ui.C.green)); process.exit(0); });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function processAgentPrompt(text, agent) {
|
|
156
|
+
ui.printUser(text);
|
|
157
|
+
const stop = ui.startThinking('Generating');
|
|
158
|
+
try {
|
|
159
|
+
const response = await agent.chat(text);
|
|
160
|
+
stop();
|
|
161
|
+
ui.printAI(response);
|
|
162
|
+
const blocks = agent.extractCodeBlocks(response);
|
|
163
|
+
if (blocks.length > 0) {
|
|
164
|
+
console.log(ui.c('\n Files generated:', ui.C.brightGreen, ui.C.bold));
|
|
165
|
+
for (const b of blocks) console.log(ui.c(' - ' + b.filename, ui.C.green));
|
|
166
|
+
// Auto-save files
|
|
167
|
+
console.log(ui.c('\n Saving files...', ui.C.dim));
|
|
168
|
+
const written = agent.writeCodeBlocks(blocks);
|
|
169
|
+
for (const f of written) console.log(ui.c(' Saved: ' + f, ui.C.green));
|
|
170
|
+
}
|
|
171
|
+
} catch (err) { stop(); ui.printError(err.message); }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function handleAgent(line, rl, agent) {
|
|
175
|
+
const text = (line || '').trim();
|
|
176
|
+
if (!text) { rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent)); return; }
|
|
177
|
+
if (text === 'exit' || text === 'quit') { console.log(ui.c('\n Goodbye!\n', ui.C.green)); rl.close(); return; }
|
|
178
|
+
|
|
179
|
+
if (text === '/models') {
|
|
180
|
+
const models = agent.getModels();
|
|
181
|
+
ui.printTable(['Model', 'Name', 'Size'], models.map(m => [m.modelId, m.name, m.size]));
|
|
182
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (text.startsWith('/switch ')) {
|
|
187
|
+
const parts = text.slice(8).split(' ');
|
|
188
|
+
agent.setModel(parts[0], parts[1] || '');
|
|
189
|
+
ui.printSuccess('Switched to ' + parts[0]);
|
|
190
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (text === '/info') {
|
|
195
|
+
const info = agent.getModelInfo();
|
|
196
|
+
ui.printTable(['Setting', 'Value'], [['Provider', info.provider], ['Model', info.model], ['Project', info.projectSummary]]);
|
|
197
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (text === 'project') {
|
|
202
|
+
if (agent.analyzer) ui.printProjectFiles(agent.analyzer.files.slice(0, 20), agent.projectContext?.projectType);
|
|
203
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Generate and save
|
|
208
|
+
console.log('');
|
|
209
|
+
ui.printUser(text);
|
|
210
|
+
const stop = ui.startThinking('Generating');
|
|
211
|
+
rl.pause();
|
|
212
|
+
try {
|
|
213
|
+
const response = await agent.chat(text);
|
|
214
|
+
stop();
|
|
215
|
+
ui.printAI(response);
|
|
216
|
+
const blocks = agent.extractCodeBlocks(response);
|
|
217
|
+
if (blocks.length > 0) {
|
|
218
|
+
console.log(ui.c('\n Files generated:', ui.C.brightGreen, ui.C.bold));
|
|
219
|
+
for (const b of blocks) console.log(ui.c(' - ' + b.filename, ui.C.green));
|
|
220
|
+
console.log(ui.c('\n Saving files...', ui.C.dim));
|
|
221
|
+
const written = agent.writeCodeBlocks(blocks);
|
|
222
|
+
for (const f of written) console.log(ui.c(' Saved: ' + f, ui.C.green));
|
|
223
|
+
}
|
|
224
|
+
} catch (err) { stop(); ui.printError(err.message); }
|
|
225
|
+
rl.resume();
|
|
226
|
+
rl.question(ui.c(' You > ', ui.C.blue, ui.C.bold), (l) => handleAgent(l, rl, agent));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ─── Settings ──────────────────────────────────────────
|
|
230
|
+
function showSettings() {
|
|
231
|
+
const config = loadNetworkConfig();
|
|
232
|
+
const detectedIP = getLocalIP();
|
|
233
|
+
const ip = config.ip || detectedIP;
|
|
234
|
+
const port = config.port || 7860;
|
|
235
|
+
|
|
236
|
+
ui.printNetworkSetup(ip, port);
|
|
237
|
+
|
|
238
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
239
|
+
rl.question(ui.c(' Select option (1-3): ', ui.C.cyan), (answer) => {
|
|
240
|
+
if (answer === '1') {
|
|
241
|
+
saveNetworkConfig({ ...config, ip: detectedIP, autoConnect: true });
|
|
242
|
+
ui.printSuccess('Auto-detect IP: ' + detectedIP);
|
|
243
|
+
rl.close();
|
|
244
|
+
} else if (answer === '2') {
|
|
245
|
+
rl.question(ui.c(' Enter IP address: ', ui.C.cyan), (customIP) => {
|
|
246
|
+
saveNetworkConfig({ ...config, ip: customIP, autoConnect: false });
|
|
247
|
+
ui.printSuccess('Custom IP set: ' + customIP);
|
|
248
|
+
rl.close();
|
|
249
|
+
});
|
|
250
|
+
} else if (answer === '3') {
|
|
251
|
+
saveNetworkConfig({ ...config, ip: 'localhost', autoConnect: false });
|
|
252
|
+
ui.printSuccess('Using localhost only');
|
|
253
|
+
rl.close();
|
|
254
|
+
} else {
|
|
255
|
+
ui.printError('Invalid option');
|
|
256
|
+
rl.close();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ─── Server ────────────────────────────────────────────
|
|
262
|
+
function startServerMode() {
|
|
263
|
+
const config = loadNetworkConfig();
|
|
264
|
+
const detectedIP = getLocalIP();
|
|
265
|
+
const ip = config.autoConnect !== false ? detectedIP : (config.ip || detectedIP);
|
|
266
|
+
const port = parsePort();
|
|
267
|
+
|
|
268
|
+
ui.printBanner();
|
|
269
|
+
console.log(ui.c(' SERVER STARTED', ui.C.brightGreen, ui.C.bold));
|
|
270
|
+
console.log('');
|
|
271
|
+
ui.printTable(['Setting', 'Value'], [
|
|
272
|
+
['Local URL', 'http://localhost:' + port],
|
|
273
|
+
['Network URL', 'http://' + ip + ':' + port],
|
|
274
|
+
['IP', ip],
|
|
275
|
+
['Auto Connect', config.autoConnect !== false ? 'YES' : 'NO'],
|
|
276
|
+
]);
|
|
277
|
+
console.log(ui.c(' Connect: http://' + ip + ':' + port, ui.C.brightCyan, ui.C.bold, ui.C.underline));
|
|
278
|
+
console.log('');
|
|
279
|
+
|
|
280
|
+
const { startHybardServer } = require('../lib/server');
|
|
281
|
+
startHybardServer({ port });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ─── Main ──────────────────────────────────────────────
|
|
285
|
+
async function main() {
|
|
286
|
+
if (args.length === 0) { startChatMode(); return; }
|
|
287
|
+
|
|
288
|
+
switch (command) {
|
|
289
|
+
case 'help': case '--help': case '-h': ui.printBanner(); ui.printHelp(); break;
|
|
290
|
+
case 'version': case '-v': ui.printSuccess('hybard-agent v1.0.0'); break;
|
|
291
|
+
case 'chat': await startChat(); break;
|
|
292
|
+
case 'agent': await startAgentMode(rest); break;
|
|
293
|
+
case 'server': startServerMode(); break;
|
|
294
|
+
case 'settings': showSettings(); break;
|
|
295
|
+
case 'models':
|
|
296
|
+
const { ModelRouter } = require('../lib/models');
|
|
297
|
+
const router = new ModelRouter();
|
|
298
|
+
for (const p of router.listProviders()) {
|
|
299
|
+
console.log(ui.c('\n ' + p.name, ui.C.brightYellow, ui.C.bold));
|
|
300
|
+
ui.printTable(['Model', 'Name', 'Size'], router.listModels(p.id).map(m => [m.modelId, m.name, m.size]));
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case 'config':
|
|
304
|
+
if (!rest) {
|
|
305
|
+
const ai = new HybardAI();
|
|
306
|
+
ui.printTable(['Setting', 'Value'], [
|
|
307
|
+
['Provider', ai.config.provider], ['Model', ai.config.model],
|
|
308
|
+
['API Key', ai.getApiKey() ? '***' + ai.getApiKey().slice(-4) : 'NOT SET'],
|
|
309
|
+
]);
|
|
310
|
+
} else if (rest.startsWith('provider ')) {
|
|
311
|
+
const ai = new HybardAI();
|
|
312
|
+
try { ai.setProvider(rest.slice(9).trim()); ui.printSuccess('Switched to ' + rest.slice(9).trim()); }
|
|
313
|
+
catch (err) { ui.printError(err.message); }
|
|
314
|
+
} else if (rest.startsWith('set-key ')) {
|
|
315
|
+
const ai = new HybardAI();
|
|
316
|
+
ai.saveConfig({ apiKey: rest.slice(8).trim() });
|
|
317
|
+
ui.printSuccess('API key saved');
|
|
318
|
+
}
|
|
319
|
+
break;
|
|
320
|
+
case 'create': await runAgent(['create ' + rest]); break;
|
|
321
|
+
case 'fix': case 'inspect': case 'install': case 'plan': await runAgent([command + ' ' + rest]); break;
|
|
322
|
+
default: await runAgent([args.join(' ')]); break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
main().catch((err) => { ui.printError(err.message); process.exit(1); });
|
package/bin/hybard.cmd
ADDED