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.
Files changed (76) hide show
  1. package/README.md +51 -45
  2. package/dist/commands/chat.js +10 -5
  3. package/dist/services/agent/slashCommands.js +163 -37
  4. package/dist/services/agent/toolLoop.d.ts +1 -1
  5. package/dist/services/agent/toolLoop.js +7 -2
  6. package/dist/services/agent/types.d.ts +2 -0
  7. package/dist/services/agent-tools.d.ts +9 -4
  8. package/dist/services/agent-tools.js +145 -21
  9. package/dist/services/agent.d.ts +8 -0
  10. package/dist/services/agent.js +294 -38
  11. package/dist/services/ai.d.ts +19 -5
  12. package/dist/services/ai.js +167 -35
  13. package/dist/services/changeLogger.d.ts +142 -0
  14. package/dist/services/changeLogger.js +132 -3
  15. package/dist/services/contextAgent.d.ts +6 -1
  16. package/dist/services/contextAgent.js +95 -14
  17. package/dist/services/embeddingIndex.d.ts +82 -0
  18. package/dist/services/embeddingIndex.js +613 -0
  19. package/dist/services/investigationComplexity.d.ts +45 -0
  20. package/dist/services/investigationComplexity.js +91 -0
  21. package/dist/services/metrics.d.ts +18 -0
  22. package/dist/services/metrics.js +7 -0
  23. package/dist/services/orchestration/fileLockRegistry.d.ts +125 -0
  24. package/dist/services/orchestration/fileLockRegistry.js +276 -0
  25. package/dist/services/orchestration/investigationAgent.d.ts +85 -0
  26. package/dist/services/orchestration/investigationAgent.js +359 -0
  27. package/dist/services/orchestration/investigationOrchestrator.d.ts +53 -0
  28. package/dist/services/orchestration/investigationOrchestrator.js +180 -0
  29. package/dist/services/orchestration/messageBus.d.ts +162 -0
  30. package/dist/services/orchestration/messageBus.js +225 -0
  31. package/dist/services/orchestration/orchestrator.d.ts +45 -0
  32. package/dist/services/orchestration/orchestrator.js +214 -0
  33. package/dist/services/orchestration/readCache.d.ts +79 -0
  34. package/dist/services/orchestration/readCache.js +108 -0
  35. package/dist/services/orchestration/scopedTools.d.ts +57 -0
  36. package/dist/services/orchestration/scopedTools.js +172 -0
  37. package/dist/services/orchestration/subAgent.d.ts +58 -0
  38. package/dist/services/orchestration/subAgent.js +187 -0
  39. package/dist/services/orchestration/taskGraph.d.ts +129 -0
  40. package/dist/services/orchestration/taskGraph.js +254 -0
  41. package/dist/services/proxyClient.d.ts +25 -0
  42. package/dist/services/proxyClient.js +60 -0
  43. package/dist/utils/asyncContext.d.ts +16 -0
  44. package/dist/utils/asyncContext.js +25 -0
  45. package/dist/utils/config.d.ts +3 -1
  46. package/dist/utils/config.js +3 -1
  47. package/dist/utils/contextPrompts.js +3 -2
  48. package/dist/utils/dependencyTracer/modules/api.d.ts +9 -0
  49. package/dist/utils/dependencyTracer/modules/api.js +62 -0
  50. package/dist/utils/dependencyTracer/modules/graph.d.ts +9 -0
  51. package/dist/utils/dependencyTracer/modules/graph.js +23 -0
  52. package/dist/utils/dependencyTracer/modules/profiles.d.ts +7 -0
  53. package/dist/utils/dependencyTracer/modules/profiles.js +120 -0
  54. package/dist/utils/dependencyTracer/modules/resolver.d.ts +7 -0
  55. package/dist/utils/dependencyTracer/modules/resolver.js +51 -0
  56. package/dist/utils/dependencyTracer/modules/types.d.ts +4 -0
  57. package/dist/utils/dependencyTracer/modules/types.js +1 -0
  58. package/dist/utils/dependencyTracer/modules/walker.d.ts +1 -0
  59. package/dist/utils/dependencyTracer/modules/walker.js +48 -0
  60. package/dist/utils/dependencyTracer.js +31 -17
  61. package/dist/utils/excludedExtensions.js +0 -1
  62. package/dist/utils/historyPrompt.d.ts +9 -0
  63. package/dist/utils/historyPrompt.js +87 -0
  64. package/dist/utils/logo.d.ts +2 -0
  65. package/dist/utils/logo.js +31 -10
  66. package/dist/utils/paste.d.ts +21 -0
  67. package/dist/utils/paste.js +22 -1
  68. package/dist/utils/profiles.d.ts +2 -0
  69. package/dist/utils/profiles.js +44 -0
  70. package/dist/utils/projectStorage.js +10 -7
  71. package/dist/utils/systemPrompts.d.ts +6 -3
  72. package/dist/utils/systemPrompts.js +106 -5
  73. package/dist/utils/types.d.ts +33 -0
  74. package/dist/utils/types.js +1 -0
  75. package/oclif.manifest.json +2 -2
  76. 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. Returns the file text. Use startLine and endLine to read specific chunks of massive files to avoid context limits.',
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. The search strings must match exactly (including whitespace). This is preferred over write_file for editing existing files because it preserves the rest of the file. Use this to batch multiple changes into a single operation.',
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 = output.substring(0, MAX_CMD_OUTPUT) + `\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.)`;
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) + `\n\n... (Error output truncated: ${message.length} bytes exceeded 15KB limit. Pipe to a file if you need full logs.)`
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 ? new RegExp('^' + fileGlob.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$', 'i') : null;
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
- return readFile(workspaceRoot, args.filePath, args.startLine, args.endLine, args.targetElements);
896
+ result = await readFile(workspaceRoot, args.filePath, args.startLine, args.endLine, args.targetElements);
897
+ break;
821
898
  case 'write_file':
822
- return writeFile(workspaceRoot, args.filePath, args.content);
899
+ result = await writeFile(workspaceRoot, args.filePath, args.content);
900
+ break;
823
901
  case 'delete_file':
824
- return deleteFile(workspaceRoot, args.filePath);
902
+ result = await deleteFile(workspaceRoot, args.filePath);
903
+ break;
825
904
  case 'rename_file':
826
- return renameFile(workspaceRoot, args.sourcePath, args.targetPath);
905
+ result = await renameFile(workspaceRoot, args.sourcePath, args.targetPath);
906
+ break;
827
907
  case 'modify_file':
828
- return modifyFile(workspaceRoot, args.filePath, args.edits);
908
+ result = await modifyFile(workspaceRoot, args.filePath, args.edits);
909
+ break;
829
910
  case 'list_directory':
830
- return listDirectory(workspaceRoot, args.dirPath, args.maxDepth ?? 3);
911
+ result = await listDirectory(workspaceRoot, args.dirPath, args.maxDepth ?? 3);
912
+ break;
831
913
  case 'run_command':
832
- return runCommand(workspaceRoot, args.command, abortSignal);
914
+ result = await runCommand(workspaceRoot, args.command, abortSignal);
915
+ break;
833
916
  case 'run_debug_script':
834
- return runDebugScript(workspaceRoot, args.language, args.code, abortSignal);
917
+ result = await runDebugScript(workspaceRoot, args.language, args.code, abortSignal);
918
+ break;
835
919
  case 'grep_search':
836
- return grepSearch(workspaceRoot, args.pattern, args.fileGlob, abortSignal);
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
- return traceDependencies(workspaceRoot, args.filePath, args.direction, args.maxDepth);
953
+ result = await traceDependencies(workspaceRoot, args.filePath, args.direction, args.maxDepth);
954
+ break;
839
955
  case 'find_recent_changes':
840
- return findRecentChanges(workspaceRoot, args.dirPath, args.minutes, args.maxDepth);
956
+ result = await findRecentChanges(workspaceRoot, args.dirPath, args.minutes, args.maxDepth);
957
+ break;
841
958
  default:
842
- return { output: '', error: `Unknown tool: "${toolName}"` };
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
  }
@@ -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>;