@pheem49/mint 1.5.1 → 1.5.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 +8 -0
- package/mint-cli.js +148 -921
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json +31 -1
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json +6 -1
- package/package.json +18 -20
- package/src/AI_Brain/proactive_engine.js +12 -2
- package/src/Automation_Layer/browser_automation.js +26 -24
- package/src/CLI/approval_handler.js +42 -0
- package/src/CLI/chat_ui.js +192 -7
- package/src/CLI/cli_colors.js +32 -0
- package/src/CLI/cli_formatters.js +89 -0
- package/src/CLI/code_agent.js +166 -57
- package/src/CLI/intent_detectors.js +181 -0
- package/src/CLI/interactive_chat.js +479 -0
- package/src/CLI/list_features.js +3 -0
- package/src/CLI/repo_summarizer.js +282 -0
- package/src/CLI/semantic_code_search.js +312 -0
- package/src/CLI/skill_manager.js +41 -0
- package/src/CLI/slash_command_handler.js +418 -0
- package/src/CLI/symbol_indexer.js +231 -0
- package/src/Channels/discord_bridge.js +11 -13
- package/src/Channels/line_bridge.js +10 -10
- package/src/Channels/slack_bridge.js +7 -12
- package/src/Channels/telegram_bridge.js +6 -14
- package/src/Channels/whatsapp_bridge.js +11 -9
- package/src/System/chat_history_manager.js +20 -12
- package/src/System/optional_require.js +23 -0
- package/src/UI/live2d_manager.js +211 -13
- package/src/UI/renderer.js +163 -3
- package/src/UI/settings.css +655 -420
- package/src/UI/settings.html +478 -432
- package/src/UI/settings.js +10 -8
- package/src/UI/styles.css +89 -25
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { colors, exitWithGoodbye } = require('./cli_colors');
|
|
4
|
+
const { splitResponseSentences } = require('./cli_formatters');
|
|
5
|
+
const {
|
|
6
|
+
isRepoSummaryRequest,
|
|
7
|
+
parseRepoSummaryArgs,
|
|
8
|
+
isSymbolIndexRequest,
|
|
9
|
+
parseSymbolIndexArgs,
|
|
10
|
+
isSemanticCodeSearchRequest,
|
|
11
|
+
parseSemanticCodeArgs,
|
|
12
|
+
extractSemanticCodeQuery
|
|
13
|
+
} = require('./intent_detectors');
|
|
14
|
+
const { handleSlashCommandUI } = require('./slash_command_handler');
|
|
15
|
+
const { createChatUI } = require('./chat_ui');
|
|
16
|
+
const { loadImageAsDataUri, loadClipboardImageAsDataUri } = require('./image_input');
|
|
17
|
+
const { summarizeRepository, formatRepoSummary } = require('./repo_summarizer');
|
|
18
|
+
const { buildSymbolIndex, formatSymbolIndex } = require('./symbol_indexer');
|
|
19
|
+
const {
|
|
20
|
+
indexSemanticCode,
|
|
21
|
+
searchSemanticCode,
|
|
22
|
+
formatSemanticCodeIndex,
|
|
23
|
+
formatSemanticCodeSearch
|
|
24
|
+
} = require('./semantic_code_search');
|
|
25
|
+
const { handleChat, getChatTranscript } = require('../AI_Brain/Gemini_API');
|
|
26
|
+
const agentOrchestrator = require('../AI_Brain/agent_orchestrator');
|
|
27
|
+
const systemMonitor = require('../Plugins/system_monitor');
|
|
28
|
+
const workspaceManager = require('./workspace_manager');
|
|
29
|
+
const { executeCodeTask } = require('./code_agent');
|
|
30
|
+
const { resetChat } = require('../AI_Brain/Gemini_API');
|
|
31
|
+
|
|
32
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Internal helpers
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Streams response text sentence-by-sentence into the TUI.
|
|
40
|
+
*/
|
|
41
|
+
async function streamAssistantSentences(text, appendMessage, metadata = {}, streamMessage = null) {
|
|
42
|
+
const sentences = splitResponseSentences(text);
|
|
43
|
+
const chunks = sentences.filter(s => String(s || '').trim());
|
|
44
|
+
|
|
45
|
+
if (typeof streamMessage === 'function') {
|
|
46
|
+
const stream = streamMessage(metadata);
|
|
47
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
48
|
+
stream.appendChunk(chunks[i]);
|
|
49
|
+
if (i < chunks.length - 1) await sleep(90);
|
|
50
|
+
}
|
|
51
|
+
stream.finalize();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
56
|
+
appendMessage('assistant', chunks[i], i === 0 ? metadata : {});
|
|
57
|
+
if (i < chunks.length - 1) await sleep(90);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Runs a timer that increments seconds and calls setThinking every 1s.
|
|
63
|
+
* Returns a cancel function.
|
|
64
|
+
*/
|
|
65
|
+
function startThinkingTimer(setThinking) {
|
|
66
|
+
let seconds = 0;
|
|
67
|
+
setThinking(true, seconds);
|
|
68
|
+
const timer = setInterval(() => {
|
|
69
|
+
seconds++;
|
|
70
|
+
setThinking(true, seconds);
|
|
71
|
+
}, 1000);
|
|
72
|
+
return () => clearInterval(timer);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Local tool message senders
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
async function sendRepoSummaryMessage({ rawArgs = '', appendMessage, streamMessage, setThinking }) {
|
|
80
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
81
|
+
try {
|
|
82
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
83
|
+
const opts = parseRepoSummaryArgs(rawArgs);
|
|
84
|
+
const summary = summarizeRepository(opts.targetPath);
|
|
85
|
+
const responseText = opts.json ? JSON.stringify(summary, null, 2) : formatRepoSummary(summary);
|
|
86
|
+
await streamAssistantSentences(responseText, appendMessage, {}, streamMessage);
|
|
87
|
+
return responseText;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
90
|
+
appendMessage('error', formatErr(err));
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function sendSymbolIndexMessage({ rawArgs = '', appendMessage, streamMessage, setThinking }) {
|
|
96
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
97
|
+
try {
|
|
98
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
99
|
+
const opts = parseSymbolIndexArgs(rawArgs);
|
|
100
|
+
const index = buildSymbolIndex(opts.targetPath);
|
|
101
|
+
const responseText = opts.json
|
|
102
|
+
? JSON.stringify(index, null, 2)
|
|
103
|
+
: formatSymbolIndex(index, { limit: opts.limit });
|
|
104
|
+
await streamAssistantSentences(responseText, appendMessage, {}, streamMessage);
|
|
105
|
+
return responseText;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
108
|
+
appendMessage('error', formatErr(err));
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function sendSemanticCodeMessage({ rawArgs = '', appendMessage, streamMessage, setThinking, appendCodeStep }) {
|
|
114
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
115
|
+
const opts = parseSemanticCodeArgs(rawArgs);
|
|
116
|
+
try {
|
|
117
|
+
if (typeof setThinking === 'function') setThinking(true, 0);
|
|
118
|
+
let responseText;
|
|
119
|
+
|
|
120
|
+
if (opts.mode === 'index') {
|
|
121
|
+
const index = await indexSemanticCode(opts.targetPath, {
|
|
122
|
+
onProgress: (info) => {
|
|
123
|
+
if (typeof appendCodeStep === 'function' &&
|
|
124
|
+
(info.current === 1 || info.current === info.total || info.current % 25 === 0)) {
|
|
125
|
+
appendCodeStep({ action: 'semantic_code_index', target: `${info.current}/${info.total} ${info.file}` });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
responseText = opts.json ? JSON.stringify(index, null, 2) : formatSemanticCodeIndex(index);
|
|
130
|
+
} else {
|
|
131
|
+
if (!opts.query) throw new Error('Usage: /semantic-code search <query>');
|
|
132
|
+
const results = await searchSemanticCode(opts.query, opts.targetPath, { topK: opts.topK });
|
|
133
|
+
responseText = opts.json ? JSON.stringify(results, null, 2) : formatSemanticCodeSearch(results);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
137
|
+
await streamAssistantSentences(responseText, appendMessage, {}, streamMessage);
|
|
138
|
+
return responseText;
|
|
139
|
+
} catch (err) {
|
|
140
|
+
if (typeof setThinking === 'function') setThinking(false);
|
|
141
|
+
appendMessage('error', formatErr(err));
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function sendImageMessage({ images, image, prompt, appendMessage, streamMessage, setThinking, appendCodeStep }) {
|
|
147
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
148
|
+
const imageList = images || (image ? [image] : []);
|
|
149
|
+
const message = prompt || 'Analyze this image.';
|
|
150
|
+
const labels = imageList.map((_, i) => `[Image #${i + 1}]`).join(' ');
|
|
151
|
+
const displayMessage = labels && message.includes(labels) ? message : `${message}\n${labels}`;
|
|
152
|
+
|
|
153
|
+
appendMessage('user', displayMessage);
|
|
154
|
+
if (appendCodeStep) {
|
|
155
|
+
appendCodeStep({
|
|
156
|
+
thought: imageList.length > 1
|
|
157
|
+
? `Analyzing ${imageList.length} attached images before answering.`
|
|
158
|
+
: 'Analyzing the attached image before answering.'
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const cancelTimer = startThinkingTimer(setThinking);
|
|
163
|
+
try {
|
|
164
|
+
const result = await handleChat(message, imageList.map(item => item.dataUri), null);
|
|
165
|
+
cancelTimer();
|
|
166
|
+
setThinking(false);
|
|
167
|
+
|
|
168
|
+
const responseText = result.response || '';
|
|
169
|
+
await streamAssistantSentences(responseText, appendMessage, { providerInfo: result.providerInfo }, streamMessage);
|
|
170
|
+
return { responseText, labels, imageList };
|
|
171
|
+
} catch (err) {
|
|
172
|
+
cancelTimer();
|
|
173
|
+
setThinking(false);
|
|
174
|
+
appendMessage('error', formatErr(err));
|
|
175
|
+
return { responseText: '', labels, imageList };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Agent task execution (shared by onSubmit + initial message)
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
async function runAgentTask(text, { appendMessage, streamMessage, setThinking, requestApproval, askUser, setMode, appendCodeStep }, sharedState) {
|
|
184
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
185
|
+
const transcript = await getChatTranscript();
|
|
186
|
+
const contextualHistory = sharedState.recentImageContextText
|
|
187
|
+
? [...transcript, { sender: 'system', text: sharedState.recentImageContextText, timestamp: new Date().toISOString() }]
|
|
188
|
+
: transcript;
|
|
189
|
+
|
|
190
|
+
if (setMode) setMode('Agent');
|
|
191
|
+
const cancelTimer = startThinkingTimer(setThinking);
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
const config = require('../System/config_manager').readConfig();
|
|
195
|
+
const availableProviders = require('../System/config_manager').getAvailableProviders(config);
|
|
196
|
+
const preferredProvider = require('./code_agent')._helpers.selectSupportedCodeProvider(config, availableProviders);
|
|
197
|
+
let streamedFinalSummary = false;
|
|
198
|
+
|
|
199
|
+
const result = await executeCodeTask(text, {
|
|
200
|
+
cwd: process.cwd(),
|
|
201
|
+
requestApproval,
|
|
202
|
+
askUser,
|
|
203
|
+
provider: preferredProvider,
|
|
204
|
+
history: contextualHistory,
|
|
205
|
+
onProgress: (info) => { if (appendCodeStep) appendCodeStep(info); },
|
|
206
|
+
onFinalSummary: async (info) => {
|
|
207
|
+
cancelTimer();
|
|
208
|
+
setThinking(false);
|
|
209
|
+
streamedFinalSummary = true;
|
|
210
|
+
await streamAssistantSentences(info.summary, appendMessage, { providerInfo: info.providerInfo }, streamMessage);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
cancelTimer();
|
|
215
|
+
setThinking(false);
|
|
216
|
+
sharedState.lastResponseText = result.summary;
|
|
217
|
+
if (!streamedFinalSummary) {
|
|
218
|
+
await streamAssistantSentences(result.summary, appendMessage, { providerInfo: result.providerInfo }, streamMessage);
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
cancelTimer();
|
|
222
|
+
setThinking(false);
|
|
223
|
+
appendMessage('error', formatErr(err));
|
|
224
|
+
} finally {
|
|
225
|
+
if (setMode) setMode('Agent');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// Public: startInteractiveChat
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Starts the interactive TUI chat session.
|
|
235
|
+
*
|
|
236
|
+
* @param {string|null} initialMessage Optional first message (from CLI arg).
|
|
237
|
+
* @param {{ imagePath?: string }} options
|
|
238
|
+
*/
|
|
239
|
+
async function startInteractiveChat(initialMessage = null, options = {}) {
|
|
240
|
+
const formatErr = (err) => err && err.message ? err.message : String(err || 'Unknown error');
|
|
241
|
+
|
|
242
|
+
// Shared mutable state between onSubmit closures
|
|
243
|
+
const sharedState = {
|
|
244
|
+
lastResponseText: '',
|
|
245
|
+
recentImageContextText: ''
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// -----------------------------------------------------------------------
|
|
249
|
+
const ui = await createChatUI({
|
|
250
|
+
onPasteImage: async () => {
|
|
251
|
+
try {
|
|
252
|
+
const image = loadClipboardImageAsDataUri();
|
|
253
|
+
return { label: image.path, image };
|
|
254
|
+
} catch (err) {
|
|
255
|
+
throw new Error(formatErr(err));
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
onSubmit: async (text, submitOptions = {}) => {
|
|
260
|
+
const {
|
|
261
|
+
appendMessage, streamMessage, setThinking, updateStatusModel,
|
|
262
|
+
copyLastResponse, requestApproval, setMode, appendCodeStep,
|
|
263
|
+
updateWorkspace, askUser, attachImage, setInputText,
|
|
264
|
+
setPendingPasteText, setFastMode, toggleFastMode, getFastMode
|
|
265
|
+
} = ui;
|
|
266
|
+
|
|
267
|
+
// ── Image submission ────────────────────────────────────────────
|
|
268
|
+
if (submitOptions.images && submitOptions.images.length > 0) {
|
|
269
|
+
const images = submitOptions.images.map(item => item.image || item);
|
|
270
|
+
const { responseText, labels, imageList } = await sendImageMessage({
|
|
271
|
+
images,
|
|
272
|
+
prompt: text.trim() || 'Analyze this image.',
|
|
273
|
+
appendMessage, streamMessage, setThinking, appendCodeStep
|
|
274
|
+
});
|
|
275
|
+
sharedState.lastResponseText = responseText;
|
|
276
|
+
if (responseText) {
|
|
277
|
+
sharedState.recentImageContextText = [
|
|
278
|
+
`Recent image context: the user attached ${imageList.length} image(s) labelled ${labels || '[Image #1]'}.`,
|
|
279
|
+
'The terminal UI displays image attachments as labels only; it does not render thumbnails inside the chat.',
|
|
280
|
+
`Assistant response to those image(s): ${responseText}`
|
|
281
|
+
].join('\n');
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ── Slash commands ──────────────────────────────────────────────
|
|
287
|
+
if (text.startsWith('/')) {
|
|
288
|
+
if (text.startsWith('/agent')) {
|
|
289
|
+
const aArgs = text.split(' ');
|
|
290
|
+
if (aArgs[1] === 'list') {
|
|
291
|
+
appendMessage('system', `Available Agents: ${agentOrchestrator.listAgents().join(', ')}`);
|
|
292
|
+
} else if (aArgs[1]) {
|
|
293
|
+
const success = agentOrchestrator.setAgent(aArgs[1]);
|
|
294
|
+
if (success) {
|
|
295
|
+
const agent = agentOrchestrator.getCurrentAgent();
|
|
296
|
+
appendMessage('system', `Switched to Agent: ${agent.icon} ${agent.name}`);
|
|
297
|
+
updateStatusModel(agent.name);
|
|
298
|
+
resetChat();
|
|
299
|
+
} else {
|
|
300
|
+
appendMessage('error', `Agent "${aArgs[1]}" not found. Try /agent list`);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
const agent = agentOrchestrator.getCurrentAgent();
|
|
304
|
+
appendMessage('system', `Current Agent: ${agent.icon} ${agent.name}\nUsage: /agent <type> or /agent list`);
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (text.startsWith('/stats')) {
|
|
310
|
+
appendMessage('system', '📊 Fetching system statistics...');
|
|
311
|
+
const stats = await systemMonitor.execute('stats');
|
|
312
|
+
appendMessage('system', stats);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (text.startsWith('/workspace')) {
|
|
317
|
+
const wArgs = text.split(' ');
|
|
318
|
+
const subCmd = wArgs[1];
|
|
319
|
+
if (subCmd === 'add') {
|
|
320
|
+
const name = wArgs[2];
|
|
321
|
+
const wsPath = wArgs[3] || '.';
|
|
322
|
+
const instructions = wArgs.slice(4).join(' ');
|
|
323
|
+
if (!name) {
|
|
324
|
+
appendMessage('error', 'Usage: /workspace add <name> [path] [instructions]');
|
|
325
|
+
} else {
|
|
326
|
+
workspaceManager.addWorkspace(name, wsPath, instructions);
|
|
327
|
+
appendMessage('system', `Workspace "${name}" registered at ${require('path').resolve(wsPath)}`);
|
|
328
|
+
resetChat();
|
|
329
|
+
}
|
|
330
|
+
} else if (subCmd === 'list') {
|
|
331
|
+
const all = workspaceManager.listWorkspaces();
|
|
332
|
+
let listMsg = 'Registered Workspaces:\n';
|
|
333
|
+
for (const n in all) listMsg += `- ${n}: ${all[n].path}\n`;
|
|
334
|
+
appendMessage('system', Object.keys(all).length ? listMsg : 'No workspaces registered.');
|
|
335
|
+
} else if (subCmd === 'remove') {
|
|
336
|
+
const name = wArgs[2];
|
|
337
|
+
if (workspaceManager.removeWorkspace(name)) {
|
|
338
|
+
appendMessage('system', `Removed workspace "${name}"`);
|
|
339
|
+
resetChat();
|
|
340
|
+
} else {
|
|
341
|
+
appendMessage('error', `Workspace "${name}" not found.`);
|
|
342
|
+
}
|
|
343
|
+
} else if (subCmd === 'use' || subCmd === 'switch') {
|
|
344
|
+
const name = wArgs[2];
|
|
345
|
+
const all = workspaceManager.listWorkspaces();
|
|
346
|
+
if (all[name]) {
|
|
347
|
+
const newPath = all[name].path;
|
|
348
|
+
try {
|
|
349
|
+
process.chdir(newPath);
|
|
350
|
+
updateWorkspace(newPath);
|
|
351
|
+
appendMessage('system', `✓ Switched to workspace "${name}" at ${newPath}`);
|
|
352
|
+
resetChat();
|
|
353
|
+
} catch (e) {
|
|
354
|
+
appendMessage('error', `Failed to change directory: ${e.message}`);
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
appendMessage('error', `Workspace "${name}" not found. Try /workspace list`);
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
const ws = workspaceManager.getWorkspaceByPath(process.cwd());
|
|
361
|
+
appendMessage('system', ws
|
|
362
|
+
? `Current Workspace: ${ws.name}\nPath: ${ws.path}`
|
|
363
|
+
: `Not currently in a registered workspace.\nActive Path: ${process.cwd()}\nUsage: /workspace <add|use|list|remove>`);
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (text.startsWith('/review')) {
|
|
369
|
+
if (!sharedState.lastResponseText) {
|
|
370
|
+
appendMessage('error', 'Nothing to review yet. Get a response first.');
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
agentOrchestrator.setAgent('reviewer');
|
|
374
|
+
appendMessage('system', '⚖️ Requesting second-pass review from Mint Reviewer...');
|
|
375
|
+
text = `Please review this previous response and provide a critique:\n\n${sharedState.lastResponseText}`;
|
|
376
|
+
} else {
|
|
377
|
+
if (!text.startsWith('/image') && !text.startsWith('/paste')) {
|
|
378
|
+
appendMessage('user', text);
|
|
379
|
+
}
|
|
380
|
+
const slashResult = await handleSlashCommandUI(
|
|
381
|
+
text, appendMessage, updateStatusModel, copyLastResponse,
|
|
382
|
+
setThinking, requestApproval, setMode, appendCodeStep, updateWorkspace, {
|
|
383
|
+
sendImageMessage, formatErrorMessage: formatErr,
|
|
384
|
+
attachImage, setInputText, setPendingPasteText,
|
|
385
|
+
setFastMode, toggleFastMode, getFastMode,
|
|
386
|
+
sendRepoSummaryMessage, sendSymbolIndexMessage,
|
|
387
|
+
sendSemanticCodeMessage, streamAssistantSentences,
|
|
388
|
+
streamMessage
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
if (slashResult && slashResult.lastResponseText) {
|
|
392
|
+
sharedState.lastResponseText = slashResult.lastResponseText;
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
appendMessage('user', text);
|
|
399
|
+
|
|
400
|
+
// ── Local tool shortcuts (natural language) ─────────────────────
|
|
401
|
+
if (isRepoSummaryRequest(text)) {
|
|
402
|
+
const r = await sendRepoSummaryMessage({ appendMessage, streamMessage, setThinking });
|
|
403
|
+
sharedState.lastResponseText = r;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (isSymbolIndexRequest(text)) {
|
|
407
|
+
const r = await sendSymbolIndexMessage({ appendMessage, streamMessage, setThinking });
|
|
408
|
+
sharedState.lastResponseText = r;
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (isSemanticCodeSearchRequest(text)) {
|
|
412
|
+
const query = extractSemanticCodeQuery(text);
|
|
413
|
+
const r = await sendSemanticCodeMessage({
|
|
414
|
+
rawArgs: `search ${query}`,
|
|
415
|
+
appendMessage, streamMessage, setThinking, appendCodeStep
|
|
416
|
+
});
|
|
417
|
+
sharedState.lastResponseText = r;
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ── Normal agent task ───────────────────────────────────────────
|
|
422
|
+
await runAgentTask(text, {
|
|
423
|
+
appendMessage, streamMessage, setThinking,
|
|
424
|
+
requestApproval, askUser, setMode, appendCodeStep
|
|
425
|
+
}, sharedState);
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
onExit: () => exitWithGoodbye(0)
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// ── Handle initial CLI --image option ───────────────────────────────────
|
|
432
|
+
if (options.imagePath) {
|
|
433
|
+
const { appendMessage, streamMessage, setThinking, appendCodeStep } = ui;
|
|
434
|
+
const image = loadImageAsDataUri(options.imagePath);
|
|
435
|
+
const prompt = initialMessage || 'Analyze this image.';
|
|
436
|
+
const { responseText, labels, imageList } = await sendImageMessage({
|
|
437
|
+
images: [image], prompt, appendMessage, streamMessage, setThinking, appendCodeStep
|
|
438
|
+
});
|
|
439
|
+
sharedState.lastResponseText = responseText;
|
|
440
|
+
if (responseText) {
|
|
441
|
+
sharedState.recentImageContextText = [
|
|
442
|
+
`Recent image context: the user attached ${imageList.length} image(s) labelled ${labels || '[Image #1]'}.`,
|
|
443
|
+
'The terminal UI displays image attachments as labels only; it does not render thumbnails inside the chat.',
|
|
444
|
+
`Assistant response to those image(s): ${responseText}`
|
|
445
|
+
].join('\n');
|
|
446
|
+
}
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ── Handle initial CLI message argument ─────────────────────────────────
|
|
451
|
+
if (initialMessage) {
|
|
452
|
+
const { appendMessage, streamMessage, setThinking, requestApproval, setMode, appendCodeStep, askUser } = ui;
|
|
453
|
+
appendMessage('user', initialMessage);
|
|
454
|
+
|
|
455
|
+
if (isRepoSummaryRequest(initialMessage)) {
|
|
456
|
+
sharedState.lastResponseText = await sendRepoSummaryMessage({ appendMessage, streamMessage, setThinking });
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (isSymbolIndexRequest(initialMessage)) {
|
|
460
|
+
sharedState.lastResponseText = await sendSymbolIndexMessage({ appendMessage, streamMessage, setThinking });
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (isSemanticCodeSearchRequest(initialMessage)) {
|
|
464
|
+
const query = extractSemanticCodeQuery(initialMessage);
|
|
465
|
+
sharedState.lastResponseText = await sendSemanticCodeMessage({
|
|
466
|
+
rawArgs: `search ${query}`,
|
|
467
|
+
appendMessage, streamMessage, setThinking, appendCodeStep
|
|
468
|
+
});
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
await runAgentTask(initialMessage, {
|
|
473
|
+
appendMessage, streamMessage, setThinking,
|
|
474
|
+
requestApproval, askUser, setMode, appendCodeStep
|
|
475
|
+
}, sharedState);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
module.exports = { startInteractiveChat };
|
package/src/CLI/list_features.js
CHANGED
|
@@ -22,6 +22,9 @@ 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 summarize [path]', desc: 'Summarize repository structure, tooling, git state, and key files' },
|
|
26
|
+
{ cmd: 'mint symbols [path]', desc: 'Build a source symbol index for supported languages' },
|
|
27
|
+
{ cmd: 'mint semantic-code', desc: 'Index and search code semantically with embeddings' },
|
|
25
28
|
{ cmd: 'mint gmail auth', desc: 'Connect Gmail OAuth and save refresh token' },
|
|
26
29
|
{ cmd: 'mint mcp', desc: 'Manage Model Context Protocol (MCP) servers' },
|
|
27
30
|
{ cmd: 'mint task "<task>"', desc: 'Queue an autonomous task for the background agent' },
|