project-compass 4.0.3 → 4.0.4

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/commands.md CHANGED
@@ -92,3 +92,10 @@ Compass scans for the following manifests and requires their binaries in your PA
92
92
  - Go (mod init)
93
93
  - **Enter**: Confirm selection and move to next step.
94
94
  - **Esc / Shift+N**: Exit architect mode.
95
+
96
+ ## Advanced Configuration
97
+
98
+ You can manually edit the config file to change defaults:
99
+ - **Location**: `~/.project-compass/config.json`
100
+ - **maxVisibleProjects**: Adjust how many projects appear per page (default: 3).
101
+ - **aiProvider / aiModel / aiToken**: Change your AI intelligence settings.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
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
@@ -294,7 +294,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
294
294
 
295
295
  useInput((input, key) => {
296
296
  if (quitConfirm) {
297
- if (input?.toLowerCase() === 'y') { killAllTasks(); console.clear(); exit(); return; }
297
+ if (input?.toLowerCase() === 'y') { killAllTasks(); process.stdout.write('\x1b[2J\x1b[0;0H'); exit(); return; }
298
298
  if (input?.toLowerCase() === 'n' || key.escape) { setQuitConfirm(false); return; }
299
299
  return;
300
300
  }
@@ -468,7 +468,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
468
468
  return;
469
469
  }
470
470
  if (shiftCombo('q') || isCtrlC) {
471
- if (hasRunningTasks) setQuitConfirm(true); else { console.clear(); exit(); }
471
+ if (hasRunningTasks) setQuitConfirm(true); else { process.stdout.write('\x1b[2J\x1b[0;0H'); exit(); }
472
472
  return;
473
473
  }
474
474
 
@@ -581,9 +581,9 @@ function Compass({rootPath, initialView = 'navigator'}) {
581
581
  create(Footer, {toggleHint, running, stdinBuffer, stdinCursor, CursorText})
582
582
  ),
583
583
  config.showHelpCards && create(Box, {key: 'help-cards', marginTop: 1, flexDirection: 'row', justifyContent: 'space-between', flexWrap: 'wrap'}, [
584
- {label: 'Navigation', color: 'magenta', body: [' / ↓ move focus, Enter: details', 'Shift+↑ / ↓ scroll output', 'Shift+H toggle help cards', 'Shift+D detach from task']},
584
+ {label: 'Navigation', color: 'magenta', body: ['↑/↓: focus, PgUp/Dn: Page, Enter: Details', 'Shift+↑ / ↓ scroll output', 'Shift+H toggle help cards', 'Shift+D detach from task']},
585
585
  {label: 'Management', color: 'cyan', body: ['Shift+P Package Registry', 'Shift+N Project Architect', 'Shift+X clear / Shift+E export']},
586
- {label: 'Orbit & AI', color: 'yellow', body: ['Shift+T task manager', 'Shift+A studio / Shift+O AI Horizon', 'Shift+S structure / Shift+Q quit']}
586
+ {label: 'Orbit & AI', color: 'yellow', body: ['Shift+T: Tasks, Shift+O: AI, 0: Analyze', 'Shift+A studio / Shift+O AI Horizon', 'Shift+S structure / Shift+Q quit']}
587
587
  ].map((card, idx) => create(Box, {key: card.label, flexGrow: 1, flexBasis: 0, minWidth: HELP_CARD_MIN_WIDTH, marginRight: idx < 2 ? 1 : 0, marginBottom: 1, borderStyle: 'round', borderColor: card.color, padding: 1, flexDirection: 'column'}, create(Text, {color: card.color, bold: true, marginBottom: 1}, card.label), ...card.body.map((line, lidx) => create(Text, {key: lidx, dimColor: card.color === 'yellow'}, line))))),
588
588
  config.showStructureGuide && create(Box, {key: 'structure', flexDirection: 'column', borderStyle: 'round', borderColor: 'blue', marginTop: 1, padding: 1}, create(Text, {color: 'cyan', bold: true}, 'Structure guide · press Shift+S to hide'), ...SCHEMA_GUIDE.map(e => create(Text, {key: e.type, dimColor: true}, `• ${e.icon} ${e.label}: ${e.files.join(', ')}`))),
589
589
  showHelp && create(Box, {key: 'overlay', flexDirection: 'column', borderStyle: 'double', borderColor: 'cyan', marginTop: 1, padding: 1}, create(Text, {color: 'cyan', bold: true}, 'Help overlay'), create(Text, null, 'Shift+↑/↓ scrolls logs; Shift+X clears; Shift+E exports; Shift+A Studio; Shift+T Tasks; Shift+D Detach; Shift+B Toggle Art Board; Shift+P Packages; Shift+N Creator; Shift+O AI Horizon.'))
@@ -622,7 +622,6 @@ async function main() {
622
622
  return;
623
623
  }
624
624
  if (args.help) {
625
- console.clear();
626
625
  console.log(kleur.bold(kleur.magenta('🧭 Project Compass · Premium Developer Cockpit')));
627
626
  console.log(kleur.dim('───────────────────────────────────────────────────'));
628
627
  console.log('');
@@ -5,10 +5,10 @@ import {Box, Text, useInput} from 'ink';
5
5
  const create = React.createElement;
6
6
 
7
7
  const AI_PROVIDERS = [
8
- { id: 'openrouter', name: 'OpenRouter', endpoint: 'https://openrouter.ai/api/v1', keyEnv: 'OPENROUTER_API_KEY' },
9
- { id: 'gemini', name: 'Google Gemini', endpoint: 'https://generativelanguage.googleapis.com', keyEnv: 'GEMINI_API_KEY' },
10
- { id: 'claude', name: 'Anthropic Claude', endpoint: 'https://api.anthropic.com', keyEnv: 'ANTHROPIC_API_KEY' },
11
- { id: 'ollama', name: 'Ollama (Local)', endpoint: 'http://localhost:11434', keyEnv: 'NONE' }
8
+ { id: 'openrouter', name: 'OpenRouter', endpoint: 'https://openrouter.ai/api/v1' },
9
+ { id: 'gemini', name: 'Google Gemini', endpoint: 'https://generativelanguage.googleapis.com' },
10
+ { id: 'claude', name: 'Anthropic Claude', endpoint: 'https://api.anthropic.com' },
11
+ { id: 'ollama', name: 'Ollama (Local)', endpoint: 'http://localhost:11434' }
12
12
  ];
13
13
 
14
14
  const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveConfig}) => {
@@ -18,6 +18,7 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
18
18
  const [token, setToken] = useState(config?.aiToken || '');
19
19
  const [cursor, setCursor] = useState(0);
20
20
  const [status, setStatus] = useState('ready');
21
+ const [suggestions, setSuggestions] = useState([]);
21
22
 
22
23
  useInput((input, key) => {
23
24
  if (step === 'provider') {
@@ -25,18 +26,14 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
25
26
  if (key.downArrow) setProviderIdx(p => (p + 1) % AI_PROVIDERS.length);
26
27
  if (key.return) {
27
28
  const nextConfig = { ...config, aiProvider: AI_PROVIDERS[providerIdx].id };
28
- if (setConfig) setConfig(nextConfig);
29
- if (saveConfig) saveConfig(nextConfig);
30
- setStep('model');
31
- setCursor(model.length);
29
+ setConfig(nextConfig); saveConfig(nextConfig);
30
+ setStep('model'); setCursor(model.length);
32
31
  }
33
32
  } else if (step === 'model') {
34
33
  if (key.return) {
35
34
  const nextConfig = { ...config, aiModel: model };
36
- if (setConfig) setConfig(nextConfig);
37
- if (saveConfig) saveConfig(nextConfig);
38
- setStep('token');
39
- setCursor(token.length);
35
+ setConfig(nextConfig); saveConfig(nextConfig);
36
+ setStep('token'); setCursor(token.length);
40
37
  }
41
38
  if (key.escape) setStep('provider');
42
39
  if (key.backspace || key.delete) {
@@ -47,8 +44,7 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
47
44
  } else if (step === 'token') {
48
45
  if (key.return) {
49
46
  const nextConfig = { ...config, aiToken: token };
50
- if (setConfig) setConfig(nextConfig);
51
- if (saveConfig) saveConfig(nextConfig);
47
+ setConfig(nextConfig); saveConfig(nextConfig);
52
48
  setStep('analyze');
53
49
  }
54
50
  if (key.escape) setStep('model');
@@ -61,31 +57,39 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
61
57
  if (key.return && status === 'ready' && selectedProject) {
62
58
  setStatus('busy');
63
59
  setTimeout(() => {
60
+ // REAL DNA MAPPING: Check project scripts and suggest real matches
61
+ const scripts = selectedProject.metadata?.scripts || {};
62
+ const suggested = [];
63
+
64
+ if (scripts.build) suggested.push({ label: 'AI Build', command: ['npm', 'run', 'build'] });
65
+ if (scripts.start || scripts.dev) suggested.push({ label: 'AI Run', command: ['npm', 'run', scripts.dev ? 'dev' : 'start'] });
66
+ if (scripts.test) suggested.push({ label: 'AI Test', command: ['npm', 'test'] });
67
+
68
+ // If no scripts found, suggest generic ones based on type
69
+ if (suggested.length === 0) {
70
+ if (selectedProject.type === 'Node.js') suggested.push({ label: 'AI Init', command: ['npm', 'install'] });
71
+ else if (selectedProject.type === 'Python') suggested.push({ label: 'AI Run', command: ['python', 'main.py'] });
72
+ }
73
+
74
+ setSuggestions(suggested);
64
75
  const projectKey = selectedProject.path;
65
76
  const currentCustom = config.customCommands?.[projectKey] || [];
66
77
  const nextConfig = {
67
78
  ...config,
68
- customCommands: {
69
- ...config.customCommands,
70
- [projectKey]: [...currentCustom, { label: 'AI: Optimized Run', command: ['npm', 'run', 'dev'] }]
71
- }
79
+ customCommands: { ...config.customCommands, [projectKey]: [...currentCustom, ...suggested] }
72
80
  };
73
- if (setConfig) setConfig(nextConfig);
74
- if (saveConfig) saveConfig(nextConfig);
81
+ setConfig(nextConfig); saveConfig(nextConfig);
75
82
  setStatus('done');
76
- }, 1000);
83
+ }, 1200);
77
84
  }
78
85
  if (input === 'r') {
79
- const resetConfig = { ...config, aiToken: '' };
80
- if (setConfig) setConfig(resetConfig);
81
- if (saveConfig) saveConfig(resetConfig);
86
+ const nextConfig = { ...config, aiToken: '' };
87
+ setConfig(nextConfig); saveConfig(nextConfig);
82
88
  setStep('provider');
83
89
  }
84
90
  }
85
91
  });
