minovative-mind-cli 1.5.0 → 2.0.0
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 +51 -45
- package/dist/commands/chat.js +10 -5
- package/dist/services/agent/slashCommands.js +163 -37
- package/dist/services/agent/toolLoop.d.ts +1 -1
- package/dist/services/agent/toolLoop.js +7 -2
- package/dist/services/agent/types.d.ts +2 -0
- package/dist/services/agent-tools.d.ts +9 -4
- package/dist/services/agent-tools.js +145 -21
- package/dist/services/agent.d.ts +8 -0
- package/dist/services/agent.js +294 -38
- package/dist/services/ai.d.ts +19 -5
- package/dist/services/ai.js +167 -35
- package/dist/services/changeLogger.d.ts +142 -0
- package/dist/services/changeLogger.js +132 -3
- package/dist/services/contextAgent.d.ts +6 -1
- package/dist/services/contextAgent.js +95 -14
- package/dist/services/embeddingIndex.d.ts +82 -0
- package/dist/services/embeddingIndex.js +613 -0
- package/dist/services/investigationComplexity.d.ts +45 -0
- package/dist/services/investigationComplexity.js +91 -0
- package/dist/services/metrics.d.ts +18 -0
- package/dist/services/metrics.js +7 -0
- package/dist/services/orchestration/fileLockRegistry.d.ts +125 -0
- package/dist/services/orchestration/fileLockRegistry.js +276 -0
- package/dist/services/orchestration/investigationAgent.d.ts +85 -0
- package/dist/services/orchestration/investigationAgent.js +359 -0
- package/dist/services/orchestration/investigationOrchestrator.d.ts +53 -0
- package/dist/services/orchestration/investigationOrchestrator.js +180 -0
- package/dist/services/orchestration/messageBus.d.ts +162 -0
- package/dist/services/orchestration/messageBus.js +225 -0
- package/dist/services/orchestration/orchestrator.d.ts +45 -0
- package/dist/services/orchestration/orchestrator.js +214 -0
- package/dist/services/orchestration/readCache.d.ts +79 -0
- package/dist/services/orchestration/readCache.js +108 -0
- package/dist/services/orchestration/scopedTools.d.ts +57 -0
- package/dist/services/orchestration/scopedTools.js +172 -0
- package/dist/services/orchestration/subAgent.d.ts +58 -0
- package/dist/services/orchestration/subAgent.js +187 -0
- package/dist/services/orchestration/taskGraph.d.ts +129 -0
- package/dist/services/orchestration/taskGraph.js +254 -0
- package/dist/services/proxyClient.d.ts +25 -0
- package/dist/services/proxyClient.js +60 -0
- package/dist/utils/asyncContext.d.ts +16 -0
- package/dist/utils/asyncContext.js +25 -0
- package/dist/utils/config.d.ts +3 -1
- package/dist/utils/config.js +3 -1
- package/dist/utils/contextPrompts.js +3 -2
- package/dist/utils/dependencyTracer/modules/api.d.ts +9 -0
- package/dist/utils/dependencyTracer/modules/api.js +62 -0
- package/dist/utils/dependencyTracer/modules/graph.d.ts +9 -0
- package/dist/utils/dependencyTracer/modules/graph.js +23 -0
- package/dist/utils/dependencyTracer/modules/profiles.d.ts +7 -0
- package/dist/utils/dependencyTracer/modules/profiles.js +120 -0
- package/dist/utils/dependencyTracer/modules/resolver.d.ts +7 -0
- package/dist/utils/dependencyTracer/modules/resolver.js +51 -0
- package/dist/utils/dependencyTracer/modules/types.d.ts +4 -0
- package/dist/utils/dependencyTracer/modules/types.js +1 -0
- package/dist/utils/dependencyTracer/modules/walker.d.ts +1 -0
- package/dist/utils/dependencyTracer/modules/walker.js +48 -0
- package/dist/utils/dependencyTracer.js +31 -17
- package/dist/utils/excludedExtensions.js +0 -1
- package/dist/utils/historyPrompt.d.ts +9 -0
- package/dist/utils/historyPrompt.js +87 -0
- package/dist/utils/logo.d.ts +2 -0
- package/dist/utils/logo.js +31 -10
- package/dist/utils/paste.d.ts +21 -0
- package/dist/utils/paste.js +22 -1
- package/dist/utils/profiles.d.ts +2 -0
- package/dist/utils/profiles.js +44 -0
- package/dist/utils/projectStorage.js +10 -7
- package/dist/utils/systemPrompts.d.ts +6 -3
- package/dist/utils/systemPrompts.js +106 -5
- package/dist/utils/types.d.ts +33 -0
- package/dist/utils/types.js +1 -0
- package/oclif.manifest.json +2 -2
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -16,39 +16,8 @@ the build/performance metrics are green.
|
|
|
16
16
|
[](https://npmjs.org/package/minovative-mind-cli)
|
|
17
17
|
[](https://npmjs.org/package/minovative-mind-cli)
|
|
18
18
|
|
|
19
|
-
- Official Website: [
|
|
20
|
-
- Latest Updates: [
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## How it works
|
|
25
|
-
|
|
26
|
-
- Standard AI coding agents: big model + noisy context = expensive and redundant mistakes
|
|
27
|
-
- Minovative Mind CLI: flash models + precise context + verified output = better and cheaper results.
|
|
28
|
-
|
|
29
|
-
### The PCV engine runs in three stages before returning a single line of code:
|
|
30
|
-
|
|
31
|
-
**1. Investigate**
|
|
32
|
-
|
|
33
|
-
- **Maps your project:** Traces import dependencies and identifies recently modified files to understand your focus.
|
|
34
|
-
- **Researches context:** Gathers external web documentation and completes background research before touching any code.
|
|
35
|
-
|
|
36
|
-
**2. Execute with precision**
|
|
37
|
-
|
|
38
|
-
- **Surgical snapshots:** Feeds the agent a compressed, relevant slice of code instead of dumping the entire codebase.
|
|
39
|
-
- **Higher success rates:** Delivers 40–50% fewer broken generations on large files compared to standard zero-shot prompts.
|
|
40
|
-
|
|
41
|
-
**3. Verify and self-correct**
|
|
42
|
-
|
|
43
|
-
- **Runs native builds & audits:** Automatically executes your actual build commands (`npm run build`, `cargo check`, etc.) and scans for performance flaws on modified files only.
|
|
44
|
-
- **Autonomously debugs:** Reads the exact compiler output and fixes its own errors across up to 5 hands-free correction cycles.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## See it in action
|
|
49
|
-
|
|
50
|
-
- [AI builds a Python Generative Art Engine in one prompt](https://www.youtube.com/watch?v=dy3qNbETqfs)
|
|
51
|
-
- [AI builds a Quiz Game from scratch](https://www.youtube.com/watch?v=KjE5nbKEf3w)
|
|
19
|
+
- Official Website: [Main Website](https://www.minovativemind.dev/)
|
|
20
|
+
- Latest Updates: [Updates](https://www.minovativemind.dev/updates)
|
|
52
21
|
|
|
53
22
|
---
|
|
54
23
|
|
|
@@ -79,9 +48,40 @@ Works in any terminal — SSH, Docker, CI pipelines, Vim, Windows Command Prompt
|
|
|
79
48
|
|
|
80
49
|
---
|
|
81
50
|
|
|
51
|
+
## See it in action
|
|
52
|
+
|
|
53
|
+
- [AI builds a Python Generative Art Engine in one prompt](https://www.youtube.com/watch?v=dy3qNbETqfs)
|
|
54
|
+
- [AI builds a Quiz Game from scratch](https://www.youtube.com/watch?v=KjE5nbKEf3w)
|
|
55
|
+
|
|
56
|
+
### 🏆 Benchmark Tests
|
|
57
|
+
|
|
58
|
+
**All-Your-Base (C++ Track)**
|
|
59
|
+
|
|
60
|
+
- **Difficulty:** Hard | **Time:** 3.5 minutes
|
|
61
|
+
- **Result:** 🟢 PASSED (17/17 assertions)
|
|
62
|
+
- Successfully deduced the O(N+M) conversion algorithm.
|
|
63
|
+
- Properly handled complex edge cases for zero-equivalents (returning an empty vector).
|
|
64
|
+
- Encountered a compilation error due to missing C++ standard library paths on macOS.
|
|
65
|
+
- Autonomously self-corrected by querying the environment, locating the sysroot, and updating clang++ flags.
|
|
66
|
+
- Flawlessly passed the test suite, handling the problem and edge cases on the first try.
|
|
67
|
+
- [All-Your-Base Summary](https://github.com/Quarantiine/polyglot-benchmark-mmcli/blob/main/cpp/exercises/practice/all-your-base/minovative-tries/attempt_1.md)
|
|
68
|
+
|
|
69
|
+
**Alphametics (Go Track)**
|
|
70
|
+
|
|
71
|
+
- **Difficulty:** Extreme | **Time:** 5.2 minutes
|
|
72
|
+
- **Result:** 🟢 PASSED
|
|
73
|
+
- Solved one of the hardest logic puzzles on the platform by engineering a mathematically rigorous pruning algorithm based on the Rearrangement Inequality.
|
|
74
|
+
- Completely bypassed naive backtracking (10! permutations).
|
|
75
|
+
- Achieved sub-millisecond execution speeds (~140 microseconds) with zero heap allocations during recursion.
|
|
76
|
+
- Autonomously navigated the Go toolchain (\`go test -bench=.\`).
|
|
77
|
+
- Parsed its own architectural performance warnings to optimize the solution.
|
|
78
|
+
- [Alphametics Summary](https://github.com/Quarantiine/polyglot-benchmark-mmcli/blob/main/go/exercises/practice/alphametics/minovative-tries/attempt_1.md)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
82
|
## Models
|
|
83
83
|
|
|
84
|
-
Hot-swap during a session
|
|
84
|
+
Hot-swap during a session using `/models`:
|
|
85
85
|
|
|
86
86
|
| Model | Best for |
|
|
87
87
|
| ------------------------------ | ----------------------------------- |
|
|
@@ -99,22 +99,28 @@ Hot-swap during a session with `/models`:
|
|
|
99
99
|
|
|
100
100
|
## Session Commands
|
|
101
101
|
|
|
102
|
-
| Command | What it does
|
|
103
|
-
| --------------- |
|
|
104
|
-
| `/models` | Hot-swap the active model
|
|
105
|
-
| `/
|
|
106
|
-
| `/
|
|
107
|
-
| `/
|
|
108
|
-
| `/
|
|
109
|
-
| `/
|
|
110
|
-
| `/
|
|
111
|
-
| `
|
|
102
|
+
| Command | What it does |
|
|
103
|
+
| --------------- | ---------------------------------------------------------------- |
|
|
104
|
+
| `/models` | Hot-swap the active model |
|
|
105
|
+
| `/plan` | Toggle plan mode to review implementation strategies |
|
|
106
|
+
| `/paste` | Multi-line input mode (cancel with Ctrl+C) |
|
|
107
|
+
| `/clear` | Clear conversation history |
|
|
108
|
+
| `/debug` | Expose internal agent diagnostics |
|
|
109
|
+
| `/auto-approve` | Toggle skipping confirmation prompts for commands |
|
|
110
|
+
| `/sub-agents` | Toggle the MMAAK Engine for parallel investigation and execution |
|
|
111
|
+
| `/stats` | View current session statistics and configuration |
|
|
112
|
+
| `/commit` | Generate a conventional commit message from your diff |
|
|
113
|
+
| `/revert` | Undo changes from the last turn, or toggle the revert logger |
|
|
114
|
+
| `/chats` | View, resume, or delete previous chat sessions |
|
|
115
|
+
| `stop` | Abort generation immediately |
|
|
112
116
|
|
|
113
117
|
---
|
|
114
118
|
|
|
115
119
|
## 🌐 Supported Languages
|
|
116
120
|
|
|
117
|
-
Minovative Mind CLI
|
|
121
|
+
Minovative Mind CLI fundamentally supports **ALL programming languages** for chat, code generation, planning, and execution, as it relies on Gemini's vast training data.
|
|
122
|
+
|
|
123
|
+
However, the PCV engine features deep, context-aware analysis across **11 major programming language families**. Our core advanced engines—**Smart Dependency Tracing**, **Performance Auditing**, and **Ephemeral Analysis Scripts**—provide tailored support depending on the language's syntax and runtime model:
|
|
118
124
|
|
|
119
125
|
| Language Family | Supported Extensions | Dependency Tracing | Performance Auditing | Ephemeral Analysis |
|
|
120
126
|
| :--------------------------- | :------------------------------------------- | :----------------: | :------------------: | :----------------: |
|
package/dist/commands/chat.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as p from '@clack/prompts';
|
|
|
6
6
|
import pc from 'picocolors';
|
|
7
7
|
import { startAgentLoop } from '../services/agent.js';
|
|
8
8
|
import { getAuthorizedIdToken, login } from '../services/auth.js';
|
|
9
|
-
import { printLogo } from '../utils/logo.js';
|
|
9
|
+
import { printLogo, brandBg, brandFg } from '../utils/logo.js';
|
|
10
10
|
import { updateWorkspaceStatus } from '../services/workspace.js';
|
|
11
11
|
/**
|
|
12
12
|
* @class DefaultCommand
|
|
@@ -23,13 +23,18 @@ export default class DefaultCommand extends Command {
|
|
|
23
23
|
|
|
24
24
|
Inside the chat session, you can use the following commands in the slash menu:
|
|
25
25
|
/models - Select the active model
|
|
26
|
+
/plan - Toggle plan mode to review implementation strategies
|
|
26
27
|
/paste - Enter multi-line paste mode for long snippets
|
|
27
28
|
/clear - Clear conversation history
|
|
28
29
|
/debug - Debug tests or command execution in a sandbox loop
|
|
29
30
|
/auto-approve - Toggle automatic approval of tool/command runs
|
|
30
|
-
/
|
|
31
|
+
/sub-agents - Toggle the MMAAK Engine for parallel investigation and execution
|
|
32
|
+
/semantic-search - Toggle local vector index capabilities
|
|
33
|
+
/stats - View current session statistics and configuration
|
|
31
34
|
/commit - Commit current workspace changes to Git
|
|
32
|
-
|
|
35
|
+
/revert - Revert the last file modification made by the agent
|
|
36
|
+
/chats - View, resume, or delete previous chat sessions
|
|
37
|
+
|
|
33
38
|
Chat Controls:
|
|
34
39
|
- Multi-line Input: End a line with \\ to continue on the next line
|
|
35
40
|
- Stop/Abort: Type "stop" to immediately interrupt agent generation
|
|
@@ -52,7 +57,7 @@ Chat Controls:
|
|
|
52
57
|
const pkg = JSON.parse(await fs.promises.readFile(new URL('../../package.json', import.meta.url), 'utf8'));
|
|
53
58
|
updateNotifier({ pkg }).notify();
|
|
54
59
|
printLogo();
|
|
55
|
-
p.intro(`${
|
|
60
|
+
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + this.config.version)}`);
|
|
56
61
|
// Check authentication
|
|
57
62
|
let idToken = await getAuthorizedIdToken();
|
|
58
63
|
if (!idToken) {
|
|
@@ -65,7 +70,7 @@ Chat Controls:
|
|
|
65
70
|
// Re-fetch token after successful login
|
|
66
71
|
idToken = await getAuthorizedIdToken();
|
|
67
72
|
}
|
|
68
|
-
p.log.info(`${pc.dim('Workspace:')} ${
|
|
73
|
+
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
69
74
|
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.`);
|
|
70
75
|
// Update workspace status in the background
|
|
71
76
|
if (idToken) {
|
|
@@ -4,13 +4,14 @@ import { promises as fs } from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { exec } from 'node:child_process';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
|
-
import
|
|
7
|
+
import crypto from 'node:crypto';
|
|
8
|
+
import { toggleDebugMode, isDebugOn } from '../../utils/logger.js';
|
|
8
9
|
import { changeLogger } from '../changeLogger.js';
|
|
9
10
|
import { chatHistoryService } from '../chatHistoryService.js';
|
|
10
|
-
import { printLogo } from '../../utils/logo.js';
|
|
11
|
+
import { printLogo, brandBg, brandFg } from '../../utils/logo.js';
|
|
11
12
|
import { readPaste } from '../../utils/paste.js';
|
|
12
|
-
import { setApprovalMode, getApprovalMode } from '../agent-tools.js';
|
|
13
|
-
import { ProxyChatSession } from '../ai.js';
|
|
13
|
+
import { setApprovalMode, getApprovalMode, isSubAgentsEnabled, setSubAgentsEnabled, isSemanticSearchEnabled, setSemanticSearchEnabled, } from '../agent-tools.js';
|
|
14
|
+
import { ProxyChatSession, setGlobalActiveModel, getGlobalActiveModel, getGlobalLatestUsageMetadata } from '../ai.js';
|
|
14
15
|
const execAsync = promisify(exec);
|
|
15
16
|
/**
|
|
16
17
|
* Handles all slash command operations (/paste, /clear, /models, /debug, /auto-approve, /revert, /commit).
|
|
@@ -39,12 +40,22 @@ export async function handleSlashCommand(command, context) {
|
|
|
39
40
|
return { shouldContinue: true, isRawPasteMode: false };
|
|
40
41
|
}
|
|
41
42
|
}
|
|
43
|
+
if (lowerCommand === '/plan') {
|
|
44
|
+
const newPlanMode = !context.isPlanMode;
|
|
45
|
+
if (newPlanMode) {
|
|
46
|
+
p.log.info(pc.cyan('Plan mode enabled. The AI will formulate a step-by-step plan instead of executing code. Type /plan again to exit.'));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
p.log.info(pc.cyan('Plan mode disabled. Returning to normal execution.'));
|
|
50
|
+
}
|
|
51
|
+
return { shouldContinue: true, isPlanModeOverride: newPlanMode };
|
|
52
|
+
}
|
|
42
53
|
if (lowerCommand === '/clear') {
|
|
43
54
|
chat.clearHistory();
|
|
44
55
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
45
56
|
printLogo();
|
|
46
|
-
p.intro(`${
|
|
47
|
-
p.log.info(`${pc.dim('Workspace:')} ${
|
|
57
|
+
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
58
|
+
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
48
59
|
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.`);
|
|
49
60
|
p.log.success('Chat history cleared.');
|
|
50
61
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
@@ -71,10 +82,16 @@ export async function handleSlashCommand(command, context) {
|
|
|
71
82
|
label: 'Gemini 3.1 Flash-Lite',
|
|
72
83
|
hint: 'Ultra-fast and cost-effective',
|
|
73
84
|
},
|
|
85
|
+
{
|
|
86
|
+
value: 'auto',
|
|
87
|
+
label: 'Auto (Flash-Lite / Flash 3.5)',
|
|
88
|
+
hint: 'Dynamically routes between Flash-Lite and Flash 3.5 based on prompt complexity',
|
|
89
|
+
},
|
|
74
90
|
],
|
|
75
91
|
});
|
|
76
92
|
if (!p.isCancel(selectedModel)) {
|
|
77
93
|
chat.setModel(selectedModel);
|
|
94
|
+
setGlobalActiveModel(selectedModel);
|
|
78
95
|
p.log.success(`Model successfully switched to ${pc.cyan(selectedModel)}`);
|
|
79
96
|
}
|
|
80
97
|
return { shouldContinue: true };
|
|
@@ -100,32 +117,121 @@ export async function handleSlashCommand(command, context) {
|
|
|
100
117
|
}
|
|
101
118
|
return { shouldContinue: true };
|
|
102
119
|
}
|
|
120
|
+
if (lowerCommand === '/sub-agents') {
|
|
121
|
+
if (isSubAgentsEnabled()) {
|
|
122
|
+
setSubAgentsEnabled(false);
|
|
123
|
+
p.log.success('MMAAK Engine disabled. Single-agent mode active.');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
setSubAgentsEnabled(true);
|
|
127
|
+
p.log.success('MMAAK Engine enabled. The system will now use parallel investigation and thread agents.');
|
|
128
|
+
}
|
|
129
|
+
return { shouldContinue: true };
|
|
130
|
+
}
|
|
131
|
+
if (lowerCommand === '/semantic-search') {
|
|
132
|
+
if (isSemanticSearchEnabled()) {
|
|
133
|
+
setSemanticSearchEnabled(false);
|
|
134
|
+
p.log.success('Semantic search disabled. The vector indexing layer is now turned off.');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
setSemanticSearchEnabled(true);
|
|
138
|
+
p.log.success('Semantic search enabled. The AST-aware vector index is active.');
|
|
139
|
+
}
|
|
140
|
+
return { shouldContinue: true };
|
|
141
|
+
}
|
|
142
|
+
if (lowerCommand === '/stats') {
|
|
143
|
+
const latestUsage = getGlobalLatestUsageMetadata();
|
|
144
|
+
const currentModel = chat.getModel();
|
|
145
|
+
const globalModel = getGlobalActiveModel();
|
|
146
|
+
const displayModel = globalModel === 'auto' ? `Auto (Last turn: ${currentModel})` : currentModel;
|
|
147
|
+
const autoApprove = getApprovalMode() === 'skip-all' ? 'Enabled' : 'Disabled';
|
|
148
|
+
const subAgents = isSubAgentsEnabled() ? 'Enabled' : 'Disabled';
|
|
149
|
+
const semanticSearch = isSemanticSearchEnabled() ? 'Enabled' : 'Disabled';
|
|
150
|
+
const planMode = context.isPlanMode ? 'Enabled' : 'Disabled';
|
|
151
|
+
p.log.step(pc.magenta('📊 Session Statistics & Status'));
|
|
152
|
+
console.log(pc.dim('----------------------------------------'));
|
|
153
|
+
console.log(`${pc.bold('AI Model:')} ${pc.cyan(displayModel)}`);
|
|
154
|
+
console.log(`${pc.bold('Auto-Approve:')} ${autoApprove === 'Enabled' ? pc.green(autoApprove) : pc.yellow(autoApprove)}`);
|
|
155
|
+
console.log(`${pc.bold('Sub-Agents:')} ${subAgents === 'Enabled' ? pc.green(subAgents) : pc.yellow(subAgents)}`);
|
|
156
|
+
console.log(`${pc.bold('Semantic Search:')} ${semanticSearch === 'Enabled' ? pc.green(semanticSearch) : pc.yellow(semanticSearch)}`);
|
|
157
|
+
console.log(`${pc.bold('Plan Mode:')} ${planMode === 'Enabled' ? pc.green(planMode) : pc.yellow(planMode)}`);
|
|
158
|
+
const debugMode = isDebugOn() ? 'Enabled' : 'Disabled';
|
|
159
|
+
console.log(`${pc.bold('Debug Log:')} ${debugMode === 'Enabled' ? pc.green(debugMode) : pc.yellow(debugMode)}`);
|
|
160
|
+
if (latestUsage) {
|
|
161
|
+
if (latestUsage.remainingBalance !== undefined) {
|
|
162
|
+
let diffStr = '';
|
|
163
|
+
if (latestUsage.creditsUsed !== undefined) {
|
|
164
|
+
const before = latestUsage.remainingBalance + latestUsage.creditsUsed;
|
|
165
|
+
console.log(`${pc.bold('Credits Before:')} ${pc.cyan(before.toLocaleString())}`);
|
|
166
|
+
const diff = -latestUsage.creditsUsed;
|
|
167
|
+
if (diff < 0) {
|
|
168
|
+
diffStr = ` ${pc.red(`(${diff})`)}`;
|
|
169
|
+
}
|
|
170
|
+
else if (diff > 0) {
|
|
171
|
+
diffStr = ` ${pc.green(`(+${diff})`)}`;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
diffStr = ` ${pc.dim(`(0)`)}`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
console.log(`${pc.bold('Credits Left:')} ${pc.cyan(latestUsage.remainingBalance.toLocaleString())}${diffStr}`);
|
|
178
|
+
}
|
|
179
|
+
const totalInputTokens = (latestUsage.promptTokens || 0) + (latestUsage.cachedTokens || 0);
|
|
180
|
+
if (totalInputTokens > 0) {
|
|
181
|
+
console.log(`${pc.bold('Last Turn Input:')} ${totalInputTokens.toLocaleString()} tokens`);
|
|
182
|
+
}
|
|
183
|
+
if (latestUsage.candidatesTokens) {
|
|
184
|
+
console.log(`${pc.bold('Last Turn Output:')} ${latestUsage.candidatesTokens.toLocaleString()} tokens`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
console.log(`${pc.bold('Token Usage:')} No data available yet.`);
|
|
189
|
+
}
|
|
190
|
+
console.log(pc.dim('----------------------------------------\n'));
|
|
191
|
+
return { shouldContinue: true };
|
|
192
|
+
}
|
|
103
193
|
if (lowerCommand === '/revert') {
|
|
194
|
+
const isEnabled = changeLogger.getIsEnabled();
|
|
104
195
|
const history = changeLogger.getHistory();
|
|
105
|
-
if (!history || history.length === 0) {
|
|
106
|
-
p.log.warn('No changes to revert.');
|
|
107
|
-
return { shouldContinue: true };
|
|
108
|
-
}
|
|
109
|
-
const lastChangeSet = history[history.length - 1];
|
|
110
196
|
const truncate = (str, max) => {
|
|
111
197
|
const singleLine = str.replace(/\s+/g, ' ').trim();
|
|
112
198
|
return singleLine.length > max ? singleLine.substring(0, max - 3) + '...' : singleLine;
|
|
113
199
|
};
|
|
200
|
+
let lastChangeSet = null;
|
|
201
|
+
const options = [];
|
|
202
|
+
if (isEnabled && history && history.length > 0) {
|
|
203
|
+
lastChangeSet = history[history.length - 1];
|
|
204
|
+
options.push({
|
|
205
|
+
value: 'revert_last',
|
|
206
|
+
label: `Revert last change (${truncate(lastChangeSet.description, 50)})${lastChangeSet.status === 'partial' ? ' [Partial]' : ''}`,
|
|
207
|
+
});
|
|
208
|
+
options.push({ value: 'view_history', label: 'View history' });
|
|
209
|
+
}
|
|
210
|
+
if (isEnabled) {
|
|
211
|
+
options.push({ value: 'disable_revert', label: 'Disable' });
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
options.push({ value: 'enable_revert', label: 'Enable' });
|
|
215
|
+
}
|
|
216
|
+
options.push({ value: 'cancel', label: 'Cancel' });
|
|
114
217
|
const revertMenu = await p['select']({
|
|
115
|
-
message: 'Revert Menu',
|
|
116
|
-
options
|
|
117
|
-
{
|
|
118
|
-
value: 'revert_last',
|
|
119
|
-
label: `Revert last change (${truncate(lastChangeSet.description, 50)})${lastChangeSet.status === 'partial' ? ' [Partial]' : ''}`,
|
|
120
|
-
},
|
|
121
|
-
{ value: 'view_history', label: 'View history' },
|
|
122
|
-
{ value: 'cancel', label: 'Cancel' },
|
|
123
|
-
],
|
|
218
|
+
message: isEnabled && history.length === 0 ? 'Revert Menu (No changes to revert)' : 'Revert Menu',
|
|
219
|
+
options,
|
|
124
220
|
});
|
|
125
221
|
if (p.isCancel(revertMenu) || revertMenu === 'cancel') {
|
|
126
222
|
return { shouldContinue: true };
|
|
127
223
|
}
|
|
128
|
-
|
|
224
|
+
if (revertMenu === 'disable_revert') {
|
|
225
|
+
changeLogger.setIsEnabled(false);
|
|
226
|
+
p.log.success('Revert command has been disabled. File modifications will no longer be tracked.');
|
|
227
|
+
return { shouldContinue: true };
|
|
228
|
+
}
|
|
229
|
+
if (revertMenu === 'enable_revert') {
|
|
230
|
+
changeLogger.setIsEnabled(true);
|
|
231
|
+
p.log.success('Revert command has been enabled. Future file modifications will be tracked.');
|
|
232
|
+
return { shouldContinue: true };
|
|
233
|
+
}
|
|
234
|
+
let targetTimestamp = lastChangeSet ? lastChangeSet.timestamp : null;
|
|
129
235
|
if (revertMenu === 'view_history') {
|
|
130
236
|
const historyOptions = history
|
|
131
237
|
.slice()
|
|
@@ -168,26 +274,40 @@ export async function handleSlashCommand(command, context) {
|
|
|
168
274
|
return { shouldContinue: true };
|
|
169
275
|
}
|
|
170
276
|
if (lowerCommand === '/chats') {
|
|
171
|
-
const sessions = chatHistoryService.getSessions();
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
277
|
+
const sessions = chatHistoryService.getSessions() || [];
|
|
278
|
+
const hasSessions = sessions.length > 0;
|
|
279
|
+
const options = [{ value: 'new', label: 'New Chat' }];
|
|
280
|
+
if (hasSessions) {
|
|
281
|
+
options.push({ value: 'resume', label: 'View Chats' });
|
|
282
|
+
options.push({ value: 'delete', label: 'Delete Chat' });
|
|
175
283
|
}
|
|
284
|
+
options.push({ value: 'cancel', label: 'Cancel' });
|
|
176
285
|
const truncate = (str, max) => {
|
|
177
286
|
const singleLine = str.replace(/\s+/g, ' ').trim();
|
|
178
287
|
return singleLine.length > max ? singleLine.substring(0, max - 3) + '...' : singleLine;
|
|
179
288
|
};
|
|
180
289
|
const chatsMenu = await p['select']({
|
|
181
290
|
message: 'Chat Sessions',
|
|
182
|
-
options
|
|
183
|
-
{ value: 'resume', label: 'Resume another chat' },
|
|
184
|
-
{ value: 'delete', label: 'Delete a past chat' },
|
|
185
|
-
{ value: 'cancel', label: 'Cancel' },
|
|
186
|
-
],
|
|
291
|
+
options,
|
|
187
292
|
});
|
|
188
293
|
if (p.isCancel(chatsMenu) || chatsMenu === 'cancel') {
|
|
189
294
|
return { shouldContinue: true };
|
|
190
295
|
}
|
|
296
|
+
if (chatsMenu === 'new') {
|
|
297
|
+
chat.clearHistory();
|
|
298
|
+
if (chatSessionState) {
|
|
299
|
+
chatSessionState.id = crypto.randomUUID();
|
|
300
|
+
chatSessionState.title = '';
|
|
301
|
+
}
|
|
302
|
+
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
303
|
+
printLogo();
|
|
304
|
+
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
305
|
+
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
306
|
+
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.`);
|
|
307
|
+
p.log.success('Started a new chat session.');
|
|
308
|
+
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
309
|
+
return { shouldContinue: true };
|
|
310
|
+
}
|
|
191
311
|
const sessionOptions = sessions
|
|
192
312
|
.slice()
|
|
193
313
|
.reverse()
|
|
@@ -212,20 +332,26 @@ export async function handleSlashCommand(command, context) {
|
|
|
212
332
|
}
|
|
213
333
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
214
334
|
printLogo();
|
|
215
|
-
p.intro(`${
|
|
216
|
-
p.log.info(`${pc.dim('Workspace:')} ${
|
|
335
|
+
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
336
|
+
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
217
337
|
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.`);
|
|
218
338
|
p.log.success(`Resumed session: ${session.title}`);
|
|
219
339
|
// Print the loaded history so the user can see past context
|
|
220
340
|
for (const item of session.history) {
|
|
221
341
|
if (item.role === 'user') {
|
|
222
|
-
const text = item.parts
|
|
342
|
+
const text = item.parts
|
|
343
|
+
.map((p) => p.text)
|
|
344
|
+
.filter(Boolean)
|
|
345
|
+
.join('');
|
|
223
346
|
if (text) {
|
|
224
|
-
p.log.step(pc.
|
|
347
|
+
p.log.step(pc.bgBlue(pc.white(` ${text} `)));
|
|
225
348
|
}
|
|
226
349
|
}
|
|
227
350
|
else if (item.role === 'model') {
|
|
228
|
-
const text = item.parts
|
|
351
|
+
const text = item.parts
|
|
352
|
+
.map((p) => p.text)
|
|
353
|
+
.filter(Boolean)
|
|
354
|
+
.join('');
|
|
229
355
|
if (text) {
|
|
230
356
|
console.log(`\n${pc.blue('◆')} ${pc.bold('Minovative Mind')} ${pc.dim('(Resumed)')}\n`);
|
|
231
357
|
const { marked } = await import('marked');
|
|
@@ -251,8 +377,8 @@ export async function handleSlashCommand(command, context) {
|
|
|
251
377
|
chat.clearHistory();
|
|
252
378
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
253
379
|
printLogo();
|
|
254
|
-
p.intro(`${
|
|
255
|
-
p.log.info(`${pc.dim('Workspace:')} ${
|
|
380
|
+
p.intro(`${brandBg(' Minovative Mind CLI ')} ${pc.dim('v' + version)}`);
|
|
381
|
+
p.log.info(`${pc.dim('Workspace:')} ${brandFg(workspaceRoot)}`);
|
|
256
382
|
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.`);
|
|
257
383
|
p.log.warn('Active session was deleted. Chat history cleared.');
|
|
258
384
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
@@ -25,7 +25,7 @@ export declare function formatToolCall(name: string, args: Record<string, unknow
|
|
|
25
25
|
* 6. **Submit Loop Frame**: Feeds execution outcomes back to the Gemini session and recursively repeats this sequence until the LLM produces a final text answer without further tool requests.
|
|
26
26
|
*
|
|
27
27
|
* ### Limits & Recovery Guardrails:
|
|
28
|
-
* - **Turn-Limiting**: Capped at `MAX_TURNS` (
|
|
28
|
+
* - **Turn-Limiting**: Capped at `MAX_TURNS` (Infinity) to prevent infinite loops, API token drain, or excessive billing if the AI gets stuck in a repetitive loop.
|
|
29
29
|
* - **Empty-Response Healing**: If the API returns an empty text response with no tools, the system initiates up to `MAX_EMPTY_RETRIES` (3) system-driven wake-up prompts to re-engage the model.
|
|
30
30
|
*
|
|
31
31
|
* @param chat - The current active proxy chat session.
|
|
@@ -5,6 +5,7 @@ import { executeTool } from '../agent-tools.js';
|
|
|
5
5
|
import { getPlanExecutionConfig } from '../ai.js';
|
|
6
6
|
import { routeIntent } from '../contextAgent.js';
|
|
7
7
|
import { requestCommandApproval } from './commandApproval.js';
|
|
8
|
+
import { getMetricCollector } from '../metrics.js';
|
|
8
9
|
// ─── Constants ───────────────────────────────────────────────────────
|
|
9
10
|
/**
|
|
10
11
|
* Mapping of tool identifiers to user-friendly terminal emojis.
|
|
@@ -92,7 +93,7 @@ export function formatToolCall(name, args) {
|
|
|
92
93
|
* 6. **Submit Loop Frame**: Feeds execution outcomes back to the Gemini session and recursively repeats this sequence until the LLM produces a final text answer without further tool requests.
|
|
93
94
|
*
|
|
94
95
|
* ### Limits & Recovery Guardrails:
|
|
95
|
-
* - **Turn-Limiting**: Capped at `MAX_TURNS` (
|
|
96
|
+
* - **Turn-Limiting**: Capped at `MAX_TURNS` (Infinity) to prevent infinite loops, API token drain, or excessive billing if the AI gets stuck in a repetitive loop.
|
|
96
97
|
* - **Empty-Response Healing**: If the API returns an empty text response with no tools, the system initiates up to `MAX_EMPTY_RETRIES` (3) system-driven wake-up prompts to re-engage the model.
|
|
97
98
|
*
|
|
98
99
|
* @param chat - The current active proxy chat session.
|
|
@@ -107,7 +108,7 @@ export async function processResponse(chat, result, workspaceRoot, inputHandler,
|
|
|
107
108
|
let response = result.response;
|
|
108
109
|
// Upper limit on autonomous sequential tool executions to prevent out-of-control loops
|
|
109
110
|
let turnCount = 0;
|
|
110
|
-
const MAX_TURNS =
|
|
111
|
+
const MAX_TURNS = Infinity;
|
|
111
112
|
// Recovery thresholds for handling unexpected empty API payloads
|
|
112
113
|
let emptyRetryCount = 0;
|
|
113
114
|
const MAX_EMPTY_RETRIES = 3;
|
|
@@ -170,6 +171,9 @@ export async function processResponse(chat, result, workspaceRoot, inputHandler,
|
|
|
170
171
|
return finalOutput;
|
|
171
172
|
}
|
|
172
173
|
// Process each tool call requested by the model (using helper to avoid nested loop warning)
|
|
174
|
+
const collector = getMetricCollector();
|
|
175
|
+
if (collector)
|
|
176
|
+
collector.recordToolTurn();
|
|
173
177
|
const execRes = await executeToolCalls(functionCalls, workspaceRoot, inputHandler, abortSignal);
|
|
174
178
|
if (execRes.aborted) {
|
|
175
179
|
return '[Generation stopped by user]';
|
|
@@ -263,6 +267,7 @@ async function executeToolCalls(functionCalls, workspaceRoot, inputHandler, abor
|
|
|
263
267
|
response: {
|
|
264
268
|
output: toolResult.output,
|
|
265
269
|
...(toolResult.error ? { error: toolResult.error } : {}),
|
|
270
|
+
...(toolResult.inlineData ? { inlineData: toolResult.inlineData } : {}),
|
|
266
271
|
},
|
|
267
272
|
},
|
|
268
273
|
});
|
|
@@ -9,6 +9,7 @@ export interface SlashCommandContext {
|
|
|
9
9
|
workspaceRoot: string;
|
|
10
10
|
version: string;
|
|
11
11
|
isRawPasteMode: boolean;
|
|
12
|
+
isPlanMode: boolean;
|
|
12
13
|
chatSessionState: {
|
|
13
14
|
id: string;
|
|
14
15
|
title: string;
|
|
@@ -18,4 +19,5 @@ export interface SlashCommandResult {
|
|
|
18
19
|
shouldContinue: boolean;
|
|
19
20
|
userInputOverride?: string;
|
|
20
21
|
isRawPasteMode?: boolean;
|
|
22
|
+
isPlanModeOverride?: boolean;
|
|
21
23
|
}
|
|
@@ -2,7 +2,14 @@ import { type FunctionDeclaration } from '@google/generative-ai';
|
|
|
2
2
|
export interface ToolResult {
|
|
3
3
|
error?: string;
|
|
4
4
|
output: string;
|
|
5
|
+
inlineData?: {
|
|
6
|
+
mimeType: string;
|
|
7
|
+
data: string;
|
|
8
|
+
};
|
|
5
9
|
}
|
|
10
|
+
export declare function isSemanticSearchEnabled(): boolean;
|
|
11
|
+
export declare function setSemanticSearchEnabled(val: boolean): void;
|
|
12
|
+
export declare function getToolDeclarations(): FunctionDeclaration[];
|
|
6
13
|
/**
|
|
7
14
|
* FunctionDeclaration-compatible schema objects that describe
|
|
8
15
|
* every tool the agent can invoke. Passed to the model at init.
|
|
@@ -11,6 +18,8 @@ export declare const toolDeclarations: FunctionDeclaration[];
|
|
|
11
18
|
export type ApprovalMode = 'ask' | 'skip-once' | 'skip-all';
|
|
12
19
|
export declare function getApprovalMode(): ApprovalMode;
|
|
13
20
|
export declare function setApprovalMode(mode: ApprovalMode): void;
|
|
21
|
+
export declare function isSubAgentsEnabled(): boolean;
|
|
22
|
+
export declare function setSubAgentsEnabled(enabled: boolean): void;
|
|
14
23
|
/**
|
|
15
24
|
* If set to 'skip-once', reverts to 'ask' after a single command is run.
|
|
16
25
|
*/
|
|
@@ -29,8 +38,4 @@ export declare function grepSearch(workspaceRoot: string, pattern: string, fileG
|
|
|
29
38
|
export declare function traceDependencies(workspaceRoot: string, filePath: string, direction?: string, maxDepth?: number): Promise<ToolResult>;
|
|
30
39
|
export declare function findRecentChanges(workspaceRoot: string, dirPath?: string, minutes?: number, maxDepth?: number): Promise<ToolResult>;
|
|
31
40
|
export declare function runDebugScript(workspaceRoot: string, language: string, code: string, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
32
|
-
/**
|
|
33
|
-
* Dispatches a function call from the model to the appropriate local tool.
|
|
34
|
-
* Returns the tool result as a string to feed back to the model.
|
|
35
|
-
*/
|
|
36
41
|
export declare function executeTool(workspaceRoot: string, toolName: string, args: Record<string, unknown>, abortSignal?: AbortSignal): Promise<ToolResult>;
|