minovative-mind-cli 1.2.3 → 1.3.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.
package/LICENSE.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Copyright (c) 2026 Minovative Mind. All Rights Reserved.**
4
4
 
5
- This software, including all source code, documentation, and associated files (the "Software"), is proprietary and confidential property of Minovative Mind.
5
+ This software, including all source code, documentation, and associated files (the "Software"), is proprietary and confidential property of Ward Innovations.
6
6
 
7
7
  ## 1. Grant of License
8
8
 
package/README.md CHANGED
@@ -1,152 +1,110 @@
1
- # Minovative Mind CLI (w/ Gemini 3.5 Flash & Gemini 3.1 Pro)
1
+ # Minovative Mind CLI
2
2
 
3
- ## Highly accurate, lightweight AI coding agent for any terminal (Designed for less errors). [(Click Demo)](https://youtu.be/KjE5nbKEf3w?si=mcjb5_2QLf4vofRC)
3
+ ## The CLI agent that makes Flash models perform like Pro.
4
4
 
5
- An automated, multi-agent AI coding assistant powered by Vertex AI. By utilizing a custom built **Precision-Context Verification (PCV)** engine (for coding) with AST-based structural analysis, it reads, writes, and refactors code with extreme accuracy—delivering a **40% to 50% reduction in broken code generations** on large files compared to standard zero-shot LLM prompts.
5
+ Most AI coding tools throw your entire codebase at the biggest model available
6
+ and hope for the best.
7
+
8
+ This CLI does the opposite — it uses a custom built agentic system called,
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
11
+ the build/performance metrics are green.
12
+
13
+ > The result: **Genuine Pro-level accuracy at Flash-level cost.**
6
14
 
