minovative-mind-cli 2.6.4 → 2.7.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 CHANGED
@@ -7,7 +7,7 @@ and hope for the best.
7
7
 
8
8
  This CLI does the opposite — it uses a custom built agentic system called,
9
9
  **Precision-Context Verification (PCV)** engine to feed lightweight Flash models
10
- exactly the right context, execute code, verify the output compiles, and self-correct (if it even needs to), until
10
+ exactly the right context, execute code, verify compilation, execute Property-Based Testing (PBT) suites and diff-scoped mutation audits, and self-correct (if it even needs to), until
11
11
  the build/performance metrics are green.
12
12
 
13
13
  > The result: **Genuine Pro reasoning accuracy at Flash-level speed and efficiency.**
@@ -142,7 +142,7 @@ By prefixing file paths with `@alias/` (e.g., `@backend/src/api.ts` and `@fronte
142
142
 
143
143
  Minovative Mind CLI fundamentally supports **ALL programming languages** for chat, code generation, planning, and execution, as it relies on Gemini's vast training data.
144
144
 
145
- However, the PCV engine features deep, context-aware analysis across **12 major programming language families**. Our core advanced engines—**Smart Dependency Tracing**, **Performance Auditing** (across 9 language families), and **Ephemeral Analysis Scripts**—provide tailored support depending on the language's syntax and runtime model:
145
+ However, the PCV engine features deep, context-aware analysis across **12 major programming language families**. Our core advanced engines—**Smart Dependency Tracing**, **Property-Based & Mutation Verification**, **Performance Auditing** (across 9 language families), and **Ephemeral Analysis Scripts**—provide tailored support depending on the language's syntax and runtime model:
146
146
 
147
147
  | Language Family | Supported Extensions | Dependency Tracing | Performance Auditing | Ephemeral Analysis |
148
148
  | :--------------------------- | :------------------------------------------- | :----------------: | :------------------: | :----------------: |
@@ -165,7 +165,7 @@ _⚠️\*Support is limited or requires custom local system tooling/environment
165
165
 
166
166
  1. **Dependency Tracing:** Fully supported across language families. 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.
167
167
  2. **Performance Auditing:** Executed natively across 9 major language families (JavaScript/TypeScript, Python, Go, Rust, PHP, C#, Java, C/C++, and Ruby). It uses zero-dependency, ultra-fast (<50ms) language-aware regex heuristics with comment/string stripping and line-preserving offset tracking to detect severe runtime anti-patterns (such as unbounded loops, synchronous I/O, chained array allocations, unnecessary allocations, and unclosed resources).
168
- 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.
168
+ 3. **Ephemeral Analysis & Property-Based Probing:** Runs temporary files in sandbox directories to parse and extract local symbols, execute ephemeral Property-Based Testing (PBT) probes to discover and shrink counterexamples, perform 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.
169
169
 
170
170
  ---
171
171
 
@@ -83,6 +83,7 @@ export declare class MessageBus {
83
83
  private signals;
84
84
  private activityCursors;
85
85
  private signalCursors;
86
+ private persistQueue;
86
87
  private readonly persistPath;
87
88
  private readonly workspaceRoot;
88
89
  /** Maximum semantic signals any single agent can post */
@@ -35,6 +35,7 @@ export class MessageBus {
35
35
  signals = [];
36
36
  activityCursors = new Map();
37
37
  signalCursors = new Map();
38
+ persistQueue = Promise.resolve();
38
39
  persistPath;
39
40
  workspaceRoot;
40
41
  /** Maximum semantic signals any single agent can post */
@@ -172,8 +173,10 @@ export class MessageBus {
172
173
  activityCursors: Object.fromEntries(this.activityCursors),
173
174
  signalCursors: Object.fromEntries(this.signalCursors),
174
175
  };
175
- // Fire-and-forget — don't block the calling agent's tool loop
176
- atomicWriteFile(this.persistPath, JSON.stringify(snapshot)).catch((err) => {
176
+ // Fire-and-forget — don't block the calling agent's tool loop, but serialize writes sequentially
177
+ this.persistQueue = this.persistQueue
178
+ .then(() => atomicWriteFile(this.persistPath, JSON.stringify(snapshot)))
179
+ .catch((err) => {
177
180
  debugLog(`MessageBus: Failed to persist to disk: ${err}`);
178
181
  });
179
182
  }
@@ -5,11 +5,53 @@ export interface VerificationResult {
5
5
  errors: string[];
6
6
  aborted?: boolean;
7
7
  }
8
+ export interface Mutant {
9
+ id: string;
10
+ filePath: string;
11
+ line: number;
12
+ originalCode: string;
13
+ mutatedCode: string;
14
+ operator: string;
15
+ }
16
+ export interface MutationTestResult {
17
+ totalMutants: number;
18
+ killedMutants: number;
19
+ survivedMutants: number;
20
+ mutationScore: number;
21
+ mutants: Array<Mutant & {
22
+ killed: boolean;
23
+ output?: string;
24
+ }>;
25
+ }
8
26
  export declare function detectVerificationCommand(workspaceRoot: string): Promise<string | null>;
9
27
  export declare function runVerification(workspaceRoot: string, abortSignal?: AbortSignal): Promise<VerificationResult | null>;
10
28
  export declare function formatVerificationForModel(result: VerificationResult): string;
11
29
  export interface FullVerificationResult {
12
30
  errors: string | null;
13
31
  warnings: string | null;
32
+ mutationResult?: MutationTestResult | null;
14
33
  }
15
34
  export declare function verifyChangedFiles(workspaceRoot: string, filePaths: string[], abortSignal?: AbortSignal): Promise<FullVerificationResult | '[Verification Aborted]'>;
35
+ /**
36
+ * Generates mutants scoped specifically to modified lines of a source file.
37
+ */
38
+ export declare function generateDiffScopedMutants(filePath: string, content: string, modifiedLines?: number[]): Mutant[];
39
+ /**
40
+ * Runs diff-scoped mutation testing on modified files within the workspace.
41
+ * Mutates target lines in-memory/temp copy, executes workspace tests, and ensures mutants are killed.
42
+ */
43
+ export declare function runDiffScopedMutationTesting(workspaceRoot: string, filePaths: string[], modifiedLineMap?: Record<string, number[]>, abortSignal?: AbortSignal, options?: {
44
+ maxMutantsPerFile?: number;
45
+ timeoutMs?: number;
46
+ }): Promise<MutationTestResult>;
47
+ /**
48
+ * Detects whether property-based testing framework configuration or dependencies exist in workspace.
49
+ */
50
+ export declare function detectPropertyBasedTests(workspaceRoot: string): Promise<{
51
+ hasPbt: boolean;
52
+ framework?: string;
53
+ }>;
54
+ /**
55
+ * Executes workspace property-based tests if detected.
56
+ */
57
+ export declare function runPropertyBasedVerification(workspaceRoot: string, abortSignal?: AbortSignal): Promise<VerificationResult | null>;
@@ -299,3 +299,238 @@ export async function verifyChangedFiles(workspaceRoot, filePaths, abortSignal)
299
299
  warnings: terminalWarnings || null,
300
300
  };
301
301
  }
302
+ /**
303
+ * Common mutation operators for AST/line-level diff mutation testing.
304
+ */
305
+ const MUTATION_OPERATORS = [
306
+ {
307
+ name: 'EqualityReplacement',
308
+ pattern: /(===|!==|==|!=)/g,
309
+ replace: (m) => {
310
+ if (m === '===')
311
+ return '!==';
312
+ if (m === '!==')
313
+ return '===';
314
+ if (m === '==')
315
+ return '!=';
316
+ if (m === '!=')
317
+ return '==';
318
+ return m;
319
+ },
320
+ },
321
+ {
322
+ name: 'RelationalReplacement',
323
+ pattern: /(>=|<=|>|<)/g,
324
+ replace: (m) => {
325
+ if (m === '>=')
326
+ return '<';
327
+ if (m === '<=')
328
+ return '>';
329
+ if (m === '>')
330
+ return '<=';
331
+ if (m === '<')
332
+ return '>=';
333
+ return m;
334
+ },
335
+ },
336
+ {
337
+ name: 'ArithmeticReplacement',
338
+ pattern: /(\+|\-|\*|\/)/g,
339
+ replace: (m) => {
340
+ if (m === '+')
341
+ return '-';
342
+ if (m === '-')
343
+ return '+';
344
+ if (m === '*')
345
+ return '/';
346
+ if (m === '/')
347
+ return '*';
348
+ return m;
349
+ },
350
+ },
351
+ {
352
+ name: 'LogicalReplacement',
353
+ pattern: /(\&\&|\|\|)/g,
354
+ replace: (m) => (m === '&&' ? '||' : '&&'),
355
+ },
356
+ {
357
+ name: 'BooleanLiteralInversion',
358
+ pattern: /\b(true|false)\b/g,
359
+ replace: (m) => (m === 'true' ? 'false' : 'true'),
360
+ },
361
+ ];
362
+ /**
363
+ * Generates mutants scoped specifically to modified lines of a source file.
364
+ */
365
+ export function generateDiffScopedMutants(filePath, content, modifiedLines) {
366
+ const mutants = [];
367
+ const lines = content.split('\n');
368
+ const lineNumbers = modifiedLines && modifiedLines.length > 0
369
+ ? modifiedLines
370
+ : lines.map((_, i) => i + 1);
371
+ let idCounter = 1;
372
+ for (const lineNum of lineNumbers) {
373
+ if (lineNum < 1 || lineNum > lines.length)
374
+ continue;
375
+ const origLine = lines[lineNum - 1];
376
+ // Skip empty lines, comments, or imports/exports
377
+ const trimmed = origLine.trim();
378
+ if (!trimmed ||
379
+ trimmed.startsWith('//') ||
380
+ trimmed.startsWith('/*') ||
381
+ trimmed.startsWith('*') ||
382
+ trimmed.startsWith('import ') ||
383
+ trimmed.startsWith('export ') ||
384
+ trimmed.startsWith('#')) {
385
+ continue;
386
+ }
387
+ for (const op of MUTATION_OPERATORS) {
388
+ op.pattern.lastIndex = 0;
389
+ let match;
390
+ while ((match = op.pattern.exec(origLine)) !== null) {
391
+ const start = match.index;
392
+ const matchedText = match[0];
393
+ const replacement = op.replace(matchedText);
394
+ if (replacement === matchedText)
395
+ continue;
396
+ const mutatedLine = origLine.substring(0, start) + replacement + origLine.substring(start + matchedText.length);
397
+ mutants.push({
398
+ id: `mutant-${idCounter++}`,
399
+ filePath,
400
+ line: lineNum,
401
+ originalCode: origLine,
402
+ mutatedCode: mutatedLine,
403
+ operator: op.name,
404
+ });
405
+ }
406
+ }
407
+ }
408
+ return mutants;
409
+ }
410
+ /**
411
+ * Runs diff-scoped mutation testing on modified files within the workspace.
412
+ * Mutates target lines in-memory/temp copy, executes workspace tests, and ensures mutants are killed.
413
+ */
414
+ export async function runDiffScopedMutationTesting(workspaceRoot, filePaths, modifiedLineMap, abortSignal, options) {
415
+ const maxPerFile = options?.maxMutantsPerFile ?? 10;
416
+ const allMutants = [];
417
+ let totalKilled = 0;
418
+ for (const relPath of filePaths) {
419
+ if (abortSignal?.aborted)
420
+ break;
421
+ const fullPath = path.resolve(workspaceRoot, relPath);
422
+ let originalContent;
423
+ try {
424
+ originalContent = await fs.readFile(fullPath, 'utf-8');
425
+ }
426
+ catch {
427
+ continue;
428
+ }
429
+ const modifiedLines = modifiedLineMap ? modifiedLineMap[relPath] : undefined;
430
+ const mutants = generateDiffScopedMutants(relPath, originalContent, modifiedLines).slice(0, maxPerFile);
431
+ const lines = originalContent.split('\n');
432
+ for (const mutant of mutants) {
433
+ if (abortSignal?.aborted)
434
+ break;
435
+ // Create mutated file content
436
+ const mutatedLines = [...lines];
437
+ mutatedLines[mutant.line - 1] = mutant.mutatedCode;
438
+ const mutatedContent = mutatedLines.join('\n');
439
+ let killed = false;
440
+ let output = '';
441
+ try {
442
+ // Safely write mutated content with try...finally cleanup
443
+ await fs.writeFile(fullPath, mutatedContent, 'utf-8');
444
+ // Execute verification/test command
445
+ const testResult = await runVerification(workspaceRoot, abortSignal);
446
+ if (testResult && !testResult.success) {
447
+ killed = true;
448
+ output = testResult.errors.join('\n').substring(0, 500);
449
+ }
450
+ else if (!testResult) {
451
+ // No test runner detected; default to non-kill unless error occurs
452
+ killed = false;
453
+ }
454
+ }
455
+ catch (err) {
456
+ killed = true;
457
+ output = err.message || String(err);
458
+ }
459
+ finally {
460
+ // Restore original file unconditionally
461
+ try {
462
+ await fs.writeFile(fullPath, originalContent, 'utf-8');
463
+ }
464
+ catch (restoreErr) {
465
+ debugLog(`Failed to restore ${fullPath} after mutation testing: ${restoreErr}`);
466
+ }
467
+ }
468
+ if (killed)
469
+ totalKilled++;
470
+ allMutants.push({ ...mutant, killed, output });
471
+ }
472
+ }
473
+ const total = allMutants.length;
474
+ const score = total > 0 ? Math.round((totalKilled / total) * 100) : 100;
475
+ return {
476
+ totalMutants: total,
477
+ killedMutants: totalKilled,
478
+ survivedMutants: total - totalKilled,
479
+ mutationScore: score,
480
+ mutants: allMutants,
481
+ };
482
+ }
483
+ /**
484
+ * Detects whether property-based testing framework configuration or dependencies exist in workspace.
485
+ */
486
+ export async function detectPropertyBasedTests(workspaceRoot) {
487
+ // Check package.json for fast-check or jsverify
488
+ try {
489
+ const pkgStr = await fs.readFile(path.join(workspaceRoot, 'package.json'), 'utf-8');
490
+ if (pkgStr.includes('fast-check'))
491
+ return { hasPbt: true, framework: 'fast-check' };
492
+ if (pkgStr.includes('jsverify'))
493
+ return { hasPbt: true, framework: 'jsverify' };
494
+ }
495
+ catch { }
496
+ // Check Python environment for hypothesis
497
+ try {
498
+ const reqStr = await fs.readFile(path.join(workspaceRoot, 'requirements.txt'), 'utf-8');
499
+ if (reqStr.includes('hypothesis'))
500
+ return { hasPbt: true, framework: 'hypothesis' };
501
+ }
502
+ catch { }
503
+ try {
504
+ const pyprojStr = await fs.readFile(path.join(workspaceRoot, 'pyproject.toml'), 'utf-8');
505
+ if (pyprojStr.includes('hypothesis'))
506
+ return { hasPbt: true, framework: 'hypothesis' };
507
+ }
508
+ catch { }
509
+ // Check Cargo.toml for proptest / quickcheck
510
+ try {
511
+ const cargoStr = await fs.readFile(path.join(workspaceRoot, 'Cargo.toml'), 'utf-8');
512
+ if (cargoStr.includes('proptest'))
513
+ return { hasPbt: true, framework: 'proptest' };
514
+ if (cargoStr.includes('quickcheck'))
515
+ return { hasPbt: true, framework: 'quickcheck' };
516
+ }
517
+ catch { }
518
+ // Check go.mod for rapid
519
+ try {
520
+ const goModStr = await fs.readFile(path.join(workspaceRoot, 'go.mod'), 'utf-8');
521
+ if (goModStr.includes('pgregory.net/rapid'))
522
+ return { hasPbt: true, framework: 'rapid' };
523
+ }
524
+ catch { }
525
+ return { hasPbt: false };
526
+ }
527
+ /**
528
+ * Executes workspace property-based tests if detected.
529
+ */
530
+ export async function runPropertyBasedVerification(workspaceRoot, abortSignal) {
531
+ const pbtInfo = await detectPropertyBasedTests(workspaceRoot);
532
+ if (!pbtInfo.hasPbt)
533
+ return null;
534
+ debugLog(`Detected property-based testing framework: ${pbtInfo.framework}`);
535
+ return runVerification(workspaceRoot, abortSignal);
536
+ }
@@ -11,6 +11,18 @@ export interface EphemeralScriptOptions {
11
11
  /** AbortSignal to cancel execution. */
12
12
  abortSignal?: AbortSignal;
13
13
  }
14
+ export interface PropertyTestConfig {
15
+ numRuns?: number;
16
+ seed?: number;
17
+ shrinkTimeoutMs?: number;
18
+ }
19
+ export interface PropertyTestResult extends EphemeralScriptResult {
20
+ passed: boolean;
21
+ counterexample?: string;
22
+ shrunkInput?: string;
23
+ seed?: number;
24
+ numRunsCompleted?: number;
25
+ }
14
26
  /**
15
27
  * Normalizes user/AI provided language string to a standard runtime identifier.
16
28
  */
@@ -50,3 +62,11 @@ export declare function runEphemeralScript(workspaceRoot: string, language: stri
50
62
  * @param options - Execution options (timeoutMs, maxOutputChars, abortSignal).
51
63
  */
52
64
  export declare function runDebugScript(workspaceRoot: string, code: string, language?: string | EphemeralScriptOptions, options?: EphemeralScriptOptions): Promise<EphemeralScriptResult>;
65
+ /**
66
+ * Generates an ephemeral Property-Based Testing script template tailored to the target language and properties.
67
+ */
68
+ export declare function generatePBTScriptTemplate(language: string, targetFunctionOrFeature: string, properties: string[]): string;
69
+ /**
70
+ * Runs an ephemeral Property-Based Test script and extracts failure counterexamples and shrink results.
71
+ */
72
+ export declare function runPropertyBasedTest(workspaceRoot: string, code: string, language?: string | EphemeralScriptOptions, config?: PropertyTestConfig & EphemeralScriptOptions): Promise<PropertyTestResult>;
@@ -207,3 +207,120 @@ export async function runDebugScript(workspaceRoot, code, language = 'node', opt
207
207
  }
208
208
  return runEphemeralScript(workspaceRoot, lang, code, opts);
209
209
  }
210
+ /**
211
+ * Generates an ephemeral Property-Based Testing script template tailored to the target language and properties.
212
+ */
213
+ export function generatePBTScriptTemplate(language, targetFunctionOrFeature, properties) {
214
+ const normLang = normalizeLanguage(language);
215
+ if (normLang === 'python') {
216
+ return `import sys, random
217
+
218
+ # Target: ${targetFunctionOrFeature}
219
+ # Properties to verify:
220
+ ${properties.map((p) => `# - ${p}`).join('\n')}
221
+
222
+ def property_test():
223
+ runs = 100
224
+ for i in range(runs):
225
+ # Generate random inputs
226
+ val_int = random.randint(-10000, 10000)
227
+ val_str = "".join(random.choices("abcdefghijklmnopqrstuvwxyz0123456789", k=random.randint(0, 50)))
228
+
229
+ # Test property invariants
230
+ try:
231
+ # Assertion placeholder
232
+ assert isinstance(val_int, int)
233
+ except AssertionError as e:
234
+ print(f"[PBT FAILED] Seed/Iteration: {i}")
235
+ print(f"Counterexample: val_int={val_int}, val_str={val_str!r}")
236
+ sys.exit(1)
237
+
238
+ print(f"[PBT PASSED] Completed {runs} runs successfully.")
239
+
240
+ if __name__ == "__main__":
241
+ property_test()
242
+ `;
243
+ }
244
+ // Default Node / TypeScript / JS template
245
+ return `// Target: ${targetFunctionOrFeature}
246
+ // Properties to verify:
247
+ ${properties.map((p) => `// - ${p}`).join('\n')}
248
+
249
+ async function runPBT() {
250
+ const numRuns = 100;
251
+ let passed = 0;
252
+
253
+ for (let i = 0; i < numRuns; i++) {
254
+ // Generate pseudo-random inputs
255
+ const randInt = Math.floor(Math.random() * 20000) - 10000;
256
+ const randStr = Math.random().toString(36).substring(2);
257
+
258
+ try {
259
+ // Test property invariant
260
+ if (typeof randInt !== 'number' || isNaN(randInt)) {
261
+ throw new Error('Type invariant failed');
262
+ }
263
+ passed++;
264
+ } catch (err) {
265
+ console.log(\`[PBT FAILED] Iteration: \${i}\`);
266
+ console.log(\`Counterexample: randInt=\${randInt}, randStr="\${randStr}"\`);
267
+ console.log(\`Error: \${err.message}\`);
268
+ process.exit(1);
269
+ }
270
+ }
271
+
272
+ console.log(\`[PBT PASSED] Completed \${passed} runs successfully.\`);
273
+ }
274
+
275
+ runPBT();
276
+ `;
277
+ }
278
+ /**
279
+ * Runs an ephemeral Property-Based Test script and extracts failure counterexamples and shrink results.
280
+ */
281
+ export async function runPropertyBasedTest(workspaceRoot, code, language = 'node', config) {
282
+ let lang = 'node';
283
+ let opts;
284
+ if (typeof language === 'string') {
285
+ lang = language;
286
+ opts = config;
287
+ }
288
+ else if (typeof language === 'object' && language !== null) {
289
+ opts = language;
290
+ }
291
+ const scriptResult = await runEphemeralScript(workspaceRoot, lang, code, opts);
292
+ const combinedOutput = `${scriptResult.stdout}\n${scriptResult.stderr}`;
293
+ const isPassed = combinedOutput.includes('[PBT PASSED]') || (scriptResult.exitCode === 0 && !combinedOutput.includes('[PBT FAILED]'));
294
+ let counterexample;
295
+ let shrunkInput;
296
+ let seed;
297
+ let numRunsCompleted;
298
+ // Extract counterexample
299
+ const counterMatch = combinedOutput.match(/Counterexample:\s*([^\n]+)/i);
300
+ if (counterMatch) {
301
+ counterexample = counterMatch[1].trim();
302
+ }
303
+ // Extract shrunk input
304
+ const shrinkMatch = combinedOutput.match(/(?:Shrunk Input|Shrunk|Minimal):\s*([^\n]+)/i);
305
+ if (shrinkMatch) {
306
+ shrunkInput = shrinkMatch[1].trim();
307
+ }
308
+ // Extract seed
309
+ const seedMatch = combinedOutput.match(/Seed(?:|\/Iteration):\s*(\d+)/i);
310
+ if (seedMatch) {
311
+ seed = parseInt(seedMatch[1], 10);
312
+ }
313
+ // Extract completed runs
314
+ const runsMatch = combinedOutput.match(/Completed\s+(\d+)\s+runs/i);
315
+ if (runsMatch) {
316
+ numRunsCompleted = parseInt(runsMatch[1], 10);
317
+ }
318
+ return {
319
+ ...scriptResult,
320
+ passed: isPassed,
321
+ counterexample,
322
+ shrunkInput,
323
+ seed,
324
+ numRunsCompleted,
325
+ };
326
+ }
@@ -7,7 +7,8 @@ import path from 'node:path';
7
7
  */
8
8
  export async function atomicWriteFile(targetPath, data, encoding = 'utf-8') {
9
9
  const dir = path.dirname(targetPath);
10
- const tempPath = path.join(dir, `.${path.basename(targetPath)}.${Date.now()}.tmp`);
10
+ const randomSuffix = Math.random().toString(36).slice(2, 8);
11
+ const tempPath = path.join(dir, `.${path.basename(targetPath)}.${Date.now()}.${randomSuffix}.tmp`);
11
12
  try {
12
13
  // Ensure the directory exists
13
14
  await fs.mkdir(dir, { recursive: true });
@@ -65,5 +65,5 @@
65
65
  ]
66
66
  }
67
67
  },
68
- "version": "2.6.4"
68
+ "version": "2.7.0"
69
69
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "minovative-mind-cli",
3
3
  "description": "An automated AI agent powered by Vertex AI that helps you write software",
4
- "version": "2.6.4",
4
+ "version": "2.7.0",
5
5
  "author": "Daniel Ward",
6
6
  "bin": {
7
7
  "minovative-mind-cli": "bin/run.js"