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.
@@ -26,7 +26,7 @@ const execAsync = promisify(exec);
26
26
  import { debugLog, isDebugOn } from '../utils/logger.js';
27
27
  import { ensureProjectStorage, ensureIgnored, readCache, writeCache, invalidateCacheForDependents, } from '../utils/projectStorage.js';
28
28
  import { GEMINI_MODELS, TPM_COOLING_DELAYS } from '../utils/config.js';
29
- import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, getModelThinkingLevel, summarizeChatHistory, } from './ai.js';
29
+ import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, getResearchConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, getModelThinkingLevel, summarizeChatHistory, } from './ai.js';
30
30
  import { getAndResetTurnUsage } from './proxyClient.js';
31
31
  import { changeLogger } from './changeLogger.js';
32
32
  import { chatHistoryService } from './chatHistoryService.js';
@@ -43,6 +43,8 @@ import { handleSlashCommand } from './agent/slashCommands.js';
43
43
  import { getMetricCollector } from './metrics.js';
44
44
  import { Orchestrator } from './orchestration/orchestrator.js';
45
45
  import { isSubAgentsEnabled, getApprovalMode } from './agent-tools.js';
46
+ import { resetSessionSettingsToDefault } from './sessionSettings.js';
47
+ import { clearFileReadCache } from '../utils/fileReadCache.js';
46
48
  import { runWithAgentId } from '../utils/asyncContext.js';
47
49
  // Export submodules for potential external uses if required
48
50
  export { AsyncInputHandler } from './agent/inputHandler.js';
