project-compass 3.9.5 → 4.0.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 +6 -35
- package/commands.md +2 -2
- package/package.json +1 -1
- package/src/cli.js +11 -4
- package/src/components/AIHorizon.js +89 -16
package/README.md
CHANGED
|
@@ -30,42 +30,13 @@ npm install -g project-compass
|
|
|
30
30
|
### 🏗️ Project Architect (`Shift+N`)
|
|
31
31
|
- **Modern Templates**: Scaffold high-performance projects with built-in support for **Bun, Next.js, Vite, Rust, and Django**.
|
|
32
32
|
|
|
33
|
-
### 🤖 AI Horizon (`Shift+O`
|
|
34
|
-
- **
|
|
35
|
-
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **Task Identity**: Rename tasks on the fly with `Shift+R` to keep your workspace organized.
|
|
39
|
-
- **Cross-Platform Safety**: Automatically handles process signaling for both Unix (SIGKILL) and Windows (taskkill) to ensure clean exits.
|
|
33
|
+
### 🤖 AI Horizon (`Shift+O` or `0`)
|
|
34
|
+
- **Intelligence Persistence**: Configure your provider (**OpenRouter, Gemini, Claude, Ollama**) once; Compass remembers your settings.
|
|
35
|
+
- **Deep DNA Analysis**: Press `0` on any project to analyze its structure.
|
|
36
|
+
- **Auto-Config (BRIT)**: AI automatically detects and configures missing **Build, Run, Install, and Test** commands, saving them directly to your `config.json`.
|
|
37
|
+
- **Direct Access**: Launch straight into intelligence mode with `project-compass --ai`.
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### 📦 Package Registry (`Shift+P`)
|
|
44
|
-
- **Context-Aware Management**: Add or remove dependencies without leaving the app.
|
|
45
|
-
- **Internal Switcher**: Quick-swap projects within the registry view using `S`.
|
|
46
|
-
- **Multi-Runtime Support**: Handles `npm`, `pnpm`, `bun`, `pip`, and more based on project type.
|
|
47
|
-
|
|
48
|
-

|
|
49
|
-
|
|
50
|
-
### 🏗️ Project Architect (`Shift+N`)
|
|
51
|
-
- **Rapid Scaffolding**: Create new projects from scratch using industry-standard templates:
|
|
52
|
-
- **Next.js** (Standard & Bun variants)
|
|
53
|
-
- **React/Vue** (Vite-powered with pnpm/npm support)
|
|
54
|
-
- **Rust** (Cargo binary)
|
|
55
|
-
- **Django** (Python web framework)
|
|
56
|
-
- **Go** (Module initialization)
|
|
57
|
-
- **Interactive Prompts**: Safe, guided setup for directory structure and initial manifests.
|
|
58
|
-
|
|
59
|
-

|
|
60
|
-
|
|
61
|
-
### 🎨 Omni-Studio & Art Board
|
|
62
|
-
- **Environment Health (`Shift+A`)**: Audit your system dependencies and runtime versions.
|
|
63
|
-
- **Build Atlas (`Shift+B`)**: A visual, art-coded representation of your project landscape.
|
|
64
|
-
|
|
65
|
-

|
|
66
|
-

