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 CHANGED
@@ -1,4 +1,4 @@
1
- # Project Compass (v2.4.0)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Ink-based project explorer that detects local repos and lets you build/test/run them without memorizing commands.",
5
5
  "main": "src/cli.js",
6
6
  "type": "module",
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 Compass({rootPath}) {
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 > 250 ? appended.slice(appended.length - 250) : appended;
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
- 'Ctrl+C abort; type feeds stdin'
625
+ 'Shift+X clear output logs'
553
626
  ]
554
627
  },
555
628
  {
556
- label: 'Recent runs',
629
+ label: 'System & Studio',
557
630
  color: 'yellow',
558
631
  body: [
559
- recentRuns.length ? `${recentRuns.length} runs recorded` : 'No runs yet Β· start with B/T/R',
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 while commands stream; type to feed stdin (Enter submits, Ctrl+C aborts).'),
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 these help cards, Shift+S toggles the structure guide, ? toggles this overlay, Shift+Q quits.'),
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 (Shift+S to toggle).')
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) => {
@@ -1098,4 +1098,4 @@ const SCHEMA_GUIDE = schemaRegistry.getSchemas().map((schema) => ({
1098
1098
  files: schema.files
1099
1099
  }));
1100
1100
 
1101
- export {discoverProjects, SCHEMA_GUIDE};
1101
+ export {discoverProjects, SCHEMA_GUIDE, checkBinary};