minovative-mind-cli 1.0.5 → 1.1.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/dist/commands/chat.js +1 -1
- package/dist/services/agent-tools.d.ts +3 -3
- package/dist/services/agent-tools.js +16 -6
- package/dist/services/agent.d.ts +124 -0
- package/dist/services/agent.js +315 -43
- package/dist/services/ai.d.ts +7 -2
- package/dist/services/ai.js +36 -17
- package/dist/services/proxyClient.js +6 -1
- package/dist/services/verificationService.js +7 -41
- package/dist/utils/config.d.ts +3 -1
- package/dist/utils/config.js +3 -1
- package/dist/utils/logger.d.ts +2 -6
- package/dist/utils/logger.js +12 -8
- package/dist/utils/systemPrompts.d.ts +5 -5
- package/dist/utils/systemPrompts.js +72 -33
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -24,7 +24,7 @@ export default class DefaultCommand extends Command {
|
|
|
24
24
|
idToken = await getAuthorizedIdToken();
|
|
25
25
|
}
|
|
26
26
|
p.log.info(`${pc.dim('Workspace:')} ${pc.cyan(workspaceRoot)}`);
|
|
27
|
-
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu. Type ${pc.yellow('exit')} to leave.`);
|
|
27
|
+
p.log.info(`${pc.dim('Commands:')} Type ${pc.yellow('/')} to open the command menu and "${pc.yellow('stop')}" to stop the ai generation. Type ${pc.yellow('exit')} to leave.`);
|
|
28
28
|
await startAgentLoop(workspaceRoot, this.config.version);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -24,13 +24,13 @@ export declare function modifyFile(workspaceRoot: string, filePath: string, edit
|
|
|
24
24
|
replaceContent: string;
|
|
25
25
|
}>): Promise<ToolResult>;
|
|
26
26
|
export declare function listDirectory(workspaceRoot: string, dirPath: string, maxDepth?: number): Promise<ToolResult>;
|
|
27
|
-
export declare function runCommand(workspaceRoot: string, command: string): Promise<ToolResult>;
|
|
27
|
+
export declare function runCommand(workspaceRoot: string, command: string, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
28
28
|
export declare function grepSearch(workspaceRoot: string, pattern: string, fileGlob?: string): Promise<ToolResult>;
|
|
29
29
|
export declare function traceDependencies(workspaceRoot: string, filePath: string, direction?: string, maxDepth?: number): Promise<ToolResult>;
|
|
30
30
|
export declare function findRecentChanges(workspaceRoot: string, dirPath?: string, minutes?: number, maxDepth?: number): Promise<ToolResult>;
|
|
31
|
-
export declare function runDebugScript(workspaceRoot: string, language: string, code: string): Promise<ToolResult>;
|
|
31
|
+
export declare function runDebugScript(workspaceRoot: string, language: string, code: string, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
32
32
|
/**
|
|
33
33
|
* Dispatches a function call from the model to the appropriate local tool.
|
|
34
34
|
* Returns the tool result as a string to feed back to the model.
|
|
35
35
|
*/
|
|
36
|
-
export declare function executeTool(workspaceRoot: string, toolName: string, args: Record<string, unknown
|
|
36
|
+
export declare function executeTool(workspaceRoot: string, toolName: string, args: Record<string, unknown>, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
@@ -312,6 +312,15 @@ export async function readFile(workspaceRoot, filePath, startLine, endLine, targ
|
|
|
312
312
|
}
|
|
313
313
|
content = lines.slice(start - 1, end).join('\n');
|
|
314
314
|
}
|
|
315
|
+
else {
|
|
316
|
+
const lines = content.split('\n');
|
|
317
|
+
if (lines.length > 1500) {
|
|
318
|
+
return {
|
|
319
|
+
output: '',
|
|
320
|
+
error: `File is too large (${lines.length} lines). You MUST use startLine/endLine or targetElements to read specific chunks instead of dumping the whole file.`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
315
324
|
const attrLines = startLine || endLine ? ` lines="${startLine || 1}-${endLine || 'end'}"` : '';
|
|
316
325
|
const attrTargets = targetElements && targetElements.length > 0 ? ` elements="${targetElements.join(',')}"` : '';
|
|
317
326
|
const wrappedContent = `<workspace_file path="${filePath}"${attrLines}${attrTargets}>\n<content_data><![CDATA[\n${sanitizeForCDATA(content)}\n]]></content_data>\n</workspace_file>`;
|
|
@@ -506,12 +515,13 @@ export async function listDirectory(workspaceRoot, dirPath, maxDepth = 3) {
|
|
|
506
515
|
};
|
|
507
516
|
}
|
|
508
517
|
}
|
|
509
|
-
export async function runCommand(workspaceRoot, command) {
|
|
518
|
+
export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
510
519
|
try {
|
|
511
520
|
const { stdout, stderr } = await execAsync(command, {
|
|
512
521
|
cwd: workspaceRoot,
|
|
513
522
|
timeout: 60_000, // 60 second timeout
|
|
514
523
|
maxBuffer: 1024 * 1024 * 2, // 2 MB buffer
|
|
524
|
+
signal: abortSignal,
|
|
515
525
|
});
|
|
516
526
|
let output = [stdout, stderr].filter(Boolean).join('\n');
|
|
517
527
|
// Truncate command output to prevent memory blowout from massive build logs
|
|
@@ -655,7 +665,7 @@ export async function findRecentChanges(workspaceRoot, dirPath = '.', minutes =
|
|
|
655
665
|
}
|
|
656
666
|
}
|
|
657
667
|
// ─── Tool Dispatcher ─────────────────────────────────────────────────
|
|
658
|
-
export async function runDebugScript(workspaceRoot, language, code) {
|
|
668
|
+
export async function runDebugScript(workspaceRoot, language, code, abortSignal) {
|
|
659
669
|
const extMap = {
|
|
660
670
|
node: '.js',
|
|
661
671
|
'ts-node': '.ts',
|
|
@@ -693,7 +703,7 @@ export async function runDebugScript(workspaceRoot, language, code) {
|
|
|
693
703
|
return { output: '', error: `Unsupported language runtime: ${language}` };
|
|
694
704
|
}
|
|
695
705
|
try {
|
|
696
|
-
const { stdout, stderr } = await execAsync(cmd, { cwd: workspaceRoot, timeout: 15_000 });
|
|
706
|
+
const { stdout, stderr } = await execAsync(cmd, { cwd: workspaceRoot, timeout: 15_000, signal: abortSignal });
|
|
697
707
|
const out = stdout.trim();
|
|
698
708
|
const errOut = stderr.trim();
|
|
699
709
|
let finalOutput = '';
|
|
@@ -739,7 +749,7 @@ export async function runDebugScript(workspaceRoot, language, code) {
|
|
|
739
749
|
* Dispatches a function call from the model to the appropriate local tool.
|
|
740
750
|
* Returns the tool result as a string to feed back to the model.
|
|
741
751
|
*/
|
|
742
|
-
export async function executeTool(workspaceRoot, toolName, args) {
|
|
752
|
+
export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
|
|
743
753
|
switch (toolName) {
|
|
744
754
|
case 'read_file':
|
|
745
755
|
return readFile(workspaceRoot, args.filePath, args.startLine, args.endLine, args.targetElements);
|
|
@@ -754,9 +764,9 @@ export async function executeTool(workspaceRoot, toolName, args) {
|
|
|
754
764
|
case 'list_directory':
|
|
755
765
|
return listDirectory(workspaceRoot, args.dirPath, args.maxDepth ?? 3);
|
|
756
766
|
case 'run_command':
|
|
757
|
-
return runCommand(workspaceRoot, args.command);
|
|
767
|
+
return runCommand(workspaceRoot, args.command, abortSignal);
|
|
758
768
|
case 'run_debug_script':
|
|
759
|
-
return runDebugScript(workspaceRoot, args.language, args.code);
|
|
769
|
+
return runDebugScript(workspaceRoot, args.language, args.code, abortSignal);
|
|
760
770
|
case 'grep_search':
|
|
761
771
|
return grepSearch(workspaceRoot, args.pattern, args.fileGlob);
|
|
762
772
|
case 'find_dependencies':
|
package/dist/services/agent.d.ts
CHANGED
|
@@ -1,21 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Core agent execution service.
|
|
3
|
+
*
|
|
4
|
+
* This file coordinates the central execution environment for Minovative Mind,
|
|
5
|
+
* an AI-powered developer CLI. It orchestrates:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Interactive REPL Loop**: Collects multiline user input, supports slash-commands,
|
|
8
|
+
* reverting changes, switching models, auto-commit, and clipboard paste injection.
|
|
9
|
+
* 2. **Context-Aware Investigation**: Gathers repo-wide context and compresses it using
|
|
10
|
+
* low-cost, high-speed LLM summarization.
|
|
11
|
+
* 3. **Autonomous Tool Loop (processResponse)**: Allows the AI model to execute file-system,
|
|
12
|
+
* shell-command, and search operations, feeding outcomes back in a recursive, multi-turn loop.
|
|
13
|
+
* 4. **Asynchronous Interrupt Handling (AsyncInputHandler)**: Intercepts keyboard events
|
|
14
|
+
* on standard input to let users pause execution, queue live feedback, or abort generation.
|
|
15
|
+
* 5. **Self-Correction Pipeline**: Compares modified files against TS/Linter diagnostics,
|
|
16
|
+
* providing feedback on syntax or semantic failures back to the AI for self-healing.
|
|
17
|
+
*/
|
|
1
18
|
import * as p from '@clack/prompts';
|
|
19
|
+
/**
|
|
20
|
+
* Asynchronous Input Handler (AsyncInputHandler)
|
|
21
|
+
*
|
|
22
|
+
* This class intercepts user keyboard input from standard input (stdin) while
|
|
23
|
+
* background processes (e.g., Gemini model generations or long shell tool runs)
|
|
24
|
+
* are executing. It provides seamless execution management by letting users:
|
|
25
|
+
*
|
|
26
|
+
* 1. **Pause execution** at any time by pressing a key.
|
|
27
|
+
* 2. **Queue feedback** ("chained messages") without waiting for the entire run to finish.
|
|
28
|
+
* 3. **Force abort** the current model or tool run by entering "stop" or "stop!".
|
|
29
|
+
*
|
|
30
|
+
* ### Raw Mode & Terminal States
|
|
31
|
+
* In normal CLI execution, Node.js waits for a line feed (Enter) before emitting input.
|
|
32
|
+
* To intercept immediate keystrokes, we put `process.stdin` into *raw mode*.
|
|
33
|
+
* While in raw mode, we listen for direct data buffers.
|
|
34
|
+
* To avoid visual conflicts with our logging output and Clack's CLI spinners,
|
|
35
|
+
* we dynamically pause spinners, detach listeners, disable raw mode, open standard
|
|
36
|
+
* interactive text-prompt forms, and resume raw mode and spinners upon completion.
|
|
37
|
+
*/
|
|
2
38
|
export declare class AsyncInputHandler {
|
|
39
|
+
/** Queue of pending user feedback/instructions typed during active background execution */
|
|
3
40
|
private queue;
|
|
41
|
+
/** Guard flag preventing multiple simultaneous input prompt overlays */
|
|
4
42
|
private isPrompting;
|
|
43
|
+
/** Reference to the Clack CLI spinner which must be paused/restarted during prompts */
|
|
5
44
|
private spinner;
|
|
45
|
+
/** Stores the terminal's raw mode configuration state before handler activation */
|
|
6
46
|
private originalRawMode;
|
|
47
|
+
/** Indicates whether the input handler is currently inactive/stopped */
|
|
7
48
|
private stopped;
|
|
49
|
+
/** Reference to the AbortController controlling the active AI request to trigger cancellations */
|
|
8
50
|
private ac;
|
|
51
|
+
/**
|
|
52
|
+
* Registers the active AbortController for the current AI request.
|
|
53
|
+
* This is triggered when the user commands a process cancel (e.g., typing "stop").
|
|
54
|
+
*
|
|
55
|
+
* @param ac - The AbortController controlling the current generation.
|
|
56
|
+
*/
|
|
9
57
|
setAbortController(ac: AbortController): void;
|
|
58
|
+
/**
|
|
59
|
+
* Determines if a user-prompt dialog is actively running.
|
|
60
|
+
* Useful for coordinating other console logging output to avoid UI overlap.
|
|
61
|
+
*
|
|
62
|
+
* @returns True if a text prompt is currently displayed, false otherwise.
|
|
63
|
+
*/
|
|
10
64
|
isCurrentlyPrompting(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Blocks and waits until any active prompting action is completed.
|
|
67
|
+
* Guarantees terminal stdout is clean before resuming logs.
|
|
68
|
+
*/
|
|
11
69
|
waitForPrompt(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Core stdin event listener. Detects pressed keys, pauses background visual elements,
|
|
72
|
+
* handles exit interrupts, and opens a Clack text dialog for input.
|
|
73
|
+
*
|
|
74
|
+
* Handles recovery of the standard input stream and raw mode states even if
|
|
75
|
+
* errors occur during prompt initialization.
|
|
76
|
+
*
|
|
77
|
+
* @param chunk - The raw terminal buffer containing keypress data.
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
12
80
|
private onData;
|
|
81
|
+
/**
|
|
82
|
+
* Starts intercepting keystrokes and enables raw terminal processing.
|
|
83
|
+
* Saves the original raw mode configuration to ensure a clean restoration later.
|
|
84
|
+
*
|
|
85
|
+
* @param spinner - The current active Clack spinner UI reference, if any.
|
|
86
|
+
*/
|
|
13
87
|
start(spinner?: ReturnType<typeof p.spinner>): void;
|
|
88
|
+
/**
|
|
89
|
+
* Disables raw mode, stops intercepting keystrokes, and restores
|
|
90
|
+
* the terminal stdin stream to its original raw/cooked state.
|
|
91
|
+
*/
|
|
14
92
|
stop(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Retrieves and flushes all user feedback messages accumulated during execution.
|
|
95
|
+
*
|
|
96
|
+
* @returns A concatenated string of all queued user messages separated by newlines,
|
|
97
|
+
* or an empty string if nothing was queued.
|
|
98
|
+
*/
|
|
15
99
|
getAndClear(): string;
|
|
16
100
|
}
|
|
17
101
|
/**
|
|
18
102
|
* Starts the interactive agent chat loop.
|
|
19
103
|
* Runs until the user types "exit", "quit", or presses Ctrl+C.
|
|
104
|
+
*
|
|
105
|
+
* @param workspaceRoot - The root directory of the workspace.
|
|
106
|
+
* @param version - The active version of the CLI utility.
|
|
107
|
+
*/
|
|
108
|
+
/**
|
|
109
|
+
* Starts and orchestrates the primary interactive command-line interface (REPL) loop.
|
|
110
|
+
*
|
|
111
|
+
* This is the central control loop of the CLI application. It runs indefinitely until
|
|
112
|
+
* the user explicitly issues an exit directive (e.g., typing "exit", "quit", `/` command menu selections,
|
|
113
|
+
* or using keyboard breaks like Ctrl+C).
|
|
114
|
+
*
|
|
115
|
+
* ### Architectural Pipeline:
|
|
116
|
+
* 1. **User Input Collection**:
|
|
117
|
+
* - Captures multiline text strings by checking for trailing backslash characters (`\`).
|
|
118
|
+
* - Prevents visual terminal glitches during multi-line typing on varying themes.
|
|
119
|
+
* - Automatically handles command menu redirection when users enter a forward slash (`/`).
|
|
120
|
+
* - Intercepts and filters OS clipboard paste buffers to allow inserting massive scripts cleanly.
|
|
121
|
+
*
|
|
122
|
+
* 2. **Slash Commands Processing**:
|
|
123
|
+
* - `/paste`: Interactively captures large copy-pasted blocks using EOF tracking.
|
|
124
|
+
* - `/clear`: Hard-clears active terminal histories and resets session state.
|
|
125
|
+
* - `/models`: Dynamic runtime model hot-swapping (e.g., swapping between Flash and Pro variants).
|
|
126
|
+
* - `/debug`: Toggles active runtime execution telemetry logging.
|
|
127
|
+
* - `/auto-approve`: Grants blanket terminal script permissions to bypass prompt approval blocks.
|
|
128
|
+
* - `/revert`: Pops the most recent change-set log and rolls back mutated files to original states.
|
|
129
|
+
* - `/commit`: Performs git diff staging, executes model summaries to write micro-commits, and executes local git commits.
|
|
130
|
+
*
|
|
131
|
+
* 3. **Workspace Context Gathering & Intention Routing**:
|
|
132
|
+
* - Leverages the Context Agent (`gatherContext`) to perform exploratory scans of the active repository.
|
|
133
|
+
* - Identifies user intention to hot-swap system prompt strategies (`CHAT` for conversational assistance vs. `EXECUTE` for multi-turn modifications).
|
|
134
|
+
* - Compresses gathered repo structures and file contents using high-speed Flash-Lite engines to respect context boundaries and budget costs.
|
|
135
|
+
*
|
|
136
|
+
* 4. **Model Execution & Self-Correction Feedback Loop**:
|
|
137
|
+
* - Passes the target request to Gemini alongside compressed workspace injections.
|
|
138
|
+
* - Recursively processes tool invocations via `processResponse`.
|
|
139
|
+
* - Runs static validation checks (`verifyChangedFiles`) against mutated files to check for compiler/linter bugs.
|
|
140
|
+
* - If files fail validation, enters a self-healing loop by submitting raw diagnostic errors directly back to the AI for remediation.
|
|
141
|
+
*
|
|
142
|
+
* @param workspaceRoot - The relative or absolute path representing the active workspace environment.
|
|
143
|
+
* @param version - The Semantic Version string of the active tool distribution.
|
|
20
144
|
*/
|
|
21
145
|
export declare function startAgentLoop(workspaceRoot: string, version: string): Promise<void>;
|