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.
@@ -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>): Promise<ToolResult>;
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':
@@ -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>;