minovative-mind-cli 1.0.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.
Files changed (53) hide show
  1. package/README.md +418 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/commands/chat.d.ts +7 -0
  7. package/dist/commands/chat.js +30 -0
  8. package/dist/commands/login.d.ts +5 -0
  9. package/dist/commands/login.js +18 -0
  10. package/dist/commands/logout.d.ts +5 -0
  11. package/dist/commands/logout.js +12 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/services/agent-tools.d.ts +36 -0
  15. package/dist/services/agent-tools.js +764 -0
  16. package/dist/services/agent.d.ts +21 -0
  17. package/dist/services/agent.js +648 -0
  18. package/dist/services/ai.d.ts +60 -0
  19. package/dist/services/ai.js +331 -0
  20. package/dist/services/auth.d.ts +3 -0
  21. package/dist/services/auth.js +183 -0
  22. package/dist/services/changeLogger.d.ts +23 -0
  23. package/dist/services/changeLogger.js +57 -0
  24. package/dist/services/contextAgent.d.ts +20 -0
  25. package/dist/services/contextAgent.js +440 -0
  26. package/dist/services/proxyClient.d.ts +21 -0
  27. package/dist/services/proxyClient.js +119 -0
  28. package/dist/services/verificationService.d.ts +10 -0
  29. package/dist/services/verificationService.js +148 -0
  30. package/dist/utils/atomicWrite.d.ts +6 -0
  31. package/dist/utils/atomicWrite.js +29 -0
  32. package/dist/utils/config.d.ts +17 -0
  33. package/dist/utils/config.js +17 -0
  34. package/dist/utils/contextPrompts.d.ts +3 -0
  35. package/dist/utils/contextPrompts.js +34 -0
  36. package/dist/utils/dependencyTracer.d.ts +48 -0
  37. package/dist/utils/dependencyTracer.js +647 -0
  38. package/dist/utils/excludedExtensions.d.ts +8 -0
  39. package/dist/utils/excludedExtensions.js +125 -0
  40. package/dist/utils/fuzzyMatch.d.ts +21 -0
  41. package/dist/utils/fuzzyMatch.js +121 -0
  42. package/dist/utils/logger.d.ts +8 -0
  43. package/dist/utils/logger.js +17 -0
  44. package/dist/utils/pathSecurity.d.ts +10 -0
  45. package/dist/utils/pathSecurity.js +26 -0
  46. package/dist/utils/symbolExtractor.d.ts +6 -0
  47. package/dist/utils/symbolExtractor.js +249 -0
  48. package/dist/utils/syntaxValidator.d.ts +5 -0
  49. package/dist/utils/syntaxValidator.js +81 -0
  50. package/dist/utils/systemPrompts.d.ts +5 -0
  51. package/dist/utils/systemPrompts.js +119 -0
  52. package/oclif.manifest.json +69 -0
  53. package/package.json +81 -0
