minovative-mind-cli 2.5.2 → 2.6.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.
Files changed (41) hide show
  1. package/README.md +29 -26
  2. package/dist/commands/chat.js +2 -2
  3. package/dist/services/agent/inputHandler.d.ts +9 -0
  4. package/dist/services/agent/inputHandler.js +34 -0
  5. package/dist/services/agent/slashCommands.js +105 -29
  6. package/dist/services/agent/syntaxAgent.d.ts +40 -0
  7. package/dist/services/agent/syntaxAgent.js +237 -23
  8. package/dist/services/agent/toolLoop.js +10 -1
  9. package/dist/services/agent/types.d.ts +1 -0
  10. package/dist/services/agent-tools.d.ts +156 -1
  11. package/dist/services/agent-tools.js +259 -67
  12. package/dist/services/agent.d.ts +74 -0
  13. package/dist/services/agent.js +193 -31
  14. package/dist/services/ai.d.ts +5 -0
  15. package/dist/services/ai.js +80 -87
  16. package/dist/services/chatHistoryService.d.ts +11 -0
  17. package/dist/services/chatHistoryService.js +20 -1
  18. package/dist/services/contextAgent.d.ts +1 -1
  19. package/dist/services/contextAgent.js +9 -29
  20. package/dist/services/orchestration/investigationAgent.d.ts +2 -1
  21. package/dist/services/orchestration/investigationAgent.js +7 -2
  22. package/dist/services/orchestration/investigationOrchestrator.d.ts +1 -1
  23. package/dist/services/orchestration/investigationOrchestrator.js +13 -2
  24. package/dist/services/orchestration/orchestrator.js +21 -4
  25. package/dist/services/orchestration/subAgent.d.ts +2 -1
  26. package/dist/services/orchestration/subAgent.js +12 -6
  27. package/dist/utils/analysisRunner.d.ts +27 -4
  28. package/dist/utils/analysisRunner.js +100 -20
  29. package/dist/utils/config.d.ts +2 -0
  30. package/dist/utils/config.js +2 -0
  31. package/dist/utils/fuzzyMatch.d.ts +32 -0
  32. package/dist/utils/fuzzyMatch.js +215 -27
  33. package/dist/utils/localSyntaxValidator.d.ts +2 -2
  34. package/dist/utils/localSyntaxValidator.js +280 -81
  35. package/dist/utils/performanceAuditor.d.ts +2 -7
  36. package/dist/utils/performanceAuditor.js +541 -89
  37. package/dist/utils/projectStorage.js +9 -0
  38. package/dist/utils/systemPrompts.d.ts +3 -2
  39. package/dist/utils/systemPrompts.js +29 -5
  40. package/oclif.manifest.json +2 -2
  41. package/package.json +1 -1
@@ -1,103 +1,302 @@
1
1
  import path from 'path';