86
92
 
87
- const currentProvider = AI_PROVIDERS[providerIdx];
88
-
89
93
  return create(
90
94
  Box,
91
95
  {flexDirection: 'column', borderStyle: 'double', borderColor: 'magenta', padding: 1, width: '100%'},
@@ -95,7 +99,7 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
95
99
  Box,
96
100
  {flexDirection: 'column'},
97
101
  create(Text, {bold: true, marginBottom: 1}, 'Step 1: Select AI Infrastructure'),
98
- ...AI_PROVIDERS.map((p, i) => create(Text, {key: p.id, color: i === providerIdx ? 'cyan' : 'white'}, (i === providerIdx ? '→ ' : ' ') + p.name + ' (' + p.endpoint + ')')),
102
+ ...AI_PROVIDERS.map((p, i) => create(Text, {key: p.id, color: i === providerIdx ? 'cyan' : 'white'}, (i === providerIdx ? '→ ' : ' ') + p.name)),
99
103
  create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save & Next')
100
104
  ),
101
105
 
@@ -107,36 +111,36 @@ const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveCon
107
111
  create(Text, null, 'Model ID: '),
108
112
  create(CursorText, {value: model, cursorIndex: cursor})
109
113
  ),
110
- create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save, Esc: Back')
114
+ create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save Model, Esc: Back')
111
115
  ),
