project-compass 4.3.2 → 4.3.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "4.3.2",
4
- "description": "🧭 Futuristic TUI workspace navigator & runner - AI-powered project detection for Node, Python, Rust, Go, Java, PHP, Ruby, .NET",
3
+ "version": "4.3.6",
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"
@@ -23,27 +23,39 @@ function getPythonPackageManager(projectPath) {
23
23
 
24
24
  function gatherPythonDependencies(projectPath) {
25
25
  const deps = new Set();
26
- const addFromRequirements = (filePath) => {
27
- if (!fs.existsSync(filePath)) return;
28
- const raw = fs.readFileSync(filePath, 'utf-8');
26
+
27
+ // Only read requirements.txt
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
- addFromRequirements(path.join(projectPath, 'requirements.txt'));
38
- addFromRequirements(path.join(projectPath, 'requirements-dev.txt'));
39
-
37
+ }
38
+
39
+ // Only read requirements-dev.txt
40
+ const reqDevPath = path.join(projectPath, 'requirements-dev.txt');
41
+ if (fs.existsSync(reqDevPath)) {
42
+ const raw = fs.readFileSync(reqDevPath, 'utf-8');
43
+ raw.split(/\r?\n/).forEach((line) => {
44
+ const clean = line.trim().split('#')[0].trim();
45
+ if (!clean || clean.startsWith('-') || clean.startsWith('"') || clean.startsWith("'")) return;
46
+ const match = clean.match(/^([a-zA-Z0-9_.-]+)/);
47
+ if (match) deps.add(match[1].toLowerCase());
48
+ });
49
+ }
50
+
51
+ // Only read pyproject.toml dependencies section
40
52
  const pyproject = path.join(projectPath, 'pyproject.toml');
41
53
  if (fs.existsSync(pyproject)) {
42
54
  const content = fs.readFileSync(pyproject, 'utf-8');
43
55
  const depSection = content.match(/(?:dependencies|requires)\s*=\s*\[([^\]]+)\]/g);
44
56
  if (depSection) {
45
57
  depSection.forEach((section) => {
46
- const matches = section.match(/["']([^"']+)["']/g);
58
+ const matches = section.match(/["']([^"']+)/g);
47
59
  if (matches) {
48
60
  matches.forEach((m) => {
49
61
  const dep = m.replace(/["']/g, '').split(/[>=<=~!]/)[0].trim();
@@ -53,11 +65,12 @@ function gatherPythonDependencies(projectPath) {
53
65
  });
54
66
  }
55
67
  }
56
-
68
+
69
+ // Only read Pipfile
57
70
  const pipfile = path.join(projectPath, 'Pipfile');
58
71
  if (fs.existsSync(pipfile)) {
59
72
  const content = fs.readFileSync(pipfile, 'utf-8');
60
- const matches = content.match(/["']([^"']+)["']/g);
73
+ const matches = content.match(/["']([^"']+)/g);
61
74
  if (matches) {
62
75
  matches.forEach((m) => {
63
76
  const dep = m.replace(/["']/g, '').split(/[>=<=~!]/)[0].trim();
@@ -65,15 +78,15 @@ function gatherPythonDependencies(projectPath) {
65
78
  });
66
79
  }
67
80
  }
68
-
81
+
69
82
  return Array.from(deps);
70
83
  }
71
84
 
72
85
  function detectPythonFramework(deps) {
73
86
  const frameworks = [];
74
87
 
75
- const hasDep = (pattern) =>
76
- deps.some(dep => {
88
+ const hasDep = (pattern) => {
89
+ return deps.some((dep) => {
77
90
  const depLower = dep.toLowerCase();
78
91
  return depLower === pattern.toLowerCase() ||
79
92
  depLower.startsWith(pattern.toLowerCase() + '==') ||
@@ -81,24 +94,25 @@ function detectPythonFramework(deps) {
81
94
  depLower.startsWith(pattern.toLowerCase() + '<=') ||
82
95
  depLower.startsWith(pattern.toLowerCase() + '~=');
83
96
  });
97
+ };
84
98
 
85
- if (hasDep('fastapi')) frameworks.push({ name: 'FastAPI', icon: '\u26A1' });
86
- if (hasDep('flask')) frameworks.push({ name: 'Flask', icon: '\uD83C\uDF36\uFE0F' });
87
- if (hasDep('django')) frameworks.push({ name: 'Django', icon: '\uD83C\uDF3F' });
88
- if (hasDep('tornado')) frameworks.push({ name: 'Tornado', icon: '\uD83C\uDF2A\uFE0F' });
89
- if (hasDep('aiohttp')) frameworks.push({ name: 'AioHTTP', icon: '\uD83D\uDD04' });
90
- if (hasDep('sanic')) frameworks.push({ name: 'Sanic', icon: '\uD83D\uDE80' });
91
- if (hasDep('pyramid')) frameworks.push({ name: 'Pyramid', icon: '\uD83D\uDE3A' });
92
- if (hasDep('falcon')) frameworks.push({ name: 'Falcon', icon: '\uD83D\uDC05' });
93
- if (hasDep('starlette')) frameworks.push({ name: 'Starlette', icon: '\u2B50' });
94
- if (hasDep('pandas')) frameworks.push({ name: 'Pandas', icon: '\uD83D\uDC3C' });
95
- if (hasDep('numpy')) frameworks.push({ name: 'NumPy', icon: '\uD83D\uDD22' });
96
- if (hasDep('scipy')) frameworks.push({ name: 'SciPy', icon: '\uD83D\uDD2C' });
97
- if (hasDep('torch') || hasDep('pytorch')) frameworks.push({ name: 'PyTorch', icon: '\uD83D\uDD25' });
98
- if (hasDep('tensorflow')) frameworks.push({ name: 'TensorFlow', icon: '\uD83E\uDD20' });
99
- if (hasDep('sqlalchemy')) frameworks.push({ name: 'SQLAlchemy', icon: '\uD83D\uDCC4\uFE0F' });
100
- if (hasDep('pytest')) frameworks.push({ name: 'Pytest', icon: '\u2705' });
101
- if (hasDep('celery')) frameworks.push({ name: 'Celery', icon: '\uD83D\uDE2C' });
99
+ if (hasDep('fastapi')) frameworks.push({ name: 'FastAPI', icon: '' });
100
+ if (hasDep('flask')) frameworks.push({ name: 'Flask', icon: '🌶️' });
101
+ if (hasDep('django')) frameworks.push({ name: 'Django', icon: '🌿' });
102
+ if (hasDep('tornado')) frameworks.push({ name: 'Tornado', icon: '🌪️' });
103
+ if (hasDep('aiohttp')) frameworks.push({ name: 'AioHTTP', icon: '🔄' });
104
+ if (hasDep('sanic')) frameworks.push({ name: 'Sanic', icon: '🚀' });
105
+ if (hasDep('pyramid')) frameworks.push({ name: 'Pyramid', icon: '🔺' });
106
+ if (hasDep('falcon')) frameworks.push({ name: 'Falcon', icon: '🦅' });
107
+ if (hasDep('starlette')) frameworks.push({ name: 'Starlette', icon: '' });
108
+ if (hasDep('pandas')) frameworks.push({ name: 'Pandas', icon: '🐼' });
109
+ if (hasDep('numpy')) frameworks.push({ name: 'NumPy', icon: '🔢' });
110
+ if (hasDep('scipy')) frameworks.push({ name: 'SciPy', icon: '🔬' });
111
+ if (hasDep('torch') || hasDep('pytorch')) frameworks.push({ name: 'PyTorch', icon: '🔥' });
112
+ if (hasDep('tensorflow')) frameworks.push({ name: 'TensorFlow', icon: '🧠' });
113
+ if (hasDep('sqlalchemy')) frameworks.push({ name: 'SQLAlchemy', icon: '🗄️' });
114
+ if (hasDep('pytest')) frameworks.push({ name: 'Pytest', icon: '' });
115
+ if (hasDep('celery')) frameworks.push({ name: 'Celery', icon: '🥬' });
102
116
 
103
117
  return frameworks;
104
118
  }
@@ -117,8 +131,10 @@ export default {
117
131
  const isPoetry = pkgManager === 'poetry';
118
132
  const isPipenv = pkgManager === 'pipenv';
119
133
 
134
+ const allDeps = gatherPythonDependencies(projectPath);
135
+ const detectedFrameworks = detectPythonFramework(allDeps);
136
+
120
137
  const commands = {};
121
-
122
138
  if (isUV) {
123
139
  commands.install = { label: 'UV Sync', command: ['uv', 'sync'], source: 'builtin' };
124
140
  commands.add = { label: 'UV Add', command: ['uv', 'add'], source: 'builtin' };
@@ -151,28 +167,16 @@ export default {
151
167
 
152
168
  if (hasProjectFile(projectPath, 'manage.py')) {
153
169
  const djangoCmd = isUV ? ['uv', 'run', 'python', 'manage.py'] :
154
- isPoetry ? ['poetry', 'run', 'python', 'manage.py'] :
155
- ['python', 'manage.py'];
170
+ ['python', 'manage.py'];
156
171
  commands['runserver'] = { label: 'Django Runserver', command: [...djangoCmd, 'runserver'], source: 'builtin' };
157
172
  commands['migrate'] = { label: 'Django Migrate', command: [...djangoCmd, 'migrate'], source: 'builtin' };
158
173
  commands['test'] = { label: 'Django Test', command: [...djangoCmd, 'test'], source: 'builtin' };
159
174
  }
160
175
 
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
176
  const metadata = {
173
177
  dependencies: allDeps,
174
- packageManager: pkgManager,
175
- frameworks: detectedFrameworks
178
+ frameworks: detectedFrameworks,
179
+ packageManager: pkgManager
176
180
  };
177
181
 
178
182
  const setupHints = [];