project-compass 4.0.6 → 4.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "4.0.6",
3
+ "version": "4.1.1",
4
4
  "description": "Futuristic project navigator and runner for Node, Python, Rust, and Go",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -153,6 +153,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
153
153
  const [activeTaskId, setActiveTaskId] = useState(null);
154
154
  const [logOffset, setLogOffset] = useState(0);
155
155
  const [customMode, setCustomMode] = useState(false);
156
+ const [portConfigMode, setPortConfigMode] = useState(false);
156
157
  const [customInput, setCustomInput] = useState('');
157
158
  const [customCursor, setCustomCursor] = useState(0);
158
159
  const [renameMode, setRenameMode] = useState(false);
@@ -301,7 +302,37 @@ function Compass({rootPath, initialView = 'navigator'}) {
301
302
 
302
303
  const isCtrlC = (key.ctrl && input === 'c') || input === '\u0003';
303
304
 
304
- if (customMode) {
305
+
306
+ if (portConfigMode) {
307
+ if (key.return) {
308
+ const portVal = customInput.trim();
309
+ if (selectedProject && portVal) {
310
+ setConfig((prev) => {
311
+ const projectKey = selectedProject.path;
312
+ const existingMeta = prev.projectMeta?.[projectKey] || {};
313
+ const nextConfig = { ...prev, projectMeta: { ...prev.projectMeta, [projectKey]: { ...existingMeta, port: portVal } } };
314
+ saveConfig(nextConfig);
315
+ return nextConfig;
316
+ });
317
+ }
318
+ setPortConfigMode(false); setCustomInput(''); setCustomCursor(0);
319
+ return;
320
+ }
321
+ if (key.escape) { setPortConfigMode(false); setCustomInput(''); setCustomCursor(0); return; }
322
+ if (key.backspace || key.delete) {
323
+ if (customCursor > 0) {
324
+ setCustomInput((prev) => prev.slice(0, customCursor - 1) + prev.slice(customCursor));
325
+ setCustomCursor(c => Math.max(0, c - 1));
326
+ }
327
+ return;
328
+ }
329
+ if (input && /[0-9]/.test(input)) {
330
+ setCustomInput((prev) => prev.slice(0, customCursor) + input + prev.slice(customCursor));
331
+ setCustomCursor(c => c + input.length);
332
+ }
333
+ return;
334
+ }
335
+ if (customMode) {
305
336
  if (key.return) {
306
337
  const raw = customInput.trim();
307
338
  const selProj = selectedProject;
@@ -453,9 +484,26 @@ function Compass({rootPath, initialView = 'navigator'}) {
453
484
 
454
485
  const pageLimit = config.maxVisibleProjects || 3;
455
486
  const pageStep = Math.max(1, pageLimit);
456
- const clampIndex = (value) => Math.max(0, Math.min(projects.length - 1, value));
457
- if (key.pageUp && projects.length > pageLimit) { console.clear(); setSelectedIndex((prev) => clampIndex(prev - pageStep)); return; }
458
- if (key.pageDown && projects.length > pageLimit) { console.clear(); setSelectedIndex((prev) => clampIndex(prev + pageStep)); return; }
487
+ const clampIndex = (value) => {
488
+ const idx = Math.max(0, Math.min(projects.length - 1, value));
489
+ return isNaN(idx) ? 0 : idx;
490
+ };
491
+ if (key.pageUp && projects.length > pageLimit) {
492
+ console.clear();
493
+ setSelectedIndex((prev) => {
494
+ const next = prev - pageStep;
495
+ return next < 0 ? 0 : next;
496
+ });
497
+ return;
498
+ }
499
+ if (key.pageDown && projects.length > pageLimit) {
500
+ console.clear();
501
+ setSelectedIndex((prev) => {
502
+ const next = prev + pageStep;
503
+ return next >= projects.length ? (Math.floor((projects.length - 1) / pageLimit) * pageLimit) : next;
504
+ });
505
+ return;
506
+ }
459
507
 
460
508
  if (normalizedInput === '?') { console.clear(); setShowHelp((prev) => !prev); return; }
461
509
  if (shiftCombo('l') && lastCommandRef.current) { runProjectCommand(lastCommandRef.current.commandMeta, lastCommandRef.current.project); return; }
@@ -478,7 +526,12 @@ function Compass({rootPath, initialView = 'navigator'}) {
478
526
  return;
479
527
  }
480
528
 
481
- if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
529
+
530
+ if (shiftCombo('r') && viewMode === 'detail' && selectedProject) {
531
+ setPortConfigMode(true); setCustomInput(selectedProject.metadata?.port || '3000'); setCustomCursor(String(selectedProject.metadata?.port || '3000').length);
532
+ return;
533
+ }
534
+ if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
482
535
 
483
536
  const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
484
537
  if (actionKey) {
@@ -221,7 +221,7 @@ Use the project's detected type (${selectedProject.type}) to ensure commands are
221
221
  status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Contacting AI Agent... mapping project structure...'),
222
222
  status === 'done' && create(Box, {flexDirection: 'column'},
223
223
  create(Text, {color: 'green', bold: true}, ' ✅ DNA Mapped via AI Agent!'),
224
- create(Text, null, ' Successfully injected ' + suggestions.length + ' optimized commands into project config.'),
224
+ create(Text, null, ' Successfully injected ' + suggestions.length + ' optimized commands. AI detected potential port conflicts? Checking...'),
225
225
  create(Text, {dimColor: true, marginTop: 1}, 'Return to Navigator to use BRIT shortcuts.')
226
226
  ),
227
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
+ };
@@ -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
+ };
@@ -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