project-compass 4.3.2 → 4.3.3
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/package.json +2 -2
- package/src/detectors/python.js +48 -58
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "project-compass",
|
|
3
|
-
"version": "4.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.3.3",
|
|
4
|
+
"description": "\ud83e\udded Futuristic TUI workspace navigator & runner - AI-powered project detection for Node, Python, Rust, Go, Java, PHP, Ruby, .NET",
|
|
5
5
|
"main": "src/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"project-compass": "src/cli.js"
|
package/src/detectors/python.js
CHANGED
|
@@ -23,27 +23,38 @@ function getPythonPackageManager(projectPath) {
|
|
|
23
23
|
|
|
24
24
|
function gatherPythonDependencies(projectPath) {
|
|
25
25
|
const deps = new Set();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
|
|
27
|
+
// Only read requirements.txt files - NOT .py files!
|
|
28
|
+
const reqPath = path.join(projectPath, 'requirements.txt');
|
|
29
|
+
if (fs.existsSync(reqPath)) {
|
|
30
|
+
const raw = fs.readFileSync(reqPath, 'utf-8');
|
|
29
31
|
raw.split(/\r?\n/).forEach((line) => {
|
|
30
32
|
const clean = line.trim().split('#')[0].trim();
|
|
31
33
|
if (!clean || clean.startsWith('-') || clean.startsWith('"') || clean.startsWith("'")) return;
|
|
32
34
|
const match = clean.match(/^([a-zA-Z0-9_.-]+)/);
|
|
33
35
|
if (match) deps.add(match[1].toLowerCase());
|
|
34
36
|
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const reqDevPath = path.join(projectPath, 'requirements-dev.txt');
|
|
40
|
+
if (fs.existsSync(reqDevPath)) {
|
|
41
|
+
const raw = fs.readFileSync(reqDevPath, 'utf-8');
|
|
42
|
+
raw.split(/\r?\n/).forEach((line) => {
|
|
43
|
+
const clean = line.trim().split('#')[0].trim();
|
|
44
|
+
if (!clean || clean.startsWith('-') || clean.startsWith('"') || clean.startsWith("'")) return;
|
|
45
|
+
const match = clean.match(/^([a-zA-Z0-9_.-]+)/);
|
|
46
|
+
if (match) deps.add(match[1].toLowerCase());
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Only read pyproject.toml dependencies section - NOT .py files!
|
|
40
51
|
const pyproject = path.join(projectPath, 'pyproject.toml');
|
|
41
52
|
if (fs.existsSync(pyproject)) {
|
|
42
53
|
const content = fs.readFileSync(pyproject, 'utf-8');
|
|
43
54
|
const depSection = content.match(/(?:dependencies|requires)\s*=\s*\[([^\]]+)\]/g);
|
|
44
55
|
if (depSection) {
|
|
45
56
|
depSection.forEach((section) => {
|
|
46
|
-
const matches = section.match(/["']([^"']+)
|
|
57
|
+
const matches = section.match(/["']([^"']+)/g);
|
|
47
58
|
if (matches) {
|
|
48
59
|
matches.forEach((m) => {
|
|
49
60
|
const dep = m.replace(/["']/g, '').split(/[>=<=~!]/)[0].trim();
|
|
@@ -53,27 +64,16 @@ function gatherPythonDependencies(projectPath) {
|
|
|
53
64
|
});
|
|
54
65
|
}
|
|
55
66
|
}
|
|
56
|
-
|
|
57
|
-
const pipfile = path.join(projectPath, 'Pipfile');
|
|
58
|
-
if (fs.existsSync(pipfile)) {
|
|
59
|
-
const content = fs.readFileSync(pipfile, 'utf-8');
|
|
60
|
-
const matches = content.match(/["']([^"']+)["']/g);
|
|
61
|
-
if (matches) {
|
|
62
|
-
matches.forEach((m) => {
|
|
63
|
-
const dep = m.replace(/["']/g, '').split(/[>=<=~!]/)[0].trim();
|
|
64
|
-
if (dep) deps.add(dep.toLowerCase());
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
67
|
+
|
|
69
68
|
return Array.from(deps);
|
|
70
69
|
}
|
|
71
70
|
|
|
71
|
+
// Uses EXACT matching - NOT substring!
|
|
72
72
|
function detectPythonFramework(deps) {
|
|
73
73
|
const frameworks = [];
|
|
74
74
|
|
|
75
75
|
const hasDep = (pattern) =>
|
|
76
|
-
deps.some(dep => {
|
|
76
|
+
deps.some((dep) => {
|
|
77
77
|
const depLower = dep.toLowerCase();
|
|
78
78
|
return depLower === pattern.toLowerCase() ||
|
|
79
79
|
depLower.startsWith(pattern.toLowerCase() + '==') ||
|
|
@@ -82,23 +82,23 @@ function detectPythonFramework(deps) {
|
|
|
82
82
|
depLower.startsWith(pattern.toLowerCase() + '~=');
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
if (hasDep('fastapi')) frameworks.push({ name: 'FastAPI', icon: '
|
|
86
|
-
if (hasDep('flask')) frameworks.push({ name: 'Flask', icon: '
|
|
87
|
-
if (hasDep('django')) frameworks.push({ name: 'Django', icon: '
|
|
88
|
-
if (hasDep('tornado')) frameworks.push({ name: 'Tornado', icon: '
|
|
89
|
-
if (hasDep('aiohttp')) frameworks.push({ name: 'AioHTTP', icon: '
|
|
90
|
-
if (hasDep('sanic')) frameworks.push({ name: 'Sanic', icon: '
|
|
91
|
-
if (hasDep('pyramid')) frameworks.push({ name: 'Pyramid', icon: '
|
|
92
|
-
if (hasDep('falcon')) frameworks.push({ name: 'Falcon', icon: '
|
|
93
|
-
if (hasDep('starlette')) frameworks.push({ name: 'Starlette', icon: '
|
|
94
|
-
if (hasDep('pandas')) frameworks.push({ name: 'Pandas', icon: '
|
|
95
|
-
if (hasDep('numpy')) frameworks.push({ name: 'NumPy', icon: '
|
|
96
|
-
if (hasDep('scipy')) frameworks.push({ name: 'SciPy', icon: '
|
|
97
|
-
if (hasDep('torch') || hasDep('pytorch')) frameworks.push({ name: 'PyTorch', icon: '
|
|
98
|
-
if (hasDep('tensorflow')) frameworks.push({ name: 'TensorFlow', icon: '
|
|
99
|
-
if (hasDep('sqlalchemy')) frameworks.push({ name: 'SQLAlchemy', icon: '
|
|
100
|
-
if (hasDep('pytest')) frameworks.push({ name: 'Pytest', icon: '
|
|
101
|
-
if (hasDep('celery')) frameworks.push({ name: 'Celery', icon: '
|
|
85
|
+
if (hasDep('fastapi')) frameworks.push({ name: 'FastAPI', icon: '⚡' });
|
|
86
|
+
if (hasDep('flask')) frameworks.push({ name: 'Flask', icon: '🌶️' });
|
|
87
|
+
if (hasDep('django')) frameworks.push({ name: 'Django', icon: '🌿' });
|
|
88
|
+
if (hasDep('tornado')) frameworks.push({ name: 'Tornado', icon: '🌪️' });
|
|
89
|
+
if (hasDep('aiohttp')) frameworks.push({ name: 'AioHTTP', icon: '🔄' });
|
|
90
|
+
if (hasDep('sanic')) frameworks.push({ name: 'Sanic', icon: '🚀' });
|
|
91
|
+
if (hasDep('pyramid')) frameworks.push({ name: 'Pyramid', icon: '🔺' });
|
|
92
|
+
if (hasDep('falcon')) frameworks.push({ name: 'Falcon', icon: '🦅' });
|
|
93
|
+
if (hasDep('starlette')) frameworks.push({ name: 'Starlette', icon: '⭐' });
|
|
94
|
+
if (hasDep('pandas')) frameworks.push({ name: 'Pandas', icon: '🐼' });
|
|
95
|
+
if (hasDep('numpy')) frameworks.push({ name: 'NumPy', icon: '🔢' });
|
|
96
|
+
if (hasDep('scipy')) frameworks.push({ name: 'SciPy', icon: '🔬' });
|
|
97
|
+
if (hasDep('torch') || hasDep('pytorch')) frameworks.push({ name: 'PyTorch', icon: '🔥' });
|
|
98
|
+
if (hasDep('tensorflow')) frameworks.push({ name: 'TensorFlow', icon: '🧠' });
|
|
99
|
+
if (hasDep('sqlalchemy')) frameworks.push({ name: 'SQLAlchemy', icon: '🗄️' });
|
|
100
|
+
if (hasDep('pytest')) frameworks.push({ name: 'Pytest', icon: '✅' });
|
|
101
|
+
if (hasDep('celery')) frameworks.push({ name: 'Celery', icon: '🥬' });
|
|
102
102
|
|
|
103
103
|
return frameworks;
|
|
104
104
|
}
|
|
@@ -117,8 +117,10 @@ export default {
|
|
|
117
117
|
const isPoetry = pkgManager === 'poetry';
|
|
118
118
|
const isPipenv = pkgManager === 'pipenv';
|
|
119
119
|
|
|
120
|
+
const allDeps = gatherPythonDependencies(projectPath);
|
|
121
|
+
const detectedFrameworks = detectPythonFramework(allDeps);
|
|
122
|
+
|
|
120
123
|
const commands = {};
|
|
121
|
-
|
|
122
124
|
if (isUV) {
|
|
123
125
|
commands.install = { label: 'UV Sync', command: ['uv', 'sync'], source: 'builtin' };
|
|
124
126
|
commands.add = { label: 'UV Add', command: ['uv', 'add'], source: 'builtin' };
|
|
@@ -134,8 +136,8 @@ export default {
|
|
|
134
136
|
commands.install = { label: 'Pip Install', command: ['pip', 'install', '-r', 'requirements.txt'], source: 'builtin' };
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
if (
|
|
138
|
-
commands.test = { label: 'Pytest', command: [isUV ? 'uv' : '
|
|
139
|
+
if (isUV || isPoetry || isPipenv) {
|
|
140
|
+
commands.test = { label: 'Pytest', command: [isUV ? 'uv' : isPoetry ? 'poetry' : 'pipenv', ...(isUV ? ['run'] : []), 'pytest'], source: 'builtin' };
|
|
139
141
|
} else {
|
|
140
142
|
commands.test = { label: 'Unittest', command: ['python', '-m', 'unittest', 'discover'], source: 'builtin' };
|
|
141
143
|
}
|
|
@@ -151,28 +153,16 @@ export default {
|
|
|
151
153
|
|
|
152
154
|
if (hasProjectFile(projectPath, 'manage.py')) {
|
|
153
155
|
const djangoCmd = isUV ? ['uv', 'run', 'python', 'manage.py'] :
|
|
154
|
-
|
|
155
|
-
['python', 'manage.py'];
|
|
156
|
+
['python', 'manage.py'];
|
|
156
157
|
commands['runserver'] = { label: 'Django Runserver', command: [...djangoCmd, 'runserver'], source: 'builtin' };
|
|
157
158
|
commands['migrate'] = { label: 'Django Migrate', command: [...djangoCmd, 'migrate'], source: 'builtin' };
|
|
158
159
|
commands['test'] = { label: 'Django Test', command: [...djangoCmd, 'test'], source: 'builtin' };
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
if (hasProjectFile(projectPath, 'fastapi') || hasProjectFile(projectPath, 'main.py')) {
|
|
162
|
-
if (hasProjectFile(projectPath, 'main.py')) {
|
|
163
|
-
const fastapiCmd = isUV ? ['uv', 'run', 'uvicorn', 'main:app', '--reload'] :
|
|
164
|
-
['uvicorn', 'main:app', '--reload'];
|
|
165
|
-
commands['dev'] = { label: 'FastAPI Dev', command: fastapiCmd, source: 'builtin' };
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const allDeps = gatherPythonDependencies(projectPath);
|
|
170
|
-
const detectedFrameworks = detectPythonFramework(allDeps);
|
|
171
|
-
|
|
172
162
|
const metadata = {
|
|
173
163
|
dependencies: allDeps,
|
|
174
|
-
|
|
175
|
-
|
|
164
|
+
frameworks: detectedFrameworks,
|
|
165
|
+
packageManager: pkgManager
|
|
176
166
|
};
|
|
177
167
|
|
|
178
168
|
const setupHints = [];
|