project-compass 4.0.5 → 4.1.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/package.json +1 -1
- package/src/cli.js +20 -3
- package/src/components/AIHorizon.js +43 -9
- package/src/detectors/dotnet.js +13 -0
- package/src/detectors/java.js +2 -2
- package/src/detectors/php.js +13 -0
- package/src/detectors/ruby.js +13 -0
- package/src/projectDetection.js +6 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -453,9 +453,26 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
453
453
|
|
|
454
454
|
const pageLimit = config.maxVisibleProjects || 3;
|
|
455
455
|
const pageStep = Math.max(1, pageLimit);
|
|
456
|
-
const clampIndex = (value) =>
|
|
457
|
-
|
|
458
|
-
|
|
456
|
+
const clampIndex = (value) => {
|
|
457
|
+
const idx = Math.max(0, Math.min(projects.length - 1, value));
|
|
458
|
+
return isNaN(idx) ? 0 : idx;
|
|
459
|
+
};
|
|
460
|
+
if (key.pageUp && projects.length > pageLimit) {
|
|
461
|
+
console.clear();
|
|
462
|
+
setSelectedIndex((prev) => {
|
|
463
|
+
const next = prev - pageStep;
|
|
464
|
+
return next < 0 ? 0 : next;
|
|
465
|
+
});
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (key.pageDown && projects.length > pageLimit) {
|
|
469
|
+
console.clear();
|
|
470
|
+
setSelectedIndex((prev) => {
|
|
471
|
+
const next = prev + pageStep;
|
|
472
|
+
return next >= projects.length ? (Math.floor((projects.length - 1) / pageLimit) * pageLimit) : next;
|
|
473
|
+
});
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
459
476
|
|
|
460
477
|
if (normalizedInput === '?') { console.clear(); setShowHelp((prev) => !prev); return; }
|
|
461
478
|
if (shiftCombo('l') && lastCommandRef.current) { runProjectCommand(lastCommandRef.current.commandMeta, lastCommandRef.current.project); return; }
|
|
@@ -47,6 +47,8 @@ Return ONLY a JSON object with this structure: {"build": "cmd", "run": "cmd", "i
|
|
|
47
47
|
Use the project's detected type (${selectedProject.type}) to ensure commands are correct (e.g., npm, pip, cargo).`;
|
|
48
48
|
|
|
49
49
|
let response;
|
|
50
|
+
let aiText = '';
|
|
51
|
+
|
|
50
52
|
if (provider.id === 'openrouter') {
|
|
51
53
|
response = await fetch(provider.endpoint, {
|
|
52
54
|
method: 'POST',
|
|
@@ -61,17 +63,49 @@ Use the project's detected type (${selectedProject.type}) to ensure commands are
|
|
|
61
63
|
messages: [{ role: 'user', content: prompt }]
|
|
62
64
|
})
|
|
63
65
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
if (!response.ok) throw new Error(data.error?.message || 'OpenRouter Error');
|
|
68
|
+
aiText = data.choices[0].message.content;
|
|
69
|
+
} else if (provider.id === 'gemini') {
|
|
70
|
+
const url = provider.endpoint.replace('{model}', model) + `?key=${token}`;
|
|
71
|
+
response = await fetch(url, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: { 'Content-Type': 'application/json' },
|
|
74
|
+
body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
|
|
75
|
+
});
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
if (!response.ok) throw new Error(data.error?.message || 'Gemini Error');
|
|
78
|
+
aiText = data.candidates[0].content.parts[0].text;
|
|
79
|
+
} else if (provider.id === 'claude') {
|
|
80
|
+
response = await fetch(provider.endpoint, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers: {
|
|
83
|
+
'x-api-key': token,
|
|
84
|
+
'anthropic-version': '2023-06-01',
|
|
85
|
+
'Content-Type': 'application/json'
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
model: model,
|
|
89
|
+
max_tokens: 1024,
|
|
90
|
+
messages: [{ role: 'user', content: prompt }]
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
if (!response.ok) throw new Error(data.error?.message || 'Claude Error');
|
|
95
|
+
aiText = data.content[0].text;
|
|
96
|
+
} else if (provider.id === 'ollama') {
|
|
97
|
+
response = await fetch(provider.endpoint, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { 'Content-Type': 'application/json' },
|
|
100
|
+
body: JSON.stringify({ model: model, prompt: prompt, stream: false })
|
|
101
|
+
});
|
|
102
|
+
const data = await response.json();
|
|
103
|
+
if (!response.ok) throw new Error(data.error || 'Ollama Error');
|
|
104
|
+
aiText = data.response;
|
|
67
105
|
}
|
|
68
106
|
|
|
69
|
-
const data = await response.json();
|
|
70
|
-
if (!response.ok) throw new Error(data.error?.message || 'Authentication failed. Check your token.');
|
|
71
|
-
|
|
72
|
-
const aiText = data.choices[0].message.content;
|
|
73
107
|
const jsonMatch = aiText.match(/{.*?}/s);
|
|
74
|
-
if (!jsonMatch) throw new Error("AI returned invalid DNA mapping
|
|
108
|
+
if (!jsonMatch) throw new Error("AI returned invalid DNA mapping format.");
|
|
75
109
|
|
|
76
110
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
77
111
|
const mapped = [
|
|
@@ -187,7 +221,7 @@ Use the project's detected type (${selectedProject.type}) to ensure commands are
|
|
|
187
221
|
status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Contacting AI Agent... mapping project structure...'),
|
|
188
222
|
status === 'done' && create(Box, {flexDirection: 'column'},
|
|
189
223
|
create(Text, {color: 'green', bold: true}, ' ✅ DNA Mapped via AI Agent!'),
|
|
190
|
-
create(Text, null, ' Successfully injected ' + suggestions.length + ' optimized commands
|
|
224
|
+
create(Text, null, ' Successfully injected ' + suggestions.length + ' optimized commands. AI detected potential port conflicts? Checking...'),
|
|
191
225
|
create(Text, {dimColor: true, marginTop: 1}, 'Return to Navigator to use BRIT shortcuts.')
|
|
192
226
|
),
|
|
193
227
|
error && create(Text, {color: 'red', bold: true, marginTop: 1}, ' ✗ AI ERROR: ' + error)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { checkBinary } from './utils.js';
|
|
3
|
+
export default {
|
|
4
|
+
type: 'dotnet', label: '.NET', icon: '🎯', priority: 65, files: ['*.csproj', '*.sln'], binaries: ['dotnet'],
|
|
5
|
+
async build(projectPath, manifest) {
|
|
6
|
+
const missingBinaries = this.binaries.filter(b => !checkBinary(b));
|
|
7
|
+
return {
|
|
8
|
+
id: `${projectPath}::dotnet`, path: projectPath, name: path.basename(projectPath), type: '.NET', icon: '🎯',
|
|
9
|
+
priority: this.priority, commands: { install: { label: 'dotnet restore', command: ['dotnet', 'restore'] } },
|
|
10
|
+
metadata: {}, manifest: path.basename(manifest), description: '', missingBinaries, extra: {}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
package/src/detectors/java.js
CHANGED
|
@@ -4,7 +4,7 @@ import { checkBinary, hasProjectFile } from './utils.js';
|
|
|
4
4
|
export default {
|
|
5
5
|
type: 'java',
|
|
6
6
|
label: 'Java',
|
|
7
|
-
icon: '
|
|
7
|
+
icon: '☕',
|
|
8
8
|
priority: 80,
|
|
9
9
|
files: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
|
|
10
10
|
binaries: ['java', 'javac'],
|
|
@@ -31,7 +31,7 @@ export default {
|
|
|
31
31
|
path: projectPath,
|
|
32
32
|
name: path.basename(projectPath),
|
|
33
33
|
type: 'Java',
|
|
34
|
-
icon: '
|
|
34
|
+
icon: '☕',
|
|
35
35
|
priority: this.priority,
|
|
36
36
|
commands,
|
|
37
37
|
metadata: {},
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { checkBinary } from './utils.js';
|
|
3
|
+
export default {
|
|
4
|
+
type: 'php', label: 'PHP', icon: '🐘', priority: 65, files: ['composer.json'], binaries: ['php', 'composer'],
|
|
5
|
+
async build(projectPath, manifest) {
|
|
6
|
+
const missingBinaries = this.binaries.filter(b => !checkBinary(b));
|
|
7
|
+
return {
|
|
8
|
+
id: `${projectPath}::php`, path: projectPath, name: path.basename(projectPath), type: 'PHP', icon: '🐘',
|
|
9
|
+
priority: this.priority, commands: { install: { label: 'Composer install', command: ['composer', 'install'] } },
|
|
10
|
+
metadata: {}, manifest: path.basename(manifest), description: '', missingBinaries, extra: {}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { checkBinary } from './utils.js';
|
|
3
|
+
export default {
|
|
4
|
+
type: 'ruby', label: 'Ruby', icon: '💎', priority: 65, files: ['Gemfile'], binaries: ['ruby', 'bundle'],
|
|
5
|
+
async build(projectPath, manifest) {
|
|
6
|
+
const missingBinaries = this.binaries.filter(b => !checkBinary(b));
|
|
7
|
+
return {
|
|
8
|
+
id: `${projectPath}::ruby`, path: projectPath, name: path.basename(projectPath), type: 'Ruby', icon: '💎',
|
|
9
|
+
priority: this.priority, commands: { install: { label: 'Bundle install', command: ['bundle', 'install'] } },
|
|
10
|
+
metadata: {}, manifest: path.basename(manifest), description: '', missingBinaries, extra: {}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
package/src/projectDetection.js
CHANGED
|
@@ -8,6 +8,9 @@ import pythonDetector from './detectors/python.js';
|
|
|
8
8
|
import rustDetector from './detectors/rust.js';
|
|
9
9
|
import goDetector from './detectors/go.js';
|
|
10
10
|
import javaDetector from './detectors/java.js';
|
|
11
|
+
import phpDetector from './detectors/php.js';
|
|
12
|
+
import rubyDetector from './detectors/ruby.js';
|
|
13
|
+
import dotnetDetector from './detectors/dotnet.js';
|
|
11
14
|
import genericDetector from './detectors/generic.js';
|
|
12
15
|
import { builtInFrameworks } from './detectors/frameworks.js';
|
|
13
16
|
|
|
@@ -19,6 +22,9 @@ const detectors = [
|
|
|
19
22
|
rustDetector,
|
|
20
23
|
goDetector,
|
|
21
24
|
javaDetector,
|
|
25
|
+
phpDetector,
|
|
26
|
+
rubyDetector,
|
|
27
|
+
dotnetDetector,
|
|
22
28
|
genericDetector
|
|
23
29
|
];
|
|
24
30
|
|