7
15
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
8
16
  [![Version](https://img.shields.io/npm/v/minovative-mind-cli.svg)](https://npmjs.org/package/minovative-mind-cli)
9
17
  [![Downloads/week](https://img.shields.io/npm/dw/minovative-mind-cli.svg)](https://npmjs.org/package/minovative-mind-cli)
10
18
 
11
- - Official Website: [https://www.minovativemind.dev/](https://www.minovativemind.dev/)
12
- - Latest Updates: [https://www.minovativemind.dev/updates](https://www.minovativemind.dev/updates)
13
-
14
- ## Supported Models
15
-
16
- The CLI supports the following advanced reasoning and coding models via Vertex AI Model Garden. You can hot-swap between these models at any time during a chat session by typing `/models` in the CLI:
17
-
18
- - **Gemini 3.1 Pro**: Best for highly complex architectural reasoning and large context windows.
19
- - **Gemini 3.5 Flash** (Default): Lightning fast, top-tier performance for everyday coding tasks.
20
- - **Gemini 3.1 Flash Lite**: Lightning fast, cost-effective performance for everyday coding tasks.
21
-
22
- ## Table of Contents
23
-
24
- - [Quick Start](#quick-start)
25
- - [Commands](#commands)
19
+ ---
26
20
 
27
- <!-- tocstop -->
21
+ ## How it works
28
22
 
29
- ## Quick Start
23
+ - Standard AI coding agents: big model + noisy context = expensive and redundant mistakes
24
+ - Minovative Mind CLI: flash models + precise context + verified output = better and cheaper results.
30
25
 
31
- Getting started with Minovative Mind CLI is easy!
26
+ ### The PCV engine runs in three stages before returning a single line of code:
32
27
 
33
- 1. **Install Globally:**
28
+ **1. Investigate**
34
29
 
35
- ```bash
36
- npm install -g minovative-mind-cli
37
- ```
30
+ - **Maps your project:** Traces import dependencies and identifies recently modified files to understand your focus.
31
+ - **Researches context:** Gathers external web documentation and completes background research before touching any code.
38
32
 
39
- 2. **Authenticate:**
40
- Before you can use the CLI, you need to create an account at [https://www.minovativemind.dev/](https://www.minovativemind.dev/).
41
- Once you have an account, sign in securely using GitHub by running:
33
+ **2. Execute with precision**
42
34
 
43
- ```bash
44
- minovative-mind-cli login
45
- ```
35
+ - **Surgical snapshots:** Feeds the agent a compressed, relevant slice of code instead of dumping the entire codebase.
36
+ - **Higher success rates:** Delivers 40–50% fewer broken generations on large files compared to standard zero-shot prompts.
46
37
 
47
- 3. **Start Coding!**
48
- Navigate to any project directory on your computer and start a chat session:
38
+ **3. Verify and self-correct**
49
39
 
50
- ```bash
51
- cd your-project-folder
52
- minovative-mind-cli chat
53
- ```
40
+ - **Runs native builds & audits:** Automatically executes your actual build commands (`npm run build`, `cargo check`, etc.) and scans for performance flaws on modified files only.
41
+ - **Autonomously debugs:** Reads the exact compiler output and fixes its own errors across up to 3 hands-free correction cycles.
54
42
 
55
- 4. **Change Models (Optional):**
56
- Once in a chat, type `/models` to switch between advanced reasoning models like Gemini 3.5 Flash and Gemini 3.1 Pro!
43
+ ---
57
44
 
58
- 5. **Update the CLI:**
59
- To ensure you have the latest features and bug fixes, you can update the CLI at any time by running the following command. (The CLI will automatically notify you when a new version is available!)
45
+ ## See it in action
60
46
 
61
- ```bash
62
- npm update -g minovative-mind-cli
63
- ```
47
+ - [AI builds a Python Generative Art Engine in one prompt](https://www.youtube.com/watch?v=dy3qNbETqfs)
48
+ - [AI builds a Quiz Game from scratch](https://www.youtube.com/watch?v=KjE5nbKEf3w)
64
49
 
65
50
  ---
66
51
 
67
- # Commands
68
-
69
- <!-- commands -->
70
- * [`minovative-mind-cli chat`](#minovative-mind-cli-chat)
71
- * [`minovative-mind-cli help [COMMAND]`](#minovative-mind-cli-help-command)
72
- * [`minovative-mind-cli login`](#minovative-mind-cli-login)
73
- * [`minovative-mind-cli logout`](#minovative-mind-cli-logout)
52
+ ## Quick Start
74
53
 
75
- ## `minovative-mind-cli chat`
54
+ ```bash
55
+ npm install -g minovative-mind-cli
56
+ ```
76
57
 
77
- Start an interactive AI coding agent session powered by Vertex AI.
58
+ ### Update to latest version
78
59
 
60
+ ```bash
61
+ npm update -g minovative-mind-cli
79
62
  ```
80
- USAGE
81
- $ minovative-mind-cli chat
82
-
83
- DESCRIPTION
84
- Start an interactive AI coding agent session powered by Vertex AI.
85
-
86
- Inside the chat session, you can use the following commands in the slash menu:
87
- /models - Select the active model
88
- /paste - Enter multi-line paste mode for long snippets
89
- /clear - Clear conversation history
90
- /debug - Debug tests or command execution in a sandbox loop
91
- /auto-approve - Toggle automatic approval of tool/command runs
92
- /revert - Revert the last file modification made by the agent
93
- /commit - Commit current workspace changes to Git
94
-
95
- Chat Controls:
96
- - Multi-line Input: End a line with \ to continue on the next line
97
- - Stop/Abort: Type "stop" to immediately interrupt agent generation
98
- - Exit Session: Type "exit" or "quit" to end the agent session
99
-
100
- EXAMPLES
101
- $ minovative-mind-cli chat
102
-
103
- $ minovative-mind-cli chat --help
104
- ```
105
-
106
- ## `minovative-mind-cli help [COMMAND]`
107
63
 
108
- Display help for minovative-mind-cli.
64
+ Create a free account at [minovativemind.dev](https://www.minovativemind.dev),
65
+ then:
109
66
 
67
+ ```bash
68
+ minovative-mind-cli login # One-click GitHub sign-in
69
+ cd your-project
70
+ minovative-mind-cli chat # Start coding
110
71
  ```
111
- USAGE
112
- $ minovative-mind-cli help [COMMAND...] [-n]
113
72
 
114
- ARGUMENTS
115
- [COMMAND...] Command to show help for.
73
+ Works in any terminal — SSH, Docker, CI pipelines, Vim, anywhere Node runs.
116
74
 
117
- FLAGS
118
- -n, --nested-commands Include all nested commands in the output.
119
-
120
- DESCRIPTION
121
- Display help for minovative-mind-cli.
122
- ```
75
+ ---
123
76
 
124
- ## `minovative-mind-cli login`
77
+ ## Models
125
78
 
126
- Sign in to your Minovative Mind account using GitHub
79
+ Hot-swap during a session with `/models`:
127
80
 
128
- ```
129
- USAGE
130
- $ minovative-mind-cli login
81
+ | Model | Best for |
82
+ | ------------------------------ | ----------------------------------- |
83
+ | **Gemini 3.5 Flash** (default) | Everyday coding — fast and accurate |
84
+ | **Gemini 3.1 Pro** | Complex architectural changes |
85
+ | **Gemini 3.1 Flash Lite** | Maximum speed and cost efficiency |
131
86
 
132
- DESCRIPTION
133
- Sign in to your Minovative Mind account using GitHub
134
- ```
87
+ > Background tasks (routing, compression, commits) always use lightweight
88
+ > models automatically. You only pay for what your selected model costs
89
+ > during chat and code execution. Use `/debug` to see exactly what's running.
135
90
 
136
- ## `minovative-mind-cli logout`
91
+ ---
137
92
 
138
- Sign out of your Minovative Mind account
93
+ ## Session Commands
139
94
 
140
- ```
141
- USAGE
142
- $ minovative-mind-cli logout
95
+ | Command | What it does |
96
+ | --------------- | ----------------------------------------------------- |
97
+ | `/models` | Hot-swap the active model |
98
+ | `/revert` | Instantly undo all changes from the last turn |
99
+ | `/commit` | Generate a conventional commit message from your diff |
100
+ | `/auto-approve` | Skip confirmation prompts for commands |
101
+ | `/paste` | Multi-line input mode |
102
+ | `/debug` | Expose internal agent diagnostics |
103
+ | `stop` | Abort generation immediately |
143
104
 
144
- DESCRIPTION
145
- Sign out of your Minovative Mind account
146
- ```
147
- <!-- commandsstop -->
105
+ ---
148
106
 
149
107
  ## Legal
150
108
 
151
- - [Terms of Service](https://www.minovativemind.dev/legal/cli-terms)
152
- - [Privacy Policy](https://www.minovativemind.dev/legal/cli-privacy)
109
+ [Terms of Service](https://www.minovativemind.dev/legal/cli-terms) ·
110
+ [Privacy Policy](https://www.minovativemind.dev/legal/cli-privacy)
@@ -893,7 +893,7 @@ ${diffOut}
893
893
  let contextInjection = buildContextInjection(gatherRes.contextResult);
894
894
  debugLog(`Raw context injection size: ${contextInjection.length} chars`);
895
895
  // Compress context inputs using Gemini Flash Lite to optimize prompt density and prevent token bloat
896
- contextInjection = await compressTextUsingFlashLite(contextInjection, 'Summarize the following project context concisely. Preserve all file paths, project types, and the high-level purpose of the read files. Keep it under 2000 characters if possible.');
896
+ contextInjection = await compressTextUsingFlashLite(contextInjection, `Summarize the following project context concisely. Preserve all file paths, project types, and the high-level purpose of the read files. Keep it under 2000 characters if possible.\nCRITICAL: Focus specifically on details relevant to the user's current request: "${userInput}"`);
897
897
  debugLog(`Compressed context injection size: ${contextInjection.length} chars`);
898
898
  dynamicSystemInstruction += '\n\n' + contextInjection;
899
899
  }
@@ -965,12 +965,16 @@ ${diffOut}
965
965
  break;
966
966
  // Stage 3: Static code analysis / verification
967
967
  p.log.step('Verifying modified files...');
968
- const verificationErrors = await verifyChangedFiles(workspaceRoot, changedFiles, ac.signal);
969
- if (verificationErrors === '[Verification Aborted]') {
968
+ const verificationResult = await verifyChangedFiles(workspaceRoot, changedFiles, ac.signal);
969
+ if (verificationResult === '[Verification Aborted]') {
970
970
  p.log.warn(pc.yellow('Verification aborted by user.'));
971
971
  break;
972
972
  }
973
- if (!verificationErrors) {
973
+ // Print non-blocking performance warnings to the terminal
974
+ if (verificationResult.warnings) {
975
+ p.log.warn('Performance Audit Warnings:\n' + verificationResult.warnings);
976
+ }
977
+ if (!verificationResult.errors) {
974
978
  p.log.success('Verification passed.');
975
979
  break;
976
980
  }
@@ -980,11 +984,11 @@ ${diffOut}
980
984
  break;
981
985
  }
982
986
  p.log.warn(`${pc.yellow('Verification failed. Auto-correcting errors')} (Attempt ${correctionAttempts}/${MAX_CORRECTIONS})...`);
983
- const displayError = verificationErrors.split('\n').slice(0, 5).join('\n');
987
+ const displayError = verificationResult.errors.split('\n').slice(0, 5).join('\n');
984
988
  console.log(pc.dim(` ${displayError.replace(/\n/g, '\n ')}\n ...`));
985
- debugLog(`Verification failed on attempt ${correctionAttempts}/${MAX_CORRECTIONS}. Errors:\n${verificationErrors}`);
989
+ debugLog(`Verification failed on attempt ${correctionAttempts}/${MAX_CORRECTIONS}. Errors:\n${verificationResult.errors}`);
986
990
  // Compile compilation and syntax diagnostic warnings into an auto-correction prompt
987
- const correctionPrompt = `AUTOMATED SYSTEM CHECK: Your previous changes resulted in the following errors:\n\n${verificationErrors}\n\nPlease analyze these errors and use your file modification tools to fix them.`;
991
+ const correctionPrompt = `AUTOMATED SYSTEM CHECK: Your previous changes resulted in the following errors:\n\n${verificationResult.errors}\n\nPlease analyze these errors and use your file modification tools to fix them.`;
988
992
  spinner.start('Thinking (Correction)...');
989
993
  result = await chat.sendMessage(correctionPrompt);
990
994
  spinner.stop('');
@@ -1,13 +1,55 @@
1
1
  import type { Content, Tool, ToolConfig, FunctionCall } from '@google/generative-ai';
2
+ /**
3
+ * ============================================================================
4
+ * PROXY CLIENT SERVICE
5
+ * ============================================================================
6
+ * Facilitates stream-based communication with the secure, Firebase-authenticated
7
+ * serverless Gemini content generation proxy.
8
+ *
9
+ * Core Capabilities:
10
+ * - Server-Sent Events (SSE) parsing for thoughts, text, and function calls.
11
+ * - Secure Authentication handling (Firebase ID Tokens).
12
+ * - Real-time stream-callback piping for instant responses.
13
+ * - Accurate token usage, credit consumption, and grounding metadata parsing.
14
+ * ============================================================================
15
+ */
16
+ /**
17
+ * Metadata containing real-time proxy token and credit usage diagnostics.
18
+ */
2
19
  export interface ProxyUsageMetadata {
20
+ /** The number of tokens detected in the prompt/input. */
3
21
  promptTokens: number;
22
+ /** The number of tokens generated as candidates. */
4
23
  candidatesTokens: number;
24
+ /** The number of cached tokens, if context caching was utilized. */
5
25
  cachedTokens?: number;
26
+ /** The credit cost of this request in micro-credits or target monetary units. */
6
27
  creditsUsed: number;
28
+ /** The remaining balance left in the user's account. */
7
29
  remainingBalance: number;
8
30
  }
31
+ /**
32
+ * Client service interacting directly with the serverless Gemini proxy endpoint.
33
+ * Ensures authorization via Firebase token passing and parses streamed content.
34
+ */
9
35
  export declare class ProxyClient {
10
36
  private readonly PROXY_URL;
37
+ /**
38
+ * Generates text, thoughts, or function calls via the secure Gemini proxy URL.
39
+ * Utilizes Server-Sent Events (SSE) to stream partial token responses back to the client.
40
+ *
41
+ * @param idToken - The Firebase ID token for authorization.
42
+ * @param modelName - The name of the Gemini model to target.
43
+ * @param contents - Structured conversations/contents matching Google's schema.
44
+ * @param tools - Optional tools available for the model to execute.
45
+ * @param toolConfig - Optional routing/forcing behavior configuration for the tools.
46
+ * @param systemInstruction - Optional instructions for guiding the model's persona/behavior.
47
+ * @param generationConfig - Optional parameters controlling model creativity, output type, etc.
48
+ * @param streamCallbacks - Optional callbacks triggered as thoughts/content stream in.
49
+ * @param abortSignal - Optional signal to abort the fetch request midway.
50
+ * @returns A structured promise resolving to gathered text, function calls, and metadata.
51
+ * @throws {Error} If authentication fails (401), credits are insufficient (402), or network/proxy errors occur.
52
+ */
11
53
  generateFunctionCallViaProxy(idToken: string, modelName: string, contents: Content[], tools?: Tool[], toolConfig?: ToolConfig, systemInstruction?: string | Content, generationConfig?: any, streamCallbacks?: {
12
54
  onChunk: (chunk: string) => void;
13
55
  }, abortSignal?: AbortSignal): Promise<{
@@ -1,6 +1,26 @@
1
1
  import { debugLog } from '../utils/logger.js';
2
+ /**
3
+ * Client service interacting directly with the serverless Gemini proxy endpoint.
4
+ * Ensures authorization via Firebase token passing and parses streamed content.
5
+ */
2
6
  export class ProxyClient {
3
7
  PROXY_URL = 'https://generatecontent-6obg3e4zwa-uc.a.run.app';
8
+ /**
9
+ * Generates text, thoughts, or function calls via the secure Gemini proxy URL.
10
+ * Utilizes Server-Sent Events (SSE) to stream partial token responses back to the client.
11
+ *
12
+ * @param idToken - The Firebase ID token for authorization.
13
+ * @param modelName - The name of the Gemini model to target.
14
+ * @param contents - Structured conversations/contents matching Google's schema.
15
+ * @param tools - Optional tools available for the model to execute.
16
+ * @param toolConfig - Optional routing/forcing behavior configuration for the tools.
17
+ * @param systemInstruction - Optional instructions for guiding the model's persona/behavior.
18
+ * @param generationConfig - Optional parameters controlling model creativity, output type, etc.
19
+ * @param streamCallbacks - Optional callbacks triggered as thoughts/content stream in.
20
+ * @param abortSignal - Optional signal to abort the fetch request midway.
21
+ * @returns A structured promise resolving to gathered text, function calls, and metadata.
22
+ * @throws {Error} If authentication fails (401), credits are insufficient (402), or network/proxy errors occur.
23
+ */
4
24
  async generateFunctionCallViaProxy(idToken, modelName, contents, tools, toolConfig, systemInstruction, generationConfig, streamCallbacks, abortSignal) {
5
25
  const response = await fetch(this.PROXY_URL, {
6
26
  method: 'POST',
@@ -3,8 +3,13 @@ export interface VerificationResult {
3
3
  command: string;
4
4
  output: string;
5
5
  errors: string[];
6
+ aborted?: boolean;
6
7
  }
7
8
  export declare function detectVerificationCommand(workspaceRoot: string): Promise<string | null>;
8
9
  export declare function runVerification(workspaceRoot: string, abortSignal?: AbortSignal): Promise<VerificationResult | null>;
9
10
  export declare function formatVerificationForModel(result: VerificationResult): string;
10
- export declare function verifyChangedFiles(workspaceRoot: string, filePaths: string[], abortSignal?: AbortSignal): Promise<string | null>;
11
+ export interface FullVerificationResult {
12
+ errors: string | null;
13
+ warnings: string | null;
14
+ }
15
+ export declare function verifyChangedFiles(workspaceRoot: string, filePaths: string[], abortSignal?: AbortSignal): Promise<FullVerificationResult | '[Verification Aborted]'>;
@@ -5,19 +5,35 @@ import { promisify } from 'node:util';
5
5
  import { debugLog } from '../utils/logger.js';
6
6
  const execAsync = promisify(exec);
7
7
  export async function detectVerificationCommand(workspaceRoot) {
8
+ // Package Manager Detection
9
+ let pmPrefix = 'npm run';
10
+ const lockFiles = [
11
+ { name: 'pnpm-lock.yaml', prefix: 'pnpm run' },
12
+ { name: 'yarn.lock', prefix: 'yarn run' },
13
+ { name: 'bun.lockb', prefix: 'bun run' },
14
+ { name: 'bun.lock', prefix: 'bun run' }
15
+ ];
16
+ for (const lf of lockFiles) {
17
+ try {
18
+ await fs.access(path.join(workspaceRoot, lf.name));
19
+ pmPrefix = lf.prefix;
20
+ break;
21
+ }
22
+ catch { }
23
+ }
8
24
  try {
9
25
  const pkgJsonPath = path.join(workspaceRoot, 'package.json');
10
26
  const pkgJsonStr = await fs.readFile(pkgJsonPath, 'utf-8');
11
27
  const pkgJson = JSON.parse(pkgJsonStr);
12
28
  if (pkgJson.scripts) {
13
29
  if (pkgJson.scripts.build)
14
- return 'npm run build';
30
+ return `${pmPrefix} build`;
15
31
  if (pkgJson.scripts.typecheck)
16
- return 'npm run typecheck';
32
+ return `${pmPrefix} typecheck`;
17
33
  if (pkgJson.scripts.lint)
18
- return 'npm run lint';
34
+ return `${pmPrefix} lint`;
19
35
  if (pkgJson.scripts.check)
20
- return 'npm run check';
36
+ return `${pmPrefix} check`;
21
37
  }
22
38
  }
23
39
  catch {
@@ -33,6 +49,83 @@ export async function detectVerificationCommand(workspaceRoot) {
33
49
  return 'cargo check';
34
50
  }
35
51
  catch { }
52
+ try {
53
+ await fs.access(path.join(workspaceRoot, 'go.mod'));
54
+ return 'go build ./...';
55
+ }
56
+ catch { }
57
+ try {
58
+ await fs.access(path.join(workspaceRoot, 'pom.xml'));
59
+ return 'mvn clean compile test-compile';
60
+ }
61
+ catch { }
62
+ try {
63
+ await fs.access(path.join(workspaceRoot, 'build.gradle'));
64
+ return (await fs.access(path.join(workspaceRoot, 'gradlew')).then(() => true).catch(() => false))
65
+ ? './gradlew classes testClasses'
66
+ : 'gradle classes testClasses';
67
+ }
68
+ catch { }
69
+ try {
70
+ await fs.access(path.join(workspaceRoot, 'build.gradle.kts'));
71
+ return (await fs.access(path.join(workspaceRoot, 'gradlew')).then(() => true).catch(() => false))
72
+ ? './gradlew classes testClasses'
73
+ : 'gradle classes testClasses';
74
+ }
75
+ catch { }
76
+ try {
77
+ await fs.access(path.join(workspaceRoot, 'pubspec.yaml'));
78
+ return 'dart analyze';
79
+ }
80
+ catch { }
81
+ // Python Environment Awareness
82
+ let isPython = false;
83
+ for (const pyFile of ['pytest.ini', 'pyproject.toml', 'poetry.lock', 'uv.lock', 'Pipfile', '.venv', 'venv']) {
84
+ try {
85
+ await fs.access(path.join(workspaceRoot, pyFile));
86
+ isPython = true;
87
+ break;
88
+ }
89
+ catch { }
90
+ }
91
+ if (isPython) {
92
+ try {
93
+ await fs.access(path.join(workspaceRoot, 'poetry.lock'));
94
+ return 'poetry run pytest';
95
+ }
96
+ catch { }
97
+ try {
98
+ await fs.access(path.join(workspaceRoot, 'uv.lock'));
99
+ return 'uv run pytest';
100
+ }
101
+ catch { }
102
+ try {
103
+ await fs.access(path.join(workspaceRoot, 'Pipfile'));
104
+ return 'pipenv run pytest';
105
+ }
106
+ catch { }
107
+ const isWindows = process.platform === 'win32';
108
+ try {
109
+ await fs.access(path.join(workspaceRoot, '.venv'));
110
+ const pytestPath = isWindows ? '.venv\\Scripts\\pytest' : '.venv/bin/pytest';
111
+ return pytestPath;
112
+ }
113
+ catch { }
114
+ try {
115
+ await fs.access(path.join(workspaceRoot, 'venv'));
116
+ const pytestPath = isWindows ? 'venv\\Scripts\\pytest' : 'venv/bin/pytest';
117
+ return pytestPath;
118
+ }
119
+ catch { }
120
+ return 'pytest';
121
+ }
122
+ try {
123
+ await fs.access(path.join(workspaceRoot, 'Gemfile'));
124
+ return (await fs.access(path.join(workspaceRoot, 'spec')).then(() => true).catch(() => false))
125
+ ? 'bundle exec rspec'
126
+ : 'bundle exec rubocop';
127
+ }
128
+ catch { }
36
129
  return null;
37
130
  }
38
131
  export async function runVerification(workspaceRoot, abortSignal) {
@@ -44,7 +137,7 @@ export async function runVerification(workspaceRoot, abortSignal) {
44
137
  try {
45
138
  const { stdout, stderr } = await execAsync(command, {
46
139
  cwd: workspaceRoot,
47
- timeout: 90_000, // 90s (1 min & 30 secs) - builds can take a while (e.g., Next.js)
140
+ timeout: 120_000, // 120s (2 mins) - builds can take a while (e.g., Next.js, Gradle)
48
141
  maxBuffer: 1024 * 1024, // 1 MB buffer
49
142
  signal: abortSignal,
50
143
  });
@@ -72,9 +165,25 @@ export async function runVerification(workspaceRoot, abortSignal) {
72
165
  // Extract error lines with context
73
166
  const errors = [];
74
167
  let capturingError = false;
168
+ const isErrorLine = (line) => {
169
+ const lower = line.toLowerCase();
170
+ if (lower.includes('fail') ||
171
+ lower.includes('failed') ||
172
+ lower.includes('exception') ||
173
+ lower.includes('fatal') ||
174
+ lower.includes('panic') ||
175
+ lower.includes('traceback') ||
176
+ lower.includes('error') ||
177
+ lower.includes('err!') ||
178
+ /:\d+:\d+:/.test(line) ||
179
+ /:\d+:/.test(line)) {
180
+ return true;
181
+ }
182
+ return false;
183
+ };
75
184
  for (const line of lines) {
76
185
  const lower = line.toLowerCase();
77
- if (lower.includes('error') || lower.includes('err!')) {
186
+ if (isErrorLine(line)) {
78
187
  capturingError = true;
79
188
  errors.push(line);
80
189
  }
@@ -87,6 +196,12 @@ export async function runVerification(workspaceRoot, abortSignal) {
87
196
  }
88
197
  }
89
198
  }
199
+ if (errors.length === 0) {
200
+ const fallbackSource = rawStderr.trim() ? rawStderr : rawStdout;
201
+ const fallbackLines = fallbackSource.split('\n');
202
+ const last40 = fallbackLines.slice(-40);
203
+ errors.push(...last40);
204
+ }
90
205
  return {
91
206
  success: false,
92
207
  command,
@@ -105,11 +220,13 @@ ${result.errors.join('\n')}
105
220
 
106
221
  Please fix these errors using the modify_file tool.`;
107
222
  }
223
+ import { auditFilePerformance, formatAuditForModel, formatAuditForTerminal, isAuditableFile } from '../utils/performanceAuditor.js';
108
224
  export async function verifyChangedFiles(workspaceRoot, filePaths, abortSignal) {
109
225
  if (filePaths.length === 0)
110
- return null;
226
+ return { errors: null, warnings: null };
111
227
  const errors = [];
112
- // Project-level build check (e.g., npm run build)
228
+ const perfAudits = [];
229
+ // 1. Project-level build check (e.g., npm run build)
113
230
  const buildResult = await runVerification(workspaceRoot, abortSignal);
114
231
  if (buildResult && !buildResult.success) {
115
232
  if (buildResult.aborted) {
@@ -118,5 +235,35 @@ export async function verifyChangedFiles(workspaceRoot, filePaths, abortSignal)
118
235
  const buildErrorMsg = `[Build Error: ${buildResult.command}]\n${buildResult.errors.join('\n').substring(0, 5000)}`;
119
236
  errors.push(buildErrorMsg);
120
237
  }
121
- return errors.length > 0 ? errors.join('\n\n---\n\n') : null;
238
+ // 2. Performance Audit
239
+ // We run this even if the build failed, so the model gets all feedback at once
240
+ for (const file of filePaths) {
241
+ if (abortSignal?.aborted)
242
+ return '[Verification Aborted]';
243
+ if (!isAuditableFile(file))
244
+ continue;
245
+ try {
246
+ const absolutePath = path.resolve(workspaceRoot, file);
247
+ const content = await fs.readFile(absolutePath, 'utf-8');
248
+ const audit = auditFilePerformance(content, file);
249
+ if (audit.findings.length > 0) {
250
+ perfAudits.push(audit);
251
+ }
252
+ }
253
+ catch (err) {
254
+ debugLog(`Failed to audit performance for ${file}: ${err}`);
255
+ }
256
+ }
257
+ // Extract blocking performance errors (Severity: ERROR)
258
+ const perfModelPrompt = formatAuditForModel(perfAudits);
259
+ if (perfModelPrompt) {
260
+ errors.push(perfModelPrompt);
261
+ }
262
+ // Extract non-blocking performance warnings for the terminal (Severity: WARNING | INFO)
263
+ // We only show terminal warnings for files that actually had warnings or info (ignoring files that only had errors)
264
+ const terminalWarnings = formatAuditForTerminal(perfAudits.filter((a) => a.warnings.length > 0 || a.infos.length > 0));
265
+ return {
266
+ errors: errors.length > 0 ? errors.join('\n\n---\n\n') : null,
267
+ warnings: terminalWarnings || null,
268
+ };
122
269
  }
@@ -0,0 +1,42 @@
1
+ export type PerfSeverity = 'ERROR' | 'WARNING' | 'INFO';
2
+ export interface PerfFinding {
3
+ severity: PerfSeverity;
4
+ code: string;
5
+ line: number;
6
+ message: string;
7
+ suggestion: string;
8
+ }
9
+ export interface PerfAuditResult {
10
+ filePath: string;
11
+ findings: PerfFinding[];
12
+ errors: PerfFinding[];
13
+ warnings: PerfFinding[];
14
+ infos: PerfFinding[];
15
+ }
16
+ /**
17
+ * Returns true if the file extension is supported by the performance auditor.
18
+ */
19
+ export declare function isAuditableFile(filePath: string): boolean;
20
+ /**
21
+ * Scans source code for performance anti-patterns using language-aware
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.
27
+ *
28
+ * @param content - The raw source code string to audit.
29
+ * @param filePath - The file path (used for language detection via extension).
30
+ * @returns A structured audit result with findings separated by severity.
31
+ */
32
+ export declare function auditFilePerformance(content: string, filePath: string): PerfAuditResult;
33
+ /**
34
+ * Formats audit findings for beautiful terminal display using picocolors.
35
+ * Used for non-blocking warnings shown to the user after verification.
36
+ */
37
+ export declare function formatAuditForTerminal(results: PerfAuditResult[]): string;
38
+ /**
39
+ * 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
+ */
42
+ export declare function formatAuditForModel(results: PerfAuditResult[]): string;