project-compass 2.2.0 โ†’ 2.3.1

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,14 +1,14 @@
1
- # Project Compass (v2.2.0)
1
+ # Project Compass (v2.3.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
 
5
5
  ## Highlights
6
6
 
7
- - ๐Ÿ” Scans directories for Node.js, Python, Rust, Go, Java, and Scala projects.
7
+ - ๐Ÿ” Scans directories for Node.js, Python, Rust, Go, Java, Scala, PHP, Ruby, and .NET projects.
8
8
  - ๐ŸŽจ Futuristic layout with glyph-based art board and split Projects/Details rows.
9
9
  - ๐Ÿš€ **New Keyboard-Centric UX**: Shortcuts now use **Shift** instead of Ctrl to avoid terminal interference.
10
10
  - ๐Ÿ’ก **Refined Output**: Improved stdin buffer with proper spacing and reliable scrolling (Shift+โ†‘/โ†“).
11
- - ๐Ÿง  **Smart Detection**: Support for 15+ frameworks (Vite, Prisma, Tailwind, etc.) with specialized build/run commands and setup hints.
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
  - ๐Ÿ”Œ **Extensible**: Add custom commands with **Shift+C** and frameworks via `plugins.json`.
13
13
 
14
14
  ## Installation
@@ -45,7 +45,13 @@ Project Compass features a split layout where Projects and Details stay paired w
45
45
 
46
46
  ## Frameworks
47
47
 
48
- Detects **Next.js**, **React**, **Vue**, **NestJS**, **FastAPI**, **Django**, **Vite**, **Prisma**, **Tailwind**, and more. Recognizes frameworks and injects specialized commands automatically.
48
+ Supports a wide array of modern stacks:
49
+ - **Node.js**: Next.js, React, Vue, NestJS, Vite, Prisma, Tailwind
50
+ - **Python**: FastAPI, Django, Flask
51
+ - **Java/Kotlin**: Spring Boot (Maven & Gradle)
52
+ - **Rust**: Rocket, Actix Web
53
+ - **.NET**: ASP.NET Core
54
+ - **PHP**: Laravel
49
55
 
50
56
  ## License
51
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
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
@@ -121,13 +121,6 @@ function Compass({rootPath}) {
121
121
  const normalized = typeof line === 'string' ? line : JSON.stringify(line);
122
122
  const appended = [...prev, normalized];
123
123
  const next = appended.length > 250 ? appended.slice(appended.length - 250) : appended;
124
- setLogOffset((prevOffset) => {
125
- const maxScroll = Math.max(0, next.length - OUTPUT_WINDOW_SIZE);
126
- if (prevOffset === 0) {
127
- return 0;
128
- }
129
- return Math.min(maxScroll, prevOffset + 1);
130
- });
131
124
  return next;
132
125
  });
133
126
  }, []);
@@ -263,7 +256,6 @@ function Compass({rootPath}) {
263
256
  }
264
257
 
265
258
  const normalizedInput = input?.toLowerCase();
266
- const ctrlCombo = (char) => key.ctrl && normalizedInput === char;
267
259
  const shiftCombo = (char) => key.shift && normalizedInput === char;
268
260
  const toggleShortcut = (char) => shiftCombo(char);
269
261
  if (toggleShortcut('h')) {
@@ -306,11 +298,11 @@ function Compass({rootPath}) {
306
298
  }
307
299
 
308
300
  if (key.shift && key.upArrow) {
309
- scrollLogs(1);
301
+ scrollLogs(-1);
310
302
  return;
311
303
  }
312
304
  if (key.shift && key.downArrow) {
313
- scrollLogs(-1);
305
+ scrollLogs(1);
314
306
  return;
315
307
  }
316
308
 
@@ -524,20 +516,20 @@ const projectRows = [];
524
516
  label: 'Navigation',
525
517
  color: 'magenta',
526
518
  body: [
527
- 'โ†‘ / โ†“ move the project focus',
528
- 'Enter toggles details view',
529
- 'Shift+โ†‘ / โ†“ scroll output buffer',
530
- 'Shift+H toggles help cards'
519
+ 'โ†‘ / โ†“ move focus, Enter: details',
520
+ 'Shift+โ†‘ / โ†“ scroll output',
521
+ 'Shift+H toggle help cards',
522
+ '? opens the overlay help'
531
523
  ]
532
524
  },
533
525
  {
534
526
  label: 'Command flow',
535
527
  color: 'cyan',
536
528
  body: [
537
- 'B / T / R run build/test/run',
538
- '1-9 execute detail commands',
539
- 'Shift+L reruns last command',
540
- 'Ctrl+C aborts; type feeds stdin'
529
+ 'B / T / R build/test/run',
530
+ '1-9 run detail commands',
531
+ 'Shift+L rerun last command',
532
+ 'Ctrl+C abort; type feeds stdin'
541
533
  ]
542
534
  },
543
535
  {
@@ -545,7 +537,7 @@ const projectRows = [];
545
537
  color: 'yellow',
546
538
  body: [
547
539
  recentRuns.length ? `${recentRuns.length} runs recorded` : 'No runs yet ยท start with B/T/R',
548
- 'Shift+S toggles structure guide',
540
+ 'Shift+S toggle structure guide',
549
541
  'Shift+C save custom action',
550
542
  'Shift+Q quit application'
551
543
  ]
@@ -609,10 +601,10 @@ const projectRows = [];
609
601
  },
610
602
  create(Text, {color: 'cyan', bold: true}, 'Help overlay ยท press ? to hide'),
611
603
  create(Text, null, 'Shift+โ†‘/โ†“ scrolls the log buffer while commands stream; type to feed stdin (Enter submits, Ctrl+C aborts).'),
