trace.ai-cli 1.1.9 → 1.2.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/cli/traceAI.js +2 -2
- package/package.json +2 -1
- package/services/aiService.js +13 -5
- package/services/fileAnalyzer.js +135 -60
- package/utils/fileUtils.js +105 -100
package/cli/traceAI.js
CHANGED
|
@@ -72,7 +72,7 @@ class TraceAI {
|
|
|
72
72
|
|
|
73
73
|
// Subtitle and version info
|
|
74
74
|
console.log(chalk.gray.bold(' ') + chalk.white.bold('AI powered CLI Platform'));
|
|
75
|
-
console.log(chalk.gray(' ') + chalk.gray('v1.
|
|
75
|
+
console.log(chalk.gray(' ') + chalk.gray('v1.2.0 | Powered by Mixkey'));
|
|
76
76
|
|
|
77
77
|
// Dynamic separator
|
|
78
78
|
const width = process.stdout.columns || 80;
|
|
@@ -254,7 +254,7 @@ class TraceAI {
|
|
|
254
254
|
await this.executeWithSpinner(
|
|
255
255
|
`Analyzing file: ${path.basename(filePath)}`,
|
|
256
256
|
async () => {
|
|
257
|
-
const result = await analyzeFile(path.resolve(filePath), query);
|
|
257
|
+
const result = await analyzeFile(path.resolve(filePath), query, this.mode);
|
|
258
258
|
this.displayResult('File Analysis', result.text, filePath);
|
|
259
259
|
}
|
|
260
260
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trace.ai-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A powerful AI-powered CLI tool",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"node-fetch": "^2.6.7",
|
|
37
37
|
"ora": "^5.4.1",
|
|
38
38
|
"os-utils": "^0.0.14",
|
|
39
|
+
"pdf-parse": "^1.1.1",
|
|
39
40
|
"systeminformation": "^5.27.1",
|
|
40
41
|
"trace.ai-cli": "^1.1.8"
|
|
41
42
|
},
|
package/services/aiService.js
CHANGED
|
@@ -575,17 +575,25 @@ function getHelpMessage(prompt) {
|
|
|
575
575
|
async function processWithAI(prompt, context = '', mode = 2) {
|
|
576
576
|
try {
|
|
577
577
|
|
|
578
|
-
// Enhanced system query detection
|
|
578
|
+
// Enhanced system query detection - but EXCLUDE file/folder analysis prompts
|
|
579
579
|
const systemKeywords = [
|
|
580
580
|
'system', 'cpu', 'memory', 'ram', 'disk', 'network', 'ip', 'process',
|
|
581
581
|
'environment', 'hardware', 'computer', 'machine', 'specs', 'info',
|
|
582
582
|
'information', 'status', 'usage', 'performance', 'storage', 'processor'
|
|
583
583
|
];
|
|
584
584
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
585
|
+
// Check if this is a file/folder analysis (these should NOT trigger system info)
|
|
586
|
+
const isFileAnalysis = prompt.includes('File:') ||
|
|
587
|
+
prompt.includes('Analyze this') ||
|
|
588
|
+
prompt.includes('code file') ||
|
|
589
|
+
prompt.includes('Content:') ||
|
|
590
|
+
prompt.includes('User Question:');
|
|
591
|
+
|
|
592
|
+
const isSystemQuery = !isFileAnalysis && (
|
|
593
|
+
systemKeywords.some(keyword => prompt.toLowerCase().includes(keyword)) ||
|
|
594
|
+
prompt.toLowerCase().startsWith('get system information') ||
|
|
595
|
+
prompt.toLowerCase().includes('/system')
|
|
596
|
+
);
|
|
589
597
|
|
|
590
598
|
if (isSystemQuery) {
|
|
591
599
|
try {
|
package/services/fileAnalyzer.js
CHANGED
|
@@ -1,60 +1,135 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs').promises;
|
|
3
|
+
const pdfParse = require('pdf-parse');
|
|
4
|
+
const { getFileType, readFileContent } = require('../utils/fileUtils');
|
|
5
|
+
const { processWithAI } = require('./aiService');
|
|
6
|
+
const { extractTextFromImage } = require('./imageService');
|
|
7
|
+
|
|
8
|
+
async function analyzeFile(filePath, query = '', mode = 2) {
|
|
9
|
+
try {
|
|
10
|
+
const fileType = getFileType(filePath);
|
|
11
|
+
|
|
12
|
+
// Handle images - use vision API only for images
|
|
13
|
+
if (fileType === 'image') {
|
|
14
|
+
const result = await extractTextFromImage(filePath, query, mode);
|
|
15
|
+
return { text: result };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Handle documents (PDFs, Word, etc.)
|
|
19
|
+
if (fileType === 'document') {
|
|
20
|
+
const fileName = path.basename(filePath);
|
|
21
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
22
|
+
|
|
23
|
+
// Extract text from PDF
|
|
24
|
+
if (ext === '.pdf') {
|
|
25
|
+
try {
|
|
26
|
+
const dataBuffer = await fs.readFile(filePath);
|
|
27
|
+
const pdfData = await pdfParse(dataBuffer);
|
|
28
|
+
const content = pdfData.text;
|
|
29
|
+
|
|
30
|
+
if (!content || content.trim().length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
text: `❌ **Unable to Extract Text from PDF**\n\n` +
|
|
33
|
+
`The PDF "${fileName}" appears to be empty or contains only images/scanned content.\n\n` +
|
|
34
|
+
`**Try using the /image command for scanned PDFs:**\n` +
|
|
35
|
+
`\`/image "${filePath}" ${query || 'analyze this document'}\``
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Build prompt for AI analysis
|
|
40
|
+
let prompt;
|
|
41
|
+
if (query) {
|
|
42
|
+
prompt = `PDF Document: ${fileName}
|
|
43
|
+
Content:
|
|
44
|
+
\`\`\`
|
|
45
|
+
${content}
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
User Question: ${query}`;
|
|
49
|
+
} else {
|
|
50
|
+
prompt = `Analyze this PDF document (${fileName}):
|
|
51
|
+
|
|
52
|
+
\`\`\`
|
|
53
|
+
${content}
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
Please provide a comprehensive summary and analysis of the document.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = await processWithAI(prompt, '', mode);
|
|
60
|
+
return { text: result || 'No response generated' };
|
|
61
|
+
|
|
62
|
+
} catch (pdfError) {
|
|
63
|
+
return {
|
|
64
|
+
text: `❌ **Error Reading PDF**\n\n` +
|
|
65
|
+
`Failed to extract text from "${fileName}": ${pdfError.message}\n\n` +
|
|
66
|
+
`**Possible reasons:**\n` +
|
|
67
|
+
`- The PDF is corrupted or password-protected\n` +
|
|
68
|
+
`- The PDF contains only images (scanned document)\n\n` +
|
|
69
|
+
`**Try using /image command for scanned PDFs:**\n` +
|
|
70
|
+
`\`/image "${filePath}" ${query || 'analyze this document'}\``
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// For other document types (Word, Excel, etc.)
|
|
76
|
+
return {
|
|
77
|
+
text: `❌ **Document Type Not Supported**\n\n` +
|
|
78
|
+
`The file "${fileName}" is a ${ext.toUpperCase()} document.\n\n` +
|
|
79
|
+
`**Supported formats:**\n` +
|
|
80
|
+
`- PDF files (.pdf) - Text extraction supported\n` +
|
|
81
|
+
`- Text files (.txt, .md, etc.)\n` +
|
|
82
|
+
`- Code files (.js, .py, .java, etc.)\n\n` +
|
|
83
|
+
`**For ${ext.toUpperCase()} files:**\n` +
|
|
84
|
+
`Please convert to PDF or text format first.`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle text-based files
|
|
89
|
+
const content = await readFileContent(filePath);
|
|
90
|
+
const fileName = path.basename(filePath);
|
|
91
|
+
|
|
92
|
+
let prompt;
|
|
93
|
+
if (query) {
|
|
94
|
+
prompt = `File: ${fileName} (${fileType})
|
|
95
|
+
Content:
|
|
96
|
+
\`\`\`
|
|
97
|
+
${content}
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
User Question: ${query}`;
|
|
101
|
+
} else {
|
|
102
|
+
if (fileType !== 'Unknown' && fileType !== 'Text' && fileType !== 'Markdown') {
|
|
103
|
+
prompt = `Analyze this ${fileType} code file (${fileName}):
|
|
104
|
+
|
|
105
|
+
\`\`\`
|
|
106
|
+
${content}
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
Please provide:
|
|
110
|
+
1. Code overview and purpose
|
|
111
|
+
2. Key functions/components
|
|
112
|
+
3. Potential issues or improvements
|
|
113
|
+
4. Code quality assessment
|
|
114
|
+
5. Suggestions for optimization`;
|
|
115
|
+
} else {
|
|
116
|
+
prompt = `Analyze this file content (${fileName}):
|
|
117
|
+
|
|
118
|
+
\`\`\`
|
|
119
|
+
${content}
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
Please provide a summary and analysis of the content.`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const result = await processWithAI(prompt, '', mode);
|
|
127
|
+
return { text: result || 'No response generated' };
|
|
128
|
+
} catch (error) {
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
analyzeFile
|
|
135
|
+
};
|
package/utils/fileUtils.js
CHANGED
|
@@ -1,101 +1,106 @@
|
|
|
1
|
-
const fs = require('fs').promises;
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
// File type detection
|
|
5
|
-
function getFileType(filePath) {
|
|
6
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
7
|
-
const codeExtensions = {
|
|
8
|
-
'.js': 'JavaScript',
|
|
9
|
-
'.jsx': 'React/JavaScript',
|
|
10
|
-
'.ts': 'TypeScript',
|
|
11
|
-
'.tsx': 'React/TypeScript',
|
|
12
|
-
'.py': 'Python',
|
|
13
|
-
'.java': 'Java',
|
|
14
|
-
'.cpp': 'C++',
|
|
15
|
-
'.c': 'C',
|
|
16
|
-
'.cs': 'C#',
|
|
17
|
-
'.php': 'PHP',
|
|
18
|
-
'.rb': 'Ruby',
|
|
19
|
-
'.go': 'Go',
|
|
20
|
-
'.rs': 'Rust',
|
|
21
|
-
'.swift': 'Swift',
|
|
22
|
-
'.kt': 'Kotlin',
|
|
23
|
-
'.scala': 'Scala',
|
|
24
|
-
'.html': 'HTML',
|
|
25
|
-
'.css': 'CSS',
|
|
26
|
-
'.scss': 'SCSS',
|
|
27
|
-
'.sass': 'SASS',
|
|
28
|
-
'.less': 'LESS',
|
|
29
|
-
'.vue': 'Vue.js',
|
|
30
|
-
'.svelte': 'Svelte',
|
|
31
|
-
'.json': 'JSON',
|
|
32
|
-
'.xml': 'XML',
|
|
33
|
-
'.yaml': 'YAML',
|
|
34
|
-
'.yml': 'YAML',
|
|
35
|
-
'.toml': 'TOML',
|
|
36
|
-
'.ini': 'INI',
|
|
37
|
-
'.conf': 'Config',
|
|
38
|
-
'.md': 'Markdown',
|
|
39
|
-
'.txt': 'Text',
|
|
40
|
-
'.sql': 'SQL',
|
|
41
|
-
'.sh': 'Shell Script',
|
|
42
|
-
'.bash': 'Bash Script',
|
|
43
|
-
'.zsh': 'Zsh Script',
|
|
44
|
-
'.ps1': 'PowerShell',
|
|
45
|
-
'.
|
|
46
|
-
'.
|
|
47
|
-
'.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
if (imageExtensions.includes(ext)) {
|
|
54
|
-
return 'image';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
'.
|
|
68
|
-
'.
|
|
69
|
-
'.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (stats.
|
|
84
|
-
throw new Error('
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// File type detection
|
|
5
|
+
function getFileType(filePath) {
|
|
6
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
7
|
+
const codeExtensions = {
|
|
8
|
+
'.js': 'JavaScript',
|
|
9
|
+
'.jsx': 'React/JavaScript',
|
|
10
|
+
'.ts': 'TypeScript',
|
|
11
|
+
'.tsx': 'React/TypeScript',
|
|
12
|
+
'.py': 'Python',
|
|
13
|
+
'.java': 'Java',
|
|
14
|
+
'.cpp': 'C++',
|
|
15
|
+
'.c': 'C',
|
|
16
|
+
'.cs': 'C#',
|
|
17
|
+
'.php': 'PHP',
|
|
18
|
+
'.rb': 'Ruby',
|
|
19
|
+
'.go': 'Go',
|
|
20
|
+
'.rs': 'Rust',
|
|
21
|
+
'.swift': 'Swift',
|
|
22
|
+
'.kt': 'Kotlin',
|
|
23
|
+
'.scala': 'Scala',
|
|
24
|
+
'.html': 'HTML',
|
|
25
|
+
'.css': 'CSS',
|
|
26
|
+
'.scss': 'SCSS',
|
|
27
|
+
'.sass': 'SASS',
|
|
28
|
+
'.less': 'LESS',
|
|
29
|
+
'.vue': 'Vue.js',
|
|
30
|
+
'.svelte': 'Svelte',
|
|
31
|
+
'.json': 'JSON',
|
|
32
|
+
'.xml': 'XML',
|
|
33
|
+
'.yaml': 'YAML',
|
|
34
|
+
'.yml': 'YAML',
|
|
35
|
+
'.toml': 'TOML',
|
|
36
|
+
'.ini': 'INI',
|
|
37
|
+
'.conf': 'Config',
|
|
38
|
+
'.md': 'Markdown',
|
|
39
|
+
'.txt': 'Text',
|
|
40
|
+
'.sql': 'SQL',
|
|
41
|
+
'.sh': 'Shell Script',
|
|
42
|
+
'.bash': 'Bash Script',
|
|
43
|
+
'.zsh': 'Zsh Script',
|
|
44
|
+
'.ps1': 'PowerShell',
|
|
45
|
+
'.dockerfile': 'Dockerfile',
|
|
46
|
+
'.gitignore': 'Git Ignore',
|
|
47
|
+
'.env': 'Environment Variables'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg'];
|
|
51
|
+
const documentExtensions = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx'];
|
|
52
|
+
|
|
53
|
+
if (imageExtensions.includes(ext)) {
|
|
54
|
+
return 'image';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (documentExtensions.includes(ext)) {
|
|
58
|
+
return 'document';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return codeExtensions[ext] || 'Unknown';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getMimeType(filePath) {
|
|
65
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
66
|
+
const mimeTypes = {
|
|
67
|
+
'.jpg': 'image/jpeg',
|
|
68
|
+
'.jpeg': 'image/jpeg',
|
|
69
|
+
'.png': 'image/png',
|
|
70
|
+
'.gif': 'image/gif',
|
|
71
|
+
'.webp': 'image/webp',
|
|
72
|
+
'.bmp': 'image/bmp',
|
|
73
|
+
'.svg': 'image/svg+xml',
|
|
74
|
+
'.pdf': 'application/pdf'
|
|
75
|
+
};
|
|
76
|
+
return mimeTypes[ext] || 'image/jpeg';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// File reading and processing
|
|
80
|
+
async function readFileContent(filePath) {
|
|
81
|
+
try {
|
|
82
|
+
const stats = await fs.stat(filePath);
|
|
83
|
+
if (stats.isDirectory()) {
|
|
84
|
+
throw new Error('Path is a directory, not a file');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check file size (limit to 1MB for safety)
|
|
88
|
+
if (stats.size > 1024 * 1024) {
|
|
89
|
+
throw new Error('File too large. Maximum size is 1MB');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
93
|
+
return content;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error.code === 'ENOENT') {
|
|
96
|
+
throw new Error(`File not found: ${filePath}`);
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
getFileType,
|
|
104
|
+
getMimeType,
|
|
105
|
+
readFileContent
|
|
101
106
|
};
|