project-compass 2.4.0 β 2.5.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/README.md +9 -2
- package/package.json +1 -1
- package/src/cli.js +86 -11
- package/src/projectDetection.js +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Project Compass (v2.
|
|
1
|
+
# Project Compass (v2.5.0)
|
|
2
2
|
|
|
3
3
|
Project Compass is a futuristic CLI navigator built with [Ink](https://github.com/vadimdemedes/ink) that scans your current folder tree for familiar code projects and gives you one-keystroke access to build, test, or run them.
|
|
4
4
|
|
|
@@ -10,6 +10,7 @@ Project Compass is a futuristic CLI navigator built with [Ink](https://github.co
|
|
|
10
10
|
- π‘ **Refined Output**: Improved stdin buffer with proper spacing and reliable scrolling (Shift+β/β).
|
|
11
11
|
- π§ **Smart Detection**: Support for 20+ frameworks including **Spring Boot** (Maven/Gradle), **ASP.NET Core**, **Rocket/Actix** (Rust), **Laravel** (PHP), **Vite**, **Prisma**, and more.
|
|
12
12
|
- β οΈ **Runtime Health**: Automatically checks if the required language/runtime (e.g., `node`, `python`, `cargo`) is installed and warns you if it's missing.
|
|
13
|
+
- π **Omni-Studio**: A new interactive environment intelligence mode to see all installed runtimes and versions.
|
|
13
14
|
- π **Extensible**: Add custom commands with **Shift+C** and frameworks via `plugins.json`.
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
@@ -21,7 +22,7 @@ npm install -g project-compass
|
|
|
21
22
|
## Usage
|
|
22
23
|
|
|
23
24
|
```bash
|
|
24
|
-
project-compass [--dir /path/to/workspace]
|
|
25
|
+
project-compass [--dir /path/to/workspace] [--studio]
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
### Keyboard Guide
|
|
@@ -31,7 +32,9 @@ project-compass [--dir /path/to/workspace]
|
|
|
31
32
|
| β / β | Move focus, **Enter**: toggle details |
|
|
32
33
|
| B / T / R | Build / Test / Run |
|
|
33
34
|
| 1β9 | Execute numbered detail commands |
|
|
35
|
+
| **Shift+A** | Open **Omni-Studio** (Environment View) |
|
|
34
36
|
| **Shift+C** | Add a custom command (`label|cmd`) |
|
|
37
|
+
| **Shift+X** | **Clear output logs** |
|
|
35
38
|
| **Shift β / β** | Scroll output buffer |
|
|
36
39
|
| **Shift+L** | Rerun last command |
|
|
37
40
|
| **Shift+H** | Toggle help cards |
|
|
@@ -40,6 +43,10 @@ project-compass [--dir /path/to/workspace]
|
|
|
40
43
|
| ? | Toggle help overlay |
|
|
41
44
|
| Ctrl+C | Interrupt running command |
|
|
42
45
|
|
|
46
|
+
## Omni-Studio
|
|
47
|
+
|
|
48
|
+
Launch with `project-compass --studio` or press **Shift+A** inside the app. Omni-Studio provides real-time intelligence on your installed development environments, checking versions for Node, Python, Rust, Go, Java, and more.
|
|
49
|
+
|
|
43
50
|
## Layout & UX
|
|
44
51
|
|
|
45
52
|
Project Compass features a split layout where Projects and Details stay paired while Output takes a full-width band. The stdin buffer (at the bottom) now has a clear distinction between the label and your input for better readability. The help cards (Shift+H) have been refactored for a cleaner, more readable look.
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import kleur from 'kleur';
|
|
7
7
|
import {execa} from 'execa';
|
|
8
|
-
import {discoverProjects, SCHEMA_GUIDE} from './projectDetection.js';
|
|
8
|
+
import {discoverProjects, SCHEMA_GUIDE, checkBinary} from './projectDetection.js';
|
|
9
9
|
import {CONFIG_PATH, PLUGIN_FILE, ensureConfigDir} from './configPaths.js';
|
|
10
10
|
|
|
11
11
|
const create = React.createElement;
|
|
@@ -95,11 +95,69 @@ function buildDetailCommands(project, config) {
|
|
|
95
95
|
return [...builtins, ...custom];
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
function
|
|
98
|
+
function Studio() {
|
|
99
|
+
const [runtimes, setRuntimes] = useState([]);
|
|
100
|
+
const [loading, setLoading] = useState(true);
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const checks = [
|
|
104
|
+
{name: 'Node.js', binary: 'node', versionCmd: ['-v']},
|
|
105
|
+
{name: 'npm', binary: 'npm', versionCmd: ['-v']},
|
|
106
|
+
{name: 'Python', binary: process.platform === 'win32' ? 'python' : 'python3', versionCmd: ['--version']},
|
|
107
|
+
{name: 'Rust (Cargo)', binary: 'cargo', versionCmd: ['--version']},
|
|
108
|
+
{name: 'Go', binary: 'go', versionCmd: ['version']},
|
|
109
|
+
{name: 'Java', binary: 'java', versionCmd: ['-version']},
|
|
110
|
+
{name: 'PHP', binary: 'php', versionCmd: ['-v']},
|
|
111
|
+
{name: 'Ruby', binary: 'ruby', versionCmd: ['-v']},
|
|
112
|
+
{name: '.NET', binary: 'dotnet', versionCmd: ['--version']}
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
(async () => {
|
|
116
|
+
const results = await Promise.all(checks.map(async (lang) => {
|
|
117
|
+
if (!checkBinary(lang.binary)) {
|
|
118
|
+
return {...lang, status: 'missing', version: 'not installed'};
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const {stdout, stderr} = await execa(lang.binary, lang.versionCmd);
|
|
122
|
+
const version = (stdout || stderr || '').split('\n')[0].trim();
|
|
123
|
+
return {...lang, status: 'ok', version};
|
|
124
|
+
} catch {
|
|
125
|
+
return {...lang, status: 'error', version: 'failed to check'};
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
128
|
+
setRuntimes(results);
|
|
129
|
+
setLoading(false);
|
|
130
|
+
})();
|
|
131
|
+
}, []);
|
|
132
|
+
|
|
133
|
+
return create(
|
|
134
|
+
Box,
|
|
135
|
+
{flexDirection: 'column', borderStyle: 'double', borderColor: 'blue', padding: 1},
|
|
136
|
+
create(Text, {bold: true, color: 'blue'}, 'π Omni-Studio | Environment Intelligence'),
|
|
137
|
+
create(Text, {dimColor: true, marginBottom: 1}, 'Overview of installed languages and build tools.'),
|
|
138
|
+
loading
|
|
139
|
+
? create(Text, {dimColor: true}, 'Gathering intelligence...')
|
|
140
|
+
: create(
|
|
141
|
+
Box,
|
|
142
|
+
{flexDirection: 'column'},
|
|
143
|
+
...runtimes.map(r => create(
|
|
144
|
+
Box,
|
|
145
|
+
{key: r.name, marginBottom: 1},
|
|
146
|
+
create(Text, {width: 15, color: r.status === 'ok' ? 'green' : 'red'}, `${r.status === 'ok' ? 'β' : 'β'} ${r.name}`),
|
|
147
|
+
create(Text, {dimColor: r.status !== 'ok'}, r.version)
|
|
148
|
+
)),
|
|
149
|
+
create(Text, {marginTop: 1, color: 'yellow'}, 'π οΈ Interactive Project Creator coming soon in v3.0'),
|
|
150
|
+
create(Text, {dimColor: true}, 'Press Shift+A to return to Navigator.')
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function Compass({rootPath, initialView = 'navigator'}) {
|
|
99
156
|
const {exit} = useApp();
|
|
100
157
|
const {projects, loading, error} = useScanner(rootPath);
|
|
101
158
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
102
159
|
const [viewMode, setViewMode] = useState('list');
|
|
160
|
+
const [mainView, setMainView] = useState(initialView);
|
|
103
161
|
const [logLines, setLogLines] = useState([]);
|
|
104
162
|
const [logOffset, setLogOffset] = useState(0);
|
|
105
163
|
const [running, setRunning] = useState(false);
|
|
@@ -120,7 +178,7 @@ function Compass({rootPath}) {
|
|
|
120
178
|
setLogLines((prev) => {
|
|
121
179
|
const normalized = typeof line === 'string' ? line : JSON.stringify(line);
|
|
122
180
|
const appended = [...prev, normalized];
|
|
123
|
-
const next = appended.length >
|
|
181
|
+
const next = appended.length > 500 ? appended.slice(appended.length - 500) : appended;
|
|
124
182
|
return next;
|
|
125
183
|
});
|
|
126
184
|
}, []);
|
|
@@ -256,6 +314,7 @@ function Compass({rootPath}) {
|
|
|
256
314
|
}
|
|
257
315
|
|
|
258
316
|
const normalizedInput = input?.toLowerCase();
|
|
317
|
+
const ctrlCombo = (char) => key.ctrl && normalizedInput === char;
|
|
259
318
|
const shiftCombo = (char) => key.shift && normalizedInput === char;
|
|
260
319
|
const toggleShortcut = (char) => shiftCombo(char);
|
|
261
320
|
if (toggleShortcut('h')) {
|
|
@@ -266,6 +325,15 @@ function Compass({rootPath}) {
|
|
|
266
325
|
setShowStructureGuide((prev) => !prev);
|
|
267
326
|
return;
|
|
268
327
|
}
|
|
328
|
+
if (toggleShortcut('a')) {
|
|
329
|
+
setMainView((prev) => (prev === 'navigator' ? 'studio' : 'navigator'));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (toggleShortcut('x')) {
|
|
333
|
+
setLogLines([]);
|
|
334
|
+
setLogOffset(0);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
269
337
|
|
|
270
338
|
const scrollLogs = (delta) => {
|
|
271
339
|
setLogOffset((prev) => {
|
|
@@ -349,6 +417,11 @@ function Compass({rootPath}) {
|
|
|
349
417
|
runProjectCommand(detailShortcutMap.get(normalizedInput), selectedProject);
|
|
350
418
|
}
|
|
351
419
|
});
|
|
420
|
+
|
|
421
|
+
if (mainView === 'studio') {
|
|
422
|
+
return create(Studio);
|
|
423
|
+
}
|
|
424
|
+
|
|
352
425
|
const projectRows = [];
|
|
353
426
|
if (loading) {
|
|
354
427
|
projectRows.push(create(Text, {dimColor: true}, 'Scanning projectsβ¦'));
|
|
@@ -549,14 +622,14 @@ const projectRows = [];
|
|
|
549
622
|
'B / T / R build/test/run',
|
|
550
623
|
'1-9 run detail commands',
|
|
551
624
|
'Shift+L rerun last command',
|
|
552
|
-
'
|
|
625
|
+
'Shift+X clear output logs'
|
|
553
626
|
]
|
|
554
627
|
},
|
|
555
628
|
{
|
|
556
|
-
label: '
|
|
629
|
+
label: 'System & Studio',
|
|
557
630
|
color: 'yellow',
|
|
558
631
|
body: [
|
|
559
|
-
|
|
632
|
+
'Shift+A open Omni-Studio',
|
|
560
633
|
'Shift+S toggle structure guide',
|
|
561
634
|
'Shift+C save custom action',
|
|
562
635
|
'Shift+Q quit application'
|
|
@@ -620,11 +693,11 @@ const projectRows = [];
|
|
|
620
693
|
padding: 1
|
|
621
694
|
},
|
|
622
695
|
create(Text, {color: 'cyan', bold: true}, 'Help overlay Β· press ? to hide'),
|
|
623
|
-
create(Text, null, 'Shift+β/β scrolls the log buffer
|
|
696
|
+
create(Text, null, 'Shift+β/β scrolls the log buffer; Shift+X clears logs; Shift+A opens Omni-Studio.'),
|
|
624
697
|
create(Text, null, 'B/T/R run build/test/run; 1-9 executes detail commands; Shift+L reruns the previous command.'),
|
|
625
|
-
create(Text, null, 'Shift+H toggles
|
|
698
|
+
create(Text, null, 'Shift+H toggles help cards, Shift+S structure guide, ? overlay, Shift+Q quits.'),
|
|
626
699
|
create(Text, null, 'Projects + Details stay paired while Output keeps its own full-width band.'),
|
|
627
|
-
create(Text, null, 'Structure guide lists the manifests that trigger each language detection
|
|
700
|
+
create(Text, null, 'Structure guide lists the manifests that trigger each language detection.')
|
|
628
701
|
)
|
|
629
702
|
: null;
|
|
630
703
|
|
|
@@ -751,6 +824,8 @@ function parseArgs() {
|
|
|
751
824
|
i += 1;
|
|
752
825
|
} else if (token === '--help' || token === '-h') {
|
|
753
826
|
args.help = true;
|
|
827
|
+
} else if (token === '--studio') {
|
|
828
|
+
args.view = 'studio';
|
|
754
829
|
}
|
|
755
830
|
}
|
|
756
831
|
return args;
|
|
@@ -760,7 +835,7 @@ async function main() {
|
|
|
760
835
|
const args = parseArgs();
|
|
761
836
|
if (args.help) {
|
|
762
837
|
console.log('Project Compass Β· Ink project runner');
|
|
763
|
-
console.log('Usage: project-compass [--dir <path>] [--mode test]');
|
|
838
|
+
console.log('Usage: project-compass [--dir <path>] [--mode test] [--studio]');
|
|
764
839
|
return;
|
|
765
840
|
}
|
|
766
841
|
const rootPath = args.root ? path.resolve(args.root) : process.cwd();
|
|
@@ -773,7 +848,7 @@ async function main() {
|
|
|
773
848
|
return;
|
|
774
849
|
}
|
|
775
850
|
|
|
776
|
-
render(create(Compass, {rootPath}));
|
|
851
|
+
render(create(Compass, {rootPath, initialView: args.view || 'navigator'}));
|
|
777
852
|
}
|
|
778
853
|
|
|
779
854
|
main().catch((error) => {
|
package/src/projectDetection.js
CHANGED