@@ -0,0 +1,148 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { exec } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ const execAsync = promisify(exec);
6
+ export async function detectVerificationCommand(workspaceRoot) {
7
+ try {
8
+ const pkgJsonPath = path.join(workspaceRoot, 'package.json');
9
+ const pkgJsonStr = await fs.readFile(pkgJsonPath, 'utf-8');
10
+ const pkgJson = JSON.parse(pkgJsonStr);
11
+ if (pkgJson.scripts) {
12
+ if (pkgJson.scripts.build)
13
+ return 'npm run build';
14
+ if (pkgJson.scripts.typecheck)
15
+ return 'npm run typecheck';
16
+ if (pkgJson.scripts.lint)
17
+ return 'npm run lint';
18
+ if (pkgJson.scripts.check)
19
+ return 'npm run check';
20
+ }
21
+ }
22
+ catch {
23
+ // not a node project or no package.json
24
+ }
25
+ try {
26
+ await fs.access(path.join(workspaceRoot, 'Makefile'));
27
+ return 'make check';
28
+ }
29
+ catch { }
30
+ try {
31
+ await fs.access(path.join(workspaceRoot, 'Cargo.toml'));
32
+ return 'cargo check';
33
+ }
34
+ catch { }
35
+ return null;
36
+ }
37
+ export async function runVerification(workspaceRoot) {
38
+ const command = await detectVerificationCommand(workspaceRoot);
39
+ if (!command)
40
+ return null;
41
+ const MAX_VERIFY_OUTPUT = 20_000; // 20KB cap on verification output
42
+ try {
43
+ const { stdout, stderr } = await execAsync(command, {
44
+ cwd: workspaceRoot,
45
+ timeout: 90_000, // 90s (1 min & 30 secs) - builds can take a while (e.g., Next.js)
46
+ maxBuffer: 1024 * 1024, // 1 MB buffer
47
+ });
48
+ return {
49
+ success: true,
50
+ command,
51
+ output: stdout.length > MAX_VERIFY_OUTPUT ? stdout.substring(0, MAX_VERIFY_OUTPUT) + '\n... (truncated)' : stdout,
52
+ errors: [],
53
+ };
54
+ }
55
+ catch (err) {
56
+ const rawStdout = (err.stdout || '').substring(0, MAX_VERIFY_OUTPUT);
57
+ const rawStderr = (err.stderr || '').substring(0, MAX_VERIFY_OUTPUT);
58
+ const output = rawStdout + '\n' + rawStderr;
59
+ const lines = output.split('\n');
60
+ // Extract error lines with context
61
+ const errors = [];
62
+ let capturingError = false;
63
+ for (const line of lines) {
64
+ const lower = line.toLowerCase();
65
+ if (lower.includes('error') || lower.includes('err!')) {
66
+ capturingError = true;
67
+ errors.push(line);
68
+ }
69
+ else if (capturingError) {
70
+ if (line.trim() === '' || lower.includes('warning') || lower.includes('info')) {
71
+ capturingError = false;
72
+ }
73
+ else {
74
+ errors.push(line);
75
+ }
76
+ }
77
+ }
78
+ return {
79
+ success: false,
80
+ command,
81
+ output,
82
+ errors: errors.slice(0, 30), // limit to 30 error lines for the model
83
+ };
84
+ }
85
+ }
86
+ export function formatVerificationForModel(result) {
87
+ return `The following verification errors were detected after your changes:
88
+
89
+ Command: ${result.command}
90
+
91
+ Errors:
92
+ ${result.errors.join('\n')}
93
+
94
+ Please fix these errors using the modify_file tool.`;
95
+ }
96
+ export async function verifyChangedFiles(workspaceRoot, filePaths) {
97
+ if (filePaths.length === 0)
98
+ return null;
99
+ const errors = [];
100
+ const tryExec = async (cmd, files, isEslint = false) => {
101
+ if (files.length === 0)
102
+ return;
103
+ const chunkedFiles = files.map((f) => `"${f}"`).join(' ');
104
+ const fullCmd = `${cmd} ${chunkedFiles}`;
105
+ try {
106
+ await execAsync(fullCmd, { cwd: workspaceRoot, timeout: 15_000 });
107
+ }
108
+ catch (err) {
109
+ const out = (err.stdout || '') + '\n' + (err.stderr || '');
110
+ const lowerOut = out.toLowerCase();
111
+ // Ignore if the linter command is missing, or if ESLint simply skipped the file because it is in .eslintignore
112
+ if (lowerOut.includes('command not found') ||
113
+ lowerOut.includes('enoent') ||
114
+ lowerOut.includes('not recognized') ||
115
+ lowerOut.includes('could not determine executable to run') ||
116
+ lowerOut.includes('file ignored because of a matching ignore pattern') ||
117
+ err.code === 127) {
118
+ return;
119
+ }
120
+ let errorMsg = `[${cmd} Error]\n${out.trim().substring(0, 5000)}`;
121
+ // Intercept ESLint fatal crashes
122
+ if (isEslint && out.includes('Oops! Something went wrong! :(')) {
123
+ return;
124
+ }
125
+ errors.push(errorMsg);
126
+ }
127
+ };
128
+ // Group by language
129
+ const jsFiles = filePaths.filter((f) => /\.(js|jsx|ts|tsx)$/.test(f));
130
+ const pyFiles = filePaths.filter((f) => f.endsWith('.py'));
131
+ const rsFiles = filePaths.filter((f) => f.endsWith('.rs'));
132
+ const goFiles = filePaths.filter((f) => f.endsWith('.go'));
133
+ // JS/TS: Use npx --no -- to prevent npm from intercepting eslint flags. Use --quiet to only report errors.
134
+ await tryExec('npx --no -- eslint --quiet', jsFiles, true);
135
+ // Python
136
+ await tryExec('flake8', pyFiles);
137
+ // Rust (rustfmt is usually global if cargo is available)
138
+ await tryExec('rustfmt --check', rsFiles);
139
+ // Go
140
+ await tryExec('go vet', goFiles);
141
+ // Project-level build check (e.g., npm run build)
142
+ const buildResult = await runVerification(workspaceRoot);
143
+ if (buildResult && !buildResult.success) {
144
+ const buildErrorMsg = `[Build Error: ${buildResult.command}]\n${buildResult.errors.join('\n').substring(0, 5000)}`;
145
+ errors.push(buildErrorMsg);
146
+ }
147
+ return errors.length > 0 ? errors.join('\n\n---\n\n') : null;
148
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Writes data to a file atomically by writing to a temporary file first,
3
+ * then renaming the temporary file to the target path.
4
+ * This prevents file corruption if the process crashes during a write operation.
5
+ */
6
+ export declare function atomicWriteFile(targetPath: string, data: string, encoding?: BufferEncoding): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Writes data to a file atomically by writing to a temporary file first,
5
+ * then renaming the temporary file to the target path.
6
+ * This prevents file corruption if the process crashes during a write operation.
7
+ */
8
+ export async function atomicWriteFile(targetPath, data, encoding = 'utf-8') {
9
+ const dir = path.dirname(targetPath);
10
+ const tempPath = path.join(dir, `.${path.basename(targetPath)}.${Date.now()}.tmp`);
11
+ try {
12
+ // Ensure the directory exists
13
+ await fs.mkdir(dir, { recursive: true });
14
+ // Write to the temporary file
15
+ await fs.writeFile(tempPath, data, encoding);
16
+ // Atomically rename it over the target file
17
+ await fs.rename(tempPath, targetPath);
18
+ }
19
+ catch (error) {
20
+ // Clean up temp file on failure if it exists
21
+ try {
22
+ await fs.unlink(tempPath);
23
+ }
24
+ catch {
25
+ // Ignore cleanup errors
26
+ }
27
+ throw error;
28
+ }
29
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Firebase configuration for Minovative Mind production backend.
3
+ */
4
+ export declare const FIREBASE_API_KEY = "AIzaSyAFqOlkNO3uFGYO1kaEBGEFD9CXLt0mnIs";
5
+ export declare const GITHUB_CLIENT_ID = "Ov23linFYFfjO3JILG7r";
6
+ export declare const GEMINI_MODELS: {
7
+ readonly FLASH_PRO: "gemini-2.5-pro";
8
+ readonly FLASH_LATEST: "gemini-2.5-flash";
9
+ };
10
+ export declare const CLAUDE_MODELS: {
11
+ readonly OPUS: "claude-opus-4-6";
12
+ readonly SONNET: "claude-sonnet-4-6";
13
+ };
14
+ /** Default Gemini model for the coding agent. */
15
+ export declare const DEFAULT_MODEL: "gemini-2.5-flash";
16
+ /** Maximum tokens the model can output per response. */
17
+ export declare const MAX_OUTPUT_TOKENS = 65000;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Firebase configuration for Minovative Mind production backend.
3
+ */
4
+ export const FIREBASE_API_KEY = 'AIzaSyAFqOlkNO3uFGYO1kaEBGEFD9CXLt0mnIs';
5
+ export const GITHUB_CLIENT_ID = 'Ov23linFYFfjO3JILG7r';
6
+ export const GEMINI_MODELS = {
7
+ FLASH_PRO: 'gemini-2.5-pro',
8
+ FLASH_LATEST: 'gemini-2.5-flash',
9
+ };
10
+ export const CLAUDE_MODELS = {
11
+ OPUS: 'claude-opus-4-6',
12
+ SONNET: 'claude-sonnet-4-6',
13
+ };
14
+ /** Default Gemini model for the coding agent. */
15
+ export const DEFAULT_MODEL = GEMINI_MODELS.FLASH_LATEST;
16
+ /** Maximum tokens the model can output per response. */
17
+ export const MAX_OUTPUT_TOKENS = 65_000;
@@ -0,0 +1,3 @@
1
+ import { ContextAgentResult } from '../services/contextAgent.js';
2
+ export declare function sanitizeForCDATA(content: string): string;
3
+ export declare function buildContextInjection(context: ContextAgentResult): string;
@@ -0,0 +1,34 @@
1
+ export function sanitizeForCDATA(content) {
2
+ // Prevent CDATA breakout by escaping ]]>
3
+ return content.replace(/\]\]>/g, ']]\\\\u200B>');
4
+ }
5
+ export function buildContextInjection(context) {
6
+ let injection = `<project_context>
7
+ ## Project Profile
8
+ ${context.projectType}
9
+
10
+ ## Project Structure
11
+ ${context.projectTree}
12
+
13
+ ## Investigation Summary
14
+ ${context.summary}
15
+ `;
16
+ if (context.webSearchSummary) {
17
+ injection += `
18
+ ## Web Search Findings
19
+ ${context.webSearchSummary}
20
+ `;
21
+ }
22
+ if (context.relevantFiles.size > 0) {
23
+ injection += `\n## Relevant File Contents\n`;
24
+ for (const [filePath, content] of context.relevantFiles.entries()) {
25
+ injection += `<workspace_file path="${filePath}">
26
+ <content_data><![CDATA[
27
+ ${sanitizeForCDATA(content)}
28
+ ]]></content_data>
29
+ </workspace_file>\n`;
30
+ }
31
+ }
32
+ injection += `</project_context>`;
33
+ return injection;
34
+ }
@@ -0,0 +1,48 @@
1
+ export interface DependencyNode {
2
+ /** Files this file directly imports (forward/downstream) */
3
+ imports: Set<string>;
4
+ /** Files that directly import this file (reverse/upstream) */
5
+ importedBy: Set<string>;
6
+ }
7
+ export interface DependencyGraph {
8
+ /** What files does `filePath` directly import? */
9
+ getImports(filePath: string): string[];
10
+ /** What files directly import `filePath`? (who breaks if this changes?) */
11
+ getImportedBy(filePath: string): string[];
12
+ /** Transitive: all files reachable via importedBy chains, up to maxDepth */
13
+ getReverseDependencyTree(filePath: string, maxDepth?: number): string[];
14
+ /** Transitive: all files reachable via import chains, up to maxDepth */
15
+ getForwardDependencyTree(filePath: string, maxDepth?: number): string[];
16
+ /** The full raw graph for inspection */
17
+ readonly nodes: ReadonlyMap<string, DependencyNode>;
18
+ }
19
+ /**
20
+ * Builds a complete bidirectional dependency graph of the workspace.
21
+ *
22
+ * Performance: This is pure regex + filesystem walking — no AST parsing.
23
+ * For a typical project (<5,000 source files), this completes in <1s.
24
+ * The graph is ephemeral: built once per `gatherContext` call and discarded.
25
+ */
26
+ export declare function buildDependencyGraph(workspaceRoot: string): Promise<DependencyGraph>;
27
+ export interface FindDependenciesResult {
28
+ filePath: string;
29
+ forwardDeps: string[];
30
+ reverseDeps: string[];
31
+ forwardTree: string[];
32
+ reverseTree: string[];
33
+ }
34
+ /**
35
+ * High-level function exposed as a tool to the agents.
36
+ * Builds the dependency graph (or reuses if already built in this invocation),
37
+ * then queries it for the specified file.
38
+ */
39
+ export declare function findDependencies(workspaceRoot: string, filePath: string, direction?: 'both' | 'forward' | 'reverse', maxDepth?: number): Promise<FindDependenciesResult>;
40
+ /**
41
+ * Formats a FindDependenciesResult into a human-readable string
42
+ * suitable for feeding back to the LLM.
43
+ */
44
+ export declare function formatDependencyResult(result: FindDependenciesResult): string;
45
+ /**
46
+ * Resets the tsconfig alias cache (useful between workspace changes).
47
+ */
48
+ export declare function resetAliasCache(): void;