minovative-mind-cli 2.1.6 → 2.1.7

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.
@@ -24,7 +24,7 @@ import { markedTerminal } from 'marked-terminal';
24
24
  import { debugLog, isDebugOn } from '../utils/logger.js';
25
25
  import { ensureProjectStorage, ensureIgnored, readCache, writeCache, invalidateCacheForDependents, } from '../utils/projectStorage.js';
26
26
  import { GEMINI_MODELS } from '../utils/config.js';
27
- import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, getGlobalLatestUsageMetadata, } from './ai.js';
27
+ import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, setGlobalActiveModel, getGlobalLatestUsageMetadata, } from './ai.js';
28
28
  import { changeLogger } from './changeLogger.js';
29
29
  import { chatHistoryService } from './chatHistoryService.js';
30
30
  import { gatherContext, routeIntent, evaluateExecutionComplexity } from './contextAgent.js';
@@ -134,8 +134,16 @@ export async function startAgentLoop(workspaceRoot, version) {
134
134
  { value: '/clear', label: '/clear', hint: 'Clear chat session history' },
135
135
  { value: '/debug', label: '/debug', hint: 'Toggle internal debug logs' },
136
136
  { value: '/auto-approve', label: '/auto-approve', hint: 'Approve all future terminal commands' },
137
- { value: '/sub-agents', label: '/sub-agents', hint: 'Toggle the MMAAK Engine for parallel investigation and execution' },
138
- { value: '/workspaces', label: '/workspaces', hint: 'Manage external workspaces for cross-project development' },
137
+ {
138
+ value: '/sub-agents',
139
+ label: '/sub-agents',
140
+ hint: 'Toggle the MMAAK Engine for parallel investigation and execution',
141
+ },
142
+ {
143
+ value: '/workspaces',
144
+ label: '/workspaces',
145
+ hint: 'Manage external workspaces for cross-project development',
146
+ },
139
147
  { value: '/stats', label: '/stats', hint: 'View current session statistics and configuration' },
140
148
  { value: '/commit', label: '/commit', hint: 'Auto-commit changes with AI message' },
141
149
  { value: '/revert', label: '/revert', hint: 'Undo last change' },
@@ -511,22 +519,65 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
511
519
  // Small delay to allow stdout to flush and terminal to finish scrolling from the markdown output
512
520
  // This prevents @clack/prompts from miscalculating the cursor position and duplicating the prompt on arrow keys
513
521
  await new Promise((resolve) => setTimeout(resolve, 200));
514
- const planAction = await p['select']({
515
- message: 'Plan generated. What would you like to do?',
516
- options: [
517
- { value: 'proceed', label: 'Proceed with plan', hint: 'Executes the generated plan immediately' },
518
- { value: 'edit', label: 'Edit plan', hint: 'Provide additional feedback to revise the plan' },
519
- { value: 'exit', label: 'Exit plan mode', hint: 'Return to normal chat without executing' },
520
- ],
521
- });
522
- if (p.isCancel(planAction) || planAction === 'exit') {
523
- planModeReturn = 'exit';
524
- }
525
- else if (planAction === 'edit') {
526
- planModeReturn = 'edit';
527
- }
528
- else if (planAction === 'proceed') {
529
- planModeReturn = 'proceed';
522
+ while (true) {
523
+ const currentModel = getGlobalActiveModel();
524
+ const planAction = await p['select']({
525
+ message: 'Plan generated. What would you like to do?',
526
+ options: [
527
+ { value: 'proceed', label: 'Proceed with plan', hint: 'Executes the generated plan immediately' },
528
+ { value: 'edit', label: 'Edit plan', hint: 'Provide additional feedback to revise the plan' },
529
+ {
530
+ value: 'choose_model',
531
+ label: 'Choose AI model',
532
+ hint: `Change the active AI model (Current: ${currentModel})`,
533
+ },
534
+ { value: 'exit', label: 'Exit plan mode', hint: 'Return to normal chat without executing' },
535
+ ],
536
+ });
537
+ if (planAction === 'choose_model') {
538
+ const selectedModel = await p['select']({
539
+ message: `Select AI Model (Current: ${pc.cyan(currentModel)})`,
540
+ initialValue: currentModel,
541
+ options: [
542
+ {
543
+ value: 'gemini-3.1-pro-preview',
544
+ label: 'Gemini 3.1 Pro',
545
+ hint: 'The Pro model for complex logic',
546
+ },
547
+ {
548
+ value: 'gemini-3.5-flash',
549
+ label: 'Gemini 3.5 Flash',
550
+ hint: 'Balanced performance',
551
+ },
552
+ {
553
+ value: 'gemini-3.1-flash-lite',
554
+ label: 'Gemini 3.1 Flash-Lite',
555
+ hint: 'Ultra-fast and cost-effective',
556
+ },
557
+ {
558
+ value: 'auto',
559
+ label: 'Auto (Flash-Lite / Flash 3.5)',
560
+ hint: 'Dynamically routes between Flash-Lite and Flash 3.5 based on prompt complexity',
561
+ },
562
+ ],
563
+ });
564
+ if (!p.isCancel(selectedModel)) {
565
+ chat.setModel(selectedModel);
566
+ setGlobalActiveModel(selectedModel);
567
+ p.log.success(`Model successfully switched to ${pc.cyan(selectedModel)}`);
568
+ }
569
+ continue;
570
+ }
571
+ if (p.isCancel(planAction) || planAction === 'exit') {
572
+ planModeReturn = 'exit';
573
+ }
574
+ else if (planAction === 'edit') {
575
+ planModeReturn = 'edit';
576
+ }
577
+ else if (planAction === 'proceed') {
578
+ planModeReturn = 'proceed';
579
+ }
580
+ break;
530
581
  }
531
582
  }
532
583
  return { planModeReturn, contextResult: gatherRes.contextResult };
@@ -325,8 +325,11 @@ export class InvestigationAgentRunner {
325
325
  */
326
326
  updateUsage(result) {
327
327
  const usage = result.response.usageMetadata?.();
328
- if (usage && usage.totalTokenCount) {
329
- this.creditsUsed += usage.totalTokenCount;
328
+ if (usage) {
329
+ const tokens = usage.totalTokenCount || ((usage.promptTokens || 0) + (usage.candidatesTokens || 0) + (usage.cachedTokens || 0));
330
+ if (tokens) {
331
+ this.creditsUsed += tokens;
332
+ }
330
333
  }
331
334
  }
332
335
  }
@@ -188,8 +188,11 @@ export class SubAgentRunner {
188
188
  */
189
189
  updateUsage(result) {
190
190
  const usage = result.response.usageMetadata?.();
191
- if (usage && usage.totalTokenCount) {
192
- this.creditsUsed += usage.totalTokenCount;
191
+ if (usage) {
192
+ const tokens = usage.totalTokenCount || ((usage.promptTokens || 0) + (usage.candidatesTokens || 0) + (usage.cachedTokens || 0));
193
+ if (tokens) {
194
+ this.creditsUsed += tokens;
195
+ }
193
196
  }
194
197
  }
195
198
  }
@@ -1,9 +1,24 @@
1
+ /**
2
+ * Configuration options for the history-enabled text prompt.
3
+ */
1
4
  export interface HistoryTextOptions {
5
+ /** The message to display to the user. */
2
6
  message: string;
7
+ /** Placeholder text shown when the input is empty. */
3
8
  placeholder?: string;
9
+ /** Default value to use if the user submits without input. */
4
10
  defaultValue?: string;
11
+ /** Initial value to populate the input with. */
5
12
  initialValue?: string;
13
+ /** An array of previous commands or strings to allow navigation through. */
6
14
  history?: string[];
15
+ /** Callback to validate the user input. */
7
16
  validate?: (value: string) => string | Error | undefined;
8
17
  }
18
+ /**
19
+ * A custom text prompt that supports command history navigation using Up/Down arrow keys.
20
+ *
21
+ * @param opts - The configuration options for the prompt.
22
+ * @returns A promise that resolves to the user's input string or a symbol if cancelled.
23
+ */
9
24
  export declare const historyText: (opts: HistoryTextOptions) => Promise<string | symbol>;
@@ -22,6 +22,12 @@ function symbol(state) {
22
22
  return pc.cyan(S_STEP_ACTIVE);
23
23
  }
24
24
  }
25
+ /**
26
+ * A custom text prompt that supports command history navigation using Up/Down arrow keys.
27
+ *
28
+ * @param opts - The configuration options for the prompt.
29
+ * @returns A promise that resolves to the user's input string or a symbol if cancelled.
30
+ */
25
31
  export const historyText = (opts) => {
26
32
  const history = opts.history || [];
27
33
  let historyIndex = -1;
@@ -1,4 +1,25 @@
1
+ /**
2
+ * Checks if debug mode is currently enabled.
3
+ *
4
+ * @returns {boolean} True if debug mode is enabled, false otherwise.
5
+ */
1
6
  export declare function isDebugOn(): boolean;
7
+ /**
8
+ * Sets the debug mode state.
9
+ *
10
+ * @param {boolean} enabled - The desired state of the debug mode.
11
+ */
2
12
  export declare function setDebugMode(enabled: boolean): void;
13
+ /**
14
+ * Toggles the current debug mode state.
15
+ *
16
+ * @returns {boolean} The new state of the debug mode.
17
+ */
3
18
  export declare function toggleDebugMode(): boolean;
19
+ /**
20
+ * Logs a message to the console if debug mode is enabled.
21
+ * The message is prefixed with "[DEBUG]" and styled in gray.
22
+ *
23
+ * @param {string} message - The message to log.
24
+ */
4
25
  export declare function debugLog(message: string): void;
@@ -1,8 +1,21 @@
1
1
  import pc from 'picocolors';
2
+ /**
3
+ * Global flag indicating whether debug mode is currently enabled.
4
+ */
2
5
  let isDebugEnabled = process.env.MINO_DEBUG === 'true';
6
+ /**
7
+ * Checks if debug mode is currently enabled.
8
+ *
9
+ * @returns {boolean} True if debug mode is enabled, false otherwise.
10
+ */
3
11
  export function isDebugOn() {
4
12
  return isDebugEnabled;
5
13
  }
14
+ /**
15
+ * Sets the debug mode state.
16
+ *
17
+ * @param {boolean} enabled - The desired state of the debug mode.
18
+ */
6
19
  export function setDebugMode(enabled) {
7
20
  isDebugEnabled = enabled;
8
21
  if (enabled)
@@ -10,10 +23,21 @@ export function setDebugMode(enabled) {
10
23
  else
11
24
  delete process.env.MINO_DEBUG;
12
25
  }
26
+ /**
27
+ * Toggles the current debug mode state.
28
+ *
29
+ * @returns {boolean} The new state of the debug mode.
30
+ */
13
31
  export function toggleDebugMode() {
14
32
  setDebugMode(!isDebugEnabled);
15
33
  return isDebugEnabled;
16
34
  }
35
+ /**
36
+ * Logs a message to the console if debug mode is enabled.
37
+ * The message is prefixed with "[DEBUG]" and styled in gray.
38
+ *
39
+ * @param {string} message - The message to log.
40
+ */
17
41
  export function debugLog(message) {
18
42
  if (isDebugEnabled) {
19
43
  console.log(pc.gray(`[DEBUG] ${message}`));
@@ -1,2 +1,15 @@
1
+ /**
2
+ * @file src/utils/profiles.ts
3
+ * @description Language profiles defining the regex patterns and post-processors
4
+ * used by the dependency tracer to extract import/dependency specifiers across
5
+ * different programming languages.
6
+ */
1
7
  import { LanguageProfile } from './types.js';
8
+ /**
9
+ * Registry of supported language profiles used to identify, extract, and normalize
10
+ * dependency specifiers from source files.
11
+ *
12
+ * Each profile defines the file extensions it applies to, the regex patterns to match
13
+ * import/export specifiers, and an optional custom normalization function.
14
+ */
2
15
  export declare const LANGUAGE_PROFILES: LanguageProfile[];
@@ -1,19 +1,62 @@
1
+ /**
2
+ * @file src/utils/profiles.ts
3
+ * @description Language profiles defining the regex patterns and post-processors
4
+ * used by the dependency tracer to extract import/dependency specifiers across
5
+ * different programming languages.
6
+ */
7
+ /**
8
+ * Registry of supported language profiles used to identify, extract, and normalize
9
+ * dependency specifiers from source files.
10
+ *
11
+ * Each profile defines the file extensions it applies to, the regex patterns to match
12
+ * import/export specifiers, and an optional custom normalization function.
13
+ */
1
14
  export const LANGUAGE_PROFILES = [
2
15
  {
16
+ /**
17
+ * JavaScript and TypeScript family profiles.
18
+ * Covers:
19
+ * - ES module static imports (e.g., `import x from 'y'`)
20
+ * - Dynamic imports (e.g., `import('y')`)
21
+ * - CommonJS require calls (e.g., `require('y')`)
22
+ * - ES module re-exports (e.g., `export * from 'y'`)
23
+ */
3
24
  extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts'],
4
25
  patterns: [
26
+ // Static ESM imports: matches `import ... from 'specifier'` or `import 'specifier'`
5
27
  /import\s+(?:[\s\S]*?\s+from\s+)?['"](?<specifier>[^'"]+)['"]/gm,
28
+ // Dynamic ESM imports: matches `import('specifier')`
6
29
  /import\s*\(\s*['"](?<specifier>[^'"]+)['"]\s*\)/gm,
30
+ // CommonJS imports: matches `require('specifier')`
7
31
  /require\s*\(\s*['"](?<specifier>[^'"]+)['"]\s*\)/gm,
32
+ // ESM re-exports: matches `export ... from 'specifier'`
8
33
  /export\s+(?:[\s\S]*?\s+from\s+)['"](?<specifier>[^'"]+)['"]/gm,
9
34
  ],
10
35
  },
11
36
  {
37
+ /**
38
+ * Python profile.
39
+ * Covers:
40
+ * - `from module import name`
41
+ * - `import module`
42
+ */
12
43
  extensions: ['.py'],
13
44
  patterns: [
45
+ // Matches `from module import name`
14
46
  /^from\s+(?<specifier>[^\s]+)\s+import\s/gm,
47
+ // Matches `import module` (ignoring any subsequent `from` clauses)
15
48
  /^import\s+(?!.*\sfrom\s)(?<specifier>[^\s,]+)/gm,
16
49
  ],
50
+ /**
51
+ * Normalizes a Python module specifier into its relative or absolute file path.
52
+ * Converts dotted imports (e.g., `foo.bar`) to forward slashes (e.g., `foo/bar.py`).
53
+ * Properly resolves relative import dots:
54
+ * - Single dot `.foo` -> `./foo.py`
55
+ * - Double dots `..foo` -> `../foo.py`
56
+ *
57
+ * @param spec - The raw Python module import specifier.
58
+ * @returns The normalized filepath specifier with a `.py` extension.
59
+ */
17
60
  normalizeSpecifier: (spec) => {
18
61
  if (spec.startsWith('.')) {
19
62
  const dots = spec.match(/^\.+/)[0];
@@ -25,11 +68,28 @@ export const LANGUAGE_PROFILES = [
25
68
  },
26
69
  },
27
70
  {
71
+ /**
72
+ * Rust profile.
73
+ * Covers:
74
+ * - `use path::to::module;`
75
+ * - `mod module_name;`
76
+ */
28
77
  extensions: ['.rs'],
29
78
  patterns: [
79
+ // Matches `use path::to::item;` beginning with crate, self, or super
30
80
  /use\s+(?<specifier>(?:crate|self|super)(?:::[a-zA-Z_][a-zA-Z0-9_]*)+)/gm,
81
+ // Matches sub-module declarations: `mod module_name;`
31
82
  /mod\s+(?<specifier>[a-zA-Z_][a-zA-Z0-9_]*)\s*;/gm,
32
83
  ],
84
+ /**
85
+ * Normalizes a Rust module path/specifier into its filesystem equivalent.
86
+ * Converts Rust path double-colons (e.g., `crate::foo::bar`) to forward slashes (e.g., `foo/bar.rs`).
87
+ * Handles path prefixes (`crate::`, `self::`, `super::`) accordingly.
88
+ *
89
+ * @param spec - The raw Rust path or sub-module name.
90
+ * @param sourceFile - The source file containing the specifier (unused here but required by the interface).
91
+ * @returns The normalized module path with a `.rs` extension.
92
+ */
33
93
  normalizeSpecifier: (spec, sourceFile) => {
34
94
  if (!spec.includes('::')) {
35
95
  return spec + '.rs';
@@ -40,5 +100,5 @@ export const LANGUAGE_PROFILES = [
40
100
  .split('::');
41
101
  return parts.join('/') + '.rs';
42
102
  },
43
- }
103
+ },
44
104
  ];
@@ -65,5 +65,5 @@
65
65
  ]
66
66
  }
67
67
  },
68
- "version": "2.1.6"
68
+ "version": "2.1.7"
69
69
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "minovative-mind-cli",
3
3
  "description": "An automated AI agent powered by Vertex AI that helps you write software",
4
- "version": "2.1.6",
4
+ "version": "2.1.7",
5
5
  "author": "Daniel Ward",
6
6
  "bin": {
7
7
  "minovative-mind-cli": "bin/run.js"