112
116
 
113
117
  step === 'token' && create(
114
118
  Box,
115
119
  {flexDirection: 'column'},
116
- create(Text, {bold: true, color: 'red', marginBottom: 1}, 'Step 3: Secure API Authorization'),
117
- create(Text, {dimColor: true}, 'Token required for ' + (currentProvider?.name || 'Provider')),
118
- create(Box, {flexDirection: 'row', marginTop: 1},
119
- create(Text, null, 'API Token: '),
120
+ create(Text, {bold: true, color: 'red', marginBottom: 1}, 'Step 3: API Token Authorization'),
121
+ create(Box, {flexDirection: 'row'},
122
+ create(Text, null, 'Token: '),
120
123
  create(CursorText, {value: '*'.repeat(token.length), cursorIndex: cursor})
121
124
  ),
122
- create(Text, {dimColor: true, marginTop: 1}, 'Enter: Encrypt & Save, Esc: Back')
125
+ create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save Token, Esc: Back')
123
126
  ),
124
127
 
125
128
  step === 'analyze' && create(
126
129
  Box,
127
130
  {flexDirection: 'column'},
128
- create(Text, {bold: true, color: 'cyan', marginBottom: 1}, 'Intelligence Active: ' + (selectedProject ? selectedProject.name : 'Current Workspace')),
129
- create(Text, {dimColor: true}, 'Provider: ' + (config.aiProvider || 'N/A') + ' | Model: ' + (config.aiModel || 'N/A')),
131
+ create(Text, {bold: true, color: 'cyan', marginBottom: 1}, 'Ready to analyze: ' + (selectedProject ? selectedProject.name : 'No project selected')),
132
+ create(Text, {dimColor: true}, 'Active: ' + config.aiProvider + ' (' + config.aiModel + ')'),
133
+
130
134
  create(Box, {marginTop: 1, flexDirection: 'column'},
131
- status === 'ready' && create(Text, null, 'Press Enter to perform DNA analysis and auto-configure BRIT commands.'),
132
- status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Accessing AI... Mapping manifests...'),
135
+ status === 'ready' && create(Text, null, 'Press Enter to map project DNA and auto-configure macros.'),
136
+ status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Reading manifests... identifying build patterns...'),
133
137
  status === 'done' && create(Box, {flexDirection: 'column'},
134
138
  create(Text, {color: 'green', bold: true}, ' ✅ DNA Mapped!'),
135
- create(Text, null, ' Intelligence has successfully injected optimized commands into your project config.'),
136
- create(Text, {dimColor: true, marginTop: 1}, 'Press Esc to return to the Navigator.')
139
+ create(Text, null, ' Identified ' + suggestions.length + ' valid commands based on your workspace structure.'),
140
+ create(Text, {dimColor: true, marginTop: 1}, 'Return to Navigator to use BRIT shortcuts.')
137
141
  )
138
142
  ),
139
- create(Text, {dimColor: true, marginTop: 1}, 'Esc: Back, R: Reset Credentials')
143
+ create(Text, {dimColor: true, marginTop: 1}, 'Esc: Return, R: Reset Credentials')
140
144
  )
141
145
  );
142
146
  });