minovative-mind-cli 2.6.4 → 2.8.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:** 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
 
@@ -223,20 +223,27 @@ export async function handleSlashCommand(command, context) {
223
223
  try {
224
224
  const { getInvestigationCacheStats } = await import('../orchestration/investigationCache.js');
225
225
  const invStats = getInvestigationCacheStats(workspaceRoot);
226
- const memBankSizeKB = (invStats.sizeBytes / 1024).toFixed(1);
227
- console.log(`${pc.bold('Memory Bank:')} ${pc.cyan(`${invStats.entries} cached investigations (${memBankSizeKB} KB / 5 MB)`)}`);
226
+ const formatBytesToSize = (bytes) => {
227
+ if (bytes >= 1024 * 1024) {
228
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
229
+ }
230
+ return `${(bytes / 1024).toFixed(1)} KB`;
231
+ };
232
+ const memBankSizeStr = formatBytesToSize(invStats.sizeBytes);
233
+ console.log(`${pc.bold('Memory Bank:')} ${pc.cyan(`${invStats.entries} cached investigations (${memBankSizeStr} / 5 MB)`)}`);
228
234
  const { readCache } = await import('../../utils/projectStorage.js');
229
235
  const contextCache = readCache(workspaceRoot, 'context_cache.json');
230
236
  const contextEntries = contextCache ? Object.keys(contextCache).length : 0;
231
- let contextSizeKB = '0.0';
237
+ let contextSizeBytes = 0;
232
238
  try {
233
239
  const fs = await import('node:fs');
234
240
  const path = await import('node:path');
235
241
  const stat = await fs.promises.stat(path.join(workspaceRoot, '.minovativemind', 'context_cache.json'));
236
- contextSizeKB = (stat.size / 1024).toFixed(1);
242
+ contextSizeBytes = stat.size;
237
243
  }
238
244
  catch (e) { }
239
- console.log(`${pc.bold('Context Cache:')} ${pc.cyan(`${contextEntries} file summaries (${contextSizeKB} KB / 5 MB)`)}`);
245
+ const contextSizeStr = formatBytesToSize(contextSizeBytes);
246
+ console.log(`${pc.bold('Context Cache:')} ${pc.cyan(`${contextEntries} file summaries (${contextSizeStr} / 5 MB)`)}`);
240
247
  }
241
248
  catch (e) {
242
249
  // Ignored if cache stats fail
@@ -1,3 +1,4 @@
1
+ import path from 'path';
1
2
  import * as p from '@clack/prompts';
2
3
  import pc from 'picocolors';
3
4
  import { debugLog } from '../../utils/logger.js';
@@ -24,6 +25,9 @@ const TOOL_ICONS = {
24
25
  find_dependencies: '🔗',
25
26
  run_analysis_script: '🔬',
26
27
  run_debug_script: '🧪',
28
+ run_fuzz_probe: '🎯',
29
+ check_heap_delta: '📊',
30
+ check_behavioral_drift: '🔀',
27
31
  };
28
32
  /**
29
33
  * Human-readable translations for tool actions.
@@ -41,6 +45,9 @@ const TOOL_LABELS = {
41
45
  find_dependencies: 'Tracing dependencies',
42
46
  run_analysis_script: 'Analyzing workspace',
43
47
  run_debug_script: 'Executing debug/validation script',
48
+ run_fuzz_probe: 'Executing fuzz testing probe',
49
+ check_heap_delta: 'Inspecting memory heap delta',
50
+ check_behavioral_drift: 'Comparing behavioral drift',
44
51
  };
45
52
  // ─── Helpers ─────────────────────────────────────────────────────────
46
53
  /**
@@ -52,8 +59,20 @@ const TOOL_LABELS = {
52
59
  * @returns A fully colorized and formatted ANSI console string.
53
60
  */
54
61
  export function formatToolCall(name, args) {
55
- const icon = TOOL_ICONS[name] ?? '🔧';
56
- const label = TOOL_LABELS[name] ?? name;
62
+ let icon = TOOL_ICONS[name] ?? '🔧';
63
+ let label = TOOL_LABELS[name] ?? name;
64
+ if (name === 'rename_file') {
65
+ const src = String(args.sourcePath ?? '');
66
+ const tgt = String(args.targetPath ?? '');
67
+ if (src && tgt && path.dirname(src) === path.dirname(tgt)) {
68
+ label = 'Renaming file';
69
+ icon = '🏷️';
70
+ }
71
+ else {
72
+ label = 'Moving file';
73
+ icon = '🚚';
74
+ }
75
+ }
57
76
  const formatPath = (path) => pc.cyan(path);
58
77
  const argsMap = {
59
78
  read_file: () => {
@@ -86,6 +105,37 @@ export function formatToolCall(name, args) {
86
105
  find_dependencies: () => `: ${formatPath(String(args.filePath))}${args.direction ? ` (${args.direction})` : ''}`,
87
106
  run_analysis_script: () => `: ${formatPath(String(args.targetFile ?? 'workspace'))}`,
88
107
  run_debug_script: () => `: ${pc.dim(`(${String(args.language ?? 'script')})`)}`,
108
+ run_fuzz_probe: () => {
109
+ const lang = String(args.language ?? 'node');
110
+ const extras = [];
111
+ if (args.iterations !== undefined)
112
+ extras.push(`${args.iterations} iterations`);
113
+ if (args.seed !== undefined)
114
+ extras.push(`seed: ${args.seed}`);
115
+ const meta = extras.length > 0 ? `, ${extras.join(', ')}` : '';
116
+ return `: ${pc.dim(`(${lang}${meta})`)}`;
117
+ },
118
+ check_heap_delta: () => {
119
+ const lang = String(args.language ?? 'node');
120
+ const extras = [];
121
+ if (args.testIterations !== undefined)
122
+ extras.push(`${args.testIterations} iterations`);
123
+ if (args.samplingIntervalMs !== undefined)
124
+ extras.push(`${args.samplingIntervalMs}ms interval`);
125
+ const meta = extras.length > 0 ? `, ${extras.join(', ')}` : '';
126
+ return `: ${pc.dim(`(${lang}${meta})`)}`;
127
+ },
128
+ check_behavioral_drift: () => {
129
+ const lang = String(args.language ?? 'node');
130
+ const extras = [];
131
+ if (args.tolerance !== undefined)
132
+ extras.push(`tol: ${args.tolerance}`);
133
+ if (Array.isArray(args.compareKeys) && args.compareKeys.length > 0) {
134
+ extras.push(`keys: ${args.compareKeys.join(', ')}`);
135
+ }
136
+ const meta = extras.length > 0 ? `, ${extras.join(', ')}` : '';
137
+ return `: ${pc.dim(`(${lang}${meta})`)}`;
138
+ },
89
139
  };
90
140
  const formatter = argsMap[name];
91
141
  const details = formatter ? formatter() : '';
@@ -183,6 +183,32 @@ export declare function findRecentChanges(workspaceRoot: string, dirPath?: strin
183
183
  * @returns A promise resolving to a {@link ToolResult} containing execution output.
184
184
  */
185
185
  export declare function runDebugScript(workspaceRoot: string, language: string, code: string, abortSignal?: AbortSignal): Promise<ToolResult>;
186
+ /**
187
+ * Executes a fuzz probing analysis script and formats the resulting pass/fail and crash statistics.
188
+ */
189
+ export declare function executeFuzzProbe(workspaceRoot: string, code: string, language?: string, config?: {
190
+ iterations?: number;
191
+ maxInputLength?: number;
192
+ seed?: number;
193
+ timeoutMs?: number;
194
+ }, abortSignal?: AbortSignal): Promise<ToolResult>;
195
+ /**
196
+ * Executes a heap memory inspection script and formats memory consumption and growth delta metrics.
197
+ */
198
+ export declare function executeHeapDelta(workspaceRoot: string, code: string, language?: string, config?: {
199
+ warmupIterations?: number;
200
+ testIterations?: number;
201
+ samplingIntervalMs?: number;
202
+ timeoutMs?: number;
203
+ }, abortSignal?: AbortSignal): Promise<ToolResult>;
204
+ /**
205
+ * Executes baseline and candidate scripts, returning output diffs and behavioral drift findings.
206
+ */
207
+ export declare function executeBehavioralDrift(workspaceRoot: string, baselineCode: string, candidateCode: string, language?: string, config?: {
208
+ tolerance?: number;
209
+ compareKeys?: string[];
210
+ timeoutMs?: number;
211
+ }, abortSignal?: AbortSignal): Promise<ToolResult>;
186
212
  /**
187
213
  * Central tool dispatcher that resolves multi-workspace paths, executes the requested tool
188
214
  * with the provided arguments, records metrics, and returns the standardized {@link ToolResult}.
@@ -24,6 +24,7 @@ import { extractSymbols } from '../utils/symbolExtractor.js';
24
24
  import { getMetricCollector } from './metrics.js';
25
25
  import { getCurrentAgentId } from '../utils/asyncContext.js';
26
26
  import { recordFileRead, hasAgentReadFile } from '../utils/fileReadGuard.js';
27
+ import { runFuzzProbe, checkHeapDelta as runCheckHeapDelta, checkBehavioralDrift as runCheckBehavioralDrift, } from '../utils/analysisRunner.js';
27
28
  import ignore from 'ignore';
28
29
  const execAsync = promisify(exec);
29
30
  // ─── Tool Declarations for Gemini Function Calling ───────────────────
@@ -341,6 +342,109 @@ export const toolDeclarations = [
341
342
  required: ['summary'],
342
343
  },
343
344
  },
345
+ {
346
+ name: 'run_fuzz_probe',
347
+ description: 'Execute a fuzz testing probe script to detect edge-case failures, unhandled exceptions, or unexpected crashes under randomized or boundary inputs.',
348
+ parameters: {
349
+ type: SchemaType.OBJECT,
350
+ properties: {
351
+ code: {
352
+ type: SchemaType.STRING,
353
+ description: 'The fuzz test script or probe code to execute.',
354
+ },
355
+ language: {
356
+ type: SchemaType.STRING,
357
+ description: 'Runtime environment: "node", "ts-node", "python", "bash", "go", or "rust". Defaults to "node".',
358
+ },
359
+ iterations: {
360
+ type: SchemaType.NUMBER,
361
+ description: 'Optional. Number of fuzz test iterations to run.',
362
+ },
363
+ maxInputLength: {
364
+ type: SchemaType.NUMBER,
365
+ description: 'Optional. Maximum length/size for generated fuzz input vectors.',
366
+ },
367
+ seed: {
368
+ type: SchemaType.NUMBER,
369
+ description: 'Optional. Random seed for deterministic fuzz generation.',
370
+ },
371
+ timeoutMs: {
372
+ type: SchemaType.NUMBER,
373
+ description: 'Optional. Execution timeout in milliseconds.',
374
+ },
375
+ },
376
+ required: ['code'],
377
+ },
378
+ },
379
+ {
380
+ name: 'check_heap_delta',
381
+ description: 'Execute a heap memory inspection script to measure memory consumption, detect heap growth/leaks, and evaluate memory delta statistics.',
382
+ parameters: {
383
+ type: SchemaType.OBJECT,
384
+ properties: {
385
+ code: {
386
+ type: SchemaType.STRING,
387
+ description: 'The script or code snippet to execute for heap memory analysis.',
388
+ },
389
+ language: {
390
+ type: SchemaType.STRING,
391
+ description: 'Runtime environment: "node", "ts-node", "python", "bash", "go", or "rust". Defaults to "node".',
392
+ },
393
+ warmupIterations: {
394
+ type: SchemaType.NUMBER,
395
+ description: 'Optional. Number of warmup iterations prior to initial heap snapshot.',
396
+ },
397
+ testIterations: {
398
+ type: SchemaType.NUMBER,
399
+ description: 'Optional. Number of test iterations executed between snapshots.',
400
+ },
401
+ samplingIntervalMs: {
402
+ type: SchemaType.NUMBER,
403
+ description: 'Optional. Memory sampling interval in milliseconds.',
404
+ },
405
+ timeoutMs: {
406
+ type: SchemaType.NUMBER,
407
+ description: 'Optional. Execution timeout in milliseconds.',
408
+ },
409
+ },
410
+ required: ['code'],
411
+ },
412
+ },
413
+ {
414
+ name: 'check_behavioral_drift',
415
+ description: 'Execute baseline and candidate scripts in parallel or sequence to detect output differences, return value mismatches, or behavioral drift.',
416
+ parameters: {
417
+ type: SchemaType.OBJECT,
418
+ properties: {
419
+ baselineCode: {
420
+ type: SchemaType.STRING,
421
+ description: 'The baseline implementation script source code.',
422
+ },
423
+ candidateCode: {
424
+ type: SchemaType.STRING,
425
+ description: 'The candidate implementation script source code to compare against baseline.',
426
+ },
427
+ language: {
428
+ type: SchemaType.STRING,
429
+ description: 'Runtime environment: "node", "ts-node", "python", "bash", "go", or "rust". Defaults to "node".',
430
+ },
431
+ tolerance: {
432
+ type: SchemaType.NUMBER,
433
+ description: 'Optional. Numerical tolerance threshold for floating point comparison.',
434
+ },
435
+ compareKeys: {
436
+ type: SchemaType.ARRAY,
437
+ items: { type: SchemaType.STRING },
438
+ description: 'Optional. Specific JSON object keys/fields to compare for drift.',
439
+ },
440
+ timeoutMs: {
441
+ type: SchemaType.NUMBER,
442
+ description: 'Optional. Execution timeout in milliseconds.',
443
+ },
444
+ },
445
+ required: ['baselineCode', 'candidateCode'],
446
+ },
447
+ },
344
448
  ];
345
449
  let currentApprovalMode = 'ask';
346
450
  /**
@@ -1312,6 +1416,112 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
1312
1416
  }
1313
1417
  }
1314
1418
  }
1419
+ /**
1420
+ * Executes a fuzz probing analysis script and formats the resulting pass/fail and crash statistics.
1421
+ */
1422
+ export async function executeFuzzProbe(workspaceRoot, code, language = 'node', config, abortSignal) {
1423
+ try {
1424
+ const res = await runFuzzProbe(workspaceRoot, code, language, {
1425
+ ...config,
1426
+ abortSignal,
1427
+ });
1428
+ let output = `Fuzz Probe Result: ${res.passed ? 'PASSED' : 'FAILED'}\n`;
1429
+ if (res.totalFuzzRuns > 0)
1430
+ output += `Total Fuzz Runs: ${res.totalFuzzRuns}\n`;
1431
+ if (res.seed !== undefined)
1432
+ output += `Seed: ${res.seed}\n`;
1433
+ if (res.failingInputs && res.failingInputs.length > 0) {
1434
+ output += `Failing Inputs / Counterexamples:\n${res.failingInputs.map((inp) => ` - ${inp}`).join('\n')}\n`;
1435
+ }
1436
+ if (res.errorSummary) {
1437
+ output += `Error Summary:\n${res.errorSummary}\n`;
1438
+ }
1439
+ if (res.stdout)
1440
+ output += `\n[STDOUT]\n${res.stdout}\n`;
1441
+ if (res.stderr)
1442
+ output += `\n[STDERR]\n${res.stderr}\n`;
1443
+ return {
1444
+ output: output.trim(),
1445
+ ...(res.exitCode !== 0 && !res.passed ? { error: `Fuzz probe failed with exit code ${res.exitCode}` } : {}),
1446
+ };
1447
+ }
1448
+ catch (err) {
1449
+ return { output: '', error: `Fuzz probe error: ${err.message || String(err)}` };
1450
+ }
1451
+ }
1452
+ /**
1453
+ * Executes a heap memory inspection script and formats memory consumption and growth delta metrics.
1454
+ */
1455
+ export async function executeHeapDelta(workspaceRoot, code, language = 'node', config, abortSignal) {
1456
+ try {
1457
+ const res = await runCheckHeapDelta(workspaceRoot, code, language, {
1458
+ ...config,
1459
+ abortSignal,
1460
+ });
1461
+ let output = `Heap Delta Analysis Result:\n`;
1462
+ output += `Initial Heap: ${res.initialHeapBytes} bytes\n`;
1463
+ output += `Final Heap: ${res.finalHeapBytes} bytes\n`;
1464
+ output += `Delta: ${res.deltaBytes} bytes\n`;
1465
+ output += `Leak Detected: ${res.leakDetected ? 'YES' : 'NO'}\n`;
1466
+ if (res.growthRateBytesPerIter !== undefined) {
1467
+ output += `Growth Rate: ${res.growthRateBytesPerIter} bytes/iter\n`;
1468
+ }
1469
+ if (res.samples && res.samples.length > 0) {
1470
+ output += `Samples (${res.samples.length}):\n`;
1471
+ for (const s of res.samples) {
1472
+ output += ` Iter ${s.iteration}: ${s.heapBytes} bytes\n`;
1473
+ }
1474
+ }
1475
+ if (res.stdout)
1476
+ output += `\n[STDOUT]\n${res.stdout}\n`;
1477
+ if (res.stderr)
1478
+ output += `\n[STDERR]\n${res.stderr}\n`;
1479
+ return {
1480
+ output: output.trim(),
1481
+ ...(res.exitCode !== 0 ? { error: `Heap delta failed with exit code ${res.exitCode}` } : {}),
1482
+ };
1483
+ }
1484
+ catch (err) {
1485
+ return { output: '', error: `Heap delta error: ${err.message || String(err)}` };
1486
+ }
1487
+ }
1488
+ /**
1489
+ * Executes baseline and candidate scripts, returning output diffs and behavioral drift findings.
1490
+ */
1491
+ export async function executeBehavioralDrift(workspaceRoot, baselineCode, candidateCode, language = 'node', config, abortSignal) {
1492
+ try {
1493
+ const res = await runCheckBehavioralDrift(workspaceRoot, baselineCode, candidateCode, language, {
1494
+ ...config,
1495
+ abortSignal,
1496
+ });
1497
+ let output = `Behavioral Drift Analysis Result:\n`;
1498
+ output += `Has Drift: ${res.hasDrift ? 'YES' : 'NO'}\n`;
1499
+ if (res.diffSummary) {
1500
+ output += `Diff Summary:\n${res.diffSummary}\n`;
1501
+ }
1502
+ if (res.driftDetails && res.driftDetails.length > 0) {
1503
+ output += `Drift Details:\n`;
1504
+ for (const detail of res.driftDetails) {
1505
+ output += ` - ${detail.field ? `[${detail.field}] ` : ''}Baseline: ${JSON.stringify(detail.baseline)} vs Candidate: ${JSON.stringify(detail.candidate)}${detail.diff ? ` (${detail.diff})` : ''}\n`;
1506
+ }
1507
+ }
1508
+ if (res.baselineOutput)
1509
+ output += `\n[BASELINE OUTPUT]\n${res.baselineOutput}\n`;
1510
+ if (res.candidateOutput)
1511
+ output += `\n[CANDIDATE OUTPUT]\n${res.candidateOutput}\n`;
1512
+ if (res.stdout)
1513
+ output += `\n[STDOUT]\n${res.stdout}\n`;
1514
+ if (res.stderr)
1515
+ output += `\n[STDERR]\n${res.stderr}\n`;
1516
+ return {
1517
+ output: output.trim(),
1518
+ ...(res.exitCode !== 0 ? { error: `Behavioral drift check failed with exit code ${res.exitCode}` } : {}),
1519
+ };
1520
+ }
1521
+ catch (err) {
1522
+ return { output: '', error: `Behavioral drift error: ${err.message || String(err)}` };
1523
+ }
1524
+ }
1315
1525
  /**
1316
1526
  * Resolves `@alias/` prefixed paths in tool arguments to the correct workspace root
1317
1527
  * and relative path. Returns the effective workspaceRoot and the cleaned arguments.
@@ -1424,6 +1634,15 @@ export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
1424
1634
  else if (normalizedToolName === 'finish_investigation') {
1425
1635
  normalizedToolName = 'finish_task';
1426
1636
  }
1637
+ else if (normalizedToolName === 'fuzz_probe' || normalizedToolName === 'run_fuzz') {
1638
+ normalizedToolName = 'run_fuzz_probe';
1639
+ }
1640
+ else if (normalizedToolName === 'heap_delta' || normalizedToolName === 'check_heap') {
1641
+ normalizedToolName = 'check_heap_delta';
1642
+ }
1643
+ else if (normalizedToolName === 'behavioral_drift' || normalizedToolName === 'check_drift') {
1644
+ normalizedToolName = 'check_behavioral_drift';
1645
+ }
1427
1646
  // ─── Multi-Workspace Path Resolution ─────────────────────────────
1428
1647
  // Intercept @alias/ prefixed paths and swap workspaceRoot + relative path
1429
1648
  // before dispatching to the underlying tool functions (which remain unchanged).
@@ -1620,6 +1839,42 @@ export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
1620
1839
  case 'find_recent_changes':
1621
1840
  result = await findRecentChanges(effectiveRoot, resolvedArgs.dirPath, resolvedArgs.minutes, resolvedArgs.maxDepth);
1622
1841
  break;
1842
+ case 'run_fuzz_probe': {
1843
+ const code = resolvedArgs.code;
1844
+ const language = resolvedArgs.language || 'node';
1845
+ const config = {
1846
+ iterations: resolvedArgs.iterations,
1847
+ maxInputLength: resolvedArgs.maxInputLength,
1848
+ seed: resolvedArgs.seed,
1849
+ timeoutMs: resolvedArgs.timeoutMs,
1850
+ };
1851
+ result = await executeFuzzProbe(effectiveRoot, code, language, config, abortSignal);
1852
+ break;
1853
+ }
1854
+ case 'check_heap_delta': {
1855
+ const code = resolvedArgs.code;
1856
+ const language = resolvedArgs.language || 'node';
1857
+ const config = {
1858
+ warmupIterations: resolvedArgs.warmupIterations,
1859
+ testIterations: resolvedArgs.testIterations,
1860
+ samplingIntervalMs: resolvedArgs.samplingIntervalMs,
1861
+ timeoutMs: resolvedArgs.timeoutMs,
1862
+ };
1863
+ result = await executeHeapDelta(effectiveRoot, code, language, config, abortSignal);
1864
+ break;
1865
+ }
1866
+ case 'check_behavioral_drift': {
1867
+ const baselineCode = resolvedArgs.baselineCode;
1868
+ const candidateCode = resolvedArgs.candidateCode;
1869
+ const language = resolvedArgs.language || 'node';
1870
+ const config = {
1871
+ tolerance: resolvedArgs.tolerance,
1872
+ compareKeys: resolvedArgs.compareKeys,
1873
+ timeoutMs: resolvedArgs.timeoutMs,
1874
+ };
1875
+ result = await executeBehavioralDrift(effectiveRoot, baselineCode, candidateCode, language, config, abortSignal);
1876
+ break;
1877
+ }
1623
1878
  default:
1624
1879
  result = { output: '', error: `Unknown tool: "${toolName}"` };
1625
1880
  break;
@@ -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
  }
@@ -1,3 +1,4 @@
1
+ import path from 'path';
1
2
  import { executeTool, getToolDeclarations as getBaseToolDeclarations } from '../agent-tools.js';
2
3
  import { MessageBus } from './messageBus.js';
3
4
  import { debugLog } from '../../utils/logger.js';
@@ -149,6 +150,31 @@ export async function executeScopedTool(name, args, workspaceRoot, agentId, bus,
149
150
  const matchCount = (outputText.match(/\.\/[^:]+:\d+:/g) || []).length;
150
151
  resultSummary = `${matchCount} matches`;
151
152
  }
153
+ else if (name === 'rename_file') {
154
+ const src = String(args.sourcePath ?? '');
155
+ const tgt = String(args.targetPath ?? '');
156
+ targetDesc = `${src} -> ${tgt}`;
157
+ actionDesc = (src && tgt && path.dirname(src) === path.dirname(tgt)) ? 'Renamed' : 'Moved';
158
+ }
159
+ else if (name === 'delete_file') {
160
+ targetDesc = String(args.filePath);
161
+ actionDesc = 'Deleted';
162
+ }
163
+ else if (name === 'run_fuzz_probe') {
164
+ targetDesc = String(args.language ?? 'node');
165
+ actionDesc = 'Ran fuzz probe';
166
+ resultSummary = typeof result === 'object' && result?.error ? result.error : 'Completed fuzz probe';
167
+ }
168
+ else if (name === 'check_heap_delta') {
169
+ targetDesc = String(args.language ?? 'node');
170
+ actionDesc = 'Inspected heap delta';
171
+ resultSummary = typeof result === 'object' && result?.error ? result.error : 'Completed heap analysis';
172
+ }
173
+ else if (name === 'check_behavioral_drift') {
174
+ targetDesc = String(args.language ?? 'node');
175
+ actionDesc = 'Checked behavioral drift';
176
+ resultSummary = typeof result === 'object' && result?.error ? result.error : 'Completed drift comparison';
177
+ }
152
178
  return result;
153
179
  }
154
180
  catch (error) {
@@ -72,7 +72,7 @@ export class SubAgentRunner {
72
72
  `3. EXECUTION WORKFLOW:\n` +
73
73
  ` - Step 1 (Investigate): Use 'grep_search', 'read_file', or 'list_directory' to inspect the codebase as needed.\n` +
74
74
  ` - Step 2 (Execute): Use 'modify_file' or 'write_file' to implement the required changes.\n` +
75
- ` - Step 3 (Verify): Use 'run_debug_script' or 'run_command' to test your changes if necessary.\n` +
75
+ ` - Step 3 (Verify): Use 'run_debug_script', 'run_fuzz_probe', 'check_heap_delta', 'check_behavioral_drift', or 'run_command' to test your changes if necessary.\n` +
76
76
  ` - Step 4 (Conclude): Once your specific objective is fully met, stop calling tools and return a text summary of your changes.\n` +
77
77
  `4. Coordinate: Use 'read_messages' to check for updates from other agents. Use 'post_message' if you discover breaking changes affecting others.\n` +
78
78
  `</critical_guidelines>`);
@@ -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>;