project-compass 4.3.3 → 4.3.7
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/AGENTS.md +1121 -22
- package/ARCHITECTURE.md +826 -10
- package/CONTRIBUTING.md +974 -10
- package/PROJECT_CONTEXT.md +404 -0
- package/README.md +594 -67
- package/commands.md +841 -104
- package/package.json +5 -4
- package/src/cli.js +310 -169
- package/src/components/AIHorizon.js +138 -255
- package/src/components/Footer.js +8 -64
- package/src/components/Header.js +8 -47
- package/src/components/Navigator.js +16 -70
- package/src/components/PackageRegistry.js +4 -3
- package/src/components/ProjectArchitect.js +6 -1
- package/src/components/TaskManager.js +12 -70
- package/src/detectors/dotnet.js +3 -2
- package/src/detectors/frameworks.js +28 -28
- package/src/detectors/go.js +6 -6
- package/src/detectors/java.js +2 -1
- package/src/detectors/node.js +3 -2
- package/src/detectors/php.js +1 -1
- package/src/detectors/python.js +33 -12
- package/src/detectors/ruby.js +1 -1
- package/src/detectors/rust.js +2 -2
- package/src/detectors/utils.js +6 -7
- package/src/projectDetection.js +41 -5
- package/src/store/useProjectStore.js +0 -32
package/src/detectors/ruby.js
CHANGED
|
@@ -58,7 +58,7 @@ export default {
|
|
|
58
58
|
const commands = {
|
|
59
59
|
install: { label: 'Bundle install', command: ['bundle', 'install'], source: 'builtin' },
|
|
60
60
|
update: { label: 'Bundle update', command: ['bundle', 'update'], source: 'builtin' },
|
|
61
|
-
console: { label: 'Ruby console', command: ['
|
|
61
|
+
console: { label: 'Ruby console', command: ['irb'], source: 'builtin' }
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
if (hasProjectFile(projectPath, 'bin/rails')) {
|
package/src/detectors/rust.js
CHANGED
|
@@ -40,8 +40,8 @@ function parseCargoToml(content) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (inDependencies && trimmed && !trimmed.startsWith('#')) {
|
|
43
|
-
const depName = trimmed.split(
|
|
44
|
-
if (depName) metadata.dependencies.push(depName);
|
|
43
|
+
const depName = trimmed.split(/[={]/)[0]?.trim();
|
|
44
|
+
if (depName && !depName.startsWith('#')) metadata.dependencies.push(depName);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
if (inBin && trimmed.startsWith('name')) {
|
package/src/detectors/utils.js
CHANGED
|
@@ -98,13 +98,12 @@ export function dependencyMatches(project, needle) {
|
|
|
98
98
|
return '';
|
|
99
99
|
}).filter(Boolean);
|
|
100
100
|
const target = needle.toLowerCase();
|
|
101
|
-
return dependencies.some((value) =>
|
|
102
|
-
value === target
|
|
103
|
-
value.startsWith(`${target}@`) ||
|
|
104
|
-
value.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
101
|
+
return dependencies.some((value) => {
|
|
102
|
+
if (value === target) return true;
|
|
103
|
+
if (value.startsWith(`${target}@`) || value.startsWith(`${target}==`) || value.startsWith(`${target}>=`) || value.startsWith(`${target}~=`)) return true;
|
|
104
|
+
if (value.startsWith(`${target}/`) || value.endsWith(`/${target}`)) return true;
|
|
105
|
+
return false;
|
|
106
|
+
});
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
export function parseCommandTokens(value) {
|
package/src/projectDetection.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fastGlob from 'fast-glob';
|
|
4
|
-
import { ensureConfigDir, PLUGIN_FILE } from './configPaths.js';
|
|
4
|
+
import { ensureConfigDir, PLUGIN_FILE, CONFIG_PATH } from './configPaths.js';
|
|
5
5
|
import { dependencyMatches, hasProjectFile, parseCommandTokens, checkBinary } from './detectors/utils.js';
|
|
6
6
|
import nodeDetector from './detectors/node.js';
|
|
7
7
|
import pythonDetector from './detectors/python.js';
|
|
@@ -13,6 +13,7 @@ import rubyDetector from './detectors/ruby.js';
|
|
|
13
13
|
import dotnetDetector from './detectors/dotnet.js';
|
|
14
14
|
import genericDetector from './detectors/generic.js';
|
|
15
15
|
import { builtInFrameworks } from './detectors/frameworks.js';
|
|
16
|
+
import { loadProjectConfig } from './detectors/compass-config.js';
|
|
16
17
|
|
|
17
18
|
const IGNORE_PATTERNS = ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**', '**/target/**'];
|
|
18
19
|
|
|
@@ -71,11 +72,20 @@ function loadUserFrameworks() {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
let cachedFrameworkPlugins = null;
|
|
75
|
+
let cachedPluginMtime = 0;
|
|
74
76
|
|
|
75
77
|
function getFrameworkPlugins() {
|
|
76
|
-
|
|
78
|
+
let currentMtime = 0;
|
|
79
|
+
try {
|
|
80
|
+
if (fs.existsSync(PLUGIN_FILE)) {
|
|
81
|
+
currentMtime = fs.statSync(PLUGIN_FILE).mtimeMs;
|
|
82
|
+
}
|
|
83
|
+
} catch { /* ignore */ }
|
|
84
|
+
|
|
85
|
+
if (cachedFrameworkPlugins && currentMtime <= cachedPluginMtime) {
|
|
77
86
|
return cachedFrameworkPlugins;
|
|
78
87
|
}
|
|
88
|
+
cachedPluginMtime = currentMtime;
|
|
79
89
|
cachedFrameworkPlugins = [...builtInFrameworks, ...loadUserFrameworks()];
|
|
80
90
|
return cachedFrameworkPlugins;
|
|
81
91
|
}
|
|
@@ -114,13 +124,16 @@ function matchesPlugin(project, plugin) {
|
|
|
114
124
|
function applyFrameworkPlugins(project) {
|
|
115
125
|
const plugins = getFrameworkPlugins();
|
|
116
126
|
let commands = { ...project.commands };
|
|
117
|
-
const frameworks = [];
|
|
127
|
+
const frameworks = [...(project.frameworks || [])];
|
|
118
128
|
let maxPriority = project.priority || 0;
|
|
119
129
|
for (const plugin of plugins) {
|
|
120
130
|
if (!matchesPlugin(project, plugin)) {
|
|
121
131
|
continue;
|
|
122
132
|
}
|
|
123
|
-
frameworks.
|
|
133
|
+
const exists = frameworks.some(f => f.name === plugin.name);
|
|
134
|
+
if (!exists) {
|
|
135
|
+
frameworks.push({ id: plugin.id, name: plugin.name, icon: plugin.icon, description: plugin.description });
|
|
136
|
+
}
|
|
124
137
|
if (plugin.priority && plugin.priority > maxPriority) {
|
|
125
138
|
maxPriority = plugin.priority;
|
|
126
139
|
}
|
|
@@ -166,6 +179,13 @@ export async function discoverProjects(root) {
|
|
|
166
179
|
if (!entry) {
|
|
167
180
|
continue;
|
|
168
181
|
}
|
|
182
|
+
const projectConfig = await loadProjectConfig(projectDir);
|
|
183
|
+
if (projectConfig) {
|
|
184
|
+
entry.commands = { ...entry.commands, ...(projectConfig.commands || {}) };
|
|
185
|
+
if (projectConfig.frameworks) {
|
|
186
|
+
entry.frameworks = [...(entry.frameworks || []), ...projectConfig.frameworks];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
169
189
|
const withFrameworks = applyFrameworkPlugins(entry);
|
|
170
190
|
projectMap.set(projectDir, withFrameworks);
|
|
171
191
|
} catch (innerError) {
|
|
@@ -176,7 +196,23 @@ export async function discoverProjects(root) {
|
|
|
176
196
|
console.error(`Error in detector ${detector.type}: ${error.message}`);
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
|
-
|
|
199
|
+
const sorted = Array.from(projectMap.values()).sort((a, b) => b.priority - a.priority);
|
|
200
|
+
|
|
201
|
+
let savedMeta = {};
|
|
202
|
+
try {
|
|
203
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
204
|
+
savedMeta = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'))?.projectMeta || {};
|
|
205
|
+
}
|
|
206
|
+
} catch { /* ignore */ }
|
|
207
|
+
|
|
208
|
+
let portBase = 3000;
|
|
209
|
+
for (const project of sorted) {
|
|
210
|
+
const saved = savedMeta[project.path];
|
|
211
|
+
const existingPort = saved?.port || project.metadata?.port;
|
|
212
|
+
project.metadata = { ...project.metadata, port: existingPort || String(portBase) };
|
|
213
|
+
if (!existingPort) portBase++;
|
|
214
|
+
}
|
|
215
|
+
return sorted;
|
|
180
216
|
}
|
|
181
217
|
|
|
182
218
|
export const SCHEMA_GUIDE = detectors.map((d) => ({
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
export function useProjectStore(initialProjects = []) {
|
|
4
|
-
const [projects, setProjects] = useState(initialProjects);
|
|
5
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
-
const [activeTab, setActiveTab] = useState('navigator');
|
|
7
|
-
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
|
8
|
-
const [config, setConfig] = useState({ maxVisibleProjects: 8 });
|
|
9
|
-
|
|
10
|
-
const selectedProject = useMemo(() => {
|
|
11
|
-
return projects.find(p => p.id === selectedProjectId) || projects[selectedIndex] || null;
|
|
12
|
-
}, [projects, selectedIndex, selectedProjectId]);
|
|
13
|
-
|
|
14
|
-
const selectProject = useCallback((index) => {
|
|
15
|
-
setSelectedIndex(index);
|
|
16
|
-
if (projects[index]) {
|
|
17
|
-
setSelectedProjectId(projects[index].id);
|
|
18
|
-
}
|
|
19
|
-
}, [projects]);
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
projects,
|
|
23
|
-
setProjects,
|
|
24
|
-
selectedIndex,
|
|
25
|
-
setSelectedIndex: selectProject,
|
|
26
|
-
activeTab,
|
|
27
|
-
setActiveTab,
|
|
28
|
-
selectedProject,
|
|
29
|
-
config,
|
|
30
|
-
setConfig
|
|
31
|
-
};
|
|
32
|
-
}
|