|
|
67
|
-
|
|
68
|
-
## ⌨️ Command Reference
|
|
39
|
+
## Command Reference
|
|
69
40
|
|
|
70
41
|
| Shortcut | Action |
|
|
71
42
|
| :--- | :--- |
|
package/commands.md
CHANGED
|
@@ -7,7 +7,7 @@ This document lists all supported languages, frameworks, and their built-in comm
|
|
|
7
7
|
| Key | Action |
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| ↑ / ↓ | Move project focus |
|
|
10
|
-
| Enter | Toggle deep detail view / Switch back from sub-views |
|
|
10
|
+
| Enter | Toggle deep detail view / Switch back from sub-views |\n| **0** | **Quick AI Analysis** (Detail View only) |
|
|
11
11
|
| **B / T / R / I**| **Macro Launch**: Build, Test, Run, **Install** |
|
|
12
12
|
| **Esc** | **Global Back**: Return to Main Navigator from any view |
|
|
13
13
|
| **Shift+A** | Open **Omni-Studio** (Environment & Runtime audit) |
|
|
@@ -20,7 +20,7 @@ This document lists all supported languages, frameworks, and their built-in comm
|
|
|
20
20
|
| **Shift+S** | Toggle **Structure Guide** (Saved to config) |
|
|
21
21
|
| **Shift+X** | **Clear** active task output logs |
|
|
22
22
|
| **Shift+E** | **Export** logs to a timestamped `.txt` file |
|
|
23
|
-
| **Shift+L** | **Rerun** the last executed command |
|
|
23
|
+
| **Shift+L** | **Rerun** the last executed command |\n| PgUp / PgDn | Jump full project page |
|
|
24
24
|
| **Shift+C** | Add a **Custom Command** (`label|cmd`) in detail view |
|
|
25
25
|
| **Shift+Q** | **Quit** application (Confirms if tasks are running) |
|
|
26
26
|
| Shift+↑ / ↓ | Scroll output logs |
|
package/package.json
CHANGED
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(); console.clear(); { 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,11 +468,16 @@ 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 { console.clear(); { console.clear(); exit(); }
|
|
472
472
|
return;
|
|
473
473
|
}
|
|
474
474
|
if (shiftCombo('c') && viewMode === 'detail' && selectedProject) { setCustomMode(true); setCustomInput(''); setCustomCursor(0); return; }
|
|
475
475
|
|
|
476
|
+
|
|
477
|
+
if (normalizedInput === '0' && viewMode === 'detail' && selectedProject) {
|
|
478
|
+
clearAndSwitch('ai');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
476
481
|
const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
|
|
477
482
|
if (actionKey) {
|
|
478
483
|
const commandMeta = selectedProject?.commands?.[actionKey];
|
|
@@ -565,7 +570,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
|
|
|
565
570
|
create(Box, {key: 'projects-row', marginTop: 1, flexDirection: 'row', alignItems: 'stretch', width: '100%', flexWrap: 'wrap'},
|
|
566
571
|
create(Box, {flexGrow: 1, flexBasis: 0, minWidth: PROJECTS_MIN_WIDTH, marginRight: 1, borderStyle: 'round', borderColor: 'magenta', padding: 1},
|
|
567
572
|
create(Text, {bold: true, color: 'magenta'}, 'Projects'),
|
|
568
|
-
create(Box, {flexDirection: 'column', marginTop: 1}, create(Navigator, {projects, selectedIndex, rootPath, loading, error, maxVisibleProjects:
|
|
573
|
+
create(Box, {flexDirection: 'column', marginTop: 1}, create(Navigator, {projects, selectedIndex, rootPath, loading, error, maxVisibleProjects: 3}))
|
|
569
574
|
),
|
|
570
575
|
create(Box, {flexGrow: 1.3, flexBasis: 0, minWidth: DETAILS_MIN_WIDTH, borderStyle: 'round', borderColor: 'cyan', padding: 1, flexDirection: 'column'}, create(Text, {bold: true, color: 'cyan'}, 'Details'), ...detailContent)
|
|
571
576
|
),
|
|
@@ -601,6 +606,8 @@ function parseArgs() {
|
|
|
601
606
|
else if (token === '--help' || token === '-h') args.help = true;
|
|
602
607
|
else if (token === '--version' || token === '-v') args.version = true;
|
|
603
608
|
else if (token === '--studio') args.view = 'studio';
|
|
609
|
+
else if (token === '--ai') args.view = 'ai';
|
|
610
|
+
else if (token === '--task' || token === '--tasks') args.view = 'tasks';
|
|
604
611
|
}
|
|
605
612
|
return args;
|
|
606
613
|
}
|
|
@@ -1,46 +1,119 @@
|
|
|
1
|
-
import React, {useState, memo} from 'react';
|
|
1
|
+
import React, {useState, useEffect, memo} from 'react';
|
|
2
2
|
import {Box, Text, useInput} from 'ink';
|
|
3
3
|
|
|
4
4
|
const create = React.createElement;
|
|
5
5
|
|
|
6
6
|
const AI_PROVIDERS = [
|
|
7
|
-
{ id: '
|
|
7
|
+
{ id: 'openrouter', name: 'OpenRouter (DeepSeek/Qwen)', endpoint: 'openrouter.ai' },
|
|
8
8
|
{ id: 'gemini', name: 'Google Gemini', endpoint: 'api.google.com' },
|
|
9
|
-
{ id: 'claude', name: 'Anthropic Claude', endpoint: 'api.anthropic.com' }
|
|
9
|
+
{ id: 'claude', name: 'Anthropic Claude', endpoint: 'api.anthropic.com' },
|
|
10
|
+
{ id: 'ollama', name: 'Ollama (Local)', endpoint: 'localhost:11434' }
|
|
10
11
|
];
|
|
11
12
|
|
|
12
|
-
const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText}) => {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
const AIHorizon = memo(({rootPath, selectedProject, onRunCommand, CursorText, config, setConfig, saveConfig}) => {
|
|
14
|
+
const savedProvider = config?.aiProvider || 'openrouter';
|
|
15
|
+
const savedModel = config?.aiModel || 'deepseek-r1';
|
|
16
|
+
|
|
17
|
+
const [step, setStep] = useState(config?.aiProvider ? 'analyze' : 'select');
|
|
18
|
+
const [providerIdx, setProviderIdx] = useState(AI_PROVIDERS.findIndex(p => p.id === savedProvider) || 0);
|
|
19
|
+
const [model, setModel] = useState(savedModel);
|
|
20
|
+
const [cursor, setCursor] = useState(model.length);
|
|
21
|
+
const [status, setStatus] = useState('ready'); // ready | busy | done
|
|
15
22
|
|
|
16
23
|
useInput((input, key) => {
|
|
17
24
|
if (step === 'select') {
|
|
18
25
|
if (key.upArrow) setProviderIdx(p => (p - 1 + AI_PROVIDERS.length) % AI_PROVIDERS.length);
|
|
19
26
|
if (key.downArrow) setProviderIdx(p => (p + 1) % AI_PROVIDERS.length);
|
|
20
|
-
if (key.return)
|
|
27
|
+
if (key.return) {
|
|
28
|
+
const nextProvider = AI_PROVIDERS[providerIdx].id;
|
|
29
|
+
const nextConfig = { ...config, aiProvider: nextProvider };
|
|
30
|
+
setConfig(nextConfig);
|
|
31
|
+
saveConfig(nextConfig);
|
|
32
|
+
setStep('model');
|
|
33
|
+
}
|
|
34
|
+
} else if (step === 'model') {
|
|
35
|
+
if (key.return) {
|
|
36
|
+
const nextConfig = { ...config, aiModel: model };
|
|
37
|
+
setConfig(nextConfig);
|
|
38
|
+
saveConfig(nextConfig);
|
|
39
|
+
setStep('analyze');
|
|
40
|
+
}
|
|
41
|
+
if (key.escape) setStep('select');
|
|
42
|
+
if (key.backspace || key.delete) {
|
|
43
|
+
if (cursor > 0) {
|
|
44
|
+
setModel(prev => prev.slice(0, cursor - 1) + prev.slice(cursor));
|
|
45
|
+
setCursor(c => Math.max(0, c - 1));
|
|
46
|
+
}
|
|
47
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
48
|
+
setModel(prev => prev.slice(0, cursor) + input + prev.slice(cursor));
|
|
49
|
+
setCursor(c => c + input.length);
|
|
50
|
+
}
|
|
51
|
+
} else if (step === 'analyze') {
|
|
52
|
+
if (key.return && status === 'ready') {
|
|
53
|
+
setStatus('busy');
|
|
54
|
+
// Logic to simulate analysis and then "inject" BRIT commands
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
if (selectedProject) {
|
|
57
|
+
const projectKey = selectedProject.path;
|
|
58
|
+
const currentCustom = config.customCommands?.[projectKey] || [];
|
|
59
|
+
const aiCommands = [
|
|
60
|
+
{ label: 'AI Build', command: ['npm', 'run', 'build'] },
|
|
61
|
+
{ label: 'AI Test', command: ['npm', 'test'] }
|
|
62
|
+
];
|
|
63
|
+
const nextConfig = {
|
|
64
|
+
...config,
|
|
65
|
+
customCommands: { ...config.customCommands, [projectKey]: [...currentCustom, ...aiCommands] }
|
|
66
|
+
};
|
|
67
|
+
setConfig(nextConfig);
|
|
68
|
+
saveConfig(nextConfig);
|
|
69
|
+
}
|
|
70
|
+
setStatus('done');
|
|
71
|
+
}, 1500);
|
|
72
|
+
}
|
|
73
|
+
if (key.escape) setStep('model');
|
|
74
|
+
if (input === 'r') setStep('select'); // Reconfigure
|
|
21
75
|
}
|
|
22
76
|
});
|
|
23
77
|
|
|
24
78
|
return create(
|
|
25
79
|
Box,
|
|
26
80
|
{flexDirection: 'column', borderStyle: 'double', borderColor: 'magenta', padding: 1, width: '100%'},
|
|
27
|
-
create(Text, {bold: true, color: 'magenta'}, '🤖 AI Horizon |
|
|
28
|
-
|
|
29
|
-
|
|
81
|
+
create(Text, {bold: true, color: 'magenta'}, '🤖 AI Horizon | Integrated Project Intelligence'),
|
|
82
|
+
|
|
30
83
|
step === 'select' && create(
|
|
31
84
|
Box,
|
|
32
85
|
{flexDirection: 'column'},
|
|
33
|
-
create(Text, {bold: true, marginBottom: 1}, 'Step 1: Select AI
|
|
34
|
-
...AI_PROVIDERS.map((p, i) => create(Text, {key: p.id, color: i === providerIdx ? 'cyan' : 'white'}, (i === providerIdx ? '→ ' : ' ') + p.name
|
|
35
|
-
create(Text, {dimColor: true, marginTop: 1}, 'Enter:
|
|
86
|
+
create(Text, {bold: true, marginBottom: 1}, 'Step 1: Select AI Provider (Saved to config)'),
|
|
87
|
+
...AI_PROVIDERS.map((p, i) => create(Text, {key: p.id, color: i === providerIdx ? 'cyan' : 'white'}, (i === providerIdx ? '→ ' : ' ') + p.name)),
|
|
88
|
+
create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save & Continue')
|
|
89
|
+
),
|
|
90
|
+
|
|
91
|
+
step === 'model' && create(
|
|
92
|
+
Box,
|
|
93
|
+
{flexDirection: 'column'},
|
|
94
|
+
create(Text, {bold: true, color: 'yellow', marginBottom: 1}, 'Step 2: Model Identity'),
|
|
95
|
+
create(Box, {flexDirection: 'row'},
|
|
96
|
+
create(Text, null, 'Model ID: '),
|
|
97
|
+
create(CursorText, {value: model, cursorIndex: cursor})
|
|
98
|
+
),
|
|
99
|
+
create(Text, {dimColor: true, marginTop: 1}, 'Enter: Save & Proceed, Esc: Back')
|
|
36
100
|
),
|
|
37
101
|
|
|
38
102
|
step === 'analyze' && create(
|
|
39
103
|
Box,
|
|
40
104
|
{flexDirection: 'column'},
|
|
41
|
-
create(Text, {bold: true, color: '
|
|
42
|
-
create(Text,
|
|
43
|
-
create(
|
|
105
|
+
create(Text, {bold: true, color: 'cyan', marginBottom: 1}, 'Ready to analyze: ' + (selectedProject ? selectedProject.name : 'Workspace')),
|
|
106
|
+
create(Text, {dimColor: true}, 'Provider: ' + config.aiProvider + ' | Model: ' + config.aiModel),
|
|
107
|
+
create(Box, {marginTop: 1, flexDirection: 'column'},
|
|
108
|
+
status === 'ready' && create(Text, null, 'Press Enter to analyze DNA and configure BRIT commands.'),
|
|
109
|
+
status === 'busy' && create(Text, {color: 'yellow'}, ' ⏳ Accessing intelligence... mapping project manifests...'),
|
|
110
|
+
status === 'done' && create(Box, {flexDirection: 'column'},
|
|
111
|
+
create(Text, {color: 'green', bold: true}, ' ✅ Analysis Complete!'),
|
|
112
|
+
create(Text, null, ' Missing BRIT commands have been injected into your project config.'),
|
|
113
|
+
create(Text, {dimColor: true, marginTop: 1}, 'Return to Navigator to use B/R/I/T macros.')
|
|
114
|
+
)
|
|
115
|
+
),
|
|
116
|
+
create(Text, {dimColor: true, marginTop: 1}, 'Esc: Back, R: Reconfigure Provider')
|
|
44
117
|
)
|
|
45
118
|
);
|
|
46
119
|
});
|