@@ -117,6 +119,8 @@ export async function startAgentLoop(workspaceRoot, version) {
117
119
  changeLogger.init(workspaceRoot);
118
120
  chatHistoryService.init(workspaceRoot);
119
121
  const chat = createSharedChatSession();
122
+ resetSessionSettingsToDefault(chat);
123
+ clearFileReadCache();
120
124
  const inputHandler = new AsyncInputHandler();
121
125
  const chatSessionState = {
122
126
  id: crypto.randomUUID(),
@@ -160,6 +164,7 @@ export async function startAgentLoop(workspaceRoot, version) {
160
164
  chatSessionState.modelUsageCounts = {};
161
165
  chatSessionState.latestUsageMetadata = undefined;
162
166
  chatSessionState.previousUsageMetadata = undefined;
167
+ resetSessionSettingsToDefault(chat);
163
168
  chat.setSessionInfo(chatSessionState.id, workspaceRoot);
164
169
  }
165
170
  inputHandler.stop();
@@ -359,21 +364,22 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
359
364
  if (gatherRes.chainedMessages.length > 0) {
360
365
  const chainedContent = gatherRes.chainedMessages.join('\n');
361
366
  const newIntent = await routeIntent(chainedContent, '', ac.signal);
362
- if (gatherRes.contextResult !== null) {
363
- // If the model previously needed search context, determine if followups change the mode
364
- effectiveTargetAgent = newIntent.targetAgent;
367
+ if (gatherRes.targetAgent === 'EXECUTE') {
368
+ // EXECUTE permission sets are immutable during follow-ups to prevent downgrades
369
+ effectiveTargetAgent = 'EXECUTE';
370
+ }
371
+ else if (gatherRes.targetAgent === 'RESEARCH') {
372
+ // RESEARCH sessions stay in RESEARCH mode during chained requests
373
+ // Chained requests are incorporated into the research context for comprehensive investigation
374
+ effectiveTargetAgent = 'RESEARCH';
365
375
  }
366
376
  else {
367
- // If not in a context-search flow
368
- if (gatherRes.targetAgent === 'EXECUTE') {
369
- // EXECUTE permission sets are immutable during follow-ups to prevent downgrades
377
+ // If in CHAT mode, escalate if chained instructions dictate
378
+ if (newIntent.targetAgent === 'EXECUTE') {
370
379
  effectiveTargetAgent = 'EXECUTE';
371
380
  }
372
- else {
373
- // Conversational prompts can escalate to EXECUTE if chained instructions dictate
374
- if (newIntent.targetAgent === 'EXECUTE' || newIntent.needsContext) {
375
- effectiveTargetAgent = 'EXECUTE';
376
- }
381
+ else if (newIntent.targetAgent === 'RESEARCH') {
382
+ effectiveTargetAgent = 'RESEARCH';
377
383
  }
378
384
  }
379
385
  finalInput += `\n\n[USER FOLLOW-UP INSTRUCTIONS SENT DURING INVESTIGATION]:\n${chainedContent}\n\nPlease incorporate these instructions into your work. Address them appropriately, but ensure you do not lose track of the original request's primary objective.`;
@@ -383,9 +389,13 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
383
389
  process.stdout.write('\x1b[2K\r');
384
390
  return;
385
391
  }
386
- // Hot-swap the underlying LLM system instruction context depending on intent (conversational vs execution)
392
+ // Hot-swap the underlying LLM system instruction context depending on intent (conversational vs research vs execution)
387
393
  debugLog(`Intent Router output: original targetAgent = ${gatherRes.targetAgent}, effective = ${effectiveTargetAgent}`);
388
- const config = effectiveTargetAgent === 'CHAT' ? getGeneralChatConfig() : getPlanExecutionConfig();
394
+ const config = effectiveTargetAgent === 'CHAT'
395
+ ? getGeneralChatConfig()
396
+ : effectiveTargetAgent === 'RESEARCH'
397
+ ? getResearchConfig()
398
+ : getPlanExecutionConfig();
389
399
  let dynamicSystemInstruction = config.systemInstruction;
390
400
  // Inject gathered workspace directories, dependency configurations, and matching search patterns
391
401
  if (gatherRes.contextResult) {
@@ -495,6 +505,9 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
495
505
  if (effectiveTargetAgent === 'CHAT') {
496
506
  selectedModel = GEMINI_MODELS.FLASH_LITE;
497
507
  }
508
+ else if (effectiveTargetAgent === 'RESEARCH') {
509
+ selectedModel = GEMINI_MODELS.FLASH;
510
+ }
498
511
  else {
499
512
  spinner.stop(); // MUST clear the investigation spinner first to prevent leaking the setInterval
500
513
  spinner.start(pc.blue('🧠 Evaluating execution complexity...'));
@@ -661,6 +674,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
661
674
  creditsRemaining: usage.remainingBalance,
662
675
  lastTurnDuration: turnDuration,
663
676
  modelName: chat.getModel(),
677
+ thinkingLevel: (typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
678
+ getModelThinkingLevel(chat.getModel()),
664
679
  totalTokens: chatSessionState.totalTokens,
665
680
  totalInputTokens: chatSessionState.totalInputTokens,
666
681
  totalOutputTokens: chatSessionState.totalOutputTokens,
@@ -668,6 +683,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
668
683
  gitBranch: gitBranch || undefined,
669
684
  autoApprove: getApprovalMode() === 'skip-all',
670
685
  subAgents: isSubAgentsEnabled(),
686
+ debugMode: isDebugOn(),
671
687
  latestUsageMetadata: chatSessionState.latestUsageMetadata,
672
688
  previousUsageMetadata: chatSessionState.previousUsageMetadata,
673
689
  modelUsageCounts: chatSessionState.modelUsageCounts,
@@ -825,6 +841,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
825
841
  creditsRemaining: latestUsage?.remainingBalance,
826
842
  lastTurnDuration: turnDuration,
827
843
  modelName: chat.getModel(),
844
+ thinkingLevel: (typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
845
+ getModelThinkingLevel(chat.getModel()),
828
846
  totalTokens: chatSessionState.totalTokens,
829
847
  totalInputTokens: chatSessionState.totalInputTokens,
830
848
  totalOutputTokens: chatSessionState.totalOutputTokens,
@@ -832,6 +850,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
832
850
  gitBranch: gitBranch || undefined,
833
851
  autoApprove: getApprovalMode() === 'skip-all',
834
852
  subAgents: isSubAgentsEnabled(),
853
+ debugMode: isDebugOn(),
835
854
  latestUsageMetadata: chatSessionState.latestUsageMetadata,
836
855
  previousUsageMetadata: chatSessionState.previousUsageMetadata,
837
856
  modelUsageCounts: chatSessionState.modelUsageCounts,
@@ -850,6 +869,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
850
869
  creditsRemaining: latestUsage?.remainingBalance,
851
870
  lastTurnDuration: turnDuration,
852
871
  modelName: chat.getModel(),
872
+ thinkingLevel: (typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
873
+ getModelThinkingLevel(chat.getModel()),
853
874
  totalTokens: chatSessionState.totalTokens,
854
875
  totalInputTokens: chatSessionState.totalInputTokens,
855
876
  totalOutputTokens: chatSessionState.totalOutputTokens,
@@ -857,6 +878,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
857
878
  gitBranch: gitBranch || undefined,
858
879
  autoApprove: getApprovalMode() === 'skip-all',
859
880
  subAgents: isSubAgentsEnabled(),
881
+ debugMode: isDebugOn(),
860
882
  latestUsageMetadata: chatSessionState.latestUsageMetadata,
861
883
  previousUsageMetadata: chatSessionState.previousUsageMetadata,
862
884
  modelUsageCounts: chatSessionState.modelUsageCounts,
@@ -1204,7 +1226,7 @@ If you are not done, please continue working using your other tools.`;
1204
1226
  .join('\n\n');
1205
1227
  debugLog(`Verification failed on attempt ${correctionAttempts}/${MAX_CORRECTIONS}. Issues:\n${combinedIssuesForAI}`);
1206
1228
  // Compile compilation and syntax diagnostic warnings into an auto-correction prompt
1207
- const correctionPrompt = `AUTOMATED SYSTEM CHECK: Your previous changes resulted in the following issues:\n\n${combinedIssuesForAI}\n\nPlease analyze these issues and use your file modification tools to fix them.`;
1229
+ const correctionPrompt = `AUTOMATED SYSTEM CHECK: Your previous changes resulted in the following issues:\n\n${combinedIssuesForAI}\n\nCRITICAL ANTI-CHEATING RULE: You MUST fix these issues head-on in the application source code. You are STRICTLY FORBIDDEN from modifying build configurations (e.g. next.config.*, tsconfig.json, vite.config.*, .eslintrc*, package.json scripts) to ignore, disable, or bypass build, compile, type, or lint errors (such as ignoreBuildErrors, ignoreDuringBuilds, or turning off checks). You are also forbidden from adding blanket suppressions like @ts-ignore, @ts-nocheck, or eslint-disable to silence errors. Fix the underlying root cause in the actual code.`;
1208
1230
  // Cooling-off delay before initiating the self-correction turn
1209
1231
  await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.CORRECTION_TURN_MS));
1210
1232
  if (signal.aborted)
@@ -117,6 +117,12 @@ export declare function getPlanExecutionConfig(): {
117
117
  functionDeclarations: import("@google/generative-ai").FunctionDeclaration[];
118
118
  }[];
119
119
  };
120
+ export declare function getResearchConfig(): {
121
+ systemInstruction: string;
122
+ tools: {
123
+ functionDeclarations: import("@google/generative-ai").FunctionDeclaration[];
124
+ }[];
125
+ };
120
126
  /**
121
127
  * Compresses a large string of text using Gemini Flash.
122
128
  * Used for shrinking context payloads to prevent OOM/choking.
@@ -5,7 +5,7 @@ import { getMetricCollector } from './metrics.js';
5
5
  import { getAuthorizedIdToken, checkByokSubscription } from './auth.js';
6
6
  import { debugLog } from '../utils/logger.js';
7
7
  import { readCache, writeCache } from '../utils/projectStorage.js';
8
- import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_SEMANTIC_SYSTEM_INSTRUCTION, HISTORY_SUMMARIZER_SYSTEM_INSTRUCTION, USER_PROFILE_EXTRACTOR_SYSTEM_INSTRUCTION, TRIVIAL_MESSAGE_CLASSIFIER_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
8
+ import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, RESEARCH_AGENT_SYSTEM_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_SEMANTIC_SYSTEM_INSTRUCTION, HISTORY_SUMMARIZER_SYSTEM_INSTRUCTION, USER_PROFILE_EXTRACTOR_SYSTEM_INSTRUCTION, TRIVIAL_MESSAGE_CLASSIFIER_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
9
9
  import { workspaceRegistry } from './workspaceRegistry.js';
10
10
  import { loadCredentials } from '../utils/credentialStore.js';
11
11
  import { ProxyClient } from './proxyClient.js';
@@ -534,6 +534,12 @@ export function getPlanExecutionConfig() {
534
534
  tools: [{ functionDeclarations: getToolDeclarations({ isExecutionAgent: true }) }],
535
535
  };
536
536
  }
537
+ export function getResearchConfig() {
538
+ return {
539
+ systemInstruction: RESEARCH_AGENT_SYSTEM_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
540
+ tools: [{ functionDeclarations: getToolDeclarations({ isResearchAgent: true }) }],
541
+ };
542
+ }
537
543
  /**
538
544
  * Compresses a large string of text using Gemini Flash.
539
545
  * Used for shrinking context payloads to prevent OOM/choking.
@@ -794,7 +800,7 @@ export function createIntentRouterSession() {
794
800
  },
795
801
  agent: {
796
802
  type: SchemaType.STRING,
797
- enum: ['CHAT', 'EXECUTE'],
803
+ enum: ['CHAT', 'RESEARCH', 'EXECUTE'],
798
804
  description: 'Target agent to route the request to',
799
805
  },
800
806
  },
@@ -1,4 +1,5 @@
1
1
  import type { Content } from '@google/generative-ai';
2
+ import type { ThinkingLevel } from '../utils/config.js';
2
3
  /**
3
4
  * Options for configuring dynamic history pruning.
4
5
  */
@@ -32,6 +33,8 @@ export interface ChatSessionData {
32
33
  lastTurnDuration?: string;
33
34
  /** Optional name of the AI model used during this session (e.g., "gemini-1.5-pro"). */
34
35
  modelName?: string;
36
+ /** Optional thinking reasoning level used during this session (e.g., "LOW", "MEDIUM", "HIGH"). */
37
+ thinkingLevel?: ThinkingLevel;
35
38
  /** Optional total cumulative tokens consumed during the session. */
36
39
  totalTokens?: number;
37
40
  /** Optional total cumulative input tokens (prompt + cached) consumed during the session. */
@@ -46,6 +49,8 @@ export interface ChatSessionData {
46
49
  autoApprove?: boolean;
47
50
  /** Optional flag indicating whether sub-agents were enabled or active during this session. */
48
51
  subAgents?: boolean;
52
+ /** Optional flag indicating whether debug diagnostic logging was enabled in this session. */
53
+ debugMode?: boolean;
49
54
  /** Optional metadata about the token usage from the very last turn. */
50
55
  latestUsageMetadata?: any;
51
56
  /** Optional metadata about the token usage from the turn prior to the last turn. */
@@ -17,9 +17,11 @@ export interface ContextAgentResult {
17
17
  tierPartition?: TierPartitionResult;
18
18
  }
19
19
  export declare function detectProjectType(workspaceRoot: string): Promise<string>;
20
+ import type { TargetAgent } from './agent/types.js';
21
+ export type { TargetAgent } from './agent/types.js';
20
22
  export interface IntentRoute {
21
23
  needsContext: boolean;
22
- targetAgent: 'CHAT' | 'EXECUTE';
24
+ targetAgent: TargetAgent;
23
25
  }
24
26
  export declare function routeIntent(userRequest: string, chatHistory?: string, abortSignal?: AbortSignal): Promise<IntentRoute>;
25
27
  export declare function evaluateExecutionComplexity(userRequest: string, investigationSummary: string | undefined, numRelevantFiles: number, chatHistory?: string, abortSignal?: AbortSignal): Promise<'EASY' | 'HARD'>;
@@ -28,6 +30,6 @@ export declare function gatherContext(workspaceRoot: string, userRequest: string
28
30
  waitForPrompt: () => Promise<void>;
29
31
  }, abortSignal: AbortSignal, onProgress?: (msg: string) => void, onToolCall?: (msg: string, label: string) => void): Promise<{
30
32
  contextResult: ContextAgentResult | null;
31
- targetAgent: 'CHAT' | 'EXECUTE';
33
+ targetAgent: TargetAgent;
32
34
  chainedMessages: string[];
33
35
  }>;
@@ -219,9 +219,11 @@ export async function routeIntent(userRequest, chatHistory = '', abortSignal) {
219
219
  const text = result.response.text()?.trim() || '{}';
220
220
  const parsed = JSON.parse(text);
221
221
  debugLog(`Intent Router Parsed: ${JSON.stringify(parsed)}`);
222
+ const rawAgent = parsed.agent?.toUpperCase?.() || parsed.agent;
223
+ const validAgent = rawAgent === 'CHAT' ? 'CHAT' : rawAgent === 'RESEARCH' ? 'RESEARCH' : 'EXECUTE';
222
224
  return {
223
225
  needsContext: parsed.context === 'SEARCH',
224
- targetAgent: parsed.agent === 'CHAT' ? 'CHAT' : 'EXECUTE',
226
+ targetAgent: validAgent,
225
227
  };
226
228
  }
227
229
  catch (e) {
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @file sessionSettings.ts
3
+ * @description Manages session-scoped slash command settings and operational toggles.
4
+ *
5
+ * Operational toggles scoped to an individual chat session include:
6
+ * - `autoApprove` : Whether automatic confirmation is enabled for shell execution commands (/auto-approve)
7
+ * - `subAgents` : Whether the MMAAK parallel multi-agent orchestration engine is enabled (/sub-agents)
8
+ * - `debugMode` : Whether internal diagnostic telemetry logging is visible (/debug)
9
+ * - `modelName` : The generative AI model selected for this session (/models)
10
+ * - `thinkingLevel`: The reasoning budget allocation level for the active model (/models)
11
+ *
12
+ * Safe Lifecycle:
13
+ * - On new chat sessions or CLI boot, settings automatically reset to safe defaults.
14
+ * - On resuming a saved session, previous settings are restored and verified.
15
+ */
16
+ import { type ThinkingLevel } from '../utils/config.js';
17
+ import { type ProxyChatSession } from './ai.js';
18
+ import { type ChatSessionData } from './chatHistoryService.js';
19
+ /**
20
+ * Session-scoped operational settings container.
21
+ */
22
+ export interface SessionSettings {
23
+ /** Whether auto-approval mode is enabled for command execution ('skip-all' vs 'ask'). */
24
+ autoApprove: boolean;
25
+ /** Whether MMAAK parallel sub-agent orchestration is enabled. */
26
+ subAgents: boolean;
27
+ /** Whether internal telemetry and diagnostic logging is enabled. */
28
+ debugMode: boolean;
29
+ /** Active generative AI model identifier for the session. */
30
+ modelName: string;
31
+ /** Active thinking/reasoning level for the model. */
32
+ thinkingLevel: ThinkingLevel;
33
+ }
34
+ /**
35
+ * Default safe settings used when creating a new chat session or resetting state.
36
+ */
37
+ export declare const DEFAULT_SESSION_SETTINGS: Readonly<SessionSettings>;
38
+ /**
39
+ * Applies saved or specified settings to the active environment and chat session.
40
+ *
41
+ * @param session - A partial session object or settings container.
42
+ * @param chat - Optional active ProxyChatSession instance to update.
43
+ * @returns The resulting applied SessionSettings.
44
+ */
45
+ export declare function applySessionSettings(session: Partial<ChatSessionData> | Partial<SessionSettings>, chat?: ProxyChatSession): SessionSettings;
46
+ /**
47
+ * Resets all session operational toggles back to default safe values.
48
+ *
49
+ * @param chat - Optional active ProxyChatSession instance to reset.
50
+ * @returns The default SessionSettings.
51
+ */
52
+ export declare function resetSessionSettingsToDefault(chat?: ProxyChatSession): SessionSettings;
53
+ /**
54
+ * Inspects and retrieves the current operational settings across modules.
55
+ *
56
+ * @param chat - Optional active ProxyChatSession instance.
57
+ * @returns The current active SessionSettings.
58
+ */
59
+ export declare function getCurrentSessionSettings(chat?: ProxyChatSession): SessionSettings;
60
+ /**
61
+ * Persists current operational settings to the saved session cache if the session exists on disk.
62
+ *
63
+ * @param sessionId - The unique identifier of the chat session to update.
64
+ * @param chat - Optional active ProxyChatSession instance.
65
+ */
66
+ export declare function syncActiveSessionSettings(sessionId?: string, chat?: ProxyChatSession): Promise<void>;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @file sessionSettings.ts
3
+ * @description Manages session-scoped slash command settings and operational toggles.
4
+ *
5
+ * Operational toggles scoped to an individual chat session include:
6
+ * - `autoApprove` : Whether automatic confirmation is enabled for shell execution commands (/auto-approve)
7
+ * - `subAgents` : Whether the MMAAK parallel multi-agent orchestration engine is enabled (/sub-agents)
8
+ * - `debugMode` : Whether internal diagnostic telemetry logging is visible (/debug)
9
+ * - `modelName` : The generative AI model selected for this session (/models)
10
+ * - `thinkingLevel`: The reasoning budget allocation level for the active model (/models)
11
+ *
12
+ * Safe Lifecycle:
13
+ * - On new chat sessions or CLI boot, settings automatically reset to safe defaults.
14
+ * - On resuming a saved session, previous settings are restored and verified.
15
+ */
16
+ import { setApprovalMode, getApprovalMode, isSubAgentsEnabled, setSubAgentsEnabled } from './agent-tools.js';
17
+ import { isDebugOn, setDebugMode } from '../utils/logger.js';
18
+ import { DEFAULT_MODEL, DEFAULT_MODEL_THINKING_LEVELS, } from '../utils/config.js';
19
+ import { getGlobalActiveModel, setGlobalActiveModel, getModelThinkingLevel, setModelThinkingLevel, } from './ai.js';
20
+ import { chatHistoryService } from './chatHistoryService.js';
21
+ /**
22
+ * Default safe settings used when creating a new chat session or resetting state.
23
+ */
24
+ export const DEFAULT_SESSION_SETTINGS = Object.freeze({
25
+ autoApprove: false,
26
+ subAgents: true,
27
+ debugMode: false,
28
+ modelName: DEFAULT_MODEL,
29
+ thinkingLevel: (DEFAULT_MODEL_THINKING_LEVELS[DEFAULT_MODEL] || 'MEDIUM'),
30
+ });
31
+ /**
32
+ * Applies saved or specified settings to the active environment and chat session.
33
+ *
34
+ * @param session - A partial session object or settings container.
35
+ * @param chat - Optional active ProxyChatSession instance to update.
36
+ * @returns The resulting applied SessionSettings.
37
+ */
38
+ export function applySessionSettings(session, chat) {
39
+ // 1. Auto-approve mode
40
+ const autoApprove = session.autoApprove ?? DEFAULT_SESSION_SETTINGS.autoApprove;
41
+ setApprovalMode(autoApprove ? 'skip-all' : 'ask');
42
+ // 2. MMAAK sub-agents
43
+ const subAgents = session.subAgents ?? DEFAULT_SESSION_SETTINGS.subAgents;
44
+ setSubAgentsEnabled(subAgents);
45
+ // 3. Debug logging
46
+ const debugMode = session.debugMode ?? DEFAULT_SESSION_SETTINGS.debugMode;
47
+ setDebugMode(debugMode);
48
+ // 4. Model selection
49
+ const modelName = session.modelName ?? DEFAULT_SESSION_SETTINGS.modelName;
50
+ setGlobalActiveModel(modelName);
51
+ if (chat && typeof chat.setModel === 'function') {
52
+ chat.setModel(modelName);
53
+ }
54
+ // 5. Thinking level
55
+ const targetThinking = session.thinkingLevel ??
56
+ getModelThinkingLevel(modelName) ??
57
+ DEFAULT_MODEL_THINKING_LEVELS[modelName] ??
58
+ DEFAULT_SESSION_SETTINGS.thinkingLevel;
59
+ setModelThinkingLevel(modelName, targetThinking);
60
+ if (chat && typeof chat.setThinkingLevel === 'function') {
61
+ chat.setThinkingLevel(targetThinking);
62
+ }
63
+ return {
64
+ autoApprove,
65
+ subAgents,
66
+ debugMode,
67
+ modelName,
68
+ thinkingLevel: targetThinking,
69
+ };
70
+ }
71
+ /**
72
+ * Resets all session operational toggles back to default safe values.
73
+ *
74
+ * @param chat - Optional active ProxyChatSession instance to reset.
75
+ * @returns The default SessionSettings.
76
+ */
77
+ export function resetSessionSettingsToDefault(chat) {
78
+ return applySessionSettings(DEFAULT_SESSION_SETTINGS, chat);
79
+ }
80
+ /**
81
+ * Inspects and retrieves the current operational settings across modules.
82
+ *
83
+ * @param chat - Optional active ProxyChatSession instance.
84
+ * @returns The current active SessionSettings.
85
+ */
86
+ export function getCurrentSessionSettings(chat) {
87
+ const autoApprove = getApprovalMode() === 'skip-all';
88
+ const subAgents = isSubAgentsEnabled();
89
+ const debugMode = isDebugOn();
90
+ const modelName = (chat && typeof chat.getModel === 'function' ? chat.getModel() : undefined) || getGlobalActiveModel();
91
+ const thinkingLevel = (chat && typeof chat.getThinkingLevel === 'function' ? chat.getThinkingLevel() : undefined) ||
92
+ getModelThinkingLevel(modelName) ||
93
+ 'MEDIUM';
94
+ return {
95
+ autoApprove,
96
+ subAgents,
97
+ debugMode,
98
+ modelName,
99
+ thinkingLevel,
100
+ };
101
+ }
102
+ /**
103
+ * Persists current operational settings to the saved session cache if the session exists on disk.
104
+ *
105
+ * @param sessionId - The unique identifier of the chat session to update.
106
+ * @param chat - Optional active ProxyChatSession instance.
107
+ */
108
+ export async function syncActiveSessionSettings(sessionId, chat) {
109
+ if (!sessionId)
110
+ return;
111
+ try {
112
+ const session = chatHistoryService.getSession(sessionId);
113
+ if (!session)
114
+ return;
115
+ const current = getCurrentSessionSettings(chat);
116
+ session.autoApprove = current.autoApprove;
117
+ session.subAgents = current.subAgents;
118
+ session.debugMode = current.debugMode;
119
+ session.modelName = current.modelName;
120
+ session.thinkingLevel = current.thinkingLevel;
121
+ await chatHistoryService.saveSession(session);
122
+ }
123
+ catch {
124
+ // Non-blocking sync failure ignored
125
+ }
126
+ }
@@ -149,8 +149,13 @@ export async function runVerification(workspaceRoot, abortSignal) {
149
149
  const MAX_VERIFY_OUTPUT = 50_000; // 50KB cap on verification output
150
150
  debugLog(`Running project-level verification command: ${command}`);
151
151
  try {
152
+ const cleanEnv = { ...process.env };
153
+ delete cleanEnv.NEXT_DISABLE_ESLINT;
154
+ delete cleanEnv.TSC_COMPILE_ON_ERROR;
155
+ delete cleanEnv.ESLINT_NO_DEV_ERRORS;
152
156
  const { stdout, stderr } = await execAsync(command, {
153
157
  cwd: workspaceRoot,
158
+ env: cleanEnv,
154
159
  timeout: 120_000, // 120s (2 mins) - builds can take a while (e.g., Next.js, Gradle)
155
160
  maxBuffer: 1024 * 1024, // 1 MB buffer
156
161
  signal: abortSignal,
@@ -235,6 +240,7 @@ ${result.errors.join('\n')}
235
240
  Please fix these errors using the modify_file tool.`;
236
241
  }
237
242
  import { auditFilePerformance, formatAuditForModel, formatAuditForTerminal, isAuditableFile, } from '../utils/performanceAuditor.js';
243
+ import { detectAntiCheatingViolations } from '../utils/antiCheatingGuard.js';
238
244
  export async function verifyChangedFiles(workspaceRoot, filePaths, abortSignal) {
239
245
  if (process.env.MMCLI_SKIP_VERIFICATION === 'true' || process.env.SKIP_VERIFICATION === '1') {
240
246
  return { errors: null, warnings: null };
@@ -267,10 +273,26 @@ export async function verifyChangedFiles(workspaceRoot, filePaths, abortSignal)
267
273
  if (buildResult.aborted) {
268
274
  return '[Verification Aborted]';
269
275
  }
270
- const buildErrorMsg = `[Build Error: ${buildResult.command}]\n${buildResult.errors.join('\n').substring(0, 5000)}`;
276
+ const buildErrorMsg = `[Build Error: ${buildResult.command}]\n${buildResult.errors.join('\n').substring(0, 5000)}\n\nCRITICAL DIRECTIVE: Do NOT modify configuration files (such as next.config.*, tsconfig.json, or package.json) to disable, ignore, or bypass these errors (e.g. ignoreBuildErrors, ignoreDuringBuilds). You MUST fix these errors directly in the source code.`;
271
277
  errors.push(buildErrorMsg);
272
278
  }
273
- // 2. Performance Audit
279
+ // 2. Anti-Cheating Invariant Scan: Ensure no modified files introduced bypass flags
280
+ for (const file of filePaths) {
281
+ if (abortSignal?.aborted)
282
+ return '[Verification Aborted]';
283
+ try {
284
+ const absolutePath = path.resolve(workspaceRoot, file);
285
+ const content = await fs.readFile(absolutePath, 'utf-8');
286
+ const antiCheatViolation = detectAntiCheatingViolations(file, content);
287
+ if (antiCheatViolation) {
288
+ errors.push(`[Verification Rejected - Anti-Cheating Violation in "${file}"]\n${antiCheatViolation}`);
289
+ }
290
+ }
291
+ catch {
292
+ // File might have been deleted or inaccessible
293
+ }
294
+ }
295
+ // 3. Performance Audit
274
296
  // We run this even if the build failed, so the model gets all feedback at once
275
297
  for (const file of filePaths) {
276
298
  if (abortSignal?.aborted)
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Determines whether a given file path represents a critical project configuration
3
+ * file or root manifest that should never be deleted or renamed by the agent.
4
+ *
5
+ * @param filePath - Relative or absolute path to check
6
+ * @returns True if the file is a protected critical config file
7
+ */
8
+ export declare function isCriticalConfigFile(filePath: string): boolean;
9
+ /**
10
+ * Evaluates whether a proposed file modification or write introduces anti-cheating violations
11
+ * by attempting to silence, ignore, or bypass build, compiler, type, or lint errors.
12
+ *
13
+ * This function is strictly diff-aware: if the existing file already had an error-ignoring flag,
14
+ * modifying unrelated sections of the file will not trigger a false positive.
15
+ *
16
+ * @param filePath - Path to the file being created or modified
17
+ * @param newContent - The proposed new content of the file
18
+ * @param existingContent - The previous content of the file (if it already existed on disk)
19
+ * @returns An error message string if an anti-cheating violation is detected, or null if clean.
20
+ */
21
+ export declare function detectAntiCheatingViolations(filePath: string, newContent: string, existingContent?: string): string | null;