navada-edge-cli 4.0.0 → 4.2.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 +297 -523
- package/lib/agent.js +392 -284
- package/lib/commands/ai.js +8 -9
- package/lib/commands/audit.js +1 -1
- package/lib/commands/compute.js +144 -165
- package/lib/commands/edge.js +139 -14
- package/lib/commands/index.js +1 -1
- package/lib/commands/lucas.js +6 -34
- package/lib/commands/mcp.js +6 -29
- package/lib/commands/nvidia.js +4 -4
- package/lib/commands/setup.js +271 -59
- package/lib/commands/skills.js +209 -0
- package/lib/commands/system.js +173 -0
- package/lib/memory.js +432 -0
- package/lib/skills.js +222 -0
- package/package.json +14 -12
- package/lib/commands/files.js +0 -164
- package/lib/knowledge.py +0 -197
package/lib/commands/lucas.js
CHANGED
|
@@ -1,40 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const navada = require('navada-edge-sdk');
|
|
4
3
|
const ui = require('../ui');
|
|
5
4
|
|
|
6
5
|
module.exports = function(reg) {
|
|
7
|
-
reg('lucas', 'Lucas CTO agent
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} else if (sub === 'ssh' && args[1] && args[2]) {
|
|
14
|
-
const result = await navada.lucas.ssh(args[1], args.slice(2).join(' '));
|
|
15
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
16
|
-
} else if (sub === 'docker' && args[1] && args[2]) {
|
|
17
|
-
const result = await navada.lucas.docker(args[1], args.slice(2).join(' '));
|
|
18
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
19
|
-
} else if (sub === 'deploy' && args[1] && args[2]) {
|
|
20
|
-
const ora = require('ora');
|
|
21
|
-
const spinner = ora({ text: ` Deploying ${args[1]} to ${args[2]}...`, color: 'white' }).start();
|
|
22
|
-
const result = await navada.lucas.deploy(args[1], args[2]);
|
|
23
|
-
spinner.stop();
|
|
24
|
-
console.log(ui.success(`Deployed ${args[1]} to ${args[2]}`));
|
|
25
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
26
|
-
} else if (sub === 'status') {
|
|
27
|
-
const result = await navada.lucas.networkStatus();
|
|
28
|
-
console.log(ui.header('LUCAS NETWORK STATUS'));
|
|
29
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
30
|
-
} else if (sub === 'files' && args[1]) {
|
|
31
|
-
const result = await navada.lucas.listFiles(args[1]);
|
|
32
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
33
|
-
} else if (sub === 'read' && args[1]) {
|
|
34
|
-
const result = await navada.lucas.readFile(args[1]);
|
|
35
|
-
console.log(typeof result === 'string' ? result : ui.jsonColorize(result));
|
|
36
|
-
} else {
|
|
37
|
-
console.log(ui.dim('Usage: /lucas exec <cmd> | ssh <node> <cmd> | docker <ctr> <cmd> | deploy <name> <node> | status | files <dir> | read <file>'));
|
|
38
|
-
}
|
|
39
|
-
}, { category: 'AGENTS', subs: ['exec', 'ssh', 'docker', 'deploy', 'status', 'files', 'read'] });
|
|
6
|
+
reg('lucas', 'Lucas CTO agent (admin only)', async () => {
|
|
7
|
+
console.log(ui.header('LUCAS CTO'));
|
|
8
|
+
console.log(ui.dim('Lucas CTO is a private admin agent and is not available in the public CLI.'));
|
|
9
|
+
console.log(ui.dim('Use /automate to submit automation requests instead.'));
|
|
10
|
+
console.log(ui.dim('Or use /compute for quick cloud execution.'));
|
|
11
|
+
}, { category: 'AGENTS' });
|
|
40
12
|
};
|
package/lib/commands/mcp.js
CHANGED
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const navada = require('navada-edge-sdk');
|
|
4
|
-
const Table = require('cli-table3');
|
|
5
3
|
const ui = require('../ui');
|
|
6
|
-
const { tableChars } = require('./helpers');
|
|
7
4
|
|
|
8
5
|
module.exports = function(reg) {
|
|
9
|
-
reg('mcp', 'MCP
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
spinner.stop();
|
|
16
|
-
console.log(ui.header(`MCP TOOLS (${tools.length})`));
|
|
17
|
-
if (tools.length === 0) { console.log(ui.dim('No tools returned (check API key tier)')); return; }
|
|
18
|
-
const t = new Table({ head: ['Tool', 'Description'], style: { head: ['white'], border: ['gray'] }, chars: tableChars() });
|
|
19
|
-
tools.forEach(tool => t.push([tool.name, tool.description || '']));
|
|
20
|
-
console.log(t.toString());
|
|
21
|
-
} else if (sub === 'call' && args[1]) {
|
|
22
|
-
const toolName = args[1];
|
|
23
|
-
let toolArgs = {};
|
|
24
|
-
if (args[2]) { try { toolArgs = JSON.parse(args.slice(2).join(' ')); } catch { toolArgs = { input: args.slice(2).join(' ') }; } }
|
|
25
|
-
const ora = require('ora');
|
|
26
|
-
const spinner = ora({ text: ` Calling ${toolName}...`, color: 'white' }).start();
|
|
27
|
-
const result = await navada.mcp.call(toolName, toolArgs);
|
|
28
|
-
spinner.stop();
|
|
29
|
-
console.log(ui.header(`MCP: ${toolName}`));
|
|
30
|
-
console.log(typeof result === 'object' ? ui.jsonColorize(result) : result);
|
|
31
|
-
} else {
|
|
32
|
-
console.log(ui.dim('Usage: /mcp tools | /mcp call <tool> [json]'));
|
|
33
|
-
}
|
|
34
|
-
}, { category: 'MCP', subs: ['tools', 'call'] });
|
|
6
|
+
reg('mcp', 'MCP tools (admin only)', async () => {
|
|
7
|
+
console.log(ui.header('MCP TOOLS'));
|
|
8
|
+
console.log(ui.dim('MCP tools require admin access to the NAVADA Edge Network.'));
|
|
9
|
+
console.log(ui.dim('Use /automate or /compute for cloud compute instead.'));
|
|
10
|
+
console.log(ui.dim('Use /edge login <key> to connect to the network.'));
|
|
11
|
+
}, { category: 'MCP' });
|
|
35
12
|
};
|
package/lib/commands/nvidia.js
CHANGED
|
@@ -23,14 +23,14 @@ const DEFAULT_NVIDIA_MODEL = 'llama-3.3-70b';
|
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
// NVIDIA API chat (streaming)
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
|
-
function streamNvidia(apiKey, messages, modelKey = DEFAULT_NVIDIA_MODEL) {
|
|
26
|
+
function streamNvidia(apiKey, messages, modelKey = DEFAULT_NVIDIA_MODEL, systemPrompt = null) {
|
|
27
27
|
const modelInfo = NVIDIA_MODELS[modelKey] || NVIDIA_MODELS[DEFAULT_NVIDIA_MODEL];
|
|
28
28
|
|
|
29
29
|
return new Promise((resolve, reject) => {
|
|
30
30
|
const body = JSON.stringify({
|
|
31
31
|
model: modelInfo.id,
|
|
32
32
|
messages: [
|
|
33
|
-
{ role: 'system', content: 'You are NAVADA, an AI infrastructure agent. Keep responses concise and technical. Use code blocks with language tags when showing code.' },
|
|
33
|
+
{ role: 'system', content: systemPrompt || 'You are NAVADA, an AI infrastructure agent. Keep responses concise and technical. Use code blocks with language tags when showing code.' },
|
|
34
34
|
...messages,
|
|
35
35
|
],
|
|
36
36
|
max_tokens: 4096,
|
|
@@ -95,14 +95,14 @@ function streamNvidia(apiKey, messages, modelKey = DEFAULT_NVIDIA_MODEL) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// Non-streaming fallback
|
|
98
|
-
async function chatNvidia(apiKey, messages, modelKey = DEFAULT_NVIDIA_MODEL) {
|
|
98
|
+
async function chatNvidia(apiKey, messages, modelKey = DEFAULT_NVIDIA_MODEL, systemPrompt = null) {
|
|
99
99
|
const modelInfo = NVIDIA_MODELS[modelKey] || NVIDIA_MODELS[DEFAULT_NVIDIA_MODEL];
|
|
100
100
|
|
|
101
101
|
return new Promise((resolve, reject) => {
|
|
102
102
|
const body = JSON.stringify({
|
|
103
103
|
model: modelInfo.id,
|
|
104
104
|
messages: [
|
|
105
|
-
{ role: 'system', content: 'You are NAVADA, an AI infrastructure agent. Keep responses concise and technical. Use code blocks with language tags when showing code.' },
|
|
105
|
+
{ role: 'system', content: systemPrompt || 'You are NAVADA, an AI infrastructure agent. Keep responses concise and technical. Use code blocks with language tags when showing code.' },
|
|
106
106
|
...messages,
|
|
107
107
|
],
|
|
108
108
|
max_tokens: 4096,
|
package/lib/commands/setup.js
CHANGED
|
@@ -1,16 +1,109 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const readline = require('readline');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
4
6
|
const navada = require('navada-edge-sdk');
|
|
5
7
|
const ui = require('../ui');
|
|
6
8
|
const config = require('../config');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
9
|
|
|
10
10
|
function ask(rl, question) {
|
|
11
11
|
return new Promise(resolve => rl.question(question, resolve));
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// Default templates
|
|
15
|
+
const SOUL_TEMPLATE = `# Soul — Who I Am
|
|
16
|
+
|
|
17
|
+
## Identity
|
|
18
|
+
name: ""
|
|
19
|
+
role: ""
|
|
20
|
+
industry: ""
|
|
21
|
+
experience_level: "" # junior, mid, senior, lead, principal
|
|
22
|
+
|
|
23
|
+
## Goals
|
|
24
|
+
- What do you want to achieve with NAVADA Edge?
|
|
25
|
+
- What problems are you trying to solve?
|
|
26
|
+
|
|
27
|
+
## Stack
|
|
28
|
+
languages: []
|
|
29
|
+
frameworks: []
|
|
30
|
+
cloud: []
|
|
31
|
+
databases: []
|
|
32
|
+
|
|
33
|
+
## Communication Style
|
|
34
|
+
tone: "professional" # professional, casual, technical, creative
|
|
35
|
+
detail_level: "balanced" # brief, balanced, detailed
|
|
36
|
+
code_comments: true
|
|
37
|
+
explain_changes: true
|
|
38
|
+
|
|
39
|
+
## Context
|
|
40
|
+
# Add anything the agent should know about you, your team, or your projects.
|
|
41
|
+
# This file is loaded every time you interact with the NAVADA agent.
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const GUARDRAIL_TEMPLATE = `# Guardrails — Agent Boundaries
|
|
45
|
+
|
|
46
|
+
## Permissions
|
|
47
|
+
allow_shell_commands: true
|
|
48
|
+
allow_file_write: true
|
|
49
|
+
allow_file_delete: false
|
|
50
|
+
allow_python_exec: true
|
|
51
|
+
allow_pip_install: true
|
|
52
|
+
allow_network_requests: true
|
|
53
|
+
|
|
54
|
+
## Safety
|
|
55
|
+
max_shell_timeout_seconds: 30
|
|
56
|
+
confirm_before_delete: true
|
|
57
|
+
confirm_before_overwrite: true
|
|
58
|
+
never_modify_paths:
|
|
59
|
+
- ~/.ssh/
|
|
60
|
+
- ~/.gnupg/
|
|
61
|
+
- ~/.aws/credentials
|
|
62
|
+
|
|
63
|
+
## Content
|
|
64
|
+
no_offensive_content: true
|
|
65
|
+
no_personal_data_in_logs: true
|
|
66
|
+
language: "en"
|
|
67
|
+
|
|
68
|
+
## Automation
|
|
69
|
+
auto_submit_requests: false # if true, agent can submit /automate without asking
|
|
70
|
+
max_automation_requests_per_day: 5
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const README_TEMPLATE = `# My NAVADA Edge Workspace
|
|
74
|
+
|
|
75
|
+
## Setup
|
|
76
|
+
- CLI: navada-edge-cli v4.0.0
|
|
77
|
+
- Agent: NAVADA Edge AI
|
|
78
|
+
- Config: ~/.navada/
|
|
79
|
+
|
|
80
|
+
## Files
|
|
81
|
+
- **soul.md** — Your identity, goals, and preferences (agent reads this)
|
|
82
|
+
- **guardrail.md** — Safety boundaries and permissions
|
|
83
|
+
- **agents/** — Custom sub-agent personas
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
\`\`\`bash
|
|
87
|
+
navada # Interactive mode
|
|
88
|
+
/help # All commands
|
|
89
|
+
/tools # Available agent tools
|
|
90
|
+
/automate # Submit automation request
|
|
91
|
+
/requests # Track your requests
|
|
92
|
+
/learn python # Learning mode
|
|
93
|
+
\`\`\`
|
|
94
|
+
|
|
95
|
+
## Automation
|
|
96
|
+
Submit automation requests and the NAVADA team will set them up for you:
|
|
97
|
+
- Marketing emails and campaigns
|
|
98
|
+
- Scheduled reports and data pipelines
|
|
99
|
+
- Application builds and deployments
|
|
100
|
+
- Custom recurring tasks
|
|
101
|
+
|
|
102
|
+
## Support
|
|
103
|
+
- Portal: https://portal.navada-edge-server.uk
|
|
104
|
+
- Docs: https://docs.navada-edge-server.uk
|
|
105
|
+
`;
|
|
106
|
+
|
|
14
107
|
async function runSetup(fromRepl = false) {
|
|
15
108
|
const rl = readline.createInterface({
|
|
16
109
|
input: process.stdin,
|
|
@@ -19,96 +112,215 @@ async function runSetup(fromRepl = false) {
|
|
|
19
112
|
});
|
|
20
113
|
|
|
21
114
|
console.log('');
|
|
22
|
-
console.log(ui.box('NAVADA EDGE SETUP', '
|
|
115
|
+
console.log(ui.box('NAVADA EDGE — SETUP', ' Configure your AI agent for full access.'));
|
|
23
116
|
console.log('');
|
|
24
117
|
|
|
25
|
-
// 1
|
|
26
|
-
console.log(ui.dim('
|
|
27
|
-
console.log(ui.dim('
|
|
28
|
-
console.log(ui.dim('
|
|
118
|
+
// Step 1: API Key
|
|
119
|
+
console.log(ui.dim(' STEP 1 — API Key'));
|
|
120
|
+
console.log(ui.dim(' Free tier: NVIDIA AI with rate limit (no key needed)'));
|
|
121
|
+
console.log(ui.dim(' Full access: Register for unlimited + automations'));
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(ui.dim(' Accepts: NAVADA Edge key (nv_edge_...), Anthropic (sk-ant-...), OpenAI (sk-...), NVIDIA (nvapi-...)'));
|
|
29
124
|
console.log('');
|
|
30
125
|
|
|
31
|
-
const apiKey = await ask(rl, ' API key: ');
|
|
126
|
+
const apiKey = await ask(rl, ' API key (Enter to skip — free tier): ');
|
|
32
127
|
if (apiKey.trim()) {
|
|
33
128
|
const key = apiKey.trim();
|
|
129
|
+
config.setApiKey(key);
|
|
34
130
|
if (key.startsWith('sk-ant')) {
|
|
35
131
|
config.set('anthropicKey', key);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
console.log(ui.success('Gemini key saved. Free unlimited access.'));
|
|
41
|
-
} else if (key.startsWith('sk-')) {
|
|
42
|
-
config.set('openaiKey', key);
|
|
43
|
-
config.setApiKey(key);
|
|
44
|
-
console.log(ui.success('OpenAI key saved. GPT-4o with tool use enabled.'));
|
|
132
|
+
console.log(ui.success('Anthropic key saved — full agent mode'));
|
|
133
|
+
} else if (key.startsWith('nv_edge')) {
|
|
134
|
+
config.set('edgeKey', key);
|
|
135
|
+
console.log(ui.success('NAVADA Edge key saved — full access'));
|
|
45
136
|
} else if (key.startsWith('nvapi-')) {
|
|
46
137
|
config.set('nvidiaKey', key);
|
|
47
|
-
console.log(ui.success('NVIDIA key saved
|
|
48
|
-
} else if (key.startsWith('
|
|
49
|
-
config.set('
|
|
50
|
-
console.log(ui.success('
|
|
138
|
+
console.log(ui.success('NVIDIA key saved'));
|
|
139
|
+
} else if (key.startsWith('sk-')) {
|
|
140
|
+
config.set('openaiKey', key);
|
|
141
|
+
console.log(ui.success('OpenAI key saved'));
|
|
51
142
|
} else {
|
|
52
|
-
|
|
53
|
-
console.log(ui.success('Key saved.'));
|
|
143
|
+
console.log(ui.success('Key saved'));
|
|
54
144
|
}
|
|
55
145
|
} else {
|
|
56
|
-
console.log(ui.dim(' Skipped
|
|
146
|
+
console.log(ui.dim(' Skipped — free NVIDIA tier active (rate limited)'));
|
|
147
|
+
console.log(ui.dim(' Unlock full access: /register or /login <key>'));
|
|
57
148
|
}
|
|
58
149
|
console.log('');
|
|
59
150
|
|
|
60
|
-
// 2.
|
|
61
|
-
|
|
62
|
-
|
|
151
|
+
// Step 2: Soul.md
|
|
152
|
+
console.log(ui.dim(' STEP 2 — soul.md (your identity)'));
|
|
153
|
+
console.log(ui.dim(' The agent reads this to understand who you are.'));
|
|
63
154
|
console.log('');
|
|
64
155
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const createAgent = await ask(rl, ' Create agent.md for custom AI personality? (Y/n): ');
|
|
69
|
-
if (createAgent.trim().toLowerCase() !== 'n') {
|
|
70
|
-
if (!fs.existsSync(config.CONFIG_DIR)) fs.mkdirSync(config.CONFIG_DIR, { recursive: true });
|
|
71
|
-
fs.writeFileSync(agentMd, `# My NAVADA Agent
|
|
72
|
-
|
|
73
|
-
## About Me
|
|
74
|
-
<!-- Tell the agent who you are and what you work on -->
|
|
75
|
-
I am a developer working on...
|
|
76
|
-
|
|
77
|
-
## Preferences
|
|
78
|
-
<!-- How should the agent behave? -->
|
|
79
|
-
- Be concise and technical
|
|
80
|
-
- Always explain before making changes
|
|
81
|
-
- Prefer TypeScript for new code
|
|
82
|
-
|
|
83
|
-
## My Stack
|
|
84
|
-
<!-- What tools and tech do you use? -->
|
|
85
|
-
- ...
|
|
86
|
-
`);
|
|
87
|
-
console.log(ui.success('Created ~/.navada/agent.md'));
|
|
88
|
-
console.log(ui.dim(' Edit this file to personalise your agent.'));
|
|
89
|
-
}
|
|
156
|
+
const soulPath = path.join(config.CONFIG_DIR, 'soul.md');
|
|
157
|
+
if (fs.existsSync(soulPath)) {
|
|
158
|
+
console.log(ui.dim(' soul.md already exists — keeping current version'));
|
|
90
159
|
} else {
|
|
91
|
-
|
|
160
|
+
const name = await ask(rl, ' Your name: ');
|
|
161
|
+
const role = await ask(rl, ' Your role (e.g. developer, marketer, founder): ');
|
|
162
|
+
const goals = await ask(rl, ' What do you want to automate? ');
|
|
163
|
+
|
|
164
|
+
let soul = SOUL_TEMPLATE;
|
|
165
|
+
if (name.trim()) soul = soul.replace('name: ""', `name: "${name.trim()}"`);
|
|
166
|
+
if (role.trim()) soul = soul.replace('role: ""', `role: "${role.trim()}"`);
|
|
167
|
+
if (goals.trim()) soul = soul.replace('- What do you want to achieve with NAVADA Edge?', `- ${goals.trim()}`);
|
|
168
|
+
|
|
169
|
+
if (!fs.existsSync(config.CONFIG_DIR)) fs.mkdirSync(config.CONFIG_DIR, { recursive: true });
|
|
170
|
+
fs.writeFileSync(soulPath, soul);
|
|
171
|
+
console.log(ui.success('Created ~/.navada/soul.md'));
|
|
92
172
|
}
|
|
93
173
|
console.log('');
|
|
94
174
|
|
|
95
|
-
//
|
|
96
|
-
console.log(ui.dim('
|
|
97
|
-
|
|
175
|
+
// Step 3: Guardrails
|
|
176
|
+
console.log(ui.dim(' STEP 3 — guardrail.md (safety boundaries)'));
|
|
177
|
+
const guardrailPath = path.join(config.CONFIG_DIR, 'guardrail.md');
|
|
178
|
+
if (fs.existsSync(guardrailPath)) {
|
|
179
|
+
console.log(ui.dim(' guardrail.md already exists — keeping current version'));
|
|
180
|
+
} else {
|
|
181
|
+
const strictMode = await ask(rl, ' Strict mode? Confirms before file changes (y/N): ');
|
|
182
|
+
let guardrail = GUARDRAIL_TEMPLATE;
|
|
183
|
+
if (strictMode.trim().toLowerCase() === 'y') {
|
|
184
|
+
guardrail = guardrail.replace('confirm_before_overwrite: true', 'confirm_before_overwrite: true');
|
|
185
|
+
guardrail = guardrail.replace('allow_file_delete: false', 'allow_file_delete: false');
|
|
186
|
+
} else {
|
|
187
|
+
guardrail = guardrail.replace('confirm_before_delete: true', 'confirm_before_delete: false');
|
|
188
|
+
guardrail = guardrail.replace('confirm_before_overwrite: true', 'confirm_before_overwrite: false');
|
|
189
|
+
}
|
|
190
|
+
fs.writeFileSync(guardrailPath, guardrail);
|
|
191
|
+
console.log(ui.success('Created ~/.navada/guardrail.md'));
|
|
192
|
+
}
|
|
193
|
+
console.log('');
|
|
194
|
+
|
|
195
|
+
// Step 4: README
|
|
196
|
+
const readmePath = path.join(config.CONFIG_DIR, 'README.md');
|
|
197
|
+
if (!fs.existsSync(readmePath)) {
|
|
198
|
+
fs.writeFileSync(readmePath, README_TEMPLATE);
|
|
199
|
+
console.log(ui.success('Created ~/.navada/README.md'));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Step 5: Agents directory
|
|
203
|
+
const agentDir = path.join(config.CONFIG_DIR, 'agents');
|
|
204
|
+
if (!fs.existsSync(agentDir)) fs.mkdirSync(agentDir, { recursive: true });
|
|
205
|
+
|
|
206
|
+
// Step 6: Memory directory
|
|
207
|
+
const memDir = path.join(config.CONFIG_DIR, 'memory');
|
|
208
|
+
if (!fs.existsSync(memDir)) fs.mkdirSync(memDir, { recursive: true });
|
|
209
|
+
|
|
210
|
+
// Step 7: Requests directory
|
|
211
|
+
const reqDir = path.join(config.CONFIG_DIR, 'requests');
|
|
212
|
+
if (!fs.existsSync(reqDir)) fs.mkdirSync(reqDir, { recursive: true });
|
|
213
|
+
|
|
214
|
+
// Step 8: Skills directory + install default skill
|
|
215
|
+
const skillsDir = path.join(config.CONFIG_DIR, 'skills');
|
|
216
|
+
if (!fs.existsSync(skillsDir)) fs.mkdirSync(skillsDir, { recursive: true });
|
|
217
|
+
|
|
218
|
+
// Offer to install template skills
|
|
219
|
+
const installSkills = await ask(rl, ' Install starter skills? (Y/n): ');
|
|
220
|
+
if (installSkills.trim().toLowerCase() !== 'n') {
|
|
221
|
+
const skills = require('../skills');
|
|
222
|
+
let installed = 0;
|
|
223
|
+
for (const [name, tmpl] of Object.entries(skills.TEMPLATES)) {
|
|
224
|
+
const skillFile = path.join(skillsDir, `${name}.md`);
|
|
225
|
+
if (!fs.existsSync(skillFile)) {
|
|
226
|
+
skills.createSkill(name, tmpl);
|
|
227
|
+
installed++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (installed > 0) {
|
|
231
|
+
console.log(ui.success(`Installed ${installed} starter skills`));
|
|
232
|
+
console.log(ui.dim(' View: /skill list | Create your own: /skill create'));
|
|
233
|
+
} else {
|
|
234
|
+
console.log(ui.dim(' All template skills already installed'));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
console.log('');
|
|
238
|
+
|
|
239
|
+
// Step 9: Theme
|
|
240
|
+
const theme = await ask(rl, ' Theme (dark/crow/matrix/light) [dark]: ');
|
|
241
|
+
config.setTheme(theme.trim() || 'dark');
|
|
98
242
|
console.log('');
|
|
99
243
|
|
|
100
244
|
// Done
|
|
101
|
-
|
|
102
|
-
|
|
245
|
+
console.log(ui.box('READY', ` Config: ${config.CONFIG_FILE}
|
|
246
|
+
Soul: ${soulPath}
|
|
247
|
+
Guard: ${guardrailPath}
|
|
248
|
+
|
|
249
|
+
Type naturally to chat, or /help for commands.
|
|
250
|
+
|
|
251
|
+
KEY COMMANDS
|
|
252
|
+
/tools — 16 agent tools across 7 categories
|
|
253
|
+
/skills — view and manage skills
|
|
254
|
+
/skill create — create your own reusable skills
|
|
255
|
+
/skill templates — install ready-made skills
|
|
256
|
+
/automate — submit automation requests
|
|
257
|
+
/about — learn about NAVADA Edge`));
|
|
103
258
|
console.log('');
|
|
104
259
|
|
|
105
260
|
rl.close();
|
|
106
261
|
}
|
|
107
262
|
|
|
108
263
|
module.exports = function(reg) {
|
|
109
|
-
reg('setup', 'Run setup wizard', async () => {
|
|
264
|
+
reg('setup', 'Run full setup wizard (soul.md + guardrails + config)', async () => {
|
|
110
265
|
await runSetup(true);
|
|
111
266
|
}, { category: 'SYSTEM' });
|
|
267
|
+
|
|
268
|
+
reg('soul', 'View or edit your soul.md', (args) => {
|
|
269
|
+
const soulPath = path.join(config.CONFIG_DIR, 'soul.md');
|
|
270
|
+
if (args[0] === 'edit') {
|
|
271
|
+
if (!fs.existsSync(soulPath)) {
|
|
272
|
+
fs.writeFileSync(soulPath, SOUL_TEMPLATE);
|
|
273
|
+
}
|
|
274
|
+
console.log(ui.header('SOUL.MD'));
|
|
275
|
+
console.log(ui.label('Path', soulPath));
|
|
276
|
+
console.log(ui.dim(' Edit this file to customise your agent\'s understanding of you.'));
|
|
277
|
+
console.log(ui.dim(' The agent reads it on every interaction.'));
|
|
278
|
+
// Try to open in editor
|
|
279
|
+
try {
|
|
280
|
+
const { exec } = require('child_process');
|
|
281
|
+
const editor = process.env.EDITOR || (process.platform === 'win32' ? 'notepad' : 'nano');
|
|
282
|
+
exec(`${editor} "${soulPath}"`);
|
|
283
|
+
console.log(ui.success(`Opening in ${editor}...`));
|
|
284
|
+
} catch {
|
|
285
|
+
console.log(ui.dim(` Open manually: ${soulPath}`));
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
if (!fs.existsSync(soulPath)) {
|
|
289
|
+
console.log(ui.dim('No soul.md yet. Run /setup to create one.'));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
console.log(ui.header('SOUL.MD'));
|
|
293
|
+
console.log(fs.readFileSync(soulPath, 'utf-8'));
|
|
294
|
+
}
|
|
295
|
+
}, { category: 'SYSTEM', subs: ['edit'] });
|
|
296
|
+
|
|
297
|
+
reg('guardrails', 'View or edit your guardrail.md', (args) => {
|
|
298
|
+
const guardrailPath = path.join(config.CONFIG_DIR, 'guardrail.md');
|
|
299
|
+
if (args[0] === 'edit') {
|
|
300
|
+
if (!fs.existsSync(guardrailPath)) {
|
|
301
|
+
fs.writeFileSync(guardrailPath, GUARDRAIL_TEMPLATE);
|
|
302
|
+
}
|
|
303
|
+
console.log(ui.header('GUARDRAIL.MD'));
|
|
304
|
+
console.log(ui.label('Path', guardrailPath));
|
|
305
|
+
try {
|
|
306
|
+
const { exec } = require('child_process');
|
|
307
|
+
const editor = process.env.EDITOR || (process.platform === 'win32' ? 'notepad' : 'nano');
|
|
308
|
+
exec(`${editor} "${guardrailPath}"`);
|
|
309
|
+
console.log(ui.success(`Opening in ${editor}...`));
|
|
310
|
+
} catch {
|
|
311
|
+
console.log(ui.dim(` Open manually: ${guardrailPath}`));
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
if (!fs.existsSync(guardrailPath)) {
|
|
315
|
+
console.log(ui.dim('No guardrail.md yet. Run /setup to create one.'));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
console.log(ui.header('GUARDRAIL.MD'));
|
|
319
|
+
console.log(fs.readFileSync(guardrailPath, 'utf-8'));
|
|
320
|
+
}
|
|
321
|
+
}, { category: 'SYSTEM', subs: ['edit'] });
|
|
112
322
|
};
|
|
113
323
|
|
|
114
324
|
module.exports.runSetup = runSetup;
|
|
325
|
+
module.exports.SOUL_TEMPLATE = SOUL_TEMPLATE;
|
|
326
|
+
module.exports.GUARDRAIL_TEMPLATE = GUARDRAIL_TEMPLATE;
|