2
+ /**
3
+ * Checks if file content contains placeholder comments indicating AI code truncation.
4
+ */
5
+ function isTruncated(content) {
6
+ const lines = content.split('\n');
7
+ const truncPattern = '^(/\\/|/\\*)\\s*(\\.\\.\\.\\s*$|\\.\\.\\.\\s*\\*\\/$|\\[?\\s*\\.\\.\\.\\s*(existing\\s*code|rest\\s*of\\s*(the\\s*)?(file|code|content|implementation)|remaining|omitted|unchanged))';
8
+ const truncRegex = new RegExp(truncPattern, 'i');
9
+ for (const line of lines) {
10
+ const trimmed = line.trim();
11
+ if (!trimmed)
12
+ continue;
13
+ if (truncRegex.test(trimmed)) {
14
+ return true;
15
+ }
16
+ }
17
+ return false;
18
+ }
2
19
  export function localValidate(filePath, content) {
3
20
  const ext = path.extname(filePath).toLowerCase();
4
- // Check for truncation markers
5
- if (content.includes('// ...') || content.includes('/* ... */')) {
21
+ // 1. Check JSON files using native JSON parser
22
+ if (ext === '.json') {
23
+ try {
24
+ JSON.parse(content);
25
+ return { isValid: true };
26
+ }
27
+ catch (err) {
28
+ return {
29
+ isValid: false,
30
+ error: 'Invalid JSON syntax: ' + err.message,
31
+ };
32
+ }
33
+ }
34
+ // 2. Check for truncation markers
35
+ if (isTruncated(content)) {
6
36
  return {
7
37
  isValid: false,
8
38
  error: 'File appears to be truncated (contains placeholder comments)',
9
39
  };
10
40
  }
11
- // C-style languages
12
41
  const C_STYLE_EXTS = [
13
- '.ts', '.js', '.tsx', '.jsx', '.json', '.css', '.html',
14
- '.rs', '.go', '.java', '.cpp', '.c', '.h', '.cs', '.php', '.swift'
42
+ '.ts',
43
+ '.js',
44
+ '.tsx',
45
+ '.jsx',
46
+ '.css',
47
+ '.html',
48
+ '.rs',
49
+ '.go',
50
+ '.java',
51
+ '.cpp',
52
+ '.c',
53
+ '.h',
54
+ '.cs',
55
+ '.php',
56
+ '.swift',
15
57
  ];
16
- // Hash-style languages (only validate [] and ())
17
58
  const HASH_STYLE_EXTS = ['.py', '.rb', '.sh', '.yaml', '.yml'];
18
- if (C_STYLE_EXTS.includes(ext) || HASH_STYLE_EXTS.includes(ext)) {
19
- const stack = [];
20
- const pairs = {
21
- '{': '}',
22
- '[': ']',
23
- '(': ')',
24
- };
25
- let inString = false;
26
- let stringChar = '';
27
- let inSingleComment = false;
28
- let inMultiComment = false;
29
- const isHashStyle = HASH_STYLE_EXTS.includes(ext);
30
- for (let i = 0; i < content.length; i++) {
31
- const char = content[i];
32
- const nextChar = content[i + 1];
33
- // Handle comments
34
- if (!isHashStyle) {
35
- if (!inString && !inMultiComment && char === '/' && nextChar === '/') {
36
- inSingleComment = true;
37
- continue;
38
- }
39
- if (inSingleComment && char === '\n') {
40
- inSingleComment = false;
41
- continue;
42
- }
43
- if (!inString && !inSingleComment && char === '/' && nextChar === '*') {
44
- inMultiComment = true;
45
- continue;
46
- }
47
- if (inMultiComment && char === '*' && nextChar === '/') {
48
- inMultiComment = false;
49
- i++; // skip '/'
50
- continue;
51
- }
59
+ const isJsTs = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'].includes(ext);
60
+ const isCStyle = C_STYLE_EXTS.includes(ext);
61
+ const isHashStyle = HASH_STYLE_EXTS.includes(ext);
62
+ if (!isCStyle && !isHashStyle && !isJsTs) {
63
+ return { isValid: true };
64
+ }
65
+ const stack = [];
66
+ const pairs = {
67
+ '{': '}',
68
+ '[': ']',
69
+ '(': ')',
70
+ '${': '}',
71
+ };
72
+ let inSingleComment = false;
73
+ let inMultiComment = false;
74
+ let inString = false;
75
+ let stringChar = '';
76
+ let inTemplate = false;
77
+ let inRegex = false;
78
+ let inRegexCharClass = false;
79
+ // Track tokens to determine if '/' can start a regex literal
80
+ let lastToken = '';
81
+ let currentWord = '';
82
+ const EXPR_KEYWORDS = new Set([
83
+ 'return',
84
+ 'case',
85
+ 'typeof',
86
+ 'void',
87
+ 'delete',
88
+ 'yield',
89
+ 'await',
90
+ 'throw',
91
+ 'instanceof',
92
+ 'in',
93
+ 'of',
94
+ 'new',
95
+ 'else',
96
+ 'do',
97
+ 'tok',
98
+ ]);
99
+ const EXPR_PUNCT = new Set([
100
+ '(',
101
+ '[',
102
+ '{',
103
+ ';',
104
+ ',',
105
+ '=',
106
+ '+',
107
+ '-',
108
+ '*',
109
+ '%',
110
+ '&',
111
+ '|',
112
+ '^',
113
+ '!',
114
+ '~',
115
+ '?',
116
+ ':',
117
+ '<',
118
+ '>',
119
+ '/',
120
+ '=>',
121
+ '${',
122
+ ]);
123
+ const wordCharRegex = new RegExp('[a-zA-Z0-9_$]');
124
+ const alphaRegex = new RegExp('[a-zA-Z]');
125
+ for (let i = 0; i < content.length; i++) {
126
+ const char = content[i];
127
+ const nextChar = content[i + 1];
128
+ // --- 1. SINGLE LINE COMMENT ---
129
+ if (inSingleComment) {
130
+ if (char === '\n') {
131
+ inSingleComment = false;
52
132
  }
53
- else {
54
- // Hash-style comment: #
55
- if (!inString && char === '#') {
56
- inSingleComment = true;
57
- continue;
58
- }
59
- if (inSingleComment && char === '\n') {
60
- inSingleComment = false;
61
- continue;
62
- }
133
+ continue;
134
+ }
135
+ // --- 2. MULTI LINE COMMENT ---
136
+ if (inMultiComment) {
137
+ if (char === '*' && nextChar === '/') {
138
+ inMultiComment = false;
139
+ i++; // skip '/'
63
140
  }
64
- // Handle strings
65
- if (!inSingleComment && !inMultiComment) {
66
- if ((char === '"' || char === "'" || char === '`') && content[i - 1] !== '\\') {
67
- if (!inString) {
68
- inString = true;
69
- stringChar = char;
70
- }
71
- else if (char === stringChar) {
72
- inString = false;
73
- }
74
- }
141
+ continue;
142
+ }
143
+ // --- 3. STRING LITERAL ('...' or "...") ---
144
+ if (inString) {
145
+ if (char === '\\') {
146
+ i++; // skip escaped char
147
+ continue;
148
+ }
149
+ if (char === stringChar) {
150
+ inString = false;
151
+ stringChar = '';
75
152
  }
76
- if (inString || inSingleComment || inMultiComment)
153
+ continue;
154
+ }
155
+ // --- 4. TEMPLATE LITERAL (`...`) ---
156
+ if (inTemplate) {
157
+ if (char === '\\') {
158
+ i++; // skip escaped char
159
+ continue;
160
+ }
161
+ if (char === '$' && nextChar === '{') {
162
+ // Enter template expression ${...}
163
+ stack.push('${');
164
+ inTemplate = false;
165
+ i++; // skip '{'
166
+ lastToken = '${';
167
+ currentWord = '';
77
168
  continue;
78
- if (['{', '[', '('].includes(char)) {
79
- if (isHashStyle && char === '{')
80
- continue;
81
- stack.push(char);
82
- }
83
- else if (['}', ']', ')'].includes(char)) {
84
- if (isHashStyle && char === '}')
85
- continue;
86
- const last = stack.pop();
87
- if (!last || pairs[last] !== char) {
88
- return {
89
- isValid: false,
90
- error: `Unbalanced character '${char}' at position ${i}`,
91
- };
169
+ }
170
+ if (char === '`') {
171
+ inTemplate = false;
172
+ }
173
+ continue;
174
+ }
175
+ // --- 5. REGEX LITERAL (/.../) ---
176
+ if (inRegex) {
177
+ if (char === '\\') {
178
+ i++; // skip escaped char
179
+ continue;
180
+ }
181
+ if (char === '[') {
182
+ inRegexCharClass = true;
183
+ continue;
184
+ }
185
+ if (char === ']') {
186
+ inRegexCharClass = false;
187
+ continue;
188
+ }
189
+ if (char === '/' && !inRegexCharClass) {
190
+ inRegex = false;
191
+ // Skip regex flags (e.g. /foo/gim)
192
+ while (i + 1 < content.length && alphaRegex.test(content[i + 1])) {
193
+ i++;
92
194
  }
93
195
  }
196
+ continue;
94
197
  }
95
- if (stack.length > 0) {
96
- return {
97
- isValid: false,
98
- error: `Unclosed character '${stack[stack.length - 1]}'`,
99
- };
198
+ // --- 6. NOT IN STRING / COMMENT / TEMPLATE / REGEX ---
199
+ // Check for comment starts
200
+ if (!isHashStyle) {
201
+ if (char === '/' && nextChar === '/') {
202
+ inSingleComment = true;
203
+ i++; // skip second '/'
204
+ continue;
205
+ }
206
+ if (char === '/' && nextChar === '*') {
207
+ inMultiComment = true;
208
+ i++; // skip '*'
209
+ continue;
210
+ }
211
+ }
212
+ else {
213
+ if (char === '#') {
214
+ inSingleComment = true;
215
+ continue;
216
+ }
217
+ }
218
+ // Check for string starts (' or ")
219
+ if (char === '"' || char === "'") {
220
+ inString = true;
221
+ stringChar = char;
222
+ continue;
223
+ }
224
+ // Check for template literal start (`)
225
+ if (isJsTs && char === '`') {
226
+ inTemplate = true;
227
+ continue;
228
+ }
229
+ // Check for regex literal start
230
+ if (isJsTs && char === '/') {
231
+ // Determine if '/' starts a regex or is a division operator
232
+ const prevToken = currentWord || lastToken;
233
+ const isExpr = !prevToken || EXPR_KEYWORDS.has(prevToken) || EXPR_PUNCT.has(prevToken);
234
+ if (isExpr) {
235
+ inRegex = true;
236
+ inRegexCharClass = false;
237
+ currentWord = '';
238
+ lastToken = '/';
239
+ continue;
240
+ }
241
+ }
242
+ // Update lastToken / currentWord tracking
243
+ if (char === ' ' || char === '\t' || char === '\n' || char === '\r') {
244
+ if (currentWord) {
245
+ lastToken = currentWord;
246
+ currentWord = '';
247
+ }
100
248
  }
249
+ else if (wordCharRegex.test(char)) {
250
+ currentWord += char;
251
+ }
252
+ else {
253
+ if (currentWord) {
254
+ lastToken = currentWord;
255
+ currentWord = '';
256
+ }
257
+ lastToken = char;
258
+ }
259
+ // --- 7. BRACKET MATCHING ---
260
+ if (['{', '[', '('].includes(char)) {
261
+ if (isHashStyle && char === '{')
262
+ continue;
263
+ stack.push(char);
264
+ }
265
+ else if (['}', ']', ')'].includes(char)) {
266
+ if (isHashStyle && char === '}')
267
+ continue;
268
+ const last = stack.pop();
269
+ if (!last || pairs[last] !== char) {
270
+ return {
271
+ isValid: false,
272
+ error: "Unbalanced character '" + char + "' at position " + i,
273
+ };
274
+ }
275
+ // If we popped a '${' template expression delimiter, return to template literal mode
276
+ if (last === '${') {
277
+ inTemplate = true;
278
+ }
279
+ }
280
+ }
281
+ // Final check for unclosed delimiters or unclosed comments/strings/regex
282
+ if (stack.length > 0) {
283
+ const unclosed = stack[stack.length - 1];
284
+ return {
285
+ isValid: false,
286
+ error: "Unclosed character '" + unclosed + "'",
287
+ };
288
+ }
289
+ if (inMultiComment) {
290
+ return { isValid: false, error: 'Unclosed multi-line comment' };
291
+ }
292
+ if (inString) {
293
+ return { isValid: false, error: 'Unclosed string literal' };
294
+ }
295
+ if (inTemplate) {
296
+ return { isValid: false, error: 'Unclosed template literal' };
297
+ }
298
+ if (inRegex) {
299
+ return { isValid: false, error: 'Unclosed regex literal' };
101
300
  }
102
301
  return { isValid: true };
103
302
  }
@@ -20,10 +20,7 @@ export declare function isAuditableFile(filePath: string): boolean;
20
20
  /**
21
21
  * Scans source code for performance anti-patterns using language-aware
22
22
  * regex-based heuristics. Returns structured findings grouped by severity.
23
- *
24
- * This function is designed to be called inline during the verification
25
- * phase — it's synchronous, zero-dependency, and executes in <50ms on
26
- * files up to 10,000 lines.
23
+ * Supports comment suppression directives (perf-ignore).
27
24
  *
28
25
  * @param content - The raw source code string to audit.
29
26
  * @param filePath - The file path (used for language detection via extension).
@@ -31,12 +28,10 @@ export declare function isAuditableFile(filePath: string): boolean;
31
28
  */
32
29
  export declare function auditFilePerformance(content: string, filePath: string): PerfAuditResult;
33
30
  /**
34
- * Formats audit findings for beautiful terminal display using picocolors.
35
- * Used for non-blocking warnings shown to the user after verification.
31
+ * Formats audit findings for terminal display using picocolors.
36
32
  */
37
33
  export declare function formatAuditForTerminal(results: PerfAuditResult[]): string;
38
34
  /**
39
35
  * Formats audit findings into a structured prompt for the AI auto-correction loop.
40
- * Only includes ERROR-severity findings (warnings and info are non-blocking).
41
36
  */
42
37
  export declare function formatAuditForModel(results: PerfAuditResult[]): string;