minovative-mind-cli 2.14.2 → 2.14.3
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 +5 -5
- package/dist/services/agent/slashCommands.js +109 -12
- package/dist/services/agent/toolLoop.js +9 -2
- package/dist/services/agent/types.d.ts +9 -2
- package/dist/services/agent-tools.d.ts +2 -1
- package/dist/services/agent-tools.js +52 -4
- package/dist/services/agent.js +37 -15
- package/dist/services/ai.d.ts +6 -0
- package/dist/services/ai.js +8 -2
- package/dist/services/chatHistoryService.d.ts +5 -0
- package/dist/services/contextAgent.d.ts +4 -2
- package/dist/services/contextAgent.js +3 -1
- package/dist/services/sessionSettings.d.ts +66 -0
- package/dist/services/sessionSettings.js +126 -0
- package/dist/services/verificationService.js +24 -2
- package/dist/utils/antiCheatingGuard.d.ts +21 -0
- package/dist/utils/antiCheatingGuard.js +554 -0
- package/dist/utils/dependencyTracer.d.ts +15 -2
- package/dist/utils/dependencyTracer.js +61 -3
- package/dist/utils/fileReadCache.d.ts +58 -0
- package/dist/utils/fileReadCache.js +162 -0
- package/dist/utils/projectStorage.js +2 -1
- package/dist/utils/symbolExtractor.d.ts +12 -0
- package/dist/utils/symbolExtractor.js +111 -15
- package/dist/utils/systemPrompts.d.ts +3 -2
- package/dist/utils/systemPrompts.js +53 -6
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,14 +156,14 @@ Minovative Mind CLI continuously adapts to your unique developer personality and
|
|
|
156
156
|
| `/profile` | View, inspect, delete, or reset global adaptive persona memory, pairing dynamics, and AI side-notes |
|
|
157
157
|
| `/models` | Hot-swap the active model or configure its native reasoning thinking level (`Low`, `Medium`, `High`) |
|
|
158
158
|
| `/paste` | Multi-line input mode (cancel with Ctrl+C) |
|
|
159
|
-
| `/clear` | Clear conversation history
|
|
160
|
-
| `/debug` |
|
|
161
|
-
| `/auto-approve` | Toggle skipping confirmation prompts for commands
|
|
162
|
-
| `/sub-agents` | Toggle the MMAAK Engine for parallel investigation and execution (concurrency limited to 2)
|
|
159
|
+
| `/clear` | Clear conversation history and reset session settings to safe defaults |
|
|
160
|
+
| `/debug` | Toggle internal agent telemetry and diagnostic logging (saved per session) |
|
|
161
|
+
| `/auto-approve` | Toggle skipping confirmation prompts for commands (saved per session, automatically resets to 'ask' on new sessions) |
|
|
162
|
+
| `/sub-agents` | Toggle the MMAAK Engine for parallel investigation and execution (saved per session, concurrency limited to 2) |
|
|
163
163
|
| `/stats` | View session and all-time statistics, token telemetry, active model settings, and live thinking level runtime telemetry |
|
|
164
164
|
| `/commit` | Generate a conventional commit message from your diff |
|
|
165
165
|
| `/revert` | Undo changes from the last turn, or toggle the revert logger |
|
|
166
|
-
| `/chats` | View, resume, rename, or delete previous chat sessions (with
|
|
166
|
+
| `/chats` | View, resume, rename, or delete previous chat sessions (with session settings restoration, Git branch, auto-approve status, and sub-agent state) |
|
|
167
167
|
| `/workspaces` | Manage active workspaces and linked cross-repo aliases |
|
|
168
168
|
| `stop` | Abort generation immediately |
|
|
169
169
|
|
|
@@ -19,6 +19,10 @@ import { GEMINI_MODELS, isByokEnabled, DEFAULT_MODEL_THINKING_LEVELS } from '../
|
|
|
19
19
|
import { loadCredentials, updateCredentialField } from '../../utils/credentialStore.js';
|
|
20
20
|
import { getGlobalActiveModel, setGlobalActiveModel, getModelThinkingLevel, setModelThinkingLevel, ProxyChatSession } from '../ai.js';
|
|
21
21
|
import { loadUserProfile, deleteSideNote, clearUserProfile, getUserProfilePath } from '../userProfileService.js';
|
|
22
|
+
import { applySessionSettings, resetSessionSettingsToDefault, syncActiveSessionSettings, } from '../sessionSettings.js';
|
|
23
|
+
import { clearFileReadCache } from '../../utils/fileReadCache.js';
|
|
24
|
+
import { invalidateDependencyGraph } from '../../utils/dependencyTracer.js';
|
|
25
|
+
import { clearSymbolExtractorCache } from '../../utils/symbolExtractor.js';
|
|
22
26
|
/**
|
|
23
27
|
* @file slashCommands.ts
|
|
24
28
|
* @description Interactive slash command handler module for Minovative Mind CLI.
|
|
@@ -79,12 +83,22 @@ export async function handleSlashCommand(command, context) {
|
|
|
79
83
|
*/
|
|
80
84
|
if (lowerCommand === '/clear') {
|
|
81
85
|
chat.clearHistory();
|
|
86
|
+
resetSessionSettingsToDefault(chat);
|
|
87
|
+
if (chatSessionState) {
|
|
88
|
+
chatSessionState.autoApprove = false;
|
|
89
|
+
chatSessionState.subAgents = true;
|
|
90
|
+
chatSessionState.debugMode = false;
|
|
91
|
+
chatSessionState.modelName = chat.getModel();
|
|
92
|
+
chatSessionState.thinkingLevel =
|
|
93
|
+
(typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
|
|
94
|
+
getModelThinkingLevel(chat.getModel());
|
|
95
|
+
}
|
|
82
96
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
83
97
|
printLogo();
|
|
84
98
|
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
85
99
|
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
86
100
|
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
87
|
-
p.log.success('Chat history cleared.');
|
|
101
|
+
p.log.success('Chat history cleared (session settings reset to defaults).');
|
|
88
102
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
89
103
|
return { shouldContinue: true };
|
|
90
104
|
}
|
|
@@ -139,11 +153,17 @@ export async function handleSlashCommand(command, context) {
|
|
|
139
153
|
if (!p.isCancel(selectedModel)) {
|
|
140
154
|
chat.setModel(selectedModel);
|
|
141
155
|
setGlobalActiveModel(selectedModel);
|
|
156
|
+
if (chatSessionState) {
|
|
157
|
+
chatSessionState.modelName = selectedModel;
|
|
158
|
+
}
|
|
142
159
|
if (selectedModel === 'auto') {
|
|
143
160
|
const defaultAutoThinking = DEFAULT_MODEL_THINKING_LEVELS[GEMINI_MODELS.AUTO] || 'MEDIUM';
|
|
144
161
|
if (typeof chat.setThinkingLevel === 'function') {
|
|
145
162
|
chat.setThinkingLevel(defaultAutoThinking);
|
|
146
163
|
}
|
|
164
|
+
if (chatSessionState) {
|
|
165
|
+
chatSessionState.thinkingLevel = defaultAutoThinking;
|
|
166
|
+
}
|
|
147
167
|
p.log.success(`Model successfully switched to ${pc.cyan('Auto (Smart Routing & Reasoning)')}`);
|
|
148
168
|
}
|
|
149
169
|
else {
|
|
@@ -174,15 +194,22 @@ export async function handleSlashCommand(command, context) {
|
|
|
174
194
|
if (typeof chat.setThinkingLevel === 'function') {
|
|
175
195
|
chat.setThinkingLevel(selectedThinking);
|
|
176
196
|
}
|
|
197
|
+
if (chatSessionState) {
|
|
198
|
+
chatSessionState.thinkingLevel = selectedThinking;
|
|
199
|
+
}
|
|
177
200
|
p.log.success(`Model successfully switched to ${pc.cyan(selectedModel)} with thinking level ${pc.cyan(selectedThinking)}`);
|
|
178
201
|
}
|
|
179
202
|
else {
|
|
180
203
|
if (typeof chat.setThinkingLevel === 'function') {
|
|
181
204
|
chat.setThinkingLevel(activeModelThinking);
|
|
182
205
|
}
|
|
206
|
+
if (chatSessionState) {
|
|
207
|
+
chatSessionState.thinkingLevel = activeModelThinking;
|
|
208
|
+
}
|
|
183
209
|
p.log.success(`Model successfully switched to ${pc.cyan(selectedModel)}`);
|
|
184
210
|
}
|
|
185
211
|
}
|
|
212
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
186
213
|
}
|
|
187
214
|
return { shouldContinue: true };
|
|
188
215
|
}
|
|
@@ -191,6 +218,10 @@ export async function handleSlashCommand(command, context) {
|
|
|
191
218
|
*/
|
|
192
219
|
if (lowerCommand === '/debug') {
|
|
193
220
|
const debugMode = toggleDebugMode();
|
|
221
|
+
if (chatSessionState) {
|
|
222
|
+
chatSessionState.debugMode = debugMode;
|
|
223
|
+
}
|
|
224
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
194
225
|
if (debugMode) {
|
|
195
226
|
const currentModel = chat.getModel();
|
|
196
227
|
const currentThinkingLevel = (typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
|
|
@@ -208,10 +239,18 @@ export async function handleSlashCommand(command, context) {
|
|
|
208
239
|
if (lowerCommand === '/auto-approve') {
|
|
209
240
|
if (getApprovalMode() === 'skip-all') {
|
|
210
241
|
setApprovalMode('ask');
|
|
242
|
+
if (chatSessionState) {
|
|
243
|
+
chatSessionState.autoApprove = false;
|
|
244
|
+
}
|
|
245
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
211
246
|
p.log.success('Auto-approve disabled. You will be prompted before commands run.');
|
|
212
247
|
}
|
|
213
248
|
else {
|
|
214
249
|
setApprovalMode('skip-all');
|
|
250
|
+
if (chatSessionState) {
|
|
251
|
+
chatSessionState.autoApprove = true;
|
|
252
|
+
}
|
|
253
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
215
254
|
p.log.success('Auto-approve enabled for all future commands in this session.');
|
|
216
255
|
}
|
|
217
256
|
return { shouldContinue: true };
|
|
@@ -222,10 +261,18 @@ export async function handleSlashCommand(command, context) {
|
|
|
222
261
|
if (lowerCommand === '/sub-agents') {
|
|
223
262
|
if (isSubAgentsEnabled()) {
|
|
224
263
|
setSubAgentsEnabled(false);
|
|
264
|
+
if (chatSessionState) {
|
|
265
|
+
chatSessionState.subAgents = false;
|
|
266
|
+
}
|
|
267
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
225
268
|
p.log.success('MMAAK Engine disabled. Single-agent mode active.');
|
|
226
269
|
}
|
|
227
270
|
else {
|
|
228
271
|
setSubAgentsEnabled(true);
|
|
272
|
+
if (chatSessionState) {
|
|
273
|
+
chatSessionState.subAgents = true;
|
|
274
|
+
}
|
|
275
|
+
await syncActiveSessionSettings(chatSessionState?.id, chat);
|
|
229
276
|
p.log.success('MMAAK Engine enabled. The system will now use parallel investigation and thread agents.');
|
|
230
277
|
}
|
|
231
278
|
return { shouldContinue: true };
|
|
@@ -478,6 +525,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
478
525
|
await fs.writeFile(absolutePath, change.originalContent, 'utf-8');
|
|
479
526
|
}
|
|
480
527
|
}
|
|
528
|
+
clearFileReadCache();
|
|
529
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
530
|
+
clearSymbolExtractorCache();
|
|
481
531
|
spinner.stop('Reverted successfully.');
|
|
482
532
|
p.log.success(`Reverted ${changesToRevert.length} changeset(s) successfully.`);
|
|
483
533
|
}
|
|
@@ -514,6 +564,7 @@ export async function handleSlashCommand(command, context) {
|
|
|
514
564
|
}
|
|
515
565
|
if (chatsMenu === 'new') {
|
|
516
566
|
chat.clearHistory();
|
|
567
|
+
resetSessionSettingsToDefault(chat);
|
|
517
568
|
if (chatSessionState) {
|
|
518
569
|
chatSessionState.id = crypto.randomUUID();
|
|
519
570
|
chatSessionState.title = '';
|
|
@@ -521,6 +572,13 @@ export async function handleSlashCommand(command, context) {
|
|
|
521
572
|
chatSessionState.totalInputTokens = 0;
|
|
522
573
|
chatSessionState.totalOutputTokens = 0;
|
|
523
574
|
chatSessionState.totalCreditsUsed = 0;
|
|
575
|
+
chatSessionState.autoApprove = false;
|
|
576
|
+
chatSessionState.subAgents = true;
|
|
577
|
+
chatSessionState.debugMode = false;
|
|
578
|
+
chatSessionState.modelName = chat.getModel();
|
|
579
|
+
chatSessionState.thinkingLevel =
|
|
580
|
+
(typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
|
|
581
|
+
getModelThinkingLevel(chat.getModel());
|
|
524
582
|
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
525
583
|
}
|
|
526
584
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
@@ -528,7 +586,7 @@ export async function handleSlashCommand(command, context) {
|
|
|
528
586
|
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
529
587
|
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
530
588
|
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
531
|
-
p.log.success('Started a new chat session.');
|
|
589
|
+
p.log.success('Started a new chat session (settings reset to defaults).');
|
|
532
590
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
533
591
|
return { shouldContinue: true };
|
|
534
592
|
}
|
|
@@ -577,6 +635,8 @@ export async function handleSlashCommand(command, context) {
|
|
|
577
635
|
}
|
|
578
636
|
const session = sessions.find((s) => s.id === selectedSessionId);
|
|
579
637
|
if (session) {
|
|
638
|
+
// Restore session-scoped operational settings
|
|
639
|
+
const applied = applySessionSettings(session, chat);
|
|
580
640
|
// Update timestamp so it becomes the most recently used session
|
|
581
641
|
session.timestamp = Date.now();
|
|
582
642
|
await chatHistoryService.saveSession(session);
|
|
@@ -591,6 +651,11 @@ export async function handleSlashCommand(command, context) {
|
|
|
591
651
|
chatSessionState.latestUsageMetadata = session.latestUsageMetadata;
|
|
592
652
|
chatSessionState.previousUsageMetadata = session.previousUsageMetadata;
|
|
593
653
|
chatSessionState.modelUsageCounts = session.modelUsageCounts || {};
|
|
654
|
+
chatSessionState.autoApprove = applied.autoApprove;
|
|
655
|
+
chatSessionState.subAgents = applied.subAgents;
|
|
656
|
+
chatSessionState.debugMode = applied.debugMode;
|
|
657
|
+
chatSessionState.modelName = applied.modelName;
|
|
658
|
+
chatSessionState.thinkingLevel = applied.thinkingLevel;
|
|
594
659
|
chat.setSessionInfo(session.id, workspaceRoot);
|
|
595
660
|
}
|
|
596
661
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
@@ -599,6 +664,16 @@ export async function handleSlashCommand(command, context) {
|
|
|
599
664
|
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
600
665
|
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
601
666
|
p.log.success(`Resumed session: ${session.title}`);
|
|
667
|
+
// Display session settings restoration status badge
|
|
668
|
+
const autoApproveBadge = applied.autoApprove ? pc.green('ON') : pc.dim('OFF');
|
|
669
|
+
const subAgentsBadge = applied.subAgents ? pc.green('ON') : pc.red('OFF');
|
|
670
|
+
const debugBadge = applied.debugMode ? pc.green('ON') : pc.dim('OFF');
|
|
671
|
+
const modelBadge = pc.cyan(applied.modelName);
|
|
672
|
+
const thinkingBadge = pc.cyan(applied.thinkingLevel);
|
|
673
|
+
p.log.info(`${pc.dim('Session Settings:')} Model: ${modelBadge} (thinking: ${thinkingBadge}) | Auto-Approve: ${autoApproveBadge} | Sub-Agents: ${subAgentsBadge} | Debug: ${debugBadge}`);
|
|
674
|
+
if (applied.autoApprove) {
|
|
675
|
+
p.log.warn(pc.yellow('Notice: Auto-approve is ENABLED for this resumed session.'));
|
|
676
|
+
}
|
|
602
677
|
// Print the loaded history cleanly: only user and AI conversational messages,
|
|
603
678
|
// with a clean indicator label if the turn involved tool/code changes.
|
|
604
679
|
let turnHadModifications = false;
|
|
@@ -689,9 +764,6 @@ export async function handleSlashCommand(command, context) {
|
|
|
689
764
|
if (session.lastTurnDuration !== undefined) {
|
|
690
765
|
p.log.info(`${pc.dim('Generated in')} ${pc.cyan(session.lastTurnDuration + 's')}`);
|
|
691
766
|
}
|
|
692
|
-
if (session.modelName) {
|
|
693
|
-
p.log.info(`${pc.dim('Model:')} ${pc.cyan(session.modelName)}`);
|
|
694
|
-
}
|
|
695
767
|
if (session.totalTokens !== undefined) {
|
|
696
768
|
const inputStr = session.totalInputTokens
|
|
697
769
|
? ` (Input: ${session.totalInputTokens.toLocaleString()}, Output: ${(session.totalOutputTokens || 0).toLocaleString()})`
|
|
@@ -704,11 +776,6 @@ export async function handleSlashCommand(command, context) {
|
|
|
704
776
|
if (session.gitBranch) {
|
|
705
777
|
p.log.info(`${pc.dim('Last Active Branch:')} ${pc.cyan(session.gitBranch)}`);
|
|
706
778
|
}
|
|
707
|
-
if (session.autoApprove !== undefined || session.subAgents !== undefined) {
|
|
708
|
-
const aa = session.autoApprove ? pc.green('Enabled') : pc.yellow('Disabled');
|
|
709
|
-
const sa = session.subAgents ? pc.green('Enabled') : pc.yellow('Disabled');
|
|
710
|
-
p.log.info(`${pc.dim('Sub-Agents:')} ${sa} | ${pc.dim('Auto-Approve:')} ${aa}`);
|
|
711
|
-
}
|
|
712
779
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
713
780
|
}
|
|
714
781
|
}
|
|
@@ -754,12 +821,27 @@ export async function handleSlashCommand(command, context) {
|
|
|
754
821
|
p.log.success('Session deleted successfully.');
|
|
755
822
|
if (chatSessionState && chatSessionState.id === selectedSessionId) {
|
|
756
823
|
chat.clearHistory();
|
|
824
|
+
resetSessionSettingsToDefault(chat);
|
|
825
|
+
chatSessionState.id = crypto.randomUUID();
|
|
826
|
+
chatSessionState.title = '';
|
|
827
|
+
chatSessionState.totalTokens = 0;
|
|
828
|
+
chatSessionState.totalInputTokens = 0;
|
|
829
|
+
chatSessionState.totalOutputTokens = 0;
|
|
830
|
+
chatSessionState.totalCreditsUsed = 0;
|
|
831
|
+
chatSessionState.autoApprove = false;
|
|
832
|
+
chatSessionState.subAgents = true;
|
|
833
|
+
chatSessionState.debugMode = false;
|
|
834
|
+
chatSessionState.modelName = chat.getModel();
|
|
835
|
+
chatSessionState.thinkingLevel =
|
|
836
|
+
(typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
|
|
837
|
+
getModelThinkingLevel(chat.getModel());
|
|
838
|
+
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
757
839
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
758
840
|
printLogo();
|
|
759
841
|
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
760
842
|
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
761
843
|
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
762
|
-
p.log.warn('Active session was deleted. Chat history
|
|
844
|
+
p.log.warn('Active session was deleted. Chat history and settings reset to defaults.');
|
|
763
845
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
764
846
|
}
|
|
765
847
|
}
|
|
@@ -787,12 +869,27 @@ export async function handleSlashCommand(command, context) {
|
|
|
787
869
|
p.log.success(`Successfully deleted ${selectedIds.length} session(s).`);
|
|
788
870
|
if (chatSessionState && selectedIds.includes(chatSessionState.id)) {
|
|
789
871
|
chat.clearHistory();
|
|
872
|
+
resetSessionSettingsToDefault(chat);
|
|
873
|
+
chatSessionState.id = crypto.randomUUID();
|
|
874
|
+
chatSessionState.title = '';
|
|
875
|
+
chatSessionState.totalTokens = 0;
|
|
876
|
+
chatSessionState.totalInputTokens = 0;
|
|
877
|
+
chatSessionState.totalOutputTokens = 0;
|
|
878
|
+
chatSessionState.totalCreditsUsed = 0;
|
|
879
|
+
chatSessionState.autoApprove = false;
|
|
880
|
+
chatSessionState.subAgents = true;
|
|
881
|
+
chatSessionState.debugMode = false;
|
|
882
|
+
chatSessionState.modelName = chat.getModel();
|
|
883
|
+
chatSessionState.thinkingLevel =
|
|
884
|
+
(typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
|
|
885
|
+
getModelThinkingLevel(chat.getModel());
|
|
886
|
+
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
790
887
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
791
888
|
printLogo();
|
|
792
889
|
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
793
890
|
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
794
891
|
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
795
|
-
p.log.warn('Active session was deleted. Chat history
|
|
892
|
+
p.log.warn('Active session was deleted. Chat history and settings reset to defaults.');
|
|
796
893
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
797
894
|
}
|
|
798
895
|
}
|
|
@@ -3,7 +3,7 @@ import * as p from '@clack/prompts';
|
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import { debugLog } from '../../utils/logger.js';
|
|
5
5
|
import { executeTool } from '../agent-tools.js';
|
|
6
|
-
import { getPlanExecutionConfig, HISTORICAL_TOOL_OUTPUT_THRESHOLD } from '../ai.js';
|
|
6
|
+
import { getPlanExecutionConfig, getResearchConfig, HISTORICAL_TOOL_OUTPUT_THRESHOLD } from '../ai.js';
|
|
7
7
|
import { routeIntent } from '../contextAgent.js';
|
|
8
8
|
import { requestCommandApproval } from './commandApproval.js';
|
|
9
9
|
import { getMetricCollector, recordRecoveryCircuitBreakerTrip } from '../metrics.js';
|
|
@@ -265,7 +265,7 @@ export async function processResponse(chat, result, workspaceRoot, inputHandler,
|
|
|
265
265
|
if (queuedMsg) {
|
|
266
266
|
additionalText = `[USER INTERRUPTION] The user sent the following message during your execution:\n"${queuedMsg}"\n\nPlease incorporate this feedback into your ongoing work. Address the user's message, but DO NOT lose track of your original overall plan or focus. After addressing this interruption, continue with your broader objective.`;
|
|
267
267
|
p.log.info(pc.cyan(`Sending queued message to AI...`));
|
|
268
|
-
// Dynamically upgrade agent permissions/intent
|
|
268
|
+
// Dynamically upgrade agent permissions/intent if the interrupted instruction requires system modifications
|
|
269
269
|
const newIntent = await routeIntent(queuedMsg, '', abortSignal);
|
|
270
270
|
if (agentState.targetAgent === 'CHAT') {
|
|
271
271
|
if (newIntent.targetAgent === 'EXECUTE' || newIntent.needsContext) {
|
|
@@ -274,7 +274,14 @@ export async function processResponse(chat, result, workspaceRoot, inputHandler,
|
|
|
274
274
|
chat.setAgentConfig(config.systemInstruction, config.tools);
|
|
275
275
|
p.log.info(pc.yellow(`Upgraded session intent to EXECUTE based on chained message.`));
|
|
276
276
|
}
|
|
277
|
+
else if (newIntent.targetAgent === 'RESEARCH') {
|
|
278
|
+
agentState.targetAgent = 'RESEARCH';
|
|
279
|
+
const config = getResearchConfig();
|
|
280
|
+
chat.setAgentConfig(config.systemInstruction, config.tools);
|
|
281
|
+
p.log.info(pc.cyan(`Upgraded session intent to RESEARCH based on chained message.`));
|
|
282
|
+
}
|
|
277
283
|
}
|
|
284
|
+
// If agentState.targetAgent === 'RESEARCH', keep RESEARCH mode and incorporate into ongoing research
|
|
278
285
|
}
|
|
279
286
|
// Apply in-place history pruning to collapse oversized tool responses older than 1 turn
|
|
280
287
|
chat.pruneToolOutputHistory(HISTORICAL_TOOL_OUTPUT_THRESHOLD, 1);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { ProxyChatSession } from '../ai.js';
|
|
2
2
|
import type { AsyncInputHandler } from './inputHandler.js';
|
|
3
|
+
export type TargetAgent = 'CHAT' | 'RESEARCH' | 'EXECUTE';
|
|
3
4
|
/**
|
|
4
5
|
* State tracking container for the active agent operational mode.
|
|
5
6
|
*/
|
|
6
7
|
export interface AgentState {
|
|
7
|
-
/** The target agent mode: 'CHAT' for conversational interactions or 'EXECUTE' for tool/command execution. */
|
|
8
|
-
targetAgent:
|
|
8
|
+
/** The target agent mode: 'CHAT' for conversational interactions, 'RESEARCH' for active diagnostics/benchmarks, or 'EXECUTE' for tool/command execution. */
|
|
9
|
+
targetAgent: TargetAgent;
|
|
9
10
|
}
|
|
11
|
+
import type { ThinkingLevel } from '../../utils/config.js';
|
|
10
12
|
/**
|
|
11
13
|
* Context object provided to slash command handlers containing session handles, terminal state, and metadata.
|
|
12
14
|
*/
|
|
@@ -32,6 +34,11 @@ export interface SlashCommandContext {
|
|
|
32
34
|
latestUsageMetadata?: any;
|
|
33
35
|
previousUsageMetadata?: any;
|
|
34
36
|
modelUsageCounts?: Record<string, number>;
|
|
37
|
+
autoApprove?: boolean;
|
|
38
|
+
subAgents?: boolean;
|
|
39
|
+
debugMode?: boolean;
|
|
40
|
+
modelName?: string;
|
|
41
|
+
thinkingLevel?: ThinkingLevel;
|
|
35
42
|
};
|
|
36
43
|
}
|
|
37
44
|
/**
|
|
@@ -31,11 +31,12 @@ export interface ToolResult {
|
|
|
31
31
|
/**
|
|
32
32
|
* Returns the list of available function declarations for Gemini function calling.
|
|
33
33
|
*
|
|
34
|
-
* @param options - Configuration options such as `isExecutionAgent`.
|
|
34
|
+
* @param options - Configuration options such as `isExecutionAgent` or `isResearchAgent`.
|
|
35
35
|
* @returns An array of Google Generative AI `FunctionDeclaration` objects.
|
|
36
36
|
*/
|
|
37
37
|
export declare function getToolDeclarations(options?: {
|
|
38
38
|
isExecutionAgent?: boolean;
|
|
39
|
+
isResearchAgent?: boolean;
|
|
39
40
|
}): FunctionDeclaration[];
|
|
40
41
|
/**
|
|
41
42
|
* FunctionDeclaration-compatible schema objects that describe
|
|
@@ -23,13 +23,15 @@ import { findBestMatch, applyMatch } from '../utils/fuzzyMatch.js';
|
|
|
23
23
|
import { localValidate } from '../utils/localSyntaxValidator.js';
|
|
24
24
|
import { validateAndFixSyntax, aiFuzzyMatch } from './agent/syntaxAgent.js';
|
|
25
25
|
import { sanitizeForCDATA } from '../utils/contextPrompts.js';
|
|
26
|
-
import { findDependencies, formatDependencyResult } from '../utils/dependencyTracer.js';
|
|
26
|
+
import { findDependencies, formatDependencyResult, invalidateDependencyGraph } from '../utils/dependencyTracer.js';
|
|
27
27
|
import { atomicWriteFile } from '../utils/atomicWrite.js';
|
|
28
28
|
import { EXCLUDED_EXTENSIONS } from '../utils/excludedExtensions.js';
|
|
29
29
|
import { extractSymbols } from '../utils/symbolExtractor.js';
|
|
30
30
|
import { getMetricCollector, recordRecoveryPrunedLogVolume } from './metrics.js';
|
|
31
31
|
import { getCurrentAgentId } from '../utils/asyncContext.js';
|
|
32
32
|
import { recordFileRead, hasAgentReadFile } from '../utils/fileReadGuard.js';
|
|
33
|
+
import { getCachedFileContent, invalidateFileReadCache, clearFileReadCache } from '../utils/fileReadCache.js';
|
|
34
|
+
import { detectAntiCheatingViolations, isCriticalConfigFile } from '../utils/antiCheatingGuard.js';
|
|
33
35
|
import { runFuzzProbe, checkHeapDelta as runCheckHeapDelta, checkBehavioralDrift as runCheckBehavioralDrift, runEphemeralScript, } from '../utils/analysisRunner.js';
|
|
34
36
|
import ignore from 'ignore';
|
|
35
37
|
const execAsync = promisify(exec);
|
|
@@ -37,13 +39,24 @@ const execAsync = promisify(exec);
|
|
|
37
39
|
/**
|
|
38
40
|
* Returns the list of available function declarations for Gemini function calling.
|
|
39
41
|
*
|
|
40
|
-
* @param options - Configuration options such as `isExecutionAgent`.
|
|
42
|
+
* @param options - Configuration options such as `isExecutionAgent` or `isResearchAgent`.
|
|
41
43
|
* @returns An array of Google Generative AI `FunctionDeclaration` objects.
|
|
42
44
|
*/
|
|
43
45
|
export function getToolDeclarations(options) {
|
|
44
46
|
if (options?.isExecutionAgent) {
|
|
45
47
|
return toolDeclarations;
|
|
46
48
|
}
|
|
49
|
+
if (options?.isResearchAgent) {
|
|
50
|
+
const excludedForResearch = new Set([
|
|
51
|
+
'modify_file',
|
|
52
|
+
'write_file',
|
|
53
|
+
'delete_file',
|
|
54
|
+
'rename_file',
|
|
55
|
+
'create_todo_list',
|
|
56
|
+
'update_todo_status',
|
|
57
|
+
]);
|
|
58
|
+
return toolDeclarations.filter((tool) => !excludedForResearch.has(tool.name));
|
|
59
|
+
}
|
|
47
60
|
return toolDeclarations.filter((tool) => tool.name !== 'create_todo_list' && tool.name !== 'update_todo_status' && tool.name !== 'finish_task');
|
|
48
61
|
}
|
|
49
62
|
/**
|
|
@@ -626,7 +639,7 @@ export async function readFile(workspaceRoot, filePath, startLine, endLine, targ
|
|
|
626
639
|
};
|
|
627
640
|
}
|
|
628
641
|
}
|
|
629
|
-
let content = await
|
|
642
|
+
let content = await getCachedFileContent(absPath);
|
|
630
643
|
// Handle Jupyter Notebooks natively
|
|
631
644
|
if (filePath.toLowerCase().endsWith('.ipynb')) {
|
|
632
645
|
try {
|
|
@@ -829,9 +842,15 @@ export async function writeFile(workspaceRoot, filePath, content) {
|
|
|
829
842
|
};
|
|
830
843
|
}
|
|
831
844
|
}
|
|
845
|
+
const antiCheatError = detectAntiCheatingViolations(filePath, finalContent, existingContent ?? undefined);
|
|
846
|
+
if (antiCheatError) {
|
|
847
|
+
return { output: '', error: antiCheatError };
|
|
848
|
+
}
|
|
832
849
|
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
833
850
|
changeLogger.logChange(filePath, existingContent, existingContent !== null ? 'modify' : 'create');
|
|
834
851
|
await atomicWriteFile(absPath, finalContent, 'utf-8');
|
|
852
|
+
invalidateFileReadCache(absPath);
|
|
853
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
835
854
|
return { output: `Successfully wrote to "${filePath}".` };
|
|
836
855
|
}
|
|
837
856
|
catch (err) {
|
|
@@ -854,6 +873,12 @@ export async function writeFile(workspaceRoot, filePath, content) {
|
|
|
854
873
|
*/
|
|
855
874
|
export async function deleteFile(workspaceRoot, filePath) {
|
|
856
875
|
try {
|
|
876
|
+
if (isCriticalConfigFile(filePath)) {
|
|
877
|
+
return {
|
|
878
|
+
output: '',
|
|
879
|
+
error: `Anti-cheating violation: Deleting critical configuration file "${filePath}" is strictly prohibited. You must fix all build, compiler, type, and lint errors head-on in the source code.`,
|
|
880
|
+
};
|
|
881
|
+
}
|
|
857
882
|
const absPath = resolveAndValidatePath(workspaceRoot, filePath);
|
|
858
883
|
let existingContent = null;
|
|
859
884
|
try {
|
|
@@ -864,6 +889,8 @@ export async function deleteFile(workspaceRoot, filePath) {
|
|
|
864
889
|
}
|
|
865
890
|
changeLogger.logChange(filePath, existingContent, 'delete');
|
|
866
891
|
await fs.rm(absPath, { force: true });
|
|
892
|
+
invalidateFileReadCache(absPath);
|
|
893
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
867
894
|
return { output: `Successfully deleted "${filePath}".` };
|
|
868
895
|
}
|
|
869
896
|
catch (err) {
|
|
@@ -881,6 +908,12 @@ export async function deleteFile(workspaceRoot, filePath) {
|
|
|
881
908
|
*/
|
|
882
909
|
export async function renameFile(workspaceRoot, sourcePath, targetPath) {
|
|
883
910
|
try {
|
|
911
|
+
if (isCriticalConfigFile(sourcePath)) {
|
|
912
|
+
return {
|
|
913
|
+
output: '',
|
|
914
|
+
error: `Anti-cheating violation: Moving or renaming critical configuration file "${sourcePath}" is strictly prohibited. You must fix all build, compiler, type, and lint errors head-on in the source code.`,
|
|
915
|
+
};
|
|
916
|
+
}
|
|
884
917
|
const absSource = resolveAndValidatePath(workspaceRoot, sourcePath);
|
|
885
918
|
const absTarget = resolveAndValidatePath(workspaceRoot, targetPath);
|
|
886
919
|
let existingContent = null;
|
|
@@ -896,6 +929,9 @@ export async function renameFile(workspaceRoot, sourcePath, targetPath) {
|
|
|
896
929
|
changeLogger.logChange(targetPath, null, 'create');
|
|
897
930
|
await fs.mkdir(path.dirname(absTarget), { recursive: true });
|
|
898
931
|
await fs.rename(absSource, absTarget);
|
|
932
|
+
invalidateFileReadCache(absSource);
|
|
933
|
+
invalidateFileReadCache(absTarget);
|
|
934
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
899
935
|
return { output: `Successfully moved/renamed "${sourcePath}" to "${targetPath}".` };
|
|
900
936
|
}
|
|
901
937
|
catch (err) {
|
|
@@ -1018,10 +1054,16 @@ export async function modifyFile(workspaceRoot, filePath, edits) {
|
|
|
1018
1054
|
};
|
|
1019
1055
|
}
|
|
1020
1056
|
}
|
|
1057
|
+
const antiCheatError = detectAntiCheatingViolations(filePath, finalModified, existing);
|
|
1058
|
+
if (antiCheatError) {
|
|
1059
|
+
return { output: '', error: antiCheatError };
|
|
1060
|
+
}
|
|
1021
1061
|
changeLogger.logChange(filePath, existing, 'modify');
|
|
1022
1062
|
await atomicWriteFile(absPath, finalModified, 'utf-8');
|
|
1063
|
+
invalidateFileReadCache(absPath);
|
|
1064
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
1023
1065
|
return {
|
|
1024
|
-
output: `Successfully applied ${edits.length} edit(s) to "${filePath}"
|
|
1066
|
+
output: `Successfully applied ${edits.length} edit(s) to "${filePath}".\nStrategies used:\n${strategies.join('\n')}`,
|
|
1025
1067
|
};
|
|
1026
1068
|
}
|
|
1027
1069
|
catch (err) {
|
|
@@ -1385,6 +1427,9 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
1385
1427
|
maxBuffer: 1024 * 1024 * 2, // 2 MB buffer
|
|
1386
1428
|
signal: abortSignal,
|
|
1387
1429
|
});
|
|
1430
|
+
// Invalidate caches as shell command may have modified the workspace filesystem
|
|
1431
|
+
clearFileReadCache();
|
|
1432
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
1388
1433
|
const output = [stdout, stderr].filter(Boolean).join('\n');
|
|
1389
1434
|
// Bounded head/tail window truncation with structured metadata receipt
|
|
1390
1435
|
const windowedOutput = truncateWithHeadTailWindow(output, {
|
|
@@ -1395,6 +1440,9 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
1395
1440
|
return { output: windowedOutput || '(command produced no output)' };
|
|
1396
1441
|
}
|
|
1397
1442
|
catch (err) {
|
|
1443
|
+
// Also invalidate in case of partial command execution or errors that wrote files
|
|
1444
|
+
clearFileReadCache();
|
|
1445
|
+
invalidateDependencyGraph(workspaceRoot);
|
|
1398
1446
|
const message = err instanceof Error ? err.message : String(err);
|
|
1399
1447
|
// Condense error output with high-signal extraction and dynamic tail sizing
|
|
1400
1448
|
const condensedError = extractHighSignalError(message);
|