612
- create(Text, null, 'B/T/R run build/test/run; 1-9 executes detail commands; Ctrl+L reruns the previous command.'),
613
- create(Text, null, 'Ctrl+H toggles these help cards, Ctrl+S toggles the structure guide, ? toggles this overlay, Ctrl+Q quits.'),
604
+ create(Text, null, 'B/T/R run build/test/run; 1-9 executes detail commands; Shift+L reruns the previous command.'),
605
+ create(Text, null, 'Shift+H toggles these help cards, Shift+S toggles the structure guide, ? toggles this overlay, Shift+Q quits.'),
614
606
  create(Text, null, 'Projects + Details stay paired while Output keeps its own full-width band.'),
615
- create(Text, null, 'Structure guide lists the manifests that trigger each language detection (Ctrl+S to toggle).')
607
+ create(Text, null, 'Structure guide lists the manifests that trigger each language detection (Shift+S to toggle).')
616
608
  )
617
609
  : null;
618
610
 
@@ -417,13 +417,24 @@ const builtInFrameworks = [
417
417
  name: 'Spring Boot',
418
418
  icon: '๐ŸŒฑ',
419
419
  description: 'Spring Boot apps',
420
- languages: ['Java'],
420
+ languages: ['Java', 'Kotlin'],
421
421
  priority: 105,
422
422
  match(project) {
423
- return dependencyMatches(project, 'spring-boot-starter') || hasProjectFile(project.path, 'src/main/java');
423
+ return dependencyMatches(project, 'spring-boot-starter') ||
424
+ dependencyMatches(project, 'spring-boot-autoconfigure') ||
425
+ hasProjectFile(project.path, 'src/main/resources/application.properties') ||
426
+ hasProjectFile(project.path, 'src/main/resources/application.yml');
424
427
  },
425
428
  commands(project) {
426
429
  const hasMvnw = hasProjectFile(project.path, 'mvnw');
430
+ const hasGradlew = hasProjectFile(project.path, 'gradlew');
431
+ if (hasGradlew) {
432
+ return {
433
+ run: {label: 'Gradle BootRun', command: ['./gradlew', 'bootRun'], source: 'framework'},
434
+ build: {label: 'Gradle Build', command: ['./gradlew', 'build'], source: 'framework'},
435
+ test: {label: 'Gradle Test', command: ['./gradlew', 'test'], source: 'framework'}
436
+ };
437
+ }
427
438
  const base = hasMvnw ? './mvnw' : 'mvn';
428
439
  return {
429
440
  run: {label: 'Spring Boot run', command: [base, 'spring-boot:run'], source: 'framework'},
@@ -431,6 +442,77 @@ const builtInFrameworks = [
431
442
  test: {label: 'Maven test', command: [base, 'test'], source: 'framework'}
432
443
  };
433
444
  }
445
+ },
446
+ {
447
+ id: 'rocket',
448
+ name: 'Rocket',
449
+ icon: '๐Ÿš€',
450
+ description: 'Rocket Rust Web',
451
+ languages: ['Rust'],
452
+ priority: 105,
453
+ match(project) {
454
+ return dependencyMatches(project, 'rocket');
455
+ },
456
+ commands() {
457
+ return {
458
+ run: {label: 'Rocket Run', command: ['cargo', 'run'], source: 'framework'},
459
+ test: {label: 'Rocket Test', command: ['cargo', 'test'], source: 'framework'}
460
+ };
461
+ }
462
+ },
463
+ {
464
+ id: 'actix',
465
+ name: 'Actix Web',
466
+ icon: '๐Ÿฆ€',
467
+ description: 'Actix Rust Web',
468
+ languages: ['Rust'],
469
+ priority: 105,
470
+ match(project) {
471
+ return dependencyMatches(project, 'actix-web');
472
+ },
473
+ commands() {
474
+ return {
475
+ run: {label: 'Actix Run', command: ['cargo', 'run'], source: 'framework'},
476
+ test: {label: 'Actix Test', command: ['cargo', 'test'], source: 'framework'}
477
+ };
478
+ }
479
+ },
480
+ {
481
+ id: 'aspnet',
482
+ name: 'ASP.NET Core',
483
+ icon: '๐ŸŒ',
484
+ description: 'ASP.NET Core Web App',
485
+ languages: ['.NET'],
486
+ priority: 105,
487
+ match(project) {
488
+ return hasProjectFile(project.path, 'Program.cs') &&
489
+ (hasProjectFile(project.path, 'appsettings.json') || hasProjectFile(project.path, 'web.config'));
490
+ },
491
+ commands() {
492
+ return {
493
+ run: {label: 'dotnet run', command: ['dotnet', 'run'], source: 'framework'},
494
+ watch: {label: 'dotnet watch', command: ['dotnet', 'watch', 'run'], source: 'framework'},
495
+ test: {label: 'dotnet test', command: ['dotnet', 'test'], source: 'framework'}
496
+ };
497
+ }
498
+ },
499
+ {
500
+ id: 'laravel',
501
+ name: 'Laravel',
502
+ icon: '๐Ÿงก',
503
+ description: 'Laravel PHP Framework',
504
+ languages: ['PHP'],
505
+ priority: 105,
506
+ match(project) {
507
+ return hasProjectFile(project.path, 'artisan') || dependencyMatches(project, 'laravel/framework');
508
+ },
509
+ commands() {
510
+ return {
511
+ run: {label: 'Artisan Serve', command: ['php', 'artisan', 'serve'], source: 'framework'},
512
+ test: {label: 'Artisan Test', command: ['php', 'artisan', 'test'], source: 'framework'},
513
+ migrate: {label: 'Artisan Migrate', command: ['php', 'artisan', 'migrate'], source: 'framework'}
514
+ };
515
+ }
434
516
  }
435
517
  ];
436
518