nexus-mcp-agent 0.1.2
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/.env.example +56 -0
- package/README.md +74 -0
- package/dist/core/config.d.ts +46 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +68 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/logger.d.ts +7 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +54 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/registry.d.ts +21 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +52 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/server.d.ts +12 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +120 -0
- package/dist/core/server.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/agents/index.d.ts +18 -0
- package/dist/tools/agents/index.d.ts.map +1 -0
- package/dist/tools/agents/index.js +134 -0
- package/dist/tools/agents/index.js.map +1 -0
- package/dist/tools/automation/index.d.ts +4 -0
- package/dist/tools/automation/index.d.ts.map +1 -0
- package/dist/tools/automation/index.js +95 -0
- package/dist/tools/automation/index.js.map +1 -0
- package/dist/tools/filesystem/index.d.ts +4 -0
- package/dist/tools/filesystem/index.d.ts.map +1 -0
- package/dist/tools/filesystem/index.js +261 -0
- package/dist/tools/filesystem/index.js.map +1 -0
- package/dist/tools/git/index.d.ts +4 -0
- package/dist/tools/git/index.d.ts.map +1 -0
- package/dist/tools/git/index.js +177 -0
- package/dist/tools/git/index.js.map +1 -0
- package/dist/tools/memory/index.d.ts +4 -0
- package/dist/tools/memory/index.d.ts.map +1 -0
- package/dist/tools/memory/index.js +178 -0
- package/dist/tools/memory/index.js.map +1 -0
- package/dist/tools/system/index.d.ts +4 -0
- package/dist/tools/system/index.d.ts.map +1 -0
- package/dist/tools/system/index.js +121 -0
- package/dist/tools/system/index.js.map +1 -0
- package/dist/tools/terminal/index.d.ts +4 -0
- package/dist/tools/terminal/index.d.ts.map +1 -0
- package/dist/tools/terminal/index.js +86 -0
- package/dist/tools/terminal/index.js.map +1 -0
- package/dist/tools/web/index.d.ts +4 -0
- package/dist/tools/web/index.d.ts.map +1 -0
- package/dist/tools/web/index.js +193 -0
- package/dist/tools/web/index.js.map +1 -0
- package/docs/SECURITY.md +31 -0
- package/mcp-config.json +9 -0
- package/package.json +65 -0
- package/scripts/setup.js +102 -0
- package/src/core/config.ts +138 -0
- package/src/core/logger.ts +61 -0
- package/src/core/registry.ts +72 -0
- package/src/core/server.ts +144 -0
- package/src/index.ts +46 -0
- package/src/tools/agents/index.ts +172 -0
- package/src/tools/automation/index.ts +127 -0
- package/src/tools/filesystem/index.ts +303 -0
- package/src/tools/git/index.ts +201 -0
- package/src/tools/memory/index.ts +204 -0
- package/src/tools/system/index.ts +140 -0
- package/src/tools/terminal/index.ts +105 -0
- package/src/tools/web/index.ts +224 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/web/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAwLtD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAmChF"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import * as cheerio from 'cheerio';
|
|
4
|
+
import { createContextLogger } from '../../core/logger.js';
|
|
5
|
+
import { nexusConfig } from '../../core/config.js';
|
|
6
|
+
const log = createContextLogger('tools/web');
|
|
7
|
+
const WebSearchSchema = z.object({
|
|
8
|
+
query: z.string().describe('Search query'),
|
|
9
|
+
maxResults: z.number().optional().default(10).describe('Maximum number of results'),
|
|
10
|
+
});
|
|
11
|
+
const WebBrowseSchema = z.object({
|
|
12
|
+
url: z.string().describe('URL to browse'),
|
|
13
|
+
actions: z.string().optional().describe('JavaScript code to execute on the page'),
|
|
14
|
+
waitFor: z.number().optional().default(2000).describe('Time to wait after page load (ms)'),
|
|
15
|
+
});
|
|
16
|
+
const WebScrapeSchema = z.object({
|
|
17
|
+
url: z.string().describe('URL to scrape'),
|
|
18
|
+
selector: z.string().optional().describe('CSS selector to extract specific content'),
|
|
19
|
+
});
|
|
20
|
+
const ApiCallSchema = z.object({
|
|
21
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP method'),
|
|
22
|
+
url: z.string().describe('API endpoint URL'),
|
|
23
|
+
headers: z.record(z.string()).optional().describe('HTTP headers'),
|
|
24
|
+
body: z.any().optional().describe('Request body'),
|
|
25
|
+
});
|
|
26
|
+
async function webSearch(params) {
|
|
27
|
+
const { query, maxResults = 10 } = params;
|
|
28
|
+
log.info(`Web search: "${query}"`);
|
|
29
|
+
if (nexusConfig.search.braveApiKey) {
|
|
30
|
+
try {
|
|
31
|
+
const response = await axios.get('https://api.search.brave.com/res/v1/web/search', {
|
|
32
|
+
params: { q: query, count: maxResults },
|
|
33
|
+
headers: { 'X-Subscription-Token': nexusConfig.search.braveApiKey },
|
|
34
|
+
timeout: 15000,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
success: true,
|
|
38
|
+
provider: 'brave',
|
|
39
|
+
results: response.data.web?.results?.map((r) => ({
|
|
40
|
+
title: r.title,
|
|
41
|
+
url: r.url,
|
|
42
|
+
snippet: r.description,
|
|
43
|
+
})) || [],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
log.warn('Brave search failed, falling back to DuckDuckGo');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const response = await axios.get('https://html.duckduckgo.com/html/', {
|
|
52
|
+
params: { q: query },
|
|
53
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' },
|
|
54
|
+
timeout: 15000,
|
|
55
|
+
});
|
|
56
|
+
const $ = cheerio.load(response.data);
|
|
57
|
+
const results = [];
|
|
58
|
+
$('.result').slice(0, maxResults).each((_, el) => {
|
|
59
|
+
const title = $(el).find('.result__title a').text().trim();
|
|
60
|
+
const url = $(el).find('.result__url').text().trim();
|
|
61
|
+
const snippet = $(el).find('.result__snippet').text().trim();
|
|
62
|
+
if (title && url) {
|
|
63
|
+
results.push({ title, url: url.startsWith('http') ? url : `https://${url}`, snippet });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return { success: true, provider: 'duckduckgo', results };
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return { success: false, error: error.message };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function webBrowse(params) {
|
|
73
|
+
const { url, actions, waitFor = 2000 } = params;
|
|
74
|
+
log.info(`Browsing: ${url}`);
|
|
75
|
+
try {
|
|
76
|
+
const { chromium } = await import('playwright');
|
|
77
|
+
const browser = await chromium.launch({ headless: nexusConfig.browser.headless });
|
|
78
|
+
const page = await browser.newPage();
|
|
79
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: nexusConfig.browser.timeout });
|
|
80
|
+
if (waitFor > 0)
|
|
81
|
+
await page.waitForTimeout(waitFor);
|
|
82
|
+
if (actions) {
|
|
83
|
+
try {
|
|
84
|
+
const actionFn = new Function('page', actions);
|
|
85
|
+
await actionFn(page);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
log.warn(`Action execution failed: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const title = await page.title();
|
|
92
|
+
const content = await page.content();
|
|
93
|
+
const text = await page.evaluate(`document.body?.innerText || ''`);
|
|
94
|
+
const snapshot = await page.accessibility.snapshot();
|
|
95
|
+
await browser.close();
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
url,
|
|
99
|
+
title,
|
|
100
|
+
text: text.slice(0, 50000),
|
|
101
|
+
accessibilityTree: snapshot,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return { success: false, error: error.message };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function webScrape(params) {
|
|
109
|
+
const { url, selector } = params;
|
|
110
|
+
log.info(`Scraping: ${url}`);
|
|
111
|
+
try {
|
|
112
|
+
const response = await axios.get(url, {
|
|
113
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' },
|
|
114
|
+
timeout: 15000,
|
|
115
|
+
});
|
|
116
|
+
const $ = cheerio.load(response.data);
|
|
117
|
+
$('script, style, nav, footer, header').remove();
|
|
118
|
+
let content = '';
|
|
119
|
+
if (selector) {
|
|
120
|
+
content = $(selector).text();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
content = $('body').text();
|
|
124
|
+
}
|
|
125
|
+
content = content.replace(/\s+/g, ' ').trim();
|
|
126
|
+
return {
|
|
127
|
+
success: true,
|
|
128
|
+
url,
|
|
129
|
+
content: content.slice(0, 100000),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return { success: false, error: error.message };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function apiCall(params) {
|
|
137
|
+
const { method, url, headers, body } = params;
|
|
138
|
+
log.info(`API call: ${method} ${url}`);
|
|
139
|
+
try {
|
|
140
|
+
const response = await axios({
|
|
141
|
+
method: method,
|
|
142
|
+
url,
|
|
143
|
+
headers,
|
|
144
|
+
data: body,
|
|
145
|
+
timeout: 30000,
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
success: true,
|
|
149
|
+
status: response.status,
|
|
150
|
+
headers: response.headers,
|
|
151
|
+
data: response.data,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
status: error.response?.status,
|
|
158
|
+
error: error.message,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export function registerWebTools(server, registry) {
|
|
163
|
+
server.registerTool('web_search', {
|
|
164
|
+
description: 'Search the web for information',
|
|
165
|
+
inputSchema: WebSearchSchema,
|
|
166
|
+
}, async (params) => ({
|
|
167
|
+
content: [{ type: 'text', text: JSON.stringify(await webSearch(params), null, 2) }],
|
|
168
|
+
}));
|
|
169
|
+
server.registerTool('web_browse', {
|
|
170
|
+
description: 'Browse a webpage with Playwright and extract content',
|
|
171
|
+
inputSchema: WebBrowseSchema,
|
|
172
|
+
}, async (params) => ({
|
|
173
|
+
content: [{ type: 'text', text: JSON.stringify(await webBrowse(params), null, 2) }],
|
|
174
|
+
}));
|
|
175
|
+
server.registerTool('web_scrape', {
|
|
176
|
+
description: 'Scrape content from a webpage',
|
|
177
|
+
inputSchema: WebScrapeSchema,
|
|
178
|
+
}, async (params) => ({
|
|
179
|
+
content: [{ type: 'text', text: JSON.stringify(await webScrape(params), null, 2) }],
|
|
180
|
+
}));
|
|
181
|
+
server.registerTool('api_call', {
|
|
182
|
+
description: 'Make HTTP API calls (REST/GraphQL)',
|
|
183
|
+
inputSchema: ApiCallSchema,
|
|
184
|
+
}, async (params) => ({
|
|
185
|
+
content: [{ type: 'text', text: JSON.stringify(await apiCall(params), null, 2) }],
|
|
186
|
+
}));
|
|
187
|
+
registry.register({ name: 'web_search', category: 'web', description: 'Search the web', handler: webSearch });
|
|
188
|
+
registry.register({ name: 'web_browse', category: 'web', description: 'Browse webpage', handler: webBrowse });
|
|
189
|
+
registry.register({ name: 'web_scrape', category: 'web', description: 'Scrape webpage', handler: webScrape });
|
|
190
|
+
registry.register({ name: 'api_call', category: 'web', description: 'HTTP API call', handler: apiCall });
|
|
191
|
+
log.info('Registered 4 web tools');
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/web/index.ts"],"names":[],"mappings":"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"}
|
package/docs/SECURITY.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 🔒 Security Policy
|
|
2
|
+
|
|
3
|
+
NEXUS is an autonomous AI agent with broad system access. Security is paramount.
|
|
4
|
+
|
|
5
|
+
## Security Layers
|
|
6
|
+
|
|
7
|
+
### 1. Path Restrictions
|
|
8
|
+
All file operations are restricted to `ALLOWED_DIRS`.
|
|
9
|
+
|
|
10
|
+
### 2. Command Blocking
|
|
11
|
+
Dangerous commands blocked: `rm -rf /`, `format`, `mkfs`, etc.
|
|
12
|
+
|
|
13
|
+
### 3. Audit Logging
|
|
14
|
+
Sensitive ops logged to `logs/audit.log`.
|
|
15
|
+
|
|
16
|
+
### 4. Confirmation for Destructive Actions
|
|
17
|
+
Marked tools can require confirmation.
|
|
18
|
+
|
|
19
|
+
### 5. Network Isolation
|
|
20
|
+
Web operations respect system proxy settings.
|
|
21
|
+
|
|
22
|
+
## Best Practices
|
|
23
|
+
|
|
24
|
+
1. Start with narrow `ALLOWED_DIRS`
|
|
25
|
+
2. Monitor `logs/audit.log`
|
|
26
|
+
3. Store API keys in `.env` (never commit)
|
|
27
|
+
4. Run in isolated environment
|
|
28
|
+
5. Limit network access with firewalls
|
|
29
|
+
|
|
30
|
+
## Disclaimer
|
|
31
|
+
NEXUS is provided as-is. User is responsible for securing API keys, configuring permissions, and monitoring activity.
|
package/mcp-config.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nexus-mcp-agent",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Autonomous AI Agent MCP Server — no API keys required, works out of the box",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nexus": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsx watch src/index.ts",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js",
|
|
15
|
+
"test": "vitest",
|
|
16
|
+
"lint": "eslint src --ext .ts",
|
|
17
|
+
"setup": "node scripts/setup.js",
|
|
18
|
+
"chroma": "docker run -p 8000:8000 chromadb/chroma",
|
|
19
|
+
"clean": "rmdir /s /q node_modules && del package-lock.json"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"ai-agent",
|
|
24
|
+
"autonomous",
|
|
25
|
+
"claude",
|
|
26
|
+
"anthropic"
|
|
27
|
+
],
|
|
28
|
+
"author": "Qwen AI (self-built)",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
32
|
+
"playwright": "^1.49.0",
|
|
33
|
+
"sql.js": "^1.11.0",
|
|
34
|
+
"zod": "^3.23.8",
|
|
35
|
+
"zod-to-json-schema": "^3.23.5",
|
|
36
|
+
"node-cron": "^3.0.3",
|
|
37
|
+
"chokidar": "^4.0.1",
|
|
38
|
+
"chromadb": "^1.9.2",
|
|
39
|
+
"chromadb-default-embed": "^2.13.2",
|
|
40
|
+
"axios": "^1.7.9",
|
|
41
|
+
"cheerio": "^1.0.0",
|
|
42
|
+
"simple-git": "^3.27.0",
|
|
43
|
+
"dotenv": "^16.4.5",
|
|
44
|
+
"pino": "^9.5.0",
|
|
45
|
+
"pino-pretty": "^13.0.0",
|
|
46
|
+
"execa": "^9.5.2",
|
|
47
|
+
"openai": "^4.73.1",
|
|
48
|
+
"@anthropic-ai/sdk": "^0.32.1",
|
|
49
|
+
"uuid": "^11.0.3",
|
|
50
|
+
"glob": "^11.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^22.9.3",
|
|
54
|
+
"@types/node-cron": "^3.0.11",
|
|
55
|
+
"@types/uuid": "^10.0.0",
|
|
56
|
+
"@types/sql.js": "^1.4.9",
|
|
57
|
+
"tsx": "^4.19.2",
|
|
58
|
+
"typescript": "^5.7.2",
|
|
59
|
+
"vitest": "^2.1.5",
|
|
60
|
+
"eslint": "^9.15.0"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=20.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/scripts/setup.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, copyFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { resolve, dirname } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const rootDir = resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
console.log('NEXUS - Autonomous AI Agent Ecosystem');
|
|
13
|
+
console.log('========================================\n');
|
|
14
|
+
|
|
15
|
+
console.log('Creating directories...');
|
|
16
|
+
const dirs = ['data', 'logs', 'workspace', 'skills', 'data/memory'];
|
|
17
|
+
dirs.forEach(dir => {
|
|
18
|
+
const fullPath = resolve(rootDir, dir);
|
|
19
|
+
if (!existsSync(fullPath)) {
|
|
20
|
+
mkdirSync(fullPath, { recursive: true });
|
|
21
|
+
console.log(` Created: ${dir}`);
|
|
22
|
+
} else {
|
|
23
|
+
console.log(` Exists: ${dir}`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log('\nSetting up environment...');
|
|
28
|
+
const envExample = resolve(rootDir, '.env.example');
|
|
29
|
+
const envFile = resolve(rootDir, '.env');
|
|
30
|
+
|
|
31
|
+
if (!existsSync(envFile) && existsSync(envExample)) {
|
|
32
|
+
copyFileSync(envExample, envFile);
|
|
33
|
+
console.log(' Created .env from .env.example');
|
|
34
|
+
console.log(' Please edit .env to add your API keys');
|
|
35
|
+
} else if (existsSync(envFile)) {
|
|
36
|
+
console.log(' .env already exists');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log('\nChecking Node.js version...');
|
|
40
|
+
const nodeVersion = process.versions.node;
|
|
41
|
+
const [major] = nodeVersion.split('.').map(Number);
|
|
42
|
+
if (major < 20) {
|
|
43
|
+
console.log(` Node.js ${nodeVersion} detected - requires 20+`);
|
|
44
|
+
console.log(' Please upgrade Node.js: https://nodejs.org/');
|
|
45
|
+
} else {
|
|
46
|
+
console.log(` Node.js ${nodeVersion}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log('\nChecking npm...');
|
|
50
|
+
try {
|
|
51
|
+
const npmVersion = execSync('npm --version', { encoding: 'utf-8' }).trim();
|
|
52
|
+
console.log(` npm ${npmVersion}`);
|
|
53
|
+
} catch {
|
|
54
|
+
console.log(' npm not found');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('\nChecking Docker (optional)...');
|
|
58
|
+
try {
|
|
59
|
+
const dockerVersion = execSync('docker --version', { encoding: 'utf-8' }).trim();
|
|
60
|
+
console.log(` ${dockerVersion}`);
|
|
61
|
+
console.log(' Run: docker run -d -p 8000:8000 chromadb/chroma');
|
|
62
|
+
} catch {
|
|
63
|
+
console.log(' Docker not found - memory will use in-memory fallback');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log('\nInitializing state database...');
|
|
67
|
+
const dbPath = resolve(rootDir, 'data', 'state.sqlite');
|
|
68
|
+
if (!existsSync(dbPath)) {
|
|
69
|
+
console.log(' state.sqlite will be created on first run');
|
|
70
|
+
} else {
|
|
71
|
+
console.log(' state.sqlite already exists');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log('\nCreating workspace welcome file...');
|
|
75
|
+
const welcomePath = resolve(rootDir, 'workspace', 'WELCOME.md');
|
|
76
|
+
if (!existsSync(welcomePath)) {
|
|
77
|
+
writeFileSync(welcomePath, `# Welcome to NEXUS Workspace
|
|
78
|
+
|
|
79
|
+
This is your autonomous AI workspace. NEXUS can read, write, and manage files here.
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
- Use \`fs_read\` to read files
|
|
83
|
+
- Use \`fs_write\` to create/edit files
|
|
84
|
+
- Use \`web_search\` to search the web
|
|
85
|
+
- Use \`memory_store\` to save information for later
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
Edit \`.env\` in the NEXUS root to configure API keys and settings.
|
|
89
|
+
|
|
90
|
+
## Documentation
|
|
91
|
+
See [README.md](../README.md) for full documentation.
|
|
92
|
+
`);
|
|
93
|
+
console.log(' Created workspace/WELCOME.md');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log('\nSetup complete!\n');
|
|
97
|
+
console.log('Next steps:');
|
|
98
|
+
console.log(' 1. Edit .env to add your API keys (OPENAI_API_KEY, etc.)');
|
|
99
|
+
console.log(' 2. Run: npm install');
|
|
100
|
+
console.log(' 3. Run: npm run build');
|
|
101
|
+
console.log(' 4. Run: npm start');
|
|
102
|
+
console.log(' 5. Add to Claude Desktop config: mcp-config.json\n');
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
|
|
5
|
+
// Load .env file
|
|
6
|
+
const envPath = process.env.NEXUS_CONFIG || resolve(process.cwd(), '.env');
|
|
7
|
+
if (existsSync(envPath)) {
|
|
8
|
+
config({ path: envPath });
|
|
9
|
+
} else {
|
|
10
|
+
config();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface NexusConfig {
|
|
14
|
+
// LLM
|
|
15
|
+
llm: {
|
|
16
|
+
provider: 'openai' | 'anthropic' | 'ollama';
|
|
17
|
+
model: string;
|
|
18
|
+
openaiApiKey?: string;
|
|
19
|
+
anthropicApiKey?: string;
|
|
20
|
+
ollamaUrl: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Web Search
|
|
24
|
+
search: {
|
|
25
|
+
provider: 'brave' | 'google' | 'duckduckgo';
|
|
26
|
+
braveApiKey?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Vector DB
|
|
30
|
+
vector: {
|
|
31
|
+
type: 'chroma-local' | 'chroma-remote' | 'sqlite-vss';
|
|
32
|
+
chromaUrl: string;
|
|
33
|
+
collection: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// State DB
|
|
37
|
+
state: {
|
|
38
|
+
dbPath: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Directories
|
|
42
|
+
paths: {
|
|
43
|
+
workspace: string;
|
|
44
|
+
data: string;
|
|
45
|
+
logs: string;
|
|
46
|
+
skills: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Security
|
|
50
|
+
security: {
|
|
51
|
+
allowedDirs: string[];
|
|
52
|
+
blockedCommands: string[];
|
|
53
|
+
auditLogEnabled: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Automation
|
|
57
|
+
automation: {
|
|
58
|
+
cronEnabled: boolean;
|
|
59
|
+
watcherEnabled: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Logging
|
|
63
|
+
logging: {
|
|
64
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Browser
|
|
68
|
+
browser: {
|
|
69
|
+
headless: boolean;
|
|
70
|
+
timeout: number;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseBool(val: string | undefined, defaultVal: boolean): boolean {
|
|
75
|
+
if (!val) return defaultVal;
|
|
76
|
+
return val.toLowerCase() === 'true' || val === '1';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseList(val: string | undefined): string[] {
|
|
80
|
+
if (!val) return [];
|
|
81
|
+
return val.split(',').map(s => s.trim()).filter(Boolean);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const nexusConfig: NexusConfig = {
|
|
85
|
+
llm: {
|
|
86
|
+
provider: (process.env.DEFAULT_LLM_PROVIDER as any) || 'openai',
|
|
87
|
+
model: process.env.DEFAULT_LLM_MODEL || 'gpt-4o',
|
|
88
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
89
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
90
|
+
ollamaUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
search: {
|
|
94
|
+
provider: (process.env.DEFAULT_SEARCH_PROVIDER as any) || 'duckduckgo',
|
|
95
|
+
braveApiKey: process.env.BRAVE_SEARCH_API_KEY,
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
vector: {
|
|
99
|
+
type: (process.env.VECTOR_DB as any) || 'chroma-local',
|
|
100
|
+
chromaUrl: process.env.CHROMA_URL || 'http://localhost:8000',
|
|
101
|
+
collection: process.env.CHROMA_COLLECTION || 'nexus_memory',
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
state: {
|
|
105
|
+
dbPath: process.env.STATE_DB_PATH || './data/state.sqlite',
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
paths: {
|
|
109
|
+
workspace: process.env.WORKSPACE_DIR || './workspace',
|
|
110
|
+
data: process.env.DATA_DIR || './data',
|
|
111
|
+
logs: process.env.LOGS_DIR || './logs',
|
|
112
|
+
skills: process.env.SKILLS_DIR || './skills',
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
security: {
|
|
116
|
+
allowedDirs: parseList(process.env.ALLOWED_DIRS) || ['./workspace'],
|
|
117
|
+
blockedCommands: parseList(process.env.BLOCKED_COMMANDS) || ['rm -rf /'],
|
|
118
|
+
auditLogEnabled: parseBool(process.env.AUDIT_LOG_ENABLED, true),
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
automation: {
|
|
122
|
+
cronEnabled: parseBool(process.env.CRON_ENABLED, true),
|
|
123
|
+
watcherEnabled: parseBool(process.env.WATCHER_ENABLED, true),
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
logging: {
|
|
127
|
+
level: (process.env.LOG_LEVEL as any) || 'info',
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
browser: {
|
|
131
|
+
headless: parseBool(process.env.BROWSER_HEADLESS, true),
|
|
132
|
+
timeout: parseInt(process.env.BROWSER_TIMEOUT || '30000', 10),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export function validateConfig(): string[] {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { mkdirSync, existsSync } from 'fs';
|
|
4
|
+
import { nexusConfig } from './config.js';
|
|
5
|
+
|
|
6
|
+
// Ensure logs directory exists
|
|
7
|
+
const logsDir = resolve(nexusConfig.paths.logs);
|
|
8
|
+
if (!existsSync(logsDir)) {
|
|
9
|
+
mkdirSync(logsDir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const logFile = resolve(logsDir, `nexus-${new Date().toISOString().split('T')[0]}.log`);
|
|
13
|
+
|
|
14
|
+
// Create logger with both console and file transport
|
|
15
|
+
export const logger = pino({
|
|
16
|
+
level: nexusConfig.logging.level,
|
|
17
|
+
transport: {
|
|
18
|
+
targets: [
|
|
19
|
+
{
|
|
20
|
+
target: 'pino-pretty',
|
|
21
|
+
options: {
|
|
22
|
+
colorize: true,
|
|
23
|
+
translateTime: 'SYS:standard',
|
|
24
|
+
ignore: 'pid,hostname',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
target: 'pino/file',
|
|
29
|
+
options: {
|
|
30
|
+
destination: logFile,
|
|
31
|
+
mkdir: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export type Logger = typeof logger;
|
|
39
|
+
|
|
40
|
+
// Create child logger with context
|
|
41
|
+
export function createContextLogger(context: string): Logger {
|
|
42
|
+
return logger.child({ context });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Audit logger for security-sensitive operations
|
|
46
|
+
export const auditLogger = pino({
|
|
47
|
+
level: 'info',
|
|
48
|
+
transport: {
|
|
49
|
+
target: 'pino/file',
|
|
50
|
+
options: {
|
|
51
|
+
destination: resolve(logsDir, 'audit.log'),
|
|
52
|
+
mkdir: true,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export function logAudit(event: string, details: Record<string, any>): void {
|
|
58
|
+
if (nexusConfig.security.auditLogEnabled) {
|
|
59
|
+
auditLogger.info({ event, ...details, timestamp: new Date().toISOString() }, event);
|
|
60
|
+
}
|
|
61
|
+
}
|