minovative-mind-cli 2.2.5 → 2.3.1
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/LICENSE.md +2 -0
- package/README.md +8 -8
- package/dist/commands/logout.js +1 -1
- package/dist/services/agent/slashCommands.js +53 -14
- package/dist/services/agent/toolLoop.js +4 -1
- package/dist/services/agent/types.d.ts +4 -0
- package/dist/services/agent-tools.js +55 -27
- package/dist/services/agent.d.ts +4 -0
- package/dist/services/agent.js +77 -60
- package/dist/services/ai.d.ts +1 -2
- package/dist/services/ai.js +21 -19
- package/dist/services/auth.d.ts +1 -1
- package/dist/services/auth.js +7 -28
- package/dist/services/chatHistoryService.d.ts +8 -0
- package/dist/services/contextAgent.js +18 -1
- package/dist/services/investigationComplexity.d.ts +1 -1
- package/dist/services/investigationComplexity.js +1 -1
- package/dist/services/orchestration/investigationAgent.d.ts +2 -2
- package/dist/services/orchestration/investigationAgent.js +25 -6
- package/dist/services/orchestration/orchestrator.d.ts +1 -1
- package/dist/services/orchestration/orchestrator.js +37 -18
- package/dist/services/orchestration/subAgent.d.ts +1 -1
- package/dist/services/orchestration/subAgent.js +23 -13
- package/dist/services/proxyClient.d.ts +16 -14
- package/dist/services/proxyClient.js +199 -103
- package/dist/utils/analysisRunner.js +2 -2
- package/dist/utils/config.d.ts +3 -3
- package/dist/utils/config.js +3 -3
- package/dist/utils/credentialStore.d.ts +30 -0
- package/dist/utils/credentialStore.js +540 -0
- package/dist/utils/projectStorage.js +70 -0
- package/dist/utils/systemPrompts.d.ts +3 -3
- package/dist/utils/systemPrompts.js +4 -4
- package/oclif.manifest.json +1 -1
- package/package.json +2 -1
package/LICENSE.md
CHANGED
|
@@ -17,6 +17,8 @@ You are expressly prohibited from doing any of the following:
|
|
|
17
17
|
- **No Reverse Engineering**: You may not decompile, reverse engineer, disassemble, or otherwise attempt to derive the source code of the compiled portions of the Software.
|
|
18
18
|
- **No Repurposing**: You may not use any part of the Software's source code in your own projects, whether commercial or non-commercial.
|
|
19
19
|
- **No Removal of Notices**: You may not remove, alter, or obscure any copyright, trademark, or other proprietary rights notices embedded in or attached to the Software.
|
|
20
|
+
- **Confidentiality**: You acknowledge that the Software contains proprietary, confidential information. You agree to take all reasonable precautions to protect the Software from unauthorized disclosure or access by third parties.
|
|
21
|
+
- **Prohibition on Benchmarking**: You are strictly prohibited from using the Software, or any output generated by the Software, for the purpose of developing, testing, or benchmarking a competing product or service, or for the purpose of training or tuning other machine learning or artificial intelligence models.
|
|
20
22
|
|
|
21
23
|
## 3. Ownership
|
|
22
24
|
|
package/README.md
CHANGED
|
@@ -86,12 +86,12 @@ Works in any terminal — SSH, Docker, CI pipelines, Vim, Windows Command Prompt
|
|
|
86
86
|
|
|
87
87
|
Hot-swap during a session using `/models`:
|
|
88
88
|
|
|
89
|
-
| Model | Best for
|
|
90
|
-
| ------------------------- |
|
|
91
|
-
| **Auto** (default) | Automatically selects (3.
|
|
92
|
-
| **Gemini 3.
|
|
93
|
-
| **Gemini 3.1 Pro** | Complex architectural changes
|
|
94
|
-
| **Gemini 3.
|
|
89
|
+
| Model | Best for |
|
|
90
|
+
| ------------------------- | --------------------------------------------------- |
|
|
91
|
+
| **Auto** (default) | Automatically selects (3.6 Flash or 3.5 Flash Lite) |
|
|
92
|
+
| **Gemini 3.6 Flash** | Everyday coding — fast and accurate |
|
|
93
|
+
| **Gemini 3.1 Pro** | Complex architectural changes |
|
|
94
|
+
| **Gemini 3.5 Flash Lite** | Best for speed and cost efficiency |
|
|
95
95
|
|
|
96
96
|
> Background tasks (routing, compression, commits) always use lightweight
|
|
97
97
|
> models automatically. You pay for those lightweight model
|
|
@@ -115,7 +115,7 @@ Hot-swap during a session using `/models`:
|
|
|
115
115
|
| `/stats` | View current session statistics and configuration |
|
|
116
116
|
| `/commit` | Generate a conventional commit message from your diff |
|
|
117
117
|
| `/revert` | Undo changes from the last turn, or toggle the revert logger |
|
|
118
|
-
| `/chats` | View, resume, or delete previous chat sessions (with token
|
|
118
|
+
| `/chats` | View, resume, or delete previous chat sessions (with centralized token telemetry, Git branch, auto-approve status, and sub-agent state) |
|
|
119
119
|
| `/workspaces` | Manage active workspaces and linked cross-repo aliases |
|
|
120
120
|
| `stop` | Abort generation immediately |
|
|
121
121
|
|
|
@@ -155,7 +155,7 @@ _⚠️\*Support is limited or requires custom local system tooling/environment
|
|
|
155
155
|
|
|
156
156
|
1. **Dependency Tracing:** Fully supported for all 11 languages. It uses lightning-fast static regex pattern matching to resolve local import structures and determine the "blast radius" of code changes without requiring local compilations.
|
|
157
157
|
2. **Performance Auditing:** Uses regex-based heuristic analysis to scan for issues. Extending this to complex grammars (such as Ruby or Swift) with pure regex can cause high false-positive rates; those require full AST parsing, which runs counter to the auditor's ultra-fast (<50ms) and zero-dependency goals.
|
|
158
|
-
3. **Ephemeral Analysis Scripts:** Runs temporary files in sandbox directories to parse and extract local symbols.
|
|
158
|
+
3. **Ephemeral Analysis Scripts:** Runs temporary files in sandbox directories to parse and extract local symbols. Also used for infrastructure probing (detecting available runtimes, checking ports, identifying project type), post-change validation (importing modified modules and asserting expected behavior), and lightweight ML-powered analysis (e.g., TF-IDF file ranking, anomaly detection, Big-O estimation). Defaults to Node.js as a safe baseline, but natively leverages host-installed runtimes (Python, Rust, Go compilers) and standard libraries whenever available in the workspace.
|
|
159
159
|
|
|
160
160
|
---
|
|
161
161
|
|
package/dist/commands/logout.js
CHANGED
|
@@ -6,7 +6,7 @@ export default class LogoutCommand extends Command {
|
|
|
6
6
|
static description = 'Sign out of your Minovative Mind account';
|
|
7
7
|
async run() {
|
|
8
8
|
p.intro(`${pc.bgCyan(pc.black(' Minovative Mind '))} - Logout`);
|
|
9
|
-
logout();
|
|
9
|
+
await logout();
|
|
10
10
|
p.outro(pc.green('You have been signed out.'));
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -11,7 +11,8 @@ import { chatHistoryService } from '../chatHistoryService.js';
|
|
|
11
11
|
import { printLogo, brandBg, brandFg } from '../../utils/logo.js';
|
|
12
12
|
import { readPaste } from '../../utils/paste.js';
|
|
13
13
|
import { setApprovalMode, getApprovalMode, isSubAgentsEnabled, setSubAgentsEnabled } from '../agent-tools.js';
|
|
14
|
-
import { ProxyChatSession, setGlobalActiveModel, getGlobalActiveModel,
|
|
14
|
+
import { ProxyChatSession, setGlobalActiveModel, getGlobalActiveModel, } from '../ai.js';
|
|
15
|
+
import { GEMINI_MODELS } from '../../utils/config.js';
|
|
15
16
|
const execAsync = promisify(exec);
|
|
16
17
|
/**
|
|
17
18
|
* Handles all slash command operations (/paste, /clear, /models, /debug, /auto-approve, /revert, /commit).
|
|
@@ -70,22 +71,22 @@ export async function handleSlashCommand(command, context) {
|
|
|
70
71
|
{
|
|
71
72
|
value: 'gemini-3.1-pro-preview',
|
|
72
73
|
label: 'Gemini 3.1 Pro',
|
|
73
|
-
hint: '
|
|
74
|
+
hint: 'For hardcore & complex problems',
|
|
74
75
|
},
|
|
75
76
|
{
|
|
76
|
-
value: 'gemini-3.
|
|
77
|
-
label: 'Gemini 3.
|
|
78
|
-
hint: 'Balanced performance',
|
|
77
|
+
value: 'gemini-3.6-flash',
|
|
78
|
+
label: 'Gemini 3.6 Flash',
|
|
79
|
+
hint: 'Balanced performance & fast',
|
|
79
80
|
},
|
|
80
81
|
{
|
|
81
|
-
value: 'gemini-3.
|
|
82
|
-
label: 'Gemini 3.
|
|
83
|
-
hint: '
|
|
82
|
+
value: 'gemini-3.5-flash-lite',
|
|
83
|
+
label: 'Gemini 3.5 Flash-Lite',
|
|
84
|
+
hint: 'Best for raw speed and cost efficiency',
|
|
84
85
|
},
|
|
85
86
|
{
|
|
86
87
|
value: 'auto',
|
|
87
88
|
label: 'Auto (Flash-Lite / Flash)',
|
|
88
|
-
hint: 'Dynamically routes between Gemini 3.
|
|
89
|
+
hint: 'Dynamically routes between Gemini 3.5 Flash-Lite and Gemini 3.6 based on prompt complexity',
|
|
89
90
|
},
|
|
90
91
|
],
|
|
91
92
|
});
|
|
@@ -129,7 +130,8 @@ export async function handleSlashCommand(command, context) {
|
|
|
129
130
|
return { shouldContinue: true };
|
|
130
131
|
}
|
|
131
132
|
if (lowerCommand === '/stats') {
|
|
132
|
-
const latestUsage =
|
|
133
|
+
const latestUsage = context.chatSessionState?.latestUsageMetadata;
|
|
134
|
+
const prevUsage = context.chatSessionState?.previousUsageMetadata;
|
|
133
135
|
const currentModel = chat.getModel();
|
|
134
136
|
const globalModel = getGlobalActiveModel();
|
|
135
137
|
const displayModel = globalModel === 'auto' ? `Auto (Last turn: ${currentModel})` : currentModel;
|
|
@@ -165,15 +167,45 @@ export async function handleSlashCommand(command, context) {
|
|
|
165
167
|
}
|
|
166
168
|
const totalInputTokens = (latestUsage.promptTokens || 0) + (latestUsage.cachedTokens || 0);
|
|
167
169
|
if (totalInputTokens > 0) {
|
|
168
|
-
|
|
170
|
+
let inputDiffStr = '';
|
|
171
|
+
if (prevUsage) {
|
|
172
|
+
const prevTotalInputTokens = (prevUsage.promptTokens || 0) + (prevUsage.cachedTokens || 0);
|
|
173
|
+
const inputDiff = totalInputTokens - prevTotalInputTokens;
|
|
174
|
+
if (inputDiff > 0) {
|
|
175
|
+
inputDiffStr = ` ${pc.yellow(`(+${inputDiff.toLocaleString()})`)}`;
|
|
176
|
+
}
|
|
177
|
+
else if (inputDiff < 0) {
|
|
178
|
+
inputDiffStr = ` ${pc.green(`(${inputDiff.toLocaleString()})`)}`;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
inputDiffStr = ` ${pc.dim(`(0)`)}`;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
console.log(`${pc.bold('Last Turn Input:')} ${totalInputTokens.toLocaleString()} tokens${inputDiffStr}`);
|
|
169
185
|
}
|
|
170
186
|
if (latestUsage.candidatesTokens) {
|
|
171
|
-
|
|
187
|
+
let outputDiffStr = '';
|
|
188
|
+
if (prevUsage && prevUsage.candidatesTokens !== undefined) {
|
|
189
|
+
const outputDiff = latestUsage.candidatesTokens - prevUsage.candidatesTokens;
|
|
190
|
+
if (outputDiff > 0) {
|
|
191
|
+
outputDiffStr = ` ${pc.yellow(`(+${outputDiff.toLocaleString()})`)}`;
|
|
192
|
+
}
|
|
193
|
+
else if (outputDiff < 0) {
|
|
194
|
+
outputDiffStr = ` ${pc.green(`(${outputDiff.toLocaleString()})`)}`;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
outputDiffStr = ` ${pc.dim(`(0)`)}`;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
console.log(`${pc.bold('Last Turn Output:')} ${latestUsage.candidatesTokens.toLocaleString()} tokens${outputDiffStr}`);
|
|
172
201
|
}
|
|
173
202
|
}
|
|
174
203
|
else {
|
|
175
204
|
console.log(`${pc.bold('Token Usage:')} No data available yet.`);
|
|
176
205
|
}
|
|
206
|
+
if (context.chatSessionState?.totalTokens > 0) {
|
|
207
|
+
console.log(`${pc.bold('Session Total:')} ${context.chatSessionState.totalTokens.toLocaleString()} tokens`);
|
|
208
|
+
}
|
|
177
209
|
console.log(pc.dim('----------------------------------------\n'));
|
|
178
210
|
return { shouldContinue: true };
|
|
179
211
|
}
|
|
@@ -306,6 +338,8 @@ export async function handleSlashCommand(command, context) {
|
|
|
306
338
|
chatSessionState.id = crypto.randomUUID();
|
|
307
339
|
chatSessionState.title = '';
|
|
308
340
|
chatSessionState.totalTokens = 0;
|
|
341
|
+
chatSessionState.totalInputTokens = 0;
|
|
342
|
+
chatSessionState.totalOutputTokens = 0;
|
|
309
343
|
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
310
344
|
}
|
|
311
345
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
@@ -367,6 +401,10 @@ export async function handleSlashCommand(command, context) {
|
|
|
367
401
|
chatSessionState.id = session.id;
|
|
368
402
|
chatSessionState.title = session.title;
|
|
369
403
|
chatSessionState.totalTokens = session.totalTokens || 0;
|
|
404
|
+
chatSessionState.totalInputTokens = session.totalInputTokens || 0;
|
|
405
|
+
chatSessionState.totalOutputTokens = session.totalOutputTokens || 0;
|
|
406
|
+
chatSessionState.latestUsageMetadata = session.latestUsageMetadata;
|
|
407
|
+
chatSessionState.previousUsageMetadata = session.previousUsageMetadata;
|
|
370
408
|
chat.setSessionInfo(session.id, workspaceRoot);
|
|
371
409
|
}
|
|
372
410
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
@@ -457,7 +495,8 @@ export async function handleSlashCommand(command, context) {
|
|
|
457
495
|
p.log.info(`${pc.dim('Model:')} ${pc.cyan(session.modelName)}`);
|
|
458
496
|
}
|
|
459
497
|
if (session.totalTokens !== undefined) {
|
|
460
|
-
|
|
498
|
+
const inputStr = session.totalInputTokens ? ` (Input: ${session.totalInputTokens.toLocaleString()}, Output: ${(session.totalOutputTokens || 0).toLocaleString()})` : '';
|
|
499
|
+
p.log.info(`${pc.dim('Session Token Usage:')} ${pc.cyan(session.totalTokens.toLocaleString() + ' total tokens')}${pc.dim(inputStr)}`);
|
|
461
500
|
}
|
|
462
501
|
if (session.gitBranch) {
|
|
463
502
|
p.log.info(`${pc.dim('Last Active Branch:')} ${pc.cyan(session.gitBranch)}`);
|
|
@@ -664,7 +703,7 @@ export async function handleSlashCommand(command, context) {
|
|
|
664
703
|
${diffOut}
|
|
665
704
|
</diff>`;
|
|
666
705
|
const commitSystemPrompt = 'You are an expert developer. Output only the git commit message, no markdown formatting, no explanations. Follow Conventional Commits format (feat:, fix:, chore:, refactor:, etc.) for the first line, keeping it under 70 characters and using the imperative mood. Then, add a blank line followed by a more descriptive bulleted list explaining the "what" and "why" of the changes based on the diff.';
|
|
667
|
-
const commitAgent = new ProxyChatSession(
|
|
706
|
+
const commitAgent = new ProxyChatSession(GEMINI_MODELS.FLASH_LITE, commitSystemPrompt, [], {});
|
|
668
707
|
const commitResult = await commitAgent.sendMessage(prompt);
|
|
669
708
|
const commitMsg = commitResult.response.text().trim();
|
|
670
709
|
commitSpinner.message('Committing...');
|
|
@@ -23,6 +23,7 @@ const TOOL_ICONS = {
|
|
|
23
23
|
rename_file: '🚚',
|
|
24
24
|
find_dependencies: '🔗',
|
|
25
25
|
run_analysis_script: '🔬',
|
|
26
|
+
run_debug_script: '🧪',
|
|
26
27
|
};
|
|
27
28
|
/**
|
|
28
29
|
* Human-readable translations for tool actions.
|
|
@@ -38,7 +39,8 @@ const TOOL_LABELS = {
|
|
|
38
39
|
delete_file: 'Deleting file',
|
|
39
40
|
rename_file: 'Moving file',
|
|
40
41
|
find_dependencies: 'Tracing dependencies',
|
|
41
|
-
run_analysis_script: 'Analyzing
|
|
42
|
+
run_analysis_script: 'Analyzing workspace',
|
|
43
|
+
run_debug_script: 'Executing debug/validation script',
|
|
42
44
|
};
|
|
43
45
|
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
44
46
|
/**
|
|
@@ -74,6 +76,7 @@ export function formatToolCall(name, args) {
|
|
|
74
76
|
rename_file: () => `: ${formatPath(String(args.sourcePath))} -> ${formatPath(String(args.targetPath))}`,
|
|
75
77
|
find_dependencies: () => `: ${formatPath(String(args.filePath))}${args.direction ? ` (${args.direction})` : ''}`,
|
|
76
78
|
run_analysis_script: () => `: ${formatPath(String(args.targetFile ?? 'workspace'))}`,
|
|
79
|
+
run_debug_script: () => `: ${pc.dim(`(${String(args.language ?? 'script')})`)}`,
|
|
77
80
|
};
|
|
78
81
|
const formatter = argsMap[name];
|
|
79
82
|
const details = formatter ? formatter() : '';
|
|
@@ -14,6 +14,10 @@ export interface SlashCommandContext {
|
|
|
14
14
|
id: string;
|
|
15
15
|
title: string;
|
|
16
16
|
totalTokens: number;
|
|
17
|
+
totalInputTokens: number;
|
|
18
|
+
totalOutputTokens: number;
|
|
19
|
+
latestUsageMetadata?: any;
|
|
20
|
+
previousUsageMetadata?: any;
|
|
17
21
|
};
|
|
18
22
|
}
|
|
19
23
|
export interface SlashCommandResult {
|
|
@@ -16,6 +16,7 @@ import { EXCLUDED_EXTENSIONS } from '../utils/excludedExtensions.js';
|
|
|
16
16
|
import { extractSymbols } from '../utils/symbolExtractor.js';
|
|
17
17
|
import { getMetricCollector } from './metrics.js';
|
|
18
18
|
import { getCurrentAgentId } from '../utils/asyncContext.js';
|
|
19
|
+
import ignore from 'ignore';
|
|
19
20
|
const execAsync = promisify(exec);
|
|
20
21
|
// ─── Tool Declarations for Gemini Function Calling ───────────────────
|
|
21
22
|
export function getToolDeclarations(options) {
|
|
@@ -237,7 +238,14 @@ export const toolDeclarations = [
|
|
|
237
238
|
},
|
|
238
239
|
{
|
|
239
240
|
name: 'run_debug_script',
|
|
240
|
-
description: 'Write a
|
|
241
|
+
description: 'Write a disposable script to a temporary file, execute it using the specified runtime, and return the exact standard output and standard error. ' +
|
|
242
|
+
'Use this to: (1) actively debug the codebase by inspecting variables or logging values, ' +
|
|
243
|
+
'(2) validate your changes by importing the modified module and asserting expected behavior with edge-case inputs, ' +
|
|
244
|
+
'(3) run quick sanity checks (e.g., verify a config file parses correctly, confirm exports are intact after a refactor, or check that a function returns the expected output), ' +
|
|
245
|
+
'(4) write lightweight ML scripts to solve complex problems — e.g., polynomial regression to estimate Big-O complexity, fuzz testing with Markov chain input generation, ' +
|
|
246
|
+
'output regression detection via statistical similarity scoring, or error message classification with Naive Bayes. ' +
|
|
247
|
+
'Default to "node" for generic tasks as a safe baseline, but act like a native inhabitant of the host environment — if Python, Go, Rust, or host-native libraries are active in the project, leverage the host\'s native runtimes for maximum efficiency. ' +
|
|
248
|
+
'Do not guess whether your code works — test it directly!',
|
|
241
249
|
parameters: {
|
|
242
250
|
type: SchemaType.OBJECT,
|
|
243
251
|
properties: {
|
|
@@ -325,34 +333,50 @@ const DEFAULT_IGNORED_DIRS = new Set([
|
|
|
325
333
|
]);
|
|
326
334
|
const DEFAULT_IGNORED_FILES = new Set(['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', '.DS_Store']);
|
|
327
335
|
/**
|
|
328
|
-
* Parses .gitignore to supplement the default ignore lists.
|
|
336
|
+
* Parses .gitignore and .minovativemindignore to supplement the default ignore lists.
|
|
329
337
|
*/
|
|
330
338
|
async function getIgnoredPaths(workspaceRoot) {
|
|
331
339
|
const ignoredDirs = new Set(DEFAULT_IGNORED_DIRS);
|
|
332
340
|
const ignoredFiles = new Set(DEFAULT_IGNORED_FILES);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
341
|
+
const ig = ignore();
|
|
342
|
+
ig.add(Array.from(DEFAULT_IGNORED_DIRS).map(d => d + '/'));
|
|
343
|
+
ig.add(Array.from(DEFAULT_IGNORED_FILES));
|
|
344
|
+
const filesToRead = ['.gitignore', '.minovativemindignore'];
|
|
345
|
+
for (const ignoreFile of filesToRead) {
|
|
346
|
+
try {
|
|
347
|
+
const content = await fs.readFile(path.join(workspaceRoot, ignoreFile), 'utf-8');
|
|
348
|
+
ig.add(content);
|
|
349
|
+
const lines = content
|
|
350
|
+
.split('\n')
|
|
351
|
+
.map((l) => l.trim())
|
|
352
|
+
.filter((l) => l && !l.startsWith('#'));
|
|
353
|
+
for (const line of lines) {
|
|
354
|
+
const cleanLine = line.replace(/\\/g, '/').replace(/^\//, '').replace(/\/$/, '');
|
|
355
|
+
if (!cleanLine.includes('*')) {
|
|
356
|
+
ignoredDirs.add(cleanLine);
|
|
357
|
+
ignoredFiles.add(cleanLine);
|
|
358
|
+
}
|
|
344
359
|
}
|
|
345
360
|
}
|
|
361
|
+
catch {
|
|
362
|
+
// Ignore missing files
|
|
363
|
+
}
|
|
346
364
|
}
|
|
347
|
-
|
|
348
|
-
// Ignore missing .gitignore
|
|
349
|
-
}
|
|
350
|
-
return { ignoredDirs, ignoredFiles };
|
|
365
|
+
return { ignoredDirs, ignoredFiles, ig };
|
|
351
366
|
}
|
|
352
367
|
// ─── Tool Implementations ────────────────────────────────────────────
|
|
353
368
|
export async function readFile(workspaceRoot, filePath, startLine, endLine, targetElements) {
|
|
354
369
|
try {
|
|
355
370
|
const absPath = resolveAndValidatePath(workspaceRoot, filePath);
|
|
371
|
+
// Check if file is explicitly ignored
|
|
372
|
+
const relPath = path.relative(workspaceRoot, absPath).replace(/\\/g, '/');
|
|
373
|
+
const { ig } = await getIgnoredPaths(workspaceRoot);
|
|
374
|
+
if (ig.ignores(relPath)) {
|
|
375
|
+
return {
|
|
376
|
+
output: '',
|
|
377
|
+
error: `File '${relPath}' is ignored by .gitignore or .minovativemindignore. The agent cannot read it. Please explore other files.`,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
356
380
|
// Handle PDF files
|
|
357
381
|
if (filePath.toLowerCase().endsWith('.pdf')) {
|
|
358
382
|
const stats = await fs.stat(absPath);
|
|
@@ -698,7 +722,7 @@ export async function listDirectory(workspaceRoot, dirPath, maxDepth = 3) {
|
|
|
698
722
|
try {
|
|
699
723
|
const absPath = resolveAndValidatePath(workspaceRoot, dirPath);
|
|
700
724
|
const lines = [];
|
|
701
|
-
const {
|
|
725
|
+
const { ig } = await getIgnoredPaths(workspaceRoot);
|
|
702
726
|
async function walk(currentPath, prefix, depth) {
|
|
703
727
|
if (depth > maxDepth)
|
|
704
728
|
return;
|
|
@@ -721,7 +745,7 @@ export async function listDirectory(workspaceRoot, dirPath, maxDepth = 3) {
|
|
|
721
745
|
const entryPath = path.join(currentPath, entry.name);
|
|
722
746
|
const relPath = path.relative(workspaceRoot, entryPath).replace(/\\/g, '/');
|
|
723
747
|
if (entry.isDirectory()) {
|
|
724
|
-
if (
|
|
748
|
+
if (ig.ignores(relPath + '/')) {
|
|
725
749
|
lines.push(`${prefix}${connector}${entry.name}/ (ignored)`);
|
|
726
750
|
continue;
|
|
727
751
|
}
|
|
@@ -729,7 +753,7 @@ export async function listDirectory(workspaceRoot, dirPath, maxDepth = 3) {
|
|
|
729
753
|
await walk(entryPath, `${prefix}${childPrefix}`, depth + 1);
|
|
730
754
|
}
|
|
731
755
|
else {
|
|
732
|
-
if (
|
|
756
|
+
if (ig.ignores(relPath))
|
|
733
757
|
continue;
|
|
734
758
|
if (EXCLUDED_EXTENSIONS.some((ext) => entry.name.endsWith(ext.replace('*', ''))))
|
|
735
759
|
continue;
|
|
@@ -779,7 +803,7 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
779
803
|
}
|
|
780
804
|
export async function grepSearch(workspaceRoot, pattern, fileGlob, abortSignal) {
|
|
781
805
|
try {
|
|
782
|
-
const { ignoredDirs } = await getIgnoredPaths(workspaceRoot);
|
|
806
|
+
const { ignoredDirs, ig } = await getIgnoredPaths(workspaceRoot);
|
|
783
807
|
if (os.platform() !== 'win32') {
|
|
784
808
|
const excludeDirArgs = Array.from(ignoredDirs)
|
|
785
809
|
.map((dir) => `--exclude-dir="${dir}"`)
|
|
@@ -828,12 +852,16 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, abortSignal)
|
|
|
828
852
|
return;
|
|
829
853
|
if (entry.name.startsWith('.'))
|
|
830
854
|
continue;
|
|
855
|
+
const entryPath = path.join(dir, entry.name);
|
|
856
|
+
const relPath = path.relative(workspaceRoot, entryPath).replace(/\\/g, '/');
|
|
831
857
|
if (entry.isDirectory()) {
|
|
832
|
-
if (
|
|
858
|
+
if (ig.ignores(relPath + '/'))
|
|
833
859
|
continue;
|
|
834
|
-
await walk(
|
|
860
|
+
await walk(entryPath);
|
|
835
861
|
}
|
|
836
862
|
else if (entry.isFile()) {
|
|
863
|
+
if (ig.ignores(relPath))
|
|
864
|
+
continue;
|
|
837
865
|
if (EXCLUDED_EXTENSIONS.some((ext) => entry.name.endsWith(ext.replace('*', ''))))
|
|
838
866
|
continue;
|
|
839
867
|
if (globPattern && !globPattern.test(entry.name))
|
|
@@ -898,7 +926,7 @@ export async function traceDependencies(workspaceRoot, filePath, direction, maxD
|
|
|
898
926
|
export async function findRecentChanges(workspaceRoot, dirPath = '.', minutes = 60, maxDepth = 5) {
|
|
899
927
|
try {
|
|
900
928
|
const absPath = resolveAndValidatePath(workspaceRoot, dirPath);
|
|
901
|
-
const {
|
|
929
|
+
const { ig } = await getIgnoredPaths(workspaceRoot);
|
|
902
930
|
const thresholdMs = Date.now() - minutes * 60 * 1000;
|
|
903
931
|
const recentFiles = [];
|
|
904
932
|
async function walk(currentPath, depth) {
|
|
@@ -917,12 +945,12 @@ export async function findRecentChanges(workspaceRoot, dirPath = '.', minutes =
|
|
|
917
945
|
const entryPath = path.join(currentPath, entry.name);
|
|
918
946
|
const relPath = path.relative(workspaceRoot, entryPath).replace(/\\/g, '/');
|
|
919
947
|
if (entry.isDirectory()) {
|
|
920
|
-
if (
|
|
948
|
+
if (ig.ignores(relPath + '/'))
|
|
921
949
|
continue;
|
|
922
950
|
await walk(entryPath, depth + 1);
|
|
923
951
|
}
|
|
924
952
|
else {
|
|
925
|
-
if (
|
|
953
|
+
if (ig.ignores(relPath))
|
|
926
954
|
continue;
|
|
927
955
|
if (EXCLUDED_EXTENSIONS.some((ext) => entry.name.endsWith(ext.replace('*', ''))))
|
|
928
956
|
continue;
|
|
@@ -1009,7 +1037,7 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
|
|
|
1009
1037
|
return { output: '', error: `Unsupported language runtime: ${language}` };
|
|
1010
1038
|
}
|
|
1011
1039
|
try {
|
|
1012
|
-
const { stdout, stderr } = await execAsync(cmd, { cwd: workspaceRoot, timeout:
|
|
1040
|
+
const { stdout, stderr } = await execAsync(cmd, { cwd: workspaceRoot, timeout: 60_000, signal: abortSignal });
|
|
1013
1041
|
const out = stdout.trim();
|
|
1014
1042
|
const errOut = stderr.trim();
|
|
1015
1043
|
let finalOutput = '';
|
package/dist/services/agent.d.ts
CHANGED
|
@@ -53,6 +53,10 @@ export declare function executeSingleTurn(workspaceRoot: string, userInput: stri
|
|
|
53
53
|
id: string;
|
|
54
54
|
title: string;
|
|
55
55
|
totalTokens: number;
|
|
56
|
+
totalInputTokens: number;
|
|
57
|
+
totalOutputTokens: number;
|
|
58
|
+
latestUsageMetadata?: any;
|
|
59
|
+
previousUsageMetadata?: any;
|
|
56
60
|
}, isPlanMode: boolean, cachedContextResult?: any): Promise<{
|
|
57
61
|
planModeReturn?: string;
|
|
58
62
|
contextResult?: any;
|