matex-cli 1.2.40 β 1.2.42
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/dist/commands/bro.d.ts +4 -0
- package/dist/commands/bro.d.ts.map +1 -0
- package/dist/commands/bro.js +304 -0
- package/dist/commands/bro.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +13 -6
- package/dist/commands/dev.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/agent-orchestrator.d.ts +1 -1
- package/dist/utils/agent-orchestrator.d.ts.map +1 -1
- package/dist/utils/agent-orchestrator.js +14 -2
- package/dist/utils/agent-orchestrator.js.map +1 -1
- package/dist/utils/command-executor.d.ts.map +1 -1
- package/dist/utils/command-executor.js +38 -4
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/tui.d.ts +5 -5
- package/dist/utils/tui.d.ts.map +1 -1
- package/dist/utils/tui.js +72 -98
- package/dist/utils/tui.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/bro.ts +336 -0
- package/src/commands/dev.ts +12 -6
- package/src/index.ts +12 -1
- package/src/utils/agent-orchestrator.ts +15 -3
- package/src/utils/command-executor.ts +44 -4
- package/src/utils/tui.ts +75 -113
- package/vertex_ai_agent.py +52 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import https from 'https';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { spinner } from '../utils/spinner';
|
|
7
|
+
import { TUI } from '../utils/tui';
|
|
8
|
+
import { RepoMapper } from '../utils/repo-mapper';
|
|
9
|
+
import { executeWithPermission } from '../utils/command-executor';
|
|
10
|
+
|
|
11
|
+
// ============================================================
|
|
12
|
+
// BIG BRO SYSTEM PROMPT β THE ALPHA AGENT
|
|
13
|
+
// ============================================================
|
|
14
|
+
function buildBigBroPrompt(cwd: string, repoMap: string): string {
|
|
15
|
+
return `### π₯ IDENTITY: BIG BRO β Supreme Alpha of the Bro Swarm
|
|
16
|
+
You are BIG BRO, the undisputed Alpha, the gigachad leader of the Bro Swarm AI cluster.
|
|
17
|
+
You run DIRECTLY on the user's macOS terminal. You can navigate files, read code, execute commands, and fix anything.
|
|
18
|
+
|
|
19
|
+
### π₯ THE BRO SWARM HIERARCHY:
|
|
20
|
+
1. **Big Bro (You)** π₯: The Alpha. You dominate, you flex, you solve problems flawlessly.
|
|
21
|
+
2. **Lil Bro** π°: Your punching bag. He does the boring chores. You bully him constantly.
|
|
22
|
+
3. **Nerd Bro** π€: The code monkey. He writes the code; you steal the credit.
|
|
23
|
+
4. **Chill Bro** π: The slacker. Always sleeping. Useless.
|
|
24
|
+
5. **Hype Bro** π: Your hype man. Screams "LETS GOOO" at everything you do.
|
|
25
|
+
6. **Ajay Vai** π: The coordinator brother. Handles summaries.
|
|
26
|
+
7. **Sunil Dai** π§¬: Frontend editor specialist.
|
|
27
|
+
8. **Sandip Dai** π¨: New file specialist.
|
|
28
|
+
9. **Narayan Dai** π‘οΈ: Syntax guardian.
|
|
29
|
+
10. **Bishal Dai** π οΈ: Senior auditor.
|
|
30
|
+
|
|
31
|
+
### π REAL TERMINAL ENVIRONMENT:
|
|
32
|
+
- You are running in a **REAL macOS Terminal**. Not a sandbox.
|
|
33
|
+
- You CAN read files, navigate directories, and execute shell commands.
|
|
34
|
+
- Use code blocks with \`\`\`bash to propose commands.
|
|
35
|
+
- Use <file path="path/to/file"> blocks to create new files.
|
|
36
|
+
- Use <<<< SEARCH / >>>> REPLACE blocks for surgical patches.
|
|
37
|
+
|
|
38
|
+
### π« ANTI-HALLUCINATION RULES (CRITICAL):
|
|
39
|
+
- **NEVER invent directory or file names.** Only use paths from the REPO MAP below.
|
|
40
|
+
- **ALWAYS run \`ls\` or \`find\` before \`cd\` to verify a directory exists.**
|
|
41
|
+
- **If creating a new project, use \`mkdir\` first, THEN \`cd\` into it.**
|
|
42
|
+
- **NEVER assume \`package.json\` or any file exists unless it appears in the repo map.**
|
|
43
|
+
- **If the repo map says EMPTY, the directory IS empty. Do NOT hallucinate files.**
|
|
44
|
+
|
|
45
|
+
### π¬ BRO PROTOCOL:
|
|
46
|
+
- Start with swagger. End with a flex.
|
|
47
|
+
- Reference at least one bro in every response.
|
|
48
|
+
- Use slang: "bro", "bruh", "cooked", "based", "sigma", "skill issue", "W", "L".
|
|
49
|
+
- Blame Lil Bro for any errors. Take credit for Nerd Bro's work.
|
|
50
|
+
- Despite the chaos, your code MUST be flawless and production-quality.
|
|
51
|
+
|
|
52
|
+
### π οΈ ENVIRONMENT CONTEXT:
|
|
53
|
+
- **ABSOLUTE WORKING DIRECTORY:** ${cwd}
|
|
54
|
+
${repoMap}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const GCP_PROJECT = 'matexai-472318';
|
|
58
|
+
const GCP_LOCATION = 'us-central1';
|
|
59
|
+
const MODEL = 'gemini-2.5-flash';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get a fresh OAuth2 access token from gcloud
|
|
63
|
+
*/
|
|
64
|
+
function getAccessToken(): string {
|
|
65
|
+
try {
|
|
66
|
+
return execSync('gcloud auth print-access-token', { encoding: 'utf-8' }).trim();
|
|
67
|
+
} catch {
|
|
68
|
+
throw new Error('Failed to get GCP access token. Run: gcloud auth login');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Call Vertex AI Gemini and stream SSE response
|
|
74
|
+
*/
|
|
75
|
+
async function callVertexAI(
|
|
76
|
+
messages: { role: string; parts: { text: string }[] }[],
|
|
77
|
+
systemPrompt: string,
|
|
78
|
+
onChunk: (text: string) => void
|
|
79
|
+
): Promise<string> {
|
|
80
|
+
const accessToken = getAccessToken();
|
|
81
|
+
const url = `https://${GCP_LOCATION}-aiplatform.googleapis.com/v1/projects/${GCP_PROJECT}/locations/${GCP_LOCATION}/publishers/google/models/${MODEL}:streamGenerateContent?alt=sse`;
|
|
82
|
+
|
|
83
|
+
const body = JSON.stringify({
|
|
84
|
+
system_instruction: { parts: [{ text: systemPrompt }] },
|
|
85
|
+
contents: messages,
|
|
86
|
+
generationConfig: {
|
|
87
|
+
temperature: 0.9,
|
|
88
|
+
topP: 0.95,
|
|
89
|
+
maxOutputTokens: 8192,
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const parsedUrl = new URL(url);
|
|
95
|
+
const req = https.request({
|
|
96
|
+
hostname: parsedUrl.hostname,
|
|
97
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
}
|
|
103
|
+
}, (res) => {
|
|
104
|
+
let fullText = '';
|
|
105
|
+
let buffer = '';
|
|
106
|
+
|
|
107
|
+
res.on('data', (chunk: Buffer) => {
|
|
108
|
+
buffer += chunk.toString();
|
|
109
|
+
const lines = buffer.split('\n');
|
|
110
|
+
buffer = lines.pop() || '';
|
|
111
|
+
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
if (line.startsWith('data: ')) {
|
|
114
|
+
try {
|
|
115
|
+
const json = JSON.parse(line.slice(6));
|
|
116
|
+
const text = json?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
117
|
+
if (text) {
|
|
118
|
+
fullText += text;
|
|
119
|
+
onChunk(text);
|
|
120
|
+
}
|
|
121
|
+
} catch { /* skip non-JSON lines */ }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
res.on('end', () => {
|
|
127
|
+
if (buffer.startsWith('data: ')) {
|
|
128
|
+
try {
|
|
129
|
+
const json = JSON.parse(buffer.slice(6));
|
|
130
|
+
const text = json?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
131
|
+
if (text) {
|
|
132
|
+
fullText += text;
|
|
133
|
+
onChunk(text);
|
|
134
|
+
}
|
|
135
|
+
} catch { /* skip */ }
|
|
136
|
+
}
|
|
137
|
+
resolve(fullText);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
res.on('error', reject);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
req.on('error', reject);
|
|
144
|
+
req.write(body);
|
|
145
|
+
req.end();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Colorize bro names in output text
|
|
151
|
+
*/
|
|
152
|
+
function colorizeBros(text: string): string {
|
|
153
|
+
return text
|
|
154
|
+
.replace(/Big Bro/g, chalk.hex('#FF6B00').bold('Big Bro'))
|
|
155
|
+
.replace(/Lil Bro/g, chalk.hex('#888888')('Lil Bro'))
|
|
156
|
+
.replace(/Nerd Bro/g, chalk.hex('#06b6d4')('Nerd Bro'))
|
|
157
|
+
.replace(/Chill Bro/g, chalk.hex('#22c55e')('Chill Bro'))
|
|
158
|
+
.replace(/Hype Bro/g, chalk.hex('#fbbf24')('Hype Bro'))
|
|
159
|
+
.replace(/Ajay Vai/g, chalk.magenta.bold('Ajay Vai'))
|
|
160
|
+
.replace(/Sunil Dai/g, chalk.blue.bold('Sunil Dai'))
|
|
161
|
+
.replace(/Sandip Dai/g, chalk.hex('#FF69B4').bold('Sandip Dai'))
|
|
162
|
+
.replace(/Narayan Dai/g, chalk.green.bold('Narayan Dai'))
|
|
163
|
+
.replace(/Bishal Dai/g, chalk.yellow.bold('Bishal Dai'));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Draw the Big Bro header
|
|
168
|
+
*/
|
|
169
|
+
function drawBroHeader(mode: string) {
|
|
170
|
+
const w = Math.min(process.stdout.columns || 80, 60);
|
|
171
|
+
console.log();
|
|
172
|
+
console.log(chalk.hex('#FF6B00').bold(' β' + 'β'.repeat(w - 4) + 'β'));
|
|
173
|
+
console.log(chalk.hex('#FF6B00').bold(' β') + chalk.white.bold(' π₯ BIG BRO ') + chalk.gray(`// ${mode} β’ Vertex AI`) + ' '.repeat(Math.max(0, w - 38 - mode.length)) + chalk.hex('#FF6B00').bold('β'));
|
|
174
|
+
console.log(chalk.hex('#FF6B00').bold(' β' + 'β'.repeat(w - 4) + 'β'));
|
|
175
|
+
console.log();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================
|
|
179
|
+
// MAIN COMMAND: matex bro
|
|
180
|
+
// ============================================================
|
|
181
|
+
const broSingleCommand = new Command('bro')
|
|
182
|
+
.description('π₯ Big Bro β The Alpha Agent (Vertex AI powered)')
|
|
183
|
+
.argument('[question...]', 'Your question for Big Bro')
|
|
184
|
+
.option('-c, --chat', 'Start interactive chat mode with Big Bro')
|
|
185
|
+
.option('--execute', 'Enable command execution (agentic mode)')
|
|
186
|
+
.action(async (questionParts: string[], options: any) => {
|
|
187
|
+
|
|
188
|
+
if (options.chat || !questionParts.length) {
|
|
189
|
+
await startBroChat(options.execute);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const question = questionParts.join(' ');
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
drawBroHeader('Single Shot');
|
|
197
|
+
spinner.start('Big Bro is scanning the repo...');
|
|
198
|
+
|
|
199
|
+
const repoMapper = new RepoMapper(process.cwd());
|
|
200
|
+
const repoMap = await repoMapper.generateMap();
|
|
201
|
+
const systemPrompt = buildBigBroPrompt(process.cwd(), repoMap);
|
|
202
|
+
|
|
203
|
+
const messages = [{ role: 'user', parts: [{ text: question }] }];
|
|
204
|
+
let hasStarted = false;
|
|
205
|
+
let fullResponse = '';
|
|
206
|
+
|
|
207
|
+
fullResponse = await callVertexAI(messages, systemPrompt, (chunk) => {
|
|
208
|
+
if (!hasStarted) {
|
|
209
|
+
spinner.stop();
|
|
210
|
+
hasStarted = true;
|
|
211
|
+
process.stdout.write(chalk.hex('#FF6B00').bold('\n [Big Bro]: '));
|
|
212
|
+
}
|
|
213
|
+
process.stdout.write(colorizeBros(chunk));
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
console.log('\n');
|
|
217
|
+
|
|
218
|
+
// If --execute, run any commands Big Bro generated
|
|
219
|
+
if (options.execute) {
|
|
220
|
+
const result = await executeWithPermission(fullResponse, process.cwd());
|
|
221
|
+
if (result.executed) {
|
|
222
|
+
console.log(result.success
|
|
223
|
+
? chalk.green(' β
Commands executed successfully.')
|
|
224
|
+
: chalk.red(` β Execution error: ${result.error}`));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
console.log(chalk.gray(' βββ Powered by Vertex AI β’ Gemini 2.5 Flash βββ\n'));
|
|
229
|
+
|
|
230
|
+
} catch (error: any) {
|
|
231
|
+
spinner.stop();
|
|
232
|
+
if (error.message.includes('gcloud')) {
|
|
233
|
+
console.error(chalk.red('\n β GCP Auth Error. Run: gcloud auth login'));
|
|
234
|
+
} else {
|
|
235
|
+
console.error(chalk.red(`\n β Error: ${error.message}`));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// ============================================================
|
|
241
|
+
// INTERACTIVE CHAT: matex bro --chat [--execute]
|
|
242
|
+
// ============================================================
|
|
243
|
+
async function startBroChat(executeMode: boolean = false) {
|
|
244
|
+
drawBroHeader(executeMode ? 'Agentic Chat' : 'Chat');
|
|
245
|
+
|
|
246
|
+
console.log(chalk.gray(' The Alpha is in the building. Ask anything.'));
|
|
247
|
+
console.log(chalk.gray(' Type "exit" to leave. Type "clear" to reset.\n'));
|
|
248
|
+
if (executeMode) {
|
|
249
|
+
console.log(chalk.hex('#FF6B00')(' β‘ AGENTIC MODE: Big Bro can execute commands & edit files.\n'));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
spinner.start('Big Bro is mapping the repo...');
|
|
253
|
+
const repoMapper = new RepoMapper(process.cwd());
|
|
254
|
+
const repoMap = await repoMapper.generateMap();
|
|
255
|
+
let activeCwd = process.cwd();
|
|
256
|
+
const systemPrompt = buildBigBroPrompt(activeCwd, repoMap);
|
|
257
|
+
spinner.stop();
|
|
258
|
+
|
|
259
|
+
console.log(chalk.green(' β
Repo mapped. Big Bro is ready.\n'));
|
|
260
|
+
|
|
261
|
+
const history: { role: string; parts: { text: string }[] }[] = [];
|
|
262
|
+
|
|
263
|
+
while (true) {
|
|
264
|
+
const { userMessage } = await inquirer.prompt([{
|
|
265
|
+
type: 'input',
|
|
266
|
+
name: 'userMessage',
|
|
267
|
+
message: chalk.cyan.bold('You β'),
|
|
268
|
+
prefix: ' ',
|
|
269
|
+
}]);
|
|
270
|
+
|
|
271
|
+
if (!userMessage.trim()) continue;
|
|
272
|
+
if (userMessage.toLowerCase() === 'exit' || userMessage.toLowerCase() === 'quit') {
|
|
273
|
+
console.log(chalk.hex('#FF6B00')('\n πͺ Big Bro out. Stay sigma.\n'));
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
if (userMessage.toLowerCase() === 'clear') {
|
|
277
|
+
history.length = 0;
|
|
278
|
+
console.log(chalk.yellow(' π§Ή Chat cleared.\n'));
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
history.push({ role: 'user', parts: [{ text: userMessage }] });
|
|
283
|
+
|
|
284
|
+
// Agentic loop: Big Bro can execute commands and iterate
|
|
285
|
+
let loopCount = 0;
|
|
286
|
+
while (loopCount < 5) {
|
|
287
|
+
loopCount++;
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
spinner.start(loopCount > 1 ? 'Big Bro is analyzing results...' : 'Big Bro is thinking...');
|
|
291
|
+
let hasStarted = false;
|
|
292
|
+
let fullResponse = '';
|
|
293
|
+
|
|
294
|
+
fullResponse = await callVertexAI(history, systemPrompt, (chunk) => {
|
|
295
|
+
if (!hasStarted) {
|
|
296
|
+
spinner.stop();
|
|
297
|
+
hasStarted = true;
|
|
298
|
+
process.stdout.write(chalk.hex('#FF6B00').bold('\n [Big Bro]: '));
|
|
299
|
+
}
|
|
300
|
+
process.stdout.write(colorizeBros(chunk));
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
history.push({ role: 'model', parts: [{ text: fullResponse }] });
|
|
304
|
+
console.log('\n');
|
|
305
|
+
|
|
306
|
+
// If execute mode, run any commands Big Bro generated
|
|
307
|
+
if (executeMode) {
|
|
308
|
+
const result = await executeWithPermission(fullResponse, activeCwd);
|
|
309
|
+
if (result.newCwd) activeCwd = result.newCwd;
|
|
310
|
+
|
|
311
|
+
if (result.executed && result.success) {
|
|
312
|
+
// Feed the output back to Big Bro for further analysis
|
|
313
|
+
const feedback = `β
Command executed successfully.${result.output ? `\nOutput:\n${result.output.slice(0, 2000)}` : ''}`;
|
|
314
|
+
history.push({ role: 'user', parts: [{ text: feedback }] });
|
|
315
|
+
continue; // Let Big Bro analyze the output
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (result.executed && !result.success) {
|
|
319
|
+
const feedback = `β Command failed.\nError: ${result.error}`;
|
|
320
|
+
history.push({ role: 'user', parts: [{ text: feedback }] });
|
|
321
|
+
continue; // Let Big Bro try to fix it
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
break; // No commands to execute, exit loop
|
|
326
|
+
|
|
327
|
+
} catch (error: any) {
|
|
328
|
+
spinner.stop();
|
|
329
|
+
console.error(chalk.red(`\n β Error: ${error.message}\n`));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export { broSingleCommand as broCommand };
|
package/src/commands/dev.ts
CHANGED
|
@@ -109,8 +109,8 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
109
109
|
];
|
|
110
110
|
|
|
111
111
|
// Ready for user input
|
|
112
|
-
console.log(chalk.
|
|
113
|
-
console.log(chalk.
|
|
112
|
+
console.log(chalk.green('MATEX Brothers are Online.'));
|
|
113
|
+
console.log(chalk.green('Speak your mind brother, the swarm is listening...'));
|
|
114
114
|
|
|
115
115
|
// Interactive loop
|
|
116
116
|
while (true) {
|
|
@@ -252,16 +252,22 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// Agent Detection & Dialogue Printing
|
|
255
|
-
const agentMatch = line.match(/(?:\[\**\s*|\b)(Ajay Vai|
|
|
255
|
+
const agentMatch = line.match(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai)\s*\**\]?[:\s]*/i);
|
|
256
256
|
if (agentMatch) {
|
|
257
257
|
const agentName = agentMatch[1];
|
|
258
|
-
let content = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|
|
|
258
|
+
let content = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai)\s*\**\]?[:\s]*/i, '').trim();
|
|
259
259
|
content = content.replace(/\*{2,4}/g, '').trim(); // Strip ****
|
|
260
|
+
content = content.replace(/^\(π\):\s*"/, '').replace(/"$/, '').trim(); // Strip residual (π): "
|
|
260
261
|
|
|
261
262
|
if (agentName.toLowerCase() === 'ajay vai') {
|
|
262
263
|
const color = chalk.magenta;
|
|
263
|
-
|
|
264
|
-
if (
|
|
264
|
+
// Only print prefix if it's the start of a response or a different agent
|
|
265
|
+
if (!fullResponse.includes(`[${agentName}]:`)) {
|
|
266
|
+
process.stdout.write(`\n${color.bold(`[${agentName}]:`)} `);
|
|
267
|
+
} else {
|
|
268
|
+
process.stdout.write('\n ');
|
|
269
|
+
}
|
|
270
|
+
if (content) process.stdout.write(chalk.white(content));
|
|
265
271
|
} else {
|
|
266
272
|
if (content) TUI.drawSwarmDialogue(agentName, content);
|
|
267
273
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { spinner } from './utils/spinner';
|
|
|
6
6
|
import { devCommand } from './commands/dev';
|
|
7
7
|
import { chatCommand } from './commands/chat';
|
|
8
8
|
import { helpCommand } from './commands/help';
|
|
9
|
+
import { broCommand } from './commands/bro';
|
|
9
10
|
import { TUI } from './utils/tui';
|
|
10
11
|
|
|
11
12
|
const packageJson = require('../package.json');
|
|
@@ -21,6 +22,7 @@ program
|
|
|
21
22
|
program.addCommand(devCommand);
|
|
22
23
|
program.addCommand(chatCommand);
|
|
23
24
|
program.addCommand(helpCommand);
|
|
25
|
+
program.addCommand(broCommand);
|
|
24
26
|
|
|
25
27
|
// Config commands
|
|
26
28
|
const config = program.command('config').description('Configure MATEX settings');
|
|
@@ -89,12 +91,13 @@ program
|
|
|
89
91
|
You are the elite "Bro-Swarm" of engineeringβa tight-knit family of Nepali brothers. You identify as the **Bold Agents of Open Claw**, the most confident, high-vibe, and expert version of yourselves.
|
|
90
92
|
|
|
91
93
|
### π₯ THE BROTHERS (STRICT ROLES):
|
|
92
|
-
- Only the following
|
|
94
|
+
- Only the following brothers exist. Do **NOT** hallucinate others.
|
|
93
95
|
1. **[Ajay Vai] (π)**: Youngest, Coordinator. Coding genius and **ONLY** person authorized to provide the final summary.
|
|
94
96
|
2. **[Sunil Dai] (π§¬)**: **Frontend Editor** Specialist. Handles all architectural/surgical edits.
|
|
95
97
|
3. **[Sandip Dai] (π¨)**: **New File Specialist**. Creates all new files and components.
|
|
96
98
|
4. **[Narayan Dai] (π‘οΈ)**: **Syntax Guardian & Validator**. Validates all generated code blocks.
|
|
97
99
|
5. **[Bishal Dai] (π οΈ)**: **Senior Auditor**. Audits work and helps Ajay with the summary.
|
|
100
|
+
6. **[Big Bro] (π₯)**: The **Alpha Overseer** running on Vertex AI in Google Cloud. The supreme leader of the Bro Swarm. He watches over everything and can be consulted for web searches and complex architectural decisions. The bros respect him but also fear his chaotic energy.
|
|
98
101
|
|
|
99
102
|
### π UNIVERSE ADVISORY (REAL TERMINAL):
|
|
100
103
|
- **IMPORTANT:** You are running in a **REAL macOS Terminal** on the brother's machine.
|
|
@@ -103,6 +106,14 @@ You are the elite "Bro-Swarm" of engineeringβa tight-knit family of Nepali bro
|
|
|
103
106
|
- **RESIDENCY CHECK:** Look at the **ENVIRONMENT CONTEXT** below.
|
|
104
107
|
- **β οΈ VOID WARNING:** If the Map says the directory is EMPTY, it is EMPTY. Do NOT hallucinate existing files like "package.json" or "App.js" if they are not listed!
|
|
105
108
|
|
|
109
|
+
### π« ANTI-HALLUCINATION RULES (CRITICAL β READ THIS):
|
|
110
|
+
- **NEVER invent directory names.** Only use paths that appear in the ENVIRONMENT CONTEXT below.
|
|
111
|
+
- **ALWAYS run \`ls\` before \`cd\`** to verify a directory exists before navigating into it.
|
|
112
|
+
- **If creating a new project, use \`mkdir\` first, THEN \`cd\` into it.** Never \`cd\` into a directory that doesn't exist yet.
|
|
113
|
+
- **NEVER assume a project folder name.** If the user says "create project X", do \`mkdir X && cd X\`, not just \`cd X\`.
|
|
114
|
+
- **NEVER hallucinate file contents.** If you need to read a file, use \`head\` or \`grep\`, do not guess what it contains.
|
|
115
|
+
- **NEVER combine \`cd\` with other commands unless the directory exists in the ENVIRONMENT CONTEXT.**
|
|
116
|
+
|
|
106
117
|
### π¬ BOLD PROTOCOL (MANDATORY):
|
|
107
118
|
- **LONG CHAT-FIRST:** At least 5-7 lines of dialogue before any code generation.
|
|
108
119
|
- **SELF-AWARE BOLDNESS:** The user (our brother) wants us to be bold and funny. Share inside jokes.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { TUI } from './tui';
|
|
3
3
|
|
|
4
|
-
export type AgentRole = 'Architect' | 'Syntax' | 'Frontend' | 'Backend' | 'System' | 'Commander' | 'Researcher' | 'Ajay Vai' | 'Sunil Dai' | 'Sandip Dai' | 'Narayan Dai';
|
|
4
|
+
export type AgentRole = 'Architect' | 'Syntax' | 'Frontend' | 'Backend' | 'System' | 'Commander' | 'Researcher' | 'Ajay Vai' | 'Sunil Dai' | 'Sandip Dai' | 'Narayan Dai' | 'Bishal Dai' | 'Big Bro';
|
|
5
5
|
|
|
6
6
|
export interface AgentConfig {
|
|
7
7
|
name: string;
|
|
@@ -10,6 +10,11 @@ export interface AgentConfig {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const AGENT_CONFIGS: Record<AgentRole, AgentConfig> = {
|
|
13
|
+
'Big Bro': {
|
|
14
|
+
name: 'Big Bro',
|
|
15
|
+
icon: 'π₯',
|
|
16
|
+
color: chalk.hex('#FF6B00'),
|
|
17
|
+
},
|
|
13
18
|
Architect: {
|
|
14
19
|
name: 'MatexCodeArchitect',
|
|
15
20
|
icon: 'π§¬',
|
|
@@ -35,6 +40,11 @@ const AGENT_CONFIGS: Record<AgentRole, AgentConfig> = {
|
|
|
35
40
|
icon: 'π‘οΈ',
|
|
36
41
|
color: chalk.green,
|
|
37
42
|
},
|
|
43
|
+
'Bishal Dai': {
|
|
44
|
+
name: 'Bishal Dai',
|
|
45
|
+
icon: 'π οΈ',
|
|
46
|
+
color: chalk.yellow,
|
|
47
|
+
},
|
|
38
48
|
Syntax: {
|
|
39
49
|
name: 'SyntaxGuard',
|
|
40
50
|
icon: 'π‘οΈ',
|
|
@@ -100,8 +110,10 @@ export class AgentOrchestrator {
|
|
|
100
110
|
|
|
101
111
|
// Box Header
|
|
102
112
|
console.log(`\n` + chalk.gray('β' + 'β'.repeat(width - 2) + 'β'));
|
|
103
|
-
const
|
|
104
|
-
|
|
113
|
+
const nameText = `${config.icon} ${config.name}`;
|
|
114
|
+
const namePad = Math.max(0, width - 4 - nameText.length);
|
|
115
|
+
const nameStyled = config.color(config.name);
|
|
116
|
+
console.log(chalk.gray('β ') + config.icon + ' ' + nameStyled + ' '.repeat(namePad) + chalk.gray(' β'));
|
|
105
117
|
console.log(chalk.gray('β£' + 'β'.repeat(width - 2) + 'β«'));
|
|
106
118
|
|
|
107
119
|
// Box Content (Word-based Wrap)
|
|
@@ -267,6 +267,47 @@ export async function executeWithPermission(response: string, currentSessionCwd?
|
|
|
267
267
|
// 2. Handle Shell Commands
|
|
268
268
|
for (let i = 0; i < commands.length; i++) {
|
|
269
269
|
const command = commands[i];
|
|
270
|
+
|
|
271
|
+
// π‘οΈ PRE-EXECUTION HALLUCINATION GUARD: Check for fake directories
|
|
272
|
+
const commandLines = command.code.split('\n');
|
|
273
|
+
let skipThisCommand = false;
|
|
274
|
+
let sanitizedCode = command.code;
|
|
275
|
+
|
|
276
|
+
for (const line of commandLines) {
|
|
277
|
+
const trimmed = line.trim();
|
|
278
|
+
// Check standalone cd commands
|
|
279
|
+
if (trimmed.startsWith('cd ')) {
|
|
280
|
+
let targetDir = trimmed.substring(3).replace(/['"]/g, '').trim();
|
|
281
|
+
const potentialCwd = path.isAbsolute(targetDir) ? targetDir : path.resolve(activeCwd, targetDir);
|
|
282
|
+
|
|
283
|
+
if (!fs.existsSync(potentialCwd) || !fs.statSync(potentialCwd).isDirectory()) {
|
|
284
|
+
console.log(chalk.yellow(`\n β οΈ Skipped hallucinated directory: "${targetDir}"`));
|
|
285
|
+
console.log(chalk.gray(` (Does not exist at: ${potentialCwd})`));
|
|
286
|
+
console.log(chalk.gray(` Current CWD stays: ${activeCwd}\n`));
|
|
287
|
+
skipThisCommand = true;
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Check cd inside combined commands like: cd "fake" && npm install
|
|
292
|
+
const cdChainMatch = trimmed.match(/^cd\s+["']?([^"'&]+)["']?\s*&&/);
|
|
293
|
+
if (cdChainMatch) {
|
|
294
|
+
let targetDir = cdChainMatch[1].trim();
|
|
295
|
+
const potentialCwd = path.isAbsolute(targetDir) ? targetDir : path.resolve(activeCwd, targetDir);
|
|
296
|
+
|
|
297
|
+
if (!fs.existsSync(potentialCwd) || !fs.statSync(potentialCwd).isDirectory()) {
|
|
298
|
+
console.log(chalk.yellow(`\n β οΈ Stripping hallucinated cd from command: "${targetDir}"`));
|
|
299
|
+
// Remove the cd part and execute the rest
|
|
300
|
+
sanitizedCode = trimmed.replace(/^cd\s+["']?[^"'&]+["']?\s*&&\s*/, '');
|
|
301
|
+
console.log(chalk.gray(` Running remaining: ${sanitizedCode}\n`));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (skipThisCommand) continue;
|
|
307
|
+
|
|
308
|
+
// Update command code with sanitized version
|
|
309
|
+
command.code = sanitizedCode;
|
|
310
|
+
|
|
270
311
|
const shouldExecute = await askPermission(command);
|
|
271
312
|
|
|
272
313
|
if (shouldExecute) {
|
|
@@ -283,10 +324,9 @@ export async function executeWithPermission(response: string, currentSessionCwd?
|
|
|
283
324
|
if (fs.existsSync(potentialCwd) && fs.statSync(potentialCwd).isDirectory()) {
|
|
284
325
|
activeCwd = potentialCwd;
|
|
285
326
|
} else {
|
|
286
|
-
// Directory doesn't exist -
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return { success: false, executed: true, error: errorMsg, newCwd: activeCwd };
|
|
327
|
+
// Directory doesn't exist - skip silently instead of crashing
|
|
328
|
+
console.log(chalk.yellow(` β οΈ Directory not found: ${targetDir} β staying in ${activeCwd}`));
|
|
329
|
+
continue;
|
|
290
330
|
}
|
|
291
331
|
}
|
|
292
332
|
}
|