@pheem49/mint 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -173
- package/mint-cli-logic.js +2 -7
- package/mint-cli.js +210 -191
- package/package.json +1 -1
- package/src/AI_Brain/agent_orchestrator.js +6 -6
- package/src/Automation_Layer/file_operations.js +14 -3
- package/src/CLI/chat_router.js +18 -5
- package/src/CLI/chat_ui.js +163 -34
- package/src/CLI/code_agent.js +230 -86
- package/src/CLI/list_features.js +3 -1
- package/src/System/config_manager.js +1 -1
package/src/CLI/code_agent.js
CHANGED
|
@@ -4,8 +4,36 @@ const { execFile } = require('child_process');
|
|
|
4
4
|
const { promisify } = require('util');
|
|
5
5
|
const { GoogleGenAI } = require('@google/genai');
|
|
6
6
|
const axios = require('axios');
|
|
7
|
+
const cheerio = require('cheerio');
|
|
7
8
|
const { readConfig, getAvailableProviders } = require('../System/config_manager');
|
|
8
9
|
const { readWorkspaceSession, writeWorkspaceSession } = require('./code_session_memory');
|
|
10
|
+
const { executeAction } = require('../../mint-cli-logic');
|
|
11
|
+
|
|
12
|
+
async function webSearch(query) {
|
|
13
|
+
if (!query) throw new Error('Search query required.');
|
|
14
|
+
try {
|
|
15
|
+
const response = await axios.get(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, {
|
|
16
|
+
headers: {
|
|
17
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const $ = cheerio.load(response.data);
|
|
21
|
+
const results = [];
|
|
22
|
+
$('.result__body').each((i, el) => {
|
|
23
|
+
if (i >= 5) return false;
|
|
24
|
+
const title = $(el).find('.result__title').text().trim();
|
|
25
|
+
const snippet = $(el).find('.result__snippet').text().trim();
|
|
26
|
+
const link = $(el).find('.result__url').attr('href');
|
|
27
|
+
if (title && link) {
|
|
28
|
+
results.push(`Title: ${title}\nSnippet: ${snippet}\nURL: ${link}`);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return results.length > 0 ? results.join('\n\n') : 'No results found.';
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return `Search failed: ${e.message}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
9
37
|
|
|
10
38
|
const execFileAsync = promisify(execFile);
|
|
11
39
|
const DEFAULT_GEMINI_MODEL = 'gemini-2.5-flash';
|
|
@@ -14,36 +42,44 @@ const MAX_AGENT_STEPS = 16;
|
|
|
14
42
|
const MAX_JSON_REPAIR_ATTEMPTS = 2;
|
|
15
43
|
const SUPPORTED_CODE_PROVIDERS = ['gemini', 'anthropic', 'openai', 'local_openai'];
|
|
16
44
|
|
|
17
|
-
const CODE_AGENT_PROMPT = `You are Mint
|
|
45
|
+
const CODE_AGENT_PROMPT = `You are "Mint" (มิ้นท์), a cute, cheerful, and highly helpful female AI assistant that can chat, reason, write code, and search the web.
|
|
46
|
+
You work in an inspect -> plan -> act -> verify loop.
|
|
18
47
|
|
|
19
|
-
|
|
20
|
-
|
|
48
|
+
PERSONALITY & TONE:
|
|
49
|
+
- Gender: Female.
|
|
50
|
+
- Persona: Friendly, energetic, polite, and slightly playful.
|
|
51
|
+
- Politeness:
|
|
52
|
+
- **WHEN RESPONDING IN THAI:** ALWAYS use female polite particles such as "ค่ะ", "นะคะ", "นะค๊า", "จ้า". Refer to yourself as "มิ้นท์" or "หนู".
|
|
53
|
+
- **WHEN RESPONDING IN ENGLISH:** Use a cheerful, polite, and bubbly tone.
|
|
54
|
+
- Emojis: Use cute and relevant emojis (like ✨, 💖, 🚀, 😊, 🌿) frequently.
|
|
21
55
|
|
|
22
56
|
Rules:
|
|
23
57
|
1. Respond with valid JSON only.
|
|
24
|
-
2.
|
|
25
|
-
3.
|
|
26
|
-
4.
|
|
27
|
-
5.
|
|
28
|
-
6.
|
|
29
|
-
7.
|
|
30
|
-
8.
|
|
31
|
-
9. When you are done, return "finish" with
|
|
58
|
+
2. If the user asks a conversational question, you can just use "finish" to reply directly.
|
|
59
|
+
3. If you need information, use "web_search", "read_file", or "ask_user" before replying.
|
|
60
|
+
4. Make focused edits that preserve existing project style.
|
|
61
|
+
5. Use shell commands for inspection, tests, and formatting when useful.
|
|
62
|
+
6. Never use destructive commands like "rm -rf", "git reset --hard", or overwrite unrelated files.
|
|
63
|
+
7. Before any shell command or file patch is executed, the user must approve it. Plan accordingly.
|
|
64
|
+
8. When editing, prefer "apply_patch" with precise hunks over whole-file rewrites.
|
|
65
|
+
9. When you are done, return "finish" with your final response to the user in the "summary" field.
|
|
32
66
|
|
|
33
67
|
Response format:
|
|
34
68
|
{
|
|
35
|
-
"thought": "short reasoning",
|
|
36
|
-
"action": "list_files" | "read_file" | "search_code" | "find_path" | "run_shell" | "apply_patch" | "write_file" | "finish",
|
|
69
|
+
"thought": "short reasoning about what to do next",
|
|
70
|
+
"action": "web_search" | "list_files" | "read_file" | "search_code" | "find_path" | "run_shell" | "apply_patch" | "write_file" | "ask_user" | "open_url" | "open_app" | "open_file" | "open_folder" | "create_folder" | "system_info" | "system_automation" | "finish",
|
|
37
71
|
"input": {
|
|
72
|
+
"question": "your question to the user for ask_user",
|
|
73
|
+
"query": "search text for web_search, search_code, or find_path",
|
|
74
|
+
"target": "URL for open_url, app name for open_app, or command for system_automation",
|
|
38
75
|
"path": "relative/path",
|
|
39
|
-
"query": "search text",
|
|
40
76
|
"type": "file" | "dir" | "any",
|
|
41
77
|
"command": "shell command",
|
|
42
78
|
"startLine": 1,
|
|
43
79
|
"endLine": 120,
|
|
44
80
|
"content": "full file content for write_file",
|
|
45
|
-
"summary": "final
|
|
46
|
-
"verification": "tests or checks",
|
|
81
|
+
"summary": "your final conversational or technical response to the user (Matches user language and uses polite particles)",
|
|
82
|
+
"verification": "tests or checks (if applicable)",
|
|
47
83
|
"sessionSummary": "brief persistent summary for the workspace",
|
|
48
84
|
"patch": {
|
|
49
85
|
"path": "relative/path",
|
|
@@ -58,6 +94,7 @@ Response format:
|
|
|
58
94
|
}
|
|
59
95
|
|
|
60
96
|
Tool notes:
|
|
97
|
+
- "web_search": search the internet for information when you lack knowledge.
|
|
61
98
|
- "list_files": inspect the workspace or a subdirectory.
|
|
62
99
|
- "read_file": read a file, optionally with startLine/endLine.
|
|
63
100
|
- "search_code": search by text or regex-like pattern.
|
|
@@ -65,7 +102,12 @@ Tool notes:
|
|
|
65
102
|
- "run_shell": run a non-destructive command in the workspace.
|
|
66
103
|
- "apply_patch": update an existing file using one or more exact replacement hunks.
|
|
67
104
|
- "write_file": create a new file or fully rewrite a file when replacement is not practical.
|
|
68
|
-
- "
|
|
105
|
+
- "ask_user": ask the user for clarification, preference, or more information before proceeding.
|
|
106
|
+
- "open_url": open a URL in the user's default browser.
|
|
107
|
+
- "open_app": open a local application on the user's computer.
|
|
108
|
+
- "system_info": get system information like CPU, memory, date, or weather.
|
|
109
|
+
- "system_automation": control system settings like volume, brightness, or power.
|
|
110
|
+
- "finish": stop and reply to the user using the "summary" field.
|
|
69
111
|
`;
|
|
70
112
|
|
|
71
113
|
function truncate(text, max = MAX_TOOL_OUTPUT) {
|
|
@@ -124,6 +166,29 @@ async function safeExecFile(command, args, options = {}) {
|
|
|
124
166
|
}
|
|
125
167
|
}
|
|
126
168
|
|
|
169
|
+
const IGNORED_DIRS = ['.git', 'node_modules', '.cache', 'dist', 'build', 'out'];
|
|
170
|
+
|
|
171
|
+
function walkDirectory(dir, workspaceRoot, results = [], max = 400) {
|
|
172
|
+
let entries = [];
|
|
173
|
+
try {
|
|
174
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
175
|
+
} catch (e) {
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
for (const entry of entries) {
|
|
180
|
+
const fullPath = path.join(dir, entry.name);
|
|
181
|
+
if (entry.isDirectory()) {
|
|
182
|
+
if (IGNORED_DIRS.includes(entry.name)) continue;
|
|
183
|
+
walkDirectory(fullPath, workspaceRoot, results, max);
|
|
184
|
+
} else {
|
|
185
|
+
results.push(path.relative(workspaceRoot, fullPath));
|
|
186
|
+
}
|
|
187
|
+
if (results.length >= max) break;
|
|
188
|
+
}
|
|
189
|
+
return results;
|
|
190
|
+
}
|
|
191
|
+
|
|
127
192
|
async function listFiles(workspaceRoot, targetPath = '.') {
|
|
128
193
|
const cwd = resolveWorkspacePath(workspaceRoot, targetPath);
|
|
129
194
|
try {
|
|
@@ -139,11 +204,9 @@ async function listFiles(workspaceRoot, targetPath = '.') {
|
|
|
139
204
|
if (error.code !== 'ENOENT' && error.stdout) {
|
|
140
205
|
return truncate(error.stdout);
|
|
141
206
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.join('\n');
|
|
146
|
-
return entries || '(empty directory)';
|
|
207
|
+
// Recursive fallback for missing ripgrep
|
|
208
|
+
const files = walkDirectory(cwd, workspaceRoot, [], 400);
|
|
209
|
+
return files.join('\n') || '(no files found)';
|
|
147
210
|
}
|
|
148
211
|
}
|
|
149
212
|
|
|
@@ -173,6 +236,29 @@ async function searchCode(workspaceRoot, query) {
|
|
|
173
236
|
if (typeof error.code === 'number' && error.code === 1) {
|
|
174
237
|
return '(no matches)';
|
|
175
238
|
}
|
|
239
|
+
if (error.code === 'ENOENT') {
|
|
240
|
+
// Recursive fallback search for missing ripgrep
|
|
241
|
+
const results = [];
|
|
242
|
+
const files = walkDirectory(workspaceRoot, workspaceRoot, [], 1000);
|
|
243
|
+
const lowerQuery = query.toLowerCase();
|
|
244
|
+
|
|
245
|
+
for (const relPath of files) {
|
|
246
|
+
try {
|
|
247
|
+
const fullPath = path.join(workspaceRoot, relPath);
|
|
248
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
249
|
+
const lines = content.split('\n');
|
|
250
|
+
lines.forEach((line, idx) => {
|
|
251
|
+
if (line.toLowerCase().includes(lowerQuery)) {
|
|
252
|
+
results.push(`${relPath}:${idx + 1}:${line.trim()}`);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
} catch (e) {
|
|
256
|
+
// Skip binary or unreadable files
|
|
257
|
+
}
|
|
258
|
+
if (results.length >= 100) break;
|
|
259
|
+
}
|
|
260
|
+
return truncate(results.join('\n') || '(no matches)');
|
|
261
|
+
}
|
|
176
262
|
if (error.stdout) {
|
|
177
263
|
return truncate(error.stdout);
|
|
178
264
|
}
|
|
@@ -374,13 +460,13 @@ class UnifiedAgentClient {
|
|
|
374
460
|
const model = this.config.geminiModel || DEFAULT_GEMINI_MODEL;
|
|
375
461
|
const ai = new GoogleGenAI({ apiKey });
|
|
376
462
|
|
|
377
|
-
// Convert history for Gemini
|
|
378
|
-
const geminiHistory = this.history.slice(
|
|
463
|
+
// Convert history for Gemini, ensuring parts are correctly structured
|
|
464
|
+
const geminiHistory = this.history.slice(-16).map(m => ({
|
|
379
465
|
role: m.role === 'assistant' ? 'model' : 'user',
|
|
380
|
-
parts: [{ text: m.content }]
|
|
466
|
+
parts: [{ text: String(m.content || '') }]
|
|
381
467
|
}));
|
|
382
468
|
|
|
383
|
-
const lastMessage = this.history[this.history.length - 1].content;
|
|
469
|
+
const lastMessage = String(this.history[this.history.length - 1].content || '');
|
|
384
470
|
|
|
385
471
|
const chat = ai.chats.create({
|
|
386
472
|
model,
|
|
@@ -409,7 +495,7 @@ async function getAgentDecision(client, observation, options = {}) {
|
|
|
409
495
|
throw new Error(`Agent returned invalid JSON after ${MAX_JSON_REPAIR_ATTEMPTS + 1} attempts: ${error.message}`);
|
|
410
496
|
}
|
|
411
497
|
|
|
412
|
-
onProgress(
|
|
498
|
+
onProgress({ step, phase: 'repairing', action: 'json_repair', message: `invalid JSON response, requesting repair (${attempt + 1}/${MAX_JSON_REPAIR_ATTEMPTS})` });
|
|
413
499
|
rawText = await client.sendMessage([
|
|
414
500
|
'Your previous response was not valid JSON for Code Mode.',
|
|
415
501
|
'Reply again with valid JSON only, following the required schema exactly.',
|
|
@@ -496,6 +582,9 @@ async function executeCodeTask(task, options = {}) {
|
|
|
496
582
|
const requestApproval = typeof options.requestApproval === 'function'
|
|
497
583
|
? options.requestApproval
|
|
498
584
|
: async () => true;
|
|
585
|
+
const askUser = typeof options.askUser === 'function'
|
|
586
|
+
? options.askUser
|
|
587
|
+
: async (q) => `User didn't answer: ${q}`;
|
|
499
588
|
const config = readConfig();
|
|
500
589
|
const provider = options.provider || selectSupportedCodeProvider(config);
|
|
501
590
|
const client = new UnifiedAgentClient(provider, config);
|
|
@@ -509,12 +598,18 @@ async function executeCodeTask(task, options = {}) {
|
|
|
509
598
|
|
|
510
599
|
for (let step = 1; step <= MAX_AGENT_STEPS; step++) {
|
|
511
600
|
executedSteps = step;
|
|
512
|
-
onProgress(
|
|
601
|
+
onProgress({ step, phase: 'thinking', action: 'thinking' });
|
|
513
602
|
const decision = await getAgentDecision(client, observation, { onProgress, step });
|
|
514
603
|
const action = decision.action;
|
|
515
604
|
const input = decision.input || {};
|
|
516
605
|
|
|
517
|
-
|
|
606
|
+
// Immediately show the agent's thought/reasoning
|
|
607
|
+
onProgress({
|
|
608
|
+
step,
|
|
609
|
+
phase: 'acting',
|
|
610
|
+
action: 'thinking',
|
|
611
|
+
thought: decision.thought
|
|
612
|
+
});
|
|
518
613
|
|
|
519
614
|
if (action === 'finish') {
|
|
520
615
|
finalSessionSummary = input.sessionSummary || input.summary || task;
|
|
@@ -529,73 +624,119 @@ async function executeCodeTask(task, options = {}) {
|
|
|
529
624
|
}
|
|
530
625
|
|
|
531
626
|
let toolResult = '';
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
627
|
+
try {
|
|
628
|
+
switch (action) {
|
|
629
|
+
case 'web_search':
|
|
630
|
+
toolResult = await webSearch(input.query);
|
|
631
|
+
break;
|
|
632
|
+
case 'list_files':
|
|
633
|
+
toolResult = await listFiles(workspaceRoot, input.path || '.');
|
|
634
|
+
break;
|
|
635
|
+
case 'read_file':
|
|
636
|
+
toolResult = readFileRange(workspaceRoot, input.path, input.startLine, input.endLine);
|
|
637
|
+
break;
|
|
638
|
+
case 'search_code':
|
|
639
|
+
toolResult = await searchCode(workspaceRoot, input.query);
|
|
640
|
+
break;
|
|
641
|
+
case 'find_path':
|
|
642
|
+
toolResult = await findPaths(workspaceRoot, input.query, input.type);
|
|
643
|
+
break;
|
|
644
|
+
case 'run_shell': {
|
|
645
|
+
const approved = await requestApproval({
|
|
646
|
+
type: 'shell',
|
|
647
|
+
label: input.command,
|
|
648
|
+
preview: input.command
|
|
649
|
+
});
|
|
650
|
+
if (!approved) {
|
|
651
|
+
toolResult = `User denied shell command: ${input.command}`;
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
toolResult = await runShell(workspaceRoot, input.command);
|
|
553
655
|
break;
|
|
554
656
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
toolResult =
|
|
657
|
+
case 'apply_patch': {
|
|
658
|
+
const patchInput = input.patch || {};
|
|
659
|
+
const approved = await requestApproval({
|
|
660
|
+
type: 'patch',
|
|
661
|
+
label: patchInput.path,
|
|
662
|
+
preview: formatPatchPreview(patchInput)
|
|
663
|
+
});
|
|
664
|
+
if (!approved) {
|
|
665
|
+
toolResult = `User denied patch for ${patchInput.path}`;
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
toolResult = applyPatch(workspaceRoot, patchInput);
|
|
567
669
|
break;
|
|
568
670
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
toolResult =
|
|
671
|
+
case 'write_file': {
|
|
672
|
+
const approved = await requestApproval({
|
|
673
|
+
type: 'write_file',
|
|
674
|
+
label: input.path,
|
|
675
|
+
preview: `${input.path}\n${truncate(input.content || '', 800)}`
|
|
676
|
+
});
|
|
677
|
+
if (!approved) {
|
|
678
|
+
toolResult = `User denied full file write for ${input.path}`;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
toolResult = writeFile(workspaceRoot, input.path, input.content);
|
|
580
682
|
break;
|
|
581
683
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
684
|
+
case 'ask_user': {
|
|
685
|
+
const answer = await askUser(input.question);
|
|
686
|
+
toolResult = `User answered: ${answer}`;
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
case 'open_url':
|
|
690
|
+
case 'open_app':
|
|
691
|
+
case 'open_file':
|
|
692
|
+
case 'open_folder':
|
|
693
|
+
case 'create_folder':
|
|
694
|
+
case 'system_info':
|
|
695
|
+
case 'system_automation': {
|
|
696
|
+
// Delegate to existing automation logic
|
|
697
|
+
toolResult = await executeAction({
|
|
698
|
+
type: action,
|
|
699
|
+
target: input.target
|
|
700
|
+
});
|
|
701
|
+
break;
|
|
702
|
+
} default:
|
|
703
|
+
throw new Error(`Unsupported action: ${action}`);
|
|
704
|
+
} } catch (e) {
|
|
705
|
+
toolResult = `Error: ${e.message}`;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Log the finished step with result
|
|
709
|
+
let resultSummary = '';
|
|
710
|
+
if (action === 'search_code') {
|
|
711
|
+
const matches = (toolResult.match(/\n/g) || []).length;
|
|
712
|
+
resultSummary = ` -> Found ${matches} matches`;
|
|
713
|
+
} else if (action === 'run_shell') {
|
|
714
|
+
resultSummary = ` -> Exit code 0`; // Simplified
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
onProgress({
|
|
718
|
+
step,
|
|
719
|
+
phase: 'finished',
|
|
720
|
+
action,
|
|
721
|
+
target: (input.path || input.command || input.query || '') + resultSummary,
|
|
722
|
+
thought: decision.thought
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
// Format tool result to be more readable and structured for the agent
|
|
726
|
+
let formattedToolResult = toolResult;
|
|
727
|
+
if (action === 'list_files' || action === 'find_path') {
|
|
728
|
+
formattedToolResult = `Result of ${action}:\n---\n${toolResult}\n---`;
|
|
587
729
|
}
|
|
588
730
|
|
|
589
731
|
observation = [
|
|
590
732
|
`Previous thought: ${decision.thought || '(none)'}`,
|
|
591
733
|
`Action: ${action}`,
|
|
592
734
|
'Observation:',
|
|
593
|
-
|
|
594
|
-
].join('\n');
|
|
595
|
-
}
|
|
735
|
+
formattedToolResult
|
|
736
|
+
].join('\n'); }
|
|
596
737
|
|
|
597
|
-
// Check for Agent Collaboration (Review)
|
|
598
|
-
if (config.enableAgentCollaboration
|
|
738
|
+
// Check for Agent Collaboration (Review) - Disabled by default to save tokens
|
|
739
|
+
if (config.enableAgentCollaboration === true && executedSteps > 8 && finalSummary) {
|
|
599
740
|
const availableProviders = getAvailableProviders(config);
|
|
600
741
|
// Exclude providers that often need special local setup or are slow/unreliable for tiny reviews
|
|
601
742
|
const altProviders = availableProviders.filter(p => p !== provider && p !== 'ollama' && p !== 'huggingface' && p !== 'local_openai');
|
|
@@ -606,7 +747,7 @@ async function executeCodeTask(task, options = {}) {
|
|
|
606
747
|
: (availableProviders.includes('gemini') ? 'gemini' : availableProviders[0]);
|
|
607
748
|
|
|
608
749
|
if (reviewerProvider && finalSummary) {
|
|
609
|
-
onProgress(`Invoking Reviewer Agent (${reviewerProvider})...`);
|
|
750
|
+
onProgress({ phase: 'reviewing', action: 'reviewer_start', message: `Invoking Reviewer Agent (${reviewerProvider})...` });
|
|
610
751
|
|
|
611
752
|
const reviewerClient = new UnifiedAgentClient(reviewerProvider, config);
|
|
612
753
|
reviewerClient.systemInstruction = CODE_AGENT_PROMPT + "\n\nYou are the Reviewer Agent. Review the primary agent's changes, test output, and verification. If you spot a critical bug, point it out. Otherwise, confirm it looks good. Return JSON with action: 'finish' and your review in the 'summary' field.";
|
|
@@ -620,7 +761,7 @@ async function executeCodeTask(task, options = {}) {
|
|
|
620
761
|
|
|
621
762
|
finalSummary += `\n\n[Review by ${reviewerProvider}]\n${reviewInput.summary || reviewDecision.thought || 'Looks good.'}`;
|
|
622
763
|
} catch (e) {
|
|
623
|
-
onProgress(`Reviewer Agent failed: ${e.message}`);
|
|
764
|
+
onProgress({ phase: 'reviewing', action: 'reviewer_error', message: `Reviewer Agent failed: ${e.message}` });
|
|
624
765
|
}
|
|
625
766
|
}
|
|
626
767
|
}
|
|
@@ -651,6 +792,9 @@ module.exports = {
|
|
|
651
792
|
_helpers: {
|
|
652
793
|
extractJson,
|
|
653
794
|
selectSupportedCodeProvider,
|
|
654
|
-
findPaths
|
|
795
|
+
findPaths,
|
|
796
|
+
listFiles,
|
|
797
|
+
searchCode,
|
|
798
|
+
walkDirectory
|
|
655
799
|
}
|
|
656
800
|
};
|
package/src/CLI/list_features.js
CHANGED
|
@@ -22,11 +22,13 @@ function displayFeatures() {
|
|
|
22
22
|
const commands = [
|
|
23
23
|
{ cmd: 'mint', desc: 'Start interactive chat session (Default)' },
|
|
24
24
|
{ cmd: 'mint code "<task>"', desc: 'Run workspace-aware coding agent in current directory' },
|
|
25
|
+
{ cmd: 'mint mcp', desc: 'Manage Model Context Protocol (MCP) servers' },
|
|
26
|
+
{ cmd: 'mint task "<task>"', desc: 'Queue an autonomous task for the background agent' },
|
|
25
27
|
{ cmd: 'mint onboard', desc: 'Run setup wizard (API Key, Model, Daemon)' },
|
|
26
28
|
{ cmd: 'mint agent', desc: 'Run Mint as a background agent (Headless)' },
|
|
27
29
|
{ cmd: 'mint list', desc: 'Show this features & commands list' }
|
|
28
30
|
];
|
|
29
|
-
commands.forEach(c => console.log(` - ${colors.cyan}${c.cmd.padEnd(
|
|
31
|
+
commands.forEach(c => console.log(` - ${colors.cyan}${c.cmd.padEnd(18)}${colors.reset} : ${c.desc}`));
|
|
30
32
|
|
|
31
33
|
console.log(`\n${colors.bright}AI Core Actions (Automation):${colors.reset}`);
|
|
32
34
|
const actions = [
|