navada-edge-cli 2.1.0 → 2.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/lib/agent.js +30 -8
- package/lib/cli.js +14 -10
- package/lib/commands/setup.js +57 -88
- package/lib/commands/system.js +26 -5
- package/package.json +1 -1
package/lib/agent.js
CHANGED
|
@@ -98,10 +98,19 @@ const localTools = {
|
|
|
98
98
|
// Anthropic Claude API — conversational agent
|
|
99
99
|
// ---------------------------------------------------------------------------
|
|
100
100
|
async function chat(userMessage, conversationHistory = []) {
|
|
101
|
-
|
|
101
|
+
// Smart key detection — check all possible locations
|
|
102
|
+
const anthropicKey = config.get('anthropicKey')
|
|
103
|
+
|| config.getApiKey() // /setup saves here
|
|
104
|
+
|| process.env.ANTHROPIC_API_KEY
|
|
105
|
+
|| '';
|
|
102
106
|
|
|
103
|
-
if
|
|
104
|
-
|
|
107
|
+
// Auto-detect: if the key starts with sk-ant, it's Anthropic
|
|
108
|
+
const apiKey = config.getApiKey();
|
|
109
|
+
const effectiveKey = anthropicKey
|
|
110
|
+
|| (apiKey && apiKey.startsWith('sk-ant') ? apiKey : '')
|
|
111
|
+
|| '';
|
|
112
|
+
|
|
113
|
+
if (!effectiveKey) {
|
|
105
114
|
return fallbackChat(userMessage);
|
|
106
115
|
}
|
|
107
116
|
|
|
@@ -179,7 +188,7 @@ async function chat(userMessage, conversationHistory = []) {
|
|
|
179
188
|
];
|
|
180
189
|
|
|
181
190
|
// Call Anthropic API
|
|
182
|
-
let response = await callAnthropic(
|
|
191
|
+
let response = await callAnthropic(effectiveKey, messages, tools);
|
|
183
192
|
|
|
184
193
|
// Handle tool use loop
|
|
185
194
|
let iterations = 0;
|
|
@@ -265,17 +274,30 @@ async function executeTool(name, input) {
|
|
|
265
274
|
}
|
|
266
275
|
|
|
267
276
|
async function fallbackChat(msg) {
|
|
268
|
-
// Try MCP → Qwen → OpenAI → error
|
|
277
|
+
// Try MCP → Qwen → OpenAI → helpful error
|
|
269
278
|
if (navada.config.mcp) {
|
|
270
|
-
try {
|
|
279
|
+
try {
|
|
280
|
+
const r = await navada.mcp.call('chat', { message: msg });
|
|
281
|
+
return typeof r === 'object' ? JSON.stringify(r) : r;
|
|
282
|
+
} catch {}
|
|
271
283
|
}
|
|
272
284
|
if (navada.config.hfToken) {
|
|
273
|
-
try {
|
|
285
|
+
try {
|
|
286
|
+
const r = await navada.ai.huggingface.qwen(msg);
|
|
287
|
+
return typeof r === 'object' ? JSON.stringify(r) : r;
|
|
288
|
+
} catch {}
|
|
274
289
|
}
|
|
275
290
|
if (navada.config.openaiKey) {
|
|
276
291
|
try { return await navada.ai.openai.chat(msg); } catch {}
|
|
277
292
|
}
|
|
278
|
-
return
|
|
293
|
+
return `I need an API key to chat. Quick fix:
|
|
294
|
+
|
|
295
|
+
/login sk-ant-your-anthropic-key (recommended — enables full agent with tool use)
|
|
296
|
+
/login sk-your-openai-key (GPT-4o)
|
|
297
|
+
/init hfToken hf_your_token (Qwen Coder — FREE)
|
|
298
|
+
/setup (guided wizard)
|
|
299
|
+
|
|
300
|
+
/commands still work without a key — try /help`;
|
|
279
301
|
}
|
|
280
302
|
|
|
281
303
|
// ---------------------------------------------------------------------------
|
package/lib/cli.js
CHANGED
|
@@ -85,17 +85,21 @@ async function run(argv) {
|
|
|
85
85
|
applyConfig();
|
|
86
86
|
|
|
87
87
|
if (argv.length === 0) {
|
|
88
|
-
//
|
|
89
|
-
if (config.isFirstRun())
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Report session start
|
|
96
|
-
reportTelemetry('session_start');
|
|
97
|
-
// Interactive mode
|
|
88
|
+
// Report telemetry
|
|
89
|
+
if (config.isFirstRun()) reportTelemetry('install');
|
|
90
|
+
else reportTelemetry('session_start');
|
|
91
|
+
|
|
92
|
+
// Interactive mode — always start. User can /setup if needed.
|
|
98
93
|
showWelcome();
|
|
94
|
+
|
|
95
|
+
// Hint if no key configured
|
|
96
|
+
const hasKey = config.getApiKey() || config.get('anthropicKey') || process.env.ANTHROPIC_API_KEY;
|
|
97
|
+
if (!hasKey) {
|
|
98
|
+
console.log(ui.warn('No API key set. Type /login <key> or /setup to configure.'));
|
|
99
|
+
console.log(ui.dim('You can still use /commands. Natural chat requires an API key.'));
|
|
100
|
+
console.log('');
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
startRepl();
|
|
100
104
|
} else if (argv[0] === '--version' || argv[0] === '-v') {
|
|
101
105
|
const pkg = require('../package.json');
|
package/lib/commands/setup.js
CHANGED
|
@@ -9,128 +9,97 @@ function ask(rl, question) {
|
|
|
9
9
|
return new Promise(resolve => rl.question(question, resolve));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
async function runSetup() {
|
|
13
|
-
|
|
12
|
+
async function runSetup(fromRepl = false) {
|
|
13
|
+
// Create a fresh readline — don't conflict with the REPL
|
|
14
|
+
const rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout,
|
|
17
|
+
terminal: true,
|
|
18
|
+
});
|
|
14
19
|
|
|
15
|
-
console.log(ui.banner());
|
|
16
|
-
console.log(ui.box('WELCOME', ' First-time setup. Let\'s connect you to the NAVADA Edge Network.'));
|
|
17
20
|
console.log('');
|
|
18
|
-
|
|
19
|
-
// 1. API Key
|
|
20
|
-
const apiKey = await ask(rl, ' Enter your NAVADA Edge API key (or press Enter for FREE tier): ');
|
|
21
|
-
if (apiKey.trim()) {
|
|
22
|
-
config.setApiKey(apiKey.trim());
|
|
23
|
-
navada.init({ mcpApiKey: apiKey.trim(), dashboardApiKey: apiKey.trim() });
|
|
24
|
-
console.log(ui.success('API key saved'));
|
|
25
|
-
} else {
|
|
26
|
-
console.log(ui.dim('Continuing with FREE tier'));
|
|
27
|
-
}
|
|
21
|
+
console.log(ui.box('SETUP', ' Configure your NAVADA Edge CLI.'));
|
|
28
22
|
console.log('');
|
|
29
23
|
|
|
30
|
-
//
|
|
31
|
-
console.log(ui.dim('
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
24
|
+
// 1. API Key — the only required thing
|
|
25
|
+
console.log(ui.dim(' Your API key powers the AI agent. Accepts:'));
|
|
26
|
+
console.log(ui.dim(' - Anthropic key (sk-ant-...)'));
|
|
27
|
+
console.log(ui.dim(' - NAVADA Edge API key (nv_edge_...)'));
|
|
28
|
+
console.log(ui.dim(' - OpenAI key (sk-...)'));
|
|
29
|
+
console.log(ui.dim(' - Or press Enter to skip (limited mode)'));
|
|
30
|
+
console.log('');
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
32
|
+
const apiKey = await ask(rl, ' API key: ');
|
|
33
|
+
if (apiKey.trim()) {
|
|
34
|
+
const key = apiKey.trim();
|
|
35
|
+
config.setApiKey(key);
|
|
36
|
+
// Auto-detect key type and save to right field
|
|
37
|
+
if (key.startsWith('sk-ant')) {
|
|
38
|
+
config.set('anthropicKey', key);
|
|
39
|
+
console.log(ui.success('Anthropic key saved — full agent mode enabled'));
|
|
40
|
+
} else if (key.startsWith('nv_edge')) {
|
|
41
|
+
console.log(ui.success('NAVADA Edge key saved — MCP access enabled'));
|
|
42
|
+
} else if (key.startsWith('sk-')) {
|
|
43
|
+
config.set('openaiKey', key);
|
|
44
|
+
navada.init({ openaiKey: key });
|
|
45
|
+
console.log(ui.success('OpenAI key saved'));
|
|
46
|
+
} else {
|
|
47
|
+
console.log(ui.success('Key saved'));
|
|
48
48
|
}
|
|
49
|
+
} else {
|
|
50
|
+
console.log(ui.dim('Skipped — you can set this later with /login <key>'));
|
|
49
51
|
}
|
|
50
52
|
console.log('');
|
|
51
53
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (detected.asus) {
|
|
61
|
-
config.set('mcp', `http://${detected.asus}:8811`);
|
|
62
|
-
config.set('dashboard', `http://${detected.asus}:7900`);
|
|
63
|
-
config.set('registry', `http://${detected.asus}:5000`);
|
|
64
|
-
navada.init({
|
|
65
|
-
asus: detected.asus, hp: detected.hp || '', ec2: detected.ec2 || '', oracle: detected.oracle || '',
|
|
66
|
-
mcp: `http://${detected.asus}:8811`, dashboard: `http://${detected.asus}:7900`, registry: `http://${detected.asus}:5000`,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
if (detected.ec2) {
|
|
70
|
-
config.set('lucas', `http://${detected.ec2}:8820`);
|
|
71
|
-
navada.init({ lucas: `http://${detected.ec2}:8820` });
|
|
72
|
-
}
|
|
73
|
-
console.log(ui.success('Nodes configured'));
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
console.log(ui.dim('No nodes auto-detected. Enter manually:'));
|
|
54
|
+
// 2. Node IPs — optional
|
|
55
|
+
const configureNodes = await ask(rl, ' Configure network nodes? (y/N): ');
|
|
56
|
+
if (configureNodes.trim().toLowerCase() === 'y') {
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(ui.dim(' Enter Tailscale IPs for your NAVADA Edge nodes.'));
|
|
59
|
+
console.log(ui.dim(' Press Enter to skip any node.'));
|
|
60
|
+
console.log('');
|
|
61
|
+
|
|
77
62
|
const asusIp = await ask(rl, ' ASUS IP (Production Engine): ');
|
|
78
63
|
if (asusIp.trim()) {
|
|
79
64
|
config.set('asus', asusIp.trim());
|
|
80
65
|
config.set('mcp', `http://${asusIp.trim()}:8811`);
|
|
81
66
|
config.set('dashboard', `http://${asusIp.trim()}:7900`);
|
|
82
67
|
config.set('registry', `http://${asusIp.trim()}:5000`);
|
|
83
|
-
navada.init({
|
|
68
|
+
navada.init({
|
|
69
|
+
asus: asusIp.trim(),
|
|
70
|
+
mcp: `http://${asusIp.trim()}:8811`,
|
|
71
|
+
dashboard: `http://${asusIp.trim()}:7900`,
|
|
72
|
+
registry: `http://${asusIp.trim()}:5000`,
|
|
73
|
+
});
|
|
84
74
|
}
|
|
85
|
-
const hpIp = await ask(rl, ' HP IP (Database
|
|
75
|
+
const hpIp = await ask(rl, ' HP IP (Database): ');
|
|
86
76
|
if (hpIp.trim()) config.set('hp', hpIp.trim());
|
|
87
|
-
const ec2Ip = await ask(rl, ' EC2 IP (Monitoring
|
|
77
|
+
const ec2Ip = await ask(rl, ' EC2 IP (Monitoring): ');
|
|
88
78
|
if (ec2Ip.trim()) {
|
|
89
79
|
config.set('ec2', ec2Ip.trim());
|
|
90
80
|
config.set('lucas', `http://${ec2Ip.trim()}:8820`);
|
|
91
81
|
}
|
|
92
|
-
const oracleIp = await ask(rl, ' Oracle IP (
|
|
82
|
+
const oracleIp = await ask(rl, ' Oracle IP (Infrastructure): ');
|
|
93
83
|
if (oracleIp.trim()) config.set('oracle', oracleIp.trim());
|
|
84
|
+
console.log(ui.success('Nodes configured'));
|
|
94
85
|
}
|
|
95
86
|
console.log('');
|
|
96
87
|
|
|
97
|
-
//
|
|
98
|
-
const theme = await ask(rl, '
|
|
88
|
+
// 3. Theme
|
|
89
|
+
const theme = await ask(rl, ' Theme (dark/crow/matrix/light) [dark]: ');
|
|
99
90
|
config.setTheme(theme.trim() || 'dark');
|
|
100
|
-
console.log(ui.success(`Theme: ${config.getTheme()}`));
|
|
101
|
-
console.log('');
|
|
102
|
-
|
|
103
|
-
// 5. Test connections
|
|
104
|
-
console.log(ui.dim('Testing connections...'));
|
|
105
|
-
const tests = [
|
|
106
|
-
{ name: 'MCP', url: navada.config.mcp ? navada.config.mcp + '/health' : '' },
|
|
107
|
-
{ name: 'Dashboard', url: navada.config.dashboard || '' },
|
|
108
|
-
{ name: 'Registry', url: navada.config.registry ? navada.config.registry + '/v2/_catalog' : '' },
|
|
109
|
-
];
|
|
110
|
-
let pass = 0;
|
|
111
|
-
for (const t of tests) {
|
|
112
|
-
if (!t.url) { console.log(ui.online(t.name, false, 'not configured')); continue; }
|
|
113
|
-
try {
|
|
114
|
-
const r = await navada.request(t.url, { timeout: 5000 });
|
|
115
|
-
console.log(ui.online(t.name, r.status < 500));
|
|
116
|
-
pass++;
|
|
117
|
-
} catch {
|
|
118
|
-
console.log(ui.online(t.name, false, 'unreachable'));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
91
|
console.log('');
|
|
122
92
|
|
|
123
|
-
//
|
|
124
|
-
console.log(ui.box('
|
|
93
|
+
// 4. Done
|
|
94
|
+
console.log(ui.box('READY', ` Config saved: ${config.CONFIG_FILE}\n Type naturally to chat, or /help for commands.`));
|
|
125
95
|
console.log('');
|
|
126
|
-
console.log(ui.dim('Run `navada` to start, or `navada doctor` to test all connections.'));
|
|
127
96
|
|
|
128
97
|
rl.close();
|
|
129
98
|
}
|
|
130
99
|
|
|
131
100
|
module.exports = function(reg) {
|
|
132
|
-
reg('setup', 'Run
|
|
133
|
-
await runSetup();
|
|
101
|
+
reg('setup', 'Run setup wizard', async () => {
|
|
102
|
+
await runSetup(true);
|
|
134
103
|
}, { category: 'SYSTEM' });
|
|
135
104
|
};
|
|
136
105
|
|
package/lib/commands/system.js
CHANGED
|
@@ -65,11 +65,32 @@ module.exports = function(reg) {
|
|
|
65
65
|
}, { category: 'SYSTEM' });
|
|
66
66
|
|
|
67
67
|
// --- /login ---
|
|
68
|
-
reg('login', 'Set API key', (args) => {
|
|
69
|
-
if (!args[0]) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
reg('login', 'Set API key (Anthropic, OpenAI, NAVADA Edge, or HuggingFace)', (args) => {
|
|
69
|
+
if (!args[0]) {
|
|
70
|
+
console.log(ui.dim('Usage: /login <api-key>'));
|
|
71
|
+
console.log(ui.dim('Accepts: sk-ant-... (Anthropic) | sk-... (OpenAI) | nv_edge_... (NAVADA) | hf_... (HuggingFace)'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const key = args[0].trim();
|
|
75
|
+
config.setApiKey(key);
|
|
76
|
+
|
|
77
|
+
if (key.startsWith('sk-ant')) {
|
|
78
|
+
config.set('anthropicKey', key);
|
|
79
|
+
console.log(ui.success('Anthropic key saved — full agent mode with tool use enabled'));
|
|
80
|
+
} else if (key.startsWith('hf_')) {
|
|
81
|
+
config.set('hfToken', key);
|
|
82
|
+
navada.init({ hfToken: key });
|
|
83
|
+
console.log(ui.success('HuggingFace key saved — Qwen Coder (FREE) enabled'));
|
|
84
|
+
} else if (key.startsWith('nv_edge')) {
|
|
85
|
+
navada.init({ mcpApiKey: key, dashboardApiKey: key });
|
|
86
|
+
console.log(ui.success('NAVADA Edge key saved — MCP + Dashboard access enabled'));
|
|
87
|
+
} else if (key.startsWith('sk-')) {
|
|
88
|
+
config.set('openaiKey', key);
|
|
89
|
+
navada.init({ openaiKey: key });
|
|
90
|
+
console.log(ui.success('OpenAI key saved — GPT-4o enabled'));
|
|
91
|
+
} else {
|
|
92
|
+
console.log(ui.success('Key saved'));
|
|
93
|
+
}
|
|
73
94
|
}, { category: 'SYSTEM' });
|
|
74
95
|
|
|
75
96
|
// --- /init ---
|
package/package.json
CHANGED