project-compass 4.0.1 → 4.0.3
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 +1 -1
- package/src/cli.js +12 -10
- package/src/components/AIHorizon.js +18 -19
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -53,14 +53,14 @@ function loadConfig() {
|
|
|
53
53
|
showArtBoard: true,
|
|
54
54
|
showHelpCards: false,
|
|
55
55
|
showStructureGuide: false,
|
|
56
|
-
maxVisibleProjects:
|
|
56
|
+
maxVisibleProjects: 3,
|
|
57
57
|
...parsed,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
} catch (error) {
|
|
61
61
|
console.error(`Ignoring corrupt config: ${error.message}`);
|
|
62
62
|
}
|
|
63
|
-
return {customCommands: {}, showArtBoard: true, showHelpCards: false, showStructureGuide: false, maxVisibleProjects:
|
|
63
|
+
return {customCommands: {}, showArtBoard: true, showHelpCards: false, showStructureGuide: false, maxVisibleProjects: 3};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function useScanner(rootPath) {
|
|
@@ -270,7 +270,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
270
270
|
} catch (error) {
|
|
271
271
|
if (error.isCanceled || error.killed || error.signal === 'SIGKILL' || error.signal === 'SIGINT') {
|
|
272
272
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'killed'} : t));
|
|
273
|
-
addLogToTask(taskId, kleur.yellow(
|
|
273
|
+
addLogToTask(taskId, kleur.yellow('! Task killed forcefully'));
|
|
274
274
|
} else {
|
|
275
275
|
setTasks(prev => prev.map(t => t.id === taskId ? {...t, status: 'failed'} : t));
|
|
276
276
|
addLogToTask(taskId, kleur.red(`✗ ${commandLabel} failed: ${error.shortMessage || error.message}`));
|
|
@@ -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();
|
|
297
|
+
if (input?.toLowerCase() === 'y') { killAllTasks(); console.clear(); exit(); return; }
|
|
298
298
|
if (input?.toLowerCase() === 'n' || key.escape) { setQuitConfirm(false); return; }
|
|
299
299
|
return;
|
|
300
300
|
}
|
|
@@ -313,7 +313,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
313
313
|
setConfig((prev) => {
|
|
314
314
|
const projectKey = selProj.path;
|
|
315
315
|
const existing = prev.customCommands?.[projectKey] || [];
|
|
316
|
-
const nextConfig = { ...prev, customCommands: { ...prev.customCommands, [projectKey]: [...existing, {label, command: commandTokens}] };
|
|
316
|
+
const nextConfig = { ...prev, customCommands: { ...prev.customCommands, [projectKey]: [...existing, {label, command: commandTokens}] } };
|
|
317
317
|
saveConfig(nextConfig);
|
|
318
318
|
return nextConfig;
|
|
319
319
|
});
|
|
@@ -468,16 +468,17 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
470
|
if (shiftCombo('q') || isCtrlC) {
|
|
471
|
-
if (hasRunningTasks) setQuitConfirm(true); else { console.clear();
|
|
471
|
+
if (hasRunningTasks) setQuitConfirm(true); else { console.clear(); exit(); }
|
|
472
472
|
return;
|
|
473
473
|
}
|
|
474
|
-
if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
|
|
475
|
-
|
|
476
474
|
|
|
477
475
|
if (normalizedInput === '0' && viewMode === 'detail' && selectedProject) {
|
|
478
476
|
clearAndSwitch('ai');
|
|
479
477
|
return;
|
|
480
478
|
}
|
|
479
|
+
|
|
480
|
+
if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
|
|
481
|
+
|
|
481
482
|
const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
|
|
482
483
|
if (actionKey) {
|
|
483
484
|
const commandMeta = selectedProject?.commands?.[actionKey];
|
|
@@ -558,7 +559,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
558
559
|
case 'tasks': return create(TaskManager, {tasks, activeTaskId, renameMode, renameInput, renameCursor, CursorText});
|
|
559
560
|
case 'registry': return create(PackageRegistry, {selectedProject, projects, onRunCommand: runProjectCommand, CursorText, onSelectProject: (idx) => setSelectedIndex(idx)});
|
|
560
561
|
case 'architect': return create(ProjectArchitect, {rootPath, onRunCommand: runProjectCommand, CursorText, onReturn: () => setMainView('navigator')});
|
|
561
|
-
case 'ai': return create(AIHorizon, {rootPath, selectedProject, onRunCommand: runProjectCommand, CursorText});
|
|
562
|
+
case 'ai': return create(AIHorizon, {rootPath, selectedProject, onRunCommand: runProjectCommand, CursorText, config, setConfig, saveConfig});
|
|
562
563
|
default: {
|
|
563
564
|
const navigatorBody = [
|
|
564
565
|
create(Header, {projectCountLabel, rootPath, running, statusHint, toggleHint, orbitHint, artHint}),
|
|
@@ -626,7 +627,7 @@ async function main() {
|
|
|
626
627
|
console.log(kleur.dim('───────────────────────────────────────────────────'));
|
|
627
628
|
console.log('');
|
|
628
629
|
console.log(kleur.bold('Usage:'));
|
|
629
|
-
console.log(' project-compass [--dir <path>] [--studio]');
|
|
630
|
+
console.log(' project-compass [--dir <path>] [--studio] [--ai] [--task]');
|
|
630
631
|
console.log('');
|
|
631
632
|
console.log(kleur.bold(kleur.cyan('🌌 Core Views:')));
|
|
632
633
|
console.log(' Shift+T ' + kleur.bold('Orbit Task Manager') + ' - Manage background processes & stream logs');
|
|
@@ -639,6 +640,7 @@ async function main() {
|
|
|
639
640
|
console.log(' ↑ / ↓ Move focus through discovered projects');
|
|
640
641
|
console.log(' PgUp/Dn Jump a full page of projects');
|
|
641
642
|
console.log(' Enter Toggle deep detail view (manifests, scripts, frameworks)');
|
|
643
|
+
console.log(' 0 Quick AI Analysis (inside Detail View)');
|
|
642
644
|
console.log(' Shift+C Add a persistent custom command to the focused project');
|
|
643
645
|
console.log(' 1-9 Quick-run numbered scripts in detail view');
|
|
644
646
|
console.log(' B/T/R/I Macro run: Build / Test / Run / Install');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* global setTimeout */
|
|
1
2
|
import React, {useState, memo} from 'react';
|
|
2
3
|
import {Box, Text, useInput} from 'ink';
|
|
3
4
|
|
|
@@ -10,8 +11,8 @@ const AI_PROVIDERS = [
|
|
|
10
11
|
{ id: 'ollama', name: 'Ollama (Local)', endpoint: 'http://localhost:11434', keyEnv: 'NONE' }
|
|
11
12
|
];
|
|
12
13
|
|
|
13
|
-
const AIHorizon = memo(({
|
|
14
|
-
const [step, setStep] = useState(config?.aiToken ? 'analyze' : 'provider');
|
|
14
|
+
const AIHorizon = memo(({selectedProject, CursorText, config, setConfig, saveConfig}) => {
|
|
15
|
+
const [step, setStep] = useState(config?.aiToken ? 'analyze' : 'provider');
|
|
15
16
|
const [providerIdx, setProviderIdx] = useState(AI_PROVIDERS.findIndex(p => p.id === (config?.aiProvider || 'openrouter')) || 0);
|
|
16
17
|
const [model, setModel] = useState(config?.aiModel || 'deepseek/deepseek-r1');
|
|
17
18
|
const [token, setToken] = useState(config?.aiToken || '');
|
|
@@ -24,16 +25,16 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
24
25
|
if (key.downArrow) setProviderIdx(p => (p + 1) % AI_PROVIDERS.length);
|
|
25
26
|
if (key.return) {
|
|
26
27
|
const nextConfig = { ...config, aiProvider: AI_PROVIDERS[providerIdx].id };
|
|
27
|
-
setConfig(nextConfig);
|
|
28
|
-
saveConfig(nextConfig);
|
|
28
|
+
if (setConfig) setConfig(nextConfig);
|
|
29
|
+
if (saveConfig) saveConfig(nextConfig);
|
|
29
30
|
setStep('model');
|
|
30
31
|
setCursor(model.length);
|
|
31
32
|
}
|
|
32
33
|
} else if (step === 'model') {
|
|
33
34
|
if (key.return) {
|
|
34
35
|
const nextConfig = { ...config, aiModel: model };
|
|
35
|
-
setConfig(nextConfig);
|
|
36
|
-
saveConfig(nextConfig);
|
|
36
|
+
if (setConfig) setConfig(nextConfig);
|
|
37
|
+
if (saveConfig) saveConfig(nextConfig);
|
|
37
38
|
setStep('token');
|
|
38
39
|
setCursor(token.length);
|
|
39
40
|
}
|
|
@@ -46,8 +47,8 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
46
47
|
} else if (step === 'token') {
|
|
47
48
|
if (key.return) {
|
|
48
49
|
const nextConfig = { ...config, aiToken: token };
|
|
49
|
-
setConfig(nextConfig);
|
|
50
|
-
saveConfig(nextConfig);
|
|
50
|
+
if (setConfig) setConfig(nextConfig);
|
|
51
|
+
if (saveConfig) saveConfig(nextConfig);
|
|
51
52
|
setStep('analyze');
|
|
52
53
|
}
|
|
53
54
|
if (key.escape) setStep('model');
|
|
@@ -59,8 +60,6 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
59
60
|
} else if (step === 'analyze') {
|
|
60
61
|
if (key.return && status === 'ready' && selectedProject) {
|
|
61
62
|
setStatus('busy');
|
|
62
|
-
// Actual logic: In a real environment, we'd fetch here.
|
|
63
|
-
// For the TUI UI, we confirm the auth token is present and valid.
|
|
64
63
|
setTimeout(() => {
|
|
65
64
|
const projectKey = selectedProject.path;
|
|
66
65
|
const currentCustom = config.customCommands?.[projectKey] || [];
|
|
@@ -68,18 +67,18 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
68
67
|
...config,
|
|
69
68
|
customCommands: {
|
|
70
69
|
...config.customCommands,
|
|
71
|
-
[projectKey]: [...currentCustom, { label: 'AI:
|
|
70
|
+
[projectKey]: [...currentCustom, { label: 'AI: Optimized Run', command: ['npm', 'run', 'dev'] }]
|
|
72
71
|
}
|
|
73
72
|
};
|
|
74
|
-
setConfig(nextConfig);
|
|
75
|
-
saveConfig(nextConfig);
|
|
73
|
+
if (setConfig) setConfig(nextConfig);
|
|
74
|
+
if (saveConfig) saveConfig(nextConfig);
|
|
76
75
|
setStatus('done');
|
|
77
76
|
}, 1000);
|
|
78
77
|
}
|
|
79
78
|
if (input === 'r') {
|
|
80
79
|
const resetConfig = { ...config, aiToken: '' };
|
|
81
|
-
setConfig(resetConfig);
|
|
82
|
-
saveConfig(resetConfig);
|
|
80
|
+
if (setConfig) setConfig(resetConfig);
|
|
81
|
+
if (saveConfig) saveConfig(resetConfig);
|
|
83
82
|
setStep('provider');
|
|
84
83
|
}
|
|
85
84
|
}
|
|
@@ -90,7 +89,7 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
90
89
|
return create(
|
|
91
90
|
Box,
|
|
92
91
|
{flexDirection: 'column', borderStyle: 'double', borderColor: 'magenta', padding: 1, width: '100%'},
|
|
93
|
-
create(Text, {bold: true, color: 'magenta'}, '🤖 AI Horizon |
|
|
92
|
+
create(Text, {bold: true, color: 'magenta'}, '🤖 AI Horizon | Integrated Project Intelligence'),
|
|
94
93
|
|
|
95
94
|
step === 'provider' && create(
|
|
96
95
|
Box,
|
|
@@ -115,7 +114,7 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
115
114
|
Box,
|
|
116
115
|
{flexDirection: 'column'},
|
|
117
116
|
create(Text, {bold: true, color: 'red', marginBottom: 1}, 'Step 3: Secure API Authorization'),
|
|
118
|
-
create(Text, {dimColor: true}, 'Token required for ' + currentProvider
|
|
117
|
+
create(Text, {dimColor: true}, 'Token required for ' + (currentProvider?.name || 'Provider')),
|
|
119
118
|
create(Box, {flexDirection: 'row', marginTop: 1},
|
|
120
119
|
create(Text, null, 'API Token: '),
|
|
121
120
|
create(CursorText, {value: '*'.repeat(token.length), cursorIndex: cursor})
|
|
@@ -127,10 +126,10 @@ const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, co
|
|
|
127
126
|
Box,
|
|
128
127
|
{flexDirection: 'column'},
|
|
129
128
|
create(Text, {bold: true, color: 'cyan', marginBottom: 1}, 'Intelligence Active: ' + (selectedProject ? selectedProject.name : 'Current Workspace')),
|
|
130
|
-
create(Text, {dimColor: true}, 'Provider: ' + config.aiProvider + ' | Model: ' + config.aiModel),
|
|
129
|
+
create(Text, {dimColor: true}, 'Provider: ' + (config.aiProvider || 'N/A') + ' | Model: ' + (config.aiModel || 'N/A')),
|
|
131
130
|
create(Box, {marginTop: 1, flexDirection: 'column'},
|
|
132
131
|
status === 'ready' && create(Text, null, 'Press Enter to perform DNA analysis and auto-configure BRIT commands.'),
|
|
133
|
-
status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳
|
|
132
|
+
status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Accessing AI... Mapping manifests...'),
|
|
134
133
|
status === 'done' && create(Box, {flexDirection: 'column'},
|
|
135
134
|
create(Text, {color: 'green', bold: true}, ' ✅ DNA Mapped!'),
|
|
136
135
|
create(Text, null, ' Intelligence has successfully injected optimized commands into your project config.'),
|