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
|
@@ -13,8 +13,22 @@ import { findDependencies, formatDependencyResult } from '../utils/dependencyTra
|
|
|
13
13
|
import { atomicWriteFile } from '../utils/atomicWrite.js';
|
|
14
14
|
import { EXCLUDED_EXTENSIONS } from '../utils/excludedExtensions.js';
|
|
15
15
|
import { extractSymbols } from '../utils/symbolExtractor.js';
|
|
16
|
+
import { getMetricCollector } from './metrics.js';
|
|
16
17
|
const execAsync = promisify(exec);
|
|
17
18
|
// ─── Tool Declarations for Gemini Function Calling ───────────────────
|
|
19
|
+
let _semanticSearchEnabled = true;
|
|
20
|
+
export function isSemanticSearchEnabled() {
|
|
21
|
+
return _semanticSearchEnabled;
|
|
22
|
+
}
|
|
23
|
+
export function setSemanticSearchEnabled(val) {
|
|
24
|
+
_semanticSearchEnabled = val;
|
|
25
|
+
}
|
|
26
|
+
export function getToolDeclarations() {
|
|
27
|
+
if (_semanticSearchEnabled) {
|
|
28
|
+
return toolDeclarations;
|
|
29
|
+
}
|
|
30
|
+
return toolDeclarations.filter((t) => t.name !== 'semantic_search');
|
|
31
|
+
}
|
|
18
32
|
/**
|
|
19
33
|
* FunctionDeclaration-compatible schema objects that describe
|
|
20
34
|
* every tool the agent can invoke. Passed to the model at init.
|
|
@@ -22,7 +36,7 @@ const execAsync = promisify(exec);
|
|
|
22
36
|
export const toolDeclarations = [
|
|
23
37
|
{
|
|
24
38
|
name: 'read_file',
|
|
25
|
-
description: 'Read the contents of a file at the given path relative to the workspace root.
|
|
39
|
+
description: 'Read the contents of a file at the given path relative to the workspace root. Supports text files and native parsing of .pdf files (including math and diagrams). Use startLine and endLine to read specific chunks of massive files to avoid context limits.',
|
|
26
40
|
parameters: {
|
|
27
41
|
type: SchemaType.OBJECT,
|
|
28
42
|
properties: {
|
|
@@ -99,7 +113,7 @@ export const toolDeclarations = [
|
|
|
99
113
|
},
|
|
100
114
|
{
|
|
101
115
|
name: 'modify_file',
|
|
102
|
-
description: 'Perform one or multiple targeted search-and-replace edits in a single file.
|
|
116
|
+
description: 'Perform one or multiple targeted search-and-replace edits in a single file. CRITICAL REQUIREMENT: You MUST use read_file or grep_search to fetch the exact current file content BEFORE using this tool. Do NOT guess or hallucinate the searchContent without reading the exact lines first, or the edit will fail. The search strings must match the current file exactly (including whitespace). This is preferred over write_file for editing existing files.',
|
|
103
117
|
parameters: {
|
|
104
118
|
type: SchemaType.OBJECT,
|
|
105
119
|
properties: {
|
|
@@ -240,6 +254,24 @@ export const toolDeclarations = [
|
|
|
240
254
|
required: ['language', 'code'],
|
|
241
255
|
},
|
|
242
256
|
},
|
|
257
|
+
{
|
|
258
|
+
name: 'semantic_search',
|
|
259
|
+
description: 'Search the codebase by meaning and concept rather than exact text match. Use this when you need to find code related to a concept, pattern, or behavior but don\'t know the exact variable or function names to grep for. Examples: "error handling for API requests", "user authentication flow", "database connection pooling logic". Returns ranked results with file paths, line ranges, and similarity scores.',
|
|
260
|
+
parameters: {
|
|
261
|
+
type: SchemaType.OBJECT,
|
|
262
|
+
properties: {
|
|
263
|
+
query: {
|
|
264
|
+
type: SchemaType.STRING,
|
|
265
|
+
description: "Natural language description of what you're looking for in the codebase.",
|
|
266
|
+
},
|
|
267
|
+
topK: {
|
|
268
|
+
type: SchemaType.NUMBER,
|
|
269
|
+
description: 'Number of results to return. Defaults to 5, maximum 15.',
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
required: ['query'],
|
|
273
|
+
},
|
|
274
|
+
},
|
|
243
275
|
];
|
|
244
276
|
let currentApprovalMode = 'ask';
|
|
245
277
|
export function getApprovalMode() {
|
|
@@ -248,6 +280,13 @@ export function getApprovalMode() {
|
|
|
248
280
|
export function setApprovalMode(mode) {
|
|
249
281
|
currentApprovalMode = mode;
|
|
250
282
|
}
|
|
283
|
+
let subAgentsEnabled = true;
|
|
284
|
+
export function isSubAgentsEnabled() {
|
|
285
|
+
return subAgentsEnabled;
|
|
286
|
+
}
|
|
287
|
+
export function setSubAgentsEnabled(enabled) {
|
|
288
|
+
subAgentsEnabled = enabled;
|
|
289
|
+
}
|
|
251
290
|
/**
|
|
252
291
|
* If set to 'skip-once', reverts to 'ask' after a single command is run.
|
|
253
292
|
*/
|
|
@@ -300,6 +339,23 @@ async function getIgnoredPaths(workspaceRoot) {
|
|
|
300
339
|
export async function readFile(workspaceRoot, filePath, startLine, endLine, targetElements) {
|
|
301
340
|
try {
|
|
302
341
|
const absPath = resolveAndValidatePath(workspaceRoot, filePath);
|
|
342
|
+
// Handle PDF files
|
|
343
|
+
if (filePath.toLowerCase().endsWith('.pdf')) {
|
|
344
|
+
const stats = await fs.stat(absPath);
|
|
345
|
+
const fileSizeMB = stats.size / (1024 * 1024);
|
|
346
|
+
if (fileSizeMB > 10) {
|
|
347
|
+
return {
|
|
348
|
+
output: '',
|
|
349
|
+
error: `File exceeds the 10MB safety limit to prevent excessive credit consumption. Please split the PDF into smaller chunks. (Size: ${fileSizeMB.toFixed(2)}MB)`,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const buffer = await fs.readFile(absPath);
|
|
353
|
+
const base64Data = buffer.toString('base64');
|
|
354
|
+
return {
|
|
355
|
+
output: `[PDF Data Attached: ${filePath}]`,
|
|
356
|
+
inlineData: { mimeType: 'application/pdf', data: base64Data },
|
|
357
|
+
};
|
|
358
|
+
}
|
|
303
359
|
let content = await fs.readFile(absPath, 'utf-8');
|
|
304
360
|
if (targetElements && targetElements.length > 0) {
|
|
305
361
|
content = extractSymbols(content, filePath, targetElements);
|
|
@@ -356,6 +412,9 @@ export async function writeFile(workspaceRoot, filePath, content) {
|
|
|
356
412
|
}
|
|
357
413
|
catch (err) {
|
|
358
414
|
const message = err instanceof Error ? err.message : String(err);
|
|
415
|
+
const collector = getMetricCollector();
|
|
416
|
+
if (collector)
|
|
417
|
+
collector.recordWriteFailure();
|
|
359
418
|
return {
|
|
360
419
|
output: '',
|
|
361
420
|
error: `Failed to write file "${filePath}": ${message}`,
|
|
@@ -417,6 +476,9 @@ export async function modifyFile(workspaceRoot, filePath, edits) {
|
|
|
417
476
|
const edit = edits[i];
|
|
418
477
|
const match = findBestMatch(modified, edit.searchContent);
|
|
419
478
|
if (!match) {
|
|
479
|
+
const collector = getMetricCollector();
|
|
480
|
+
if (collector)
|
|
481
|
+
collector.recordModifyFailure();
|
|
420
482
|
if (attempt < MAX_MODIFY_RETRIES) {
|
|
421
483
|
// Break out of inner loop, triggering a retry in outer loop
|
|
422
484
|
modified = existing; // reset
|
|
@@ -431,6 +493,18 @@ export async function modifyFile(workspaceRoot, filePath, edits) {
|
|
|
431
493
|
}
|
|
432
494
|
modified = applyMatch(modified, match, edit.replaceContent);
|
|
433
495
|
strategies.push(`Edit #${i + 1}: ${match.strategy}`);
|
|
496
|
+
const collector = getMetricCollector();
|
|
497
|
+
if (collector) {
|
|
498
|
+
if (match.strategy.startsWith('Exact Match')) {
|
|
499
|
+
collector.recordMatchTier('exact');
|
|
500
|
+
}
|
|
501
|
+
else if (match.strategy.startsWith('Levenshtein')) {
|
|
502
|
+
collector.recordMatchTier('levenshtein');
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
collector.recordMatchTier('normalized');
|
|
506
|
+
}
|
|
507
|
+
}
|
|
434
508
|
}
|
|
435
509
|
// If we broke out early for a retry, the modified string will equal the existing string
|
|
436
510
|
// (or we haven't completed all edits), so we continue to the next attempt.
|
|
@@ -528,7 +602,9 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
528
602
|
// Truncate command output to prevent memory blowout from massive build logs
|
|
529
603
|
const MAX_CMD_OUTPUT = 15_000;
|
|
530
604
|
if (output.length > MAX_CMD_OUTPUT) {
|
|
531
|
-
output =
|
|
605
|
+
output =
|
|
606
|
+
output.substring(0, MAX_CMD_OUTPUT) +
|
|
607
|
+
`\n\n... (Output truncated: ${output.length} bytes exceeded 15KB limit. To view the rest, pipe the command to a file and read it in chunks, or use grep.)`;
|
|
532
608
|
}
|
|
533
609
|
return { output: output || '(command produced no output)' };
|
|
534
610
|
}
|
|
@@ -537,7 +613,8 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
537
613
|
// Also truncate error output
|
|
538
614
|
const MAX_ERR_OUTPUT = 15_000;
|
|
539
615
|
const truncatedMsg = message.length > MAX_ERR_OUTPUT
|
|
540
|
-
? message.substring(0, MAX_ERR_OUTPUT) +
|
|
616
|
+
? message.substring(0, MAX_ERR_OUTPUT) +
|
|
617
|
+
`\n\n... (Error output truncated: ${message.length} bytes exceeded 15KB limit. Pipe to a file if you need full logs.)`
|
|
541
618
|
: message;
|
|
542
619
|
return { output: '', error: `Command failed: ${truncatedMsg}` };
|
|
543
620
|
}
|
|
@@ -574,7 +651,9 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, abortSignal)
|
|
|
574
651
|
}
|
|
575
652
|
// Node.js fallback for Windows
|
|
576
653
|
const regexPattern = new RegExp(pattern, 'gi'); // Emulate grep -i and global match
|
|
577
|
-
const globPattern = fileGlob
|
|
654
|
+
const globPattern = fileGlob
|
|
655
|
+
? new RegExp('^' + fileGlob.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$', 'i')
|
|
656
|
+
: null;
|
|
578
657
|
const results = [];
|
|
579
658
|
async function walk(dir) {
|
|
580
659
|
if (results.length >= 50)
|
|
@@ -810,35 +889,80 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
|
|
|
810
889
|
}
|
|
811
890
|
}
|
|
812
891
|
}
|
|
813
|
-
/**
|
|
814
|
-
* Dispatches a function call from the model to the appropriate local tool.
|
|
815
|
-
* Returns the tool result as a string to feed back to the model.
|
|
816
|
-
*/
|
|
817
892
|
export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
|
|
893
|
+
let result;
|
|
818
894
|
switch (toolName) {
|
|
819
895
|
case 'read_file':
|
|
820
|
-
|
|
896
|
+
result = await readFile(workspaceRoot, args.filePath, args.startLine, args.endLine, args.targetElements);
|
|
897
|
+
break;
|
|
821
898
|
case 'write_file':
|
|
822
|
-
|
|
899
|
+
result = await writeFile(workspaceRoot, args.filePath, args.content);
|
|
900
|
+
break;
|
|
823
901
|
case 'delete_file':
|
|
824
|
-
|
|
902
|
+
result = await deleteFile(workspaceRoot, args.filePath);
|
|
903
|
+
break;
|
|
825
904
|
case 'rename_file':
|
|
826
|
-
|
|
905
|
+
result = await renameFile(workspaceRoot, args.sourcePath, args.targetPath);
|
|
906
|
+
break;
|
|
827
907
|
case 'modify_file':
|
|
828
|
-
|
|
908
|
+
result = await modifyFile(workspaceRoot, args.filePath, args.edits);
|
|
909
|
+
break;
|
|
829
910
|
case 'list_directory':
|
|
830
|
-
|
|
911
|
+
result = await listDirectory(workspaceRoot, args.dirPath, args.maxDepth ?? 3);
|
|
912
|
+
break;
|
|
831
913
|
case 'run_command':
|
|
832
|
-
|
|
914
|
+
result = await runCommand(workspaceRoot, args.command, abortSignal);
|
|
915
|
+
break;
|
|
833
916
|
case 'run_debug_script':
|
|
834
|
-
|
|
917
|
+
result = await runDebugScript(workspaceRoot, args.language, args.code, abortSignal);
|
|
918
|
+
break;
|
|
835
919
|
case 'grep_search':
|
|
836
|
-
|
|
920
|
+
result = await grepSearch(workspaceRoot, args.pattern, args.fileGlob, abortSignal);
|
|
921
|
+
break;
|
|
922
|
+
case 'semantic_search': {
|
|
923
|
+
const query = args.query;
|
|
924
|
+
const topK = args.topK || 5;
|
|
925
|
+
let output = '';
|
|
926
|
+
try {
|
|
927
|
+
const { getEmbeddingIndex } = await import('./embeddingIndex.js');
|
|
928
|
+
const index = getEmbeddingIndex();
|
|
929
|
+
if (!index.isReady()) {
|
|
930
|
+
const loaded = await index.load(workspaceRoot);
|
|
931
|
+
if (!loaded) {
|
|
932
|
+
await index.buildIndex(workspaceRoot);
|
|
933
|
+
await index.save(workspaceRoot);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
const results = await index.search(query, topK);
|
|
937
|
+
if (results.length === 0) {
|
|
938
|
+
output = 'No semantically similar code found. (Index might be empty or embedding failed)';
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
output = results
|
|
942
|
+
.map((r) => `[Score: ${r.score.toFixed(3)}] ${r.filePath}:${r.startLine}-${r.endLine}\n${r.preview}`)
|
|
943
|
+
.join('\n---\n');
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
catch (e) {
|
|
947
|
+
output = `Semantic search failed: ${e.message}`;
|
|
948
|
+
}
|
|
949
|
+
result = { output };
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
837
952
|
case 'find_dependencies':
|
|
838
|
-
|
|
953
|
+
result = await traceDependencies(workspaceRoot, args.filePath, args.direction, args.maxDepth);
|
|
954
|
+
break;
|
|
839
955
|
case 'find_recent_changes':
|
|
840
|
-
|
|
956
|
+
result = await findRecentChanges(workspaceRoot, args.dirPath, args.minutes, args.maxDepth);
|
|
957
|
+
break;
|
|
841
958
|
default:
|
|
842
|
-
|
|
959
|
+
result = { output: '', error: `Unknown tool: "${toolName}"` };
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
if (result.error) {
|
|
963
|
+
const collector = getMetricCollector();
|
|
964
|
+
if (collector)
|
|
965
|
+
collector.recordToolFailure(toolName);
|
|
843
966
|
}
|
|
967
|
+
return result;
|
|
844
968
|
}
|
package/dist/services/agent.d.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* 5. **Self-Correction Pipeline**: Compares modified files against TS/Linter diagnostics,
|
|
16
16
|
* providing feedback on syntax or semantic failures back to the AI for self-healing.
|
|
17
17
|
*/
|
|
18
|
+
import { AsyncInputHandler } from './agent/inputHandler.js';
|
|
18
19
|
export { AsyncInputHandler } from './agent/inputHandler.js';
|
|
19
20
|
/**
|
|
20
21
|
* Starts and orchestrates the primary interactive command-line interface (REPL) loop.
|
|
@@ -48,3 +49,10 @@ export { AsyncInputHandler } from './agent/inputHandler.js';
|
|
|
48
49
|
* @param version - The Semantic Version string of the active tool distribution.
|
|
49
50
|
*/
|
|
50
51
|
export declare function startAgentLoop(workspaceRoot: string, version: string): Promise<void>;
|
|
52
|
+
export declare function executeSingleTurn(workspaceRoot: string, userInput: string, chat: any, inputHandler: AsyncInputHandler, chatSessionState: {
|
|
53
|
+
id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
}, isPlanMode: boolean, cachedContextResult?: any): Promise<{
|
|
56
|
+
planModeReturn?: string;
|
|
57
|
+
contextResult?: any;
|
|
58
|
+
} | void>;
|