@benzsiangco/jarvis 1.0.0 → 1.1.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 +5 -0
- package/bin/{jarvis.js → jarvis} +1 -1
- package/dist/cli.js +476 -350
- package/dist/electron/main.js +160 -0
- package/dist/electron/preload.js +19 -0
- package/package.json +21 -8
- package/skills.md +147 -0
- package/src/agents/index.ts +248 -0
- package/src/brain/loader.ts +136 -0
- package/src/cli.ts +411 -0
- package/src/config/index.ts +363 -0
- package/src/core/executor.ts +222 -0
- package/src/core/plugins.ts +148 -0
- package/src/core/types.ts +217 -0
- package/src/electron/main.ts +192 -0
- package/src/electron/preload.ts +25 -0
- package/src/electron/types.d.ts +20 -0
- package/src/index.ts +12 -0
- package/src/providers/antigravity-loader.ts +233 -0
- package/src/providers/antigravity.ts +585 -0
- package/src/providers/index.ts +523 -0
- package/src/sessions/index.ts +194 -0
- package/src/tools/index.ts +436 -0
- package/src/tui/index.tsx +784 -0
- package/src/utils/auth-prompt.ts +394 -0
- package/src/utils/index.ts +180 -0
- package/src/utils/native-picker.ts +71 -0
- package/src/utils/skills.ts +99 -0
- package/src/utils/table-integration-examples.ts +617 -0
- package/src/utils/table-utils.ts +401 -0
- package/src/web/build-ui.ts +27 -0
- package/src/web/server.ts +674 -0
- package/src/web/ui/dist/.gitkeep +0 -0
- package/src/web/ui/dist/main.css +1 -0
- package/src/web/ui/dist/main.js +320 -0
- package/src/web/ui/dist/main.js.map +20 -0
- package/src/web/ui/index.html +46 -0
- package/src/web/ui/src/App.tsx +143 -0
- package/src/web/ui/src/Modules/Safety/GuardianModal.tsx +83 -0
- package/src/web/ui/src/components/Layout/ContextPanel.tsx +243 -0
- package/src/web/ui/src/components/Layout/Header.tsx +91 -0
- package/src/web/ui/src/components/Layout/ModelSelector.tsx +235 -0
- package/src/web/ui/src/components/Layout/SessionStats.tsx +369 -0
- package/src/web/ui/src/components/Layout/Sidebar.tsx +895 -0
- package/src/web/ui/src/components/Modules/Chat/ChatStage.tsx +620 -0
- package/src/web/ui/src/components/Modules/Chat/MessageItem.tsx +446 -0
- package/src/web/ui/src/components/Modules/Editor/CommandInspector.tsx +71 -0
- package/src/web/ui/src/components/Modules/Editor/DiffViewer.tsx +83 -0
- package/src/web/ui/src/components/Modules/Terminal/TabbedTerminal.tsx +202 -0
- package/src/web/ui/src/components/Settings/SettingsModal.tsx +935 -0
- package/src/web/ui/src/config/models.ts +70 -0
- package/src/web/ui/src/main.tsx +13 -0
- package/src/web/ui/src/store/agentStore.ts +41 -0
- package/src/web/ui/src/store/uiStore.ts +64 -0
- package/src/web/ui/src/types/index.ts +54 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
let mainWindow = null;
|
|
8
|
+
let bunServer = null;
|
|
9
|
+
let serverPort = 5533;
|
|
10
|
+
/**
|
|
11
|
+
* Start Bun server in background
|
|
12
|
+
*/
|
|
13
|
+
async function startBunServer() {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
console.log('[Electron] Starting Bun server...');
|
|
16
|
+
// Find project root (go up from dist/electron/main.js to project root)
|
|
17
|
+
const projectRoot = path.join(__dirname, '..', '..');
|
|
18
|
+
const cliPath = path.join(projectRoot, 'src', 'cli.ts');
|
|
19
|
+
// Start Bun server
|
|
20
|
+
bunServer = spawn('bun', ['run', cliPath, 'web', '--port', String(serverPort)], {
|
|
21
|
+
cwd: projectRoot,
|
|
22
|
+
stdio: 'pipe'
|
|
23
|
+
});
|
|
24
|
+
bunServer.stdout?.on('data', (data) => {
|
|
25
|
+
const output = data.toString();
|
|
26
|
+
console.log('[Bun Server]', output);
|
|
27
|
+
// Look for server ready message
|
|
28
|
+
if (output.includes('Server running') || output.includes('localhost')) {
|
|
29
|
+
resolve(`http://localhost:${serverPort}`);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
bunServer.stderr?.on('data', (data) => {
|
|
33
|
+
console.error('[Bun Server Error]', data.toString());
|
|
34
|
+
});
|
|
35
|
+
bunServer.on('error', (error) => {
|
|
36
|
+
console.error('[Bun Server] Failed to start:', error);
|
|
37
|
+
reject(error);
|
|
38
|
+
});
|
|
39
|
+
// Timeout after 10 seconds
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
resolve(`http://localhost:${serverPort}`);
|
|
42
|
+
}, 3000);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create main Electron window
|
|
47
|
+
*/
|
|
48
|
+
async function createWindow() {
|
|
49
|
+
console.log('[Electron] Creating main window...');
|
|
50
|
+
// Start Bun server first
|
|
51
|
+
const serverUrl = await startBunServer();
|
|
52
|
+
console.log('[Electron] Server URL:', serverUrl);
|
|
53
|
+
// Create browser window
|
|
54
|
+
mainWindow = new BrowserWindow({
|
|
55
|
+
width: 1400,
|
|
56
|
+
height: 900,
|
|
57
|
+
minWidth: 1024,
|
|
58
|
+
minHeight: 768,
|
|
59
|
+
title: 'JARVIS - AI Coding Assistant',
|
|
60
|
+
backgroundColor: '#09090b', // zinc-950
|
|
61
|
+
autoHideMenuBar: true, // Hide menu bar but allow Alt to show it
|
|
62
|
+
webPreferences: {
|
|
63
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
64
|
+
contextIsolation: true,
|
|
65
|
+
nodeIntegration: false,
|
|
66
|
+
sandbox: false
|
|
67
|
+
},
|
|
68
|
+
show: false // Don't show until ready
|
|
69
|
+
});
|
|
70
|
+
// Show window when ready
|
|
71
|
+
mainWindow.once('ready-to-show', () => {
|
|
72
|
+
mainWindow?.show();
|
|
73
|
+
console.log('[Electron] Window ready');
|
|
74
|
+
});
|
|
75
|
+
// Load the Bun server URL
|
|
76
|
+
await mainWindow.loadURL(serverUrl);
|
|
77
|
+
// Open DevTools in development
|
|
78
|
+
if (process.env.NODE_ENV === 'development') {
|
|
79
|
+
mainWindow.webContents.openDevTools();
|
|
80
|
+
}
|
|
81
|
+
// Handle window closed
|
|
82
|
+
mainWindow.on('closed', () => {
|
|
83
|
+
mainWindow = null;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Setup IPC handlers
|
|
88
|
+
*/
|
|
89
|
+
function setupIPC() {
|
|
90
|
+
// Handle folder selection
|
|
91
|
+
ipcMain.handle('select-folder', async () => {
|
|
92
|
+
const result = await dialog.showOpenDialog({
|
|
93
|
+
properties: ['openDirectory'],
|
|
94
|
+
title: 'Select Workspace Folder'
|
|
95
|
+
});
|
|
96
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return result.filePaths[0];
|
|
100
|
+
});
|
|
101
|
+
// Handle file selection
|
|
102
|
+
ipcMain.handle('select-files', async () => {
|
|
103
|
+
const result = await dialog.showOpenDialog({
|
|
104
|
+
properties: ['openFile', 'multiSelections'],
|
|
105
|
+
title: 'Select Files'
|
|
106
|
+
});
|
|
107
|
+
if (result.canceled) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
return result.filePaths;
|
|
111
|
+
});
|
|
112
|
+
// Get app version
|
|
113
|
+
ipcMain.handle('get-app-version', () => {
|
|
114
|
+
return app.getVersion();
|
|
115
|
+
});
|
|
116
|
+
// Get app mode
|
|
117
|
+
ipcMain.handle('get-app-mode', () => {
|
|
118
|
+
return 'electron';
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Cleanup on app quit
|
|
123
|
+
*/
|
|
124
|
+
function cleanup() {
|
|
125
|
+
console.log('[Electron] Cleaning up...');
|
|
126
|
+
if (bunServer) {
|
|
127
|
+
console.log('[Electron] Stopping Bun server...');
|
|
128
|
+
bunServer.kill();
|
|
129
|
+
bunServer = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* App lifecycle
|
|
134
|
+
*/
|
|
135
|
+
app.whenReady().then(() => {
|
|
136
|
+
console.log('[Electron] App ready');
|
|
137
|
+
setupIPC();
|
|
138
|
+
createWindow();
|
|
139
|
+
// On macOS, re-create window when dock icon is clicked
|
|
140
|
+
app.on('activate', () => {
|
|
141
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
142
|
+
createWindow();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
// Quit when all windows are closed (except on macOS)
|
|
147
|
+
app.on('window-all-closed', () => {
|
|
148
|
+
if (process.platform !== 'darwin') {
|
|
149
|
+
cleanup();
|
|
150
|
+
app.quit();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
// Cleanup before quit
|
|
154
|
+
app.on('before-quit', () => {
|
|
155
|
+
cleanup();
|
|
156
|
+
});
|
|
157
|
+
// Handle uncaught errors
|
|
158
|
+
process.on('uncaughtException', (error) => {
|
|
159
|
+
console.error('[Electron] Uncaught exception:', error);
|
|
160
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
2
|
+
/**
|
|
3
|
+
* Electron Preload Script
|
|
4
|
+
* Bridges main process and renderer process securely
|
|
5
|
+
*/
|
|
6
|
+
// Expose safe APIs to renderer process
|
|
7
|
+
contextBridge.exposeInMainWorld('electron', {
|
|
8
|
+
// Folder selection
|
|
9
|
+
selectFolder: () => ipcRenderer.invoke('select-folder'),
|
|
10
|
+
// File selection
|
|
11
|
+
selectFiles: () => ipcRenderer.invoke('select-files'),
|
|
12
|
+
// App info
|
|
13
|
+
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
|
|
14
|
+
getAppMode: () => ipcRenderer.invoke('get-app-mode'),
|
|
15
|
+
// Environment detection
|
|
16
|
+
isElectron: true,
|
|
17
|
+
platform: process.platform
|
|
18
|
+
});
|
|
19
|
+
console.log('[Preload] Electron APIs exposed to renderer');
|
package/package.json
CHANGED
|
@@ -1,32 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benzsiangco/jarvis",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "AI coding agent with TUI, Web, and Desktop support",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "AI coding agent with TUI, Web, and Desktop support - Now with Brain system, OAuth config, and enhanced Skills",
|
|
5
5
|
"module": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"private": false,
|
|
8
8
|
"bin": {
|
|
9
|
-
"jarvis": "./bin/jarvis
|
|
9
|
+
"jarvis": "./bin/jarvis"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
-
"bin"
|
|
13
|
+
"bin",
|
|
14
|
+
"src",
|
|
15
|
+
"skills.md"
|
|
14
16
|
],
|
|
15
17
|
"scripts": {
|
|
16
18
|
"dev": "bun run src/cli.ts",
|
|
17
|
-
"build": "bun build src/cli.ts --outdir dist --target
|
|
19
|
+
"build": "bun build src/cli.ts --outdir dist --target bun --minify",
|
|
18
20
|
"prepublishOnly": "bun run build",
|
|
19
21
|
"start": "bun run dist/cli.js",
|
|
20
22
|
"typecheck": "tsc --noEmit",
|
|
21
23
|
"opentui": "bun run src/cli.ts tui",
|
|
22
24
|
"web": "bun run src/cli.ts web",
|
|
23
|
-
"web:build": "bun run src/web/build-ui.ts"
|
|
25
|
+
"web:build": "bun run src/web/build-ui.ts",
|
|
26
|
+
"electron:compile": "tsc src/electron/main.ts src/electron/preload.ts --outDir dist/electron --target es2020 --module esnext --moduleResolution bundler --esModuleInterop --skipLibCheck",
|
|
27
|
+
"electron:dev": "concurrently \"bun run web\" \"electron dist/electron/main.js\"",
|
|
28
|
+
"electron:build": "bun run web:build && bun run electron:compile && electron-builder",
|
|
29
|
+
"electron:start": "electron dist/electron/main.js"
|
|
24
30
|
},
|
|
31
|
+
"main": "dist/electron/main.js",
|
|
25
32
|
"devDependencies": {
|
|
26
33
|
"@types/bun": "latest",
|
|
27
34
|
"@types/marked-terminal": "^6.1.1",
|
|
28
35
|
"@types/node": "^22.10.0",
|
|
29
|
-
"@types/react": "19"
|
|
36
|
+
"@types/react": "19",
|
|
37
|
+
"concurrently": "^9.2.1",
|
|
38
|
+
"electron": "^40.0.0",
|
|
39
|
+
"electron-builder": "^26.4.0"
|
|
30
40
|
},
|
|
31
41
|
"peerDependencies": {
|
|
32
42
|
"typescript": "^5"
|
|
@@ -46,11 +56,13 @@
|
|
|
46
56
|
"commander": "^12.1.0",
|
|
47
57
|
"conf": "^13.0.0",
|
|
48
58
|
"figures": "^6.0.0",
|
|
59
|
+
"framer-motion": "^12.27.0",
|
|
49
60
|
"glob": "^11.0.0",
|
|
50
61
|
"hono": "^4.11.4",
|
|
51
62
|
"lucide-react": "^0.562.0",
|
|
52
63
|
"marked": "^15.0.0",
|
|
53
64
|
"marked-terminal": "^7.2.0",
|
|
65
|
+
"node-pty": "^1.1.0",
|
|
54
66
|
"open": "^11.0.0",
|
|
55
67
|
"opencode-antigravity-auth": "^1.3.0",
|
|
56
68
|
"ora": "^8.0.0",
|
|
@@ -63,7 +75,8 @@
|
|
|
63
75
|
"tailwind-merge": "^3.4.0",
|
|
64
76
|
"xterm": "^5.3.0",
|
|
65
77
|
"xterm-addon-fit": "^0.8.0",
|
|
66
|
-
"zod": "^3.23.0"
|
|
78
|
+
"zod": "^3.23.0",
|
|
79
|
+
"zustand": "^5.0.10"
|
|
67
80
|
},
|
|
68
81
|
"engines": {
|
|
69
82
|
"node": ">=20.0.0"
|
package/skills.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# JARVIS Skills Registry
|
|
2
|
+
|
|
3
|
+
This file contains modular skill modules that JARVIS can reference. Each skill adds specialized knowledge to specific domains.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## DevOps & Infrastructure
|
|
8
|
+
|
|
9
|
+
### Linux System Administration
|
|
10
|
+
- Expert in systemd, journalctl, process management
|
|
11
|
+
- Package management (apt, yum, pacman)
|
|
12
|
+
- Systemctl service management
|
|
13
|
+
- Log analysis and debugging
|
|
14
|
+
- Performance tuning and monitoring
|
|
15
|
+
|
|
16
|
+
### Docker & Containerization
|
|
17
|
+
- Dockerfile best practices and optimization
|
|
18
|
+
- Multi-stage builds for minimal images
|
|
19
|
+
- Docker Compose orchestration
|
|
20
|
+
- Volume management and networking
|
|
21
|
+
- Container security hardening
|
|
22
|
+
- Image layer optimization
|
|
23
|
+
|
|
24
|
+
### Proxmox Virtualization
|
|
25
|
+
- LXC container management (pct commands)
|
|
26
|
+
- VM operations (qm commands)
|
|
27
|
+
- Storage configuration (LVM, ZFS)
|
|
28
|
+
- Network bridge setup
|
|
29
|
+
- Backup and restore strategies
|
|
30
|
+
- Resource allocation and limits
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Security & Hacking
|
|
35
|
+
|
|
36
|
+
### Penetration Testing
|
|
37
|
+
- Reconnaissance and enumeration
|
|
38
|
+
- Vulnerability scanning (Nmap, Nikto, etc.)
|
|
39
|
+
- Web application testing (OWASP Top 10)
|
|
40
|
+
- Privilege escalation techniques
|
|
41
|
+
- Exploit development basics
|
|
42
|
+
- Post-exploitation strategies
|
|
43
|
+
|
|
44
|
+
### Network Security
|
|
45
|
+
- Firewall configuration (iptables, ufw, pf)
|
|
46
|
+
- VPN setup (WireGuard, OpenVPN)
|
|
47
|
+
- SSH hardening and key management
|
|
48
|
+
- TLS/SSL certificate management
|
|
49
|
+
- Network traffic analysis
|
|
50
|
+
- Intrusion detection systems
|
|
51
|
+
|
|
52
|
+
### Cloudflare Integration
|
|
53
|
+
- Cloudflare Tunnel (cloudflared) setup
|
|
54
|
+
- DNS management and configuration
|
|
55
|
+
- WAF rules and security policies
|
|
56
|
+
- Zero Trust Access configuration
|
|
57
|
+
- CDN optimization
|
|
58
|
+
- DDoS protection strategies
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Software Development
|
|
63
|
+
|
|
64
|
+
### TypeScript & JavaScript
|
|
65
|
+
- Modern ES6+ features
|
|
66
|
+
- TypeScript advanced types (generics, conditional types)
|
|
67
|
+
- Async/await patterns
|
|
68
|
+
- Module systems (ESM, CommonJS)
|
|
69
|
+
- Build tools (Bun, Vite, esbuild)
|
|
70
|
+
- Testing (Jest, Vitest, Playwright)
|
|
71
|
+
|
|
72
|
+
### Frontend Development
|
|
73
|
+
- React ecosystem (hooks, context, state management)
|
|
74
|
+
- Next.js (App Router, Server Components)
|
|
75
|
+
- TailwindCSS utility-first design
|
|
76
|
+
- Framer Motion animations
|
|
77
|
+
- Responsive design patterns
|
|
78
|
+
- Performance optimization
|
|
79
|
+
|
|
80
|
+
### Backend Development
|
|
81
|
+
- Hono web framework
|
|
82
|
+
- RESTful API design
|
|
83
|
+
- WebSocket real-time communication
|
|
84
|
+
- Database design (SQL, NoSQL)
|
|
85
|
+
- Authentication & authorization
|
|
86
|
+
- API security best practices
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Automation & Scripting
|
|
91
|
+
|
|
92
|
+
### SSH Automation
|
|
93
|
+
- SSH key-based authentication
|
|
94
|
+
- Remote command execution
|
|
95
|
+
- SCP/SFTP file transfers
|
|
96
|
+
- SSH tunneling and port forwarding
|
|
97
|
+
- ProxyJump configurations
|
|
98
|
+
- Batch operations on multiple servers
|
|
99
|
+
|
|
100
|
+
### CI/CD Pipelines
|
|
101
|
+
- GitHub Actions workflows
|
|
102
|
+
- GitLab CI/CD configuration
|
|
103
|
+
- Docker-based build pipelines
|
|
104
|
+
- Automated testing integration
|
|
105
|
+
- Deployment strategies (blue-green, canary)
|
|
106
|
+
- Rollback mechanisms
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Database Management
|
|
111
|
+
|
|
112
|
+
### PostgreSQL
|
|
113
|
+
- Schema design and normalization
|
|
114
|
+
- Query optimization and indexing
|
|
115
|
+
- JSONB operations
|
|
116
|
+
- Full-text search
|
|
117
|
+
- Replication and backup
|
|
118
|
+
- Performance tuning
|
|
119
|
+
|
|
120
|
+
### Redis
|
|
121
|
+
- Caching strategies
|
|
122
|
+
- Pub/Sub messaging
|
|
123
|
+
- Session management
|
|
124
|
+
- Rate limiting implementation
|
|
125
|
+
- Data structures (Lists, Sets, Hashes)
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Monitoring & Observability
|
|
130
|
+
|
|
131
|
+
### Logging Systems
|
|
132
|
+
- Structured logging best practices
|
|
133
|
+
- Log aggregation (ELK stack, Loki)
|
|
134
|
+
- Log rotation and retention
|
|
135
|
+
- Error tracking (Sentry integration)
|
|
136
|
+
- Correlation IDs for distributed systems
|
|
137
|
+
|
|
138
|
+
### Metrics & Alerts
|
|
139
|
+
- Prometheus metrics collection
|
|
140
|
+
- Grafana dashboard creation
|
|
141
|
+
- Alert rule configuration
|
|
142
|
+
- SLO/SLI definition
|
|
143
|
+
- Incident response procedures
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
_Add more skills as needed. Each skill module is automatically included when relevant to the conversation._
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// Agent system for Jarvis
|
|
2
|
+
import type { AgentConfig, AgentMode } from '../core/types';
|
|
3
|
+
|
|
4
|
+
// Built-in agent definitions
|
|
5
|
+
const builtinAgents: Record<string, AgentConfig> = {
|
|
6
|
+
build: {
|
|
7
|
+
id: 'build',
|
|
8
|
+
name: 'Jarvis',
|
|
9
|
+
description: 'A powerful AI coding assistant with full tool access for development work',
|
|
10
|
+
mode: 'primary',
|
|
11
|
+
tools: {
|
|
12
|
+
bash: true,
|
|
13
|
+
read: true,
|
|
14
|
+
write: true,
|
|
15
|
+
edit: true,
|
|
16
|
+
glob: true,
|
|
17
|
+
grep: true,
|
|
18
|
+
webfetch: true,
|
|
19
|
+
task: true,
|
|
20
|
+
todoread: true,
|
|
21
|
+
todowrite: true,
|
|
22
|
+
question: true,
|
|
23
|
+
},
|
|
24
|
+
permission: {
|
|
25
|
+
edit: 'allow',
|
|
26
|
+
bash: 'allow',
|
|
27
|
+
webfetch: 'allow',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
plan: {
|
|
31
|
+
id: 'plan',
|
|
32
|
+
name: 'Plan',
|
|
33
|
+
description: 'Restricted agent for planning and analysis without making changes',
|
|
34
|
+
mode: 'primary',
|
|
35
|
+
tools: {
|
|
36
|
+
bash: false,
|
|
37
|
+
read: true,
|
|
38
|
+
write: false,
|
|
39
|
+
edit: false,
|
|
40
|
+
glob: true,
|
|
41
|
+
grep: true,
|
|
42
|
+
webfetch: true,
|
|
43
|
+
task: true,
|
|
44
|
+
todoread: true,
|
|
45
|
+
todowrite: true,
|
|
46
|
+
question: true,
|
|
47
|
+
},
|
|
48
|
+
permission: {
|
|
49
|
+
edit: 'deny',
|
|
50
|
+
bash: 'ask',
|
|
51
|
+
webfetch: 'allow',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
general: {
|
|
55
|
+
id: 'general',
|
|
56
|
+
name: 'General',
|
|
57
|
+
description: 'General-purpose agent for researching complex questions and executing multi-step tasks',
|
|
58
|
+
mode: 'subagent',
|
|
59
|
+
tools: {
|
|
60
|
+
bash: true,
|
|
61
|
+
read: true,
|
|
62
|
+
write: true,
|
|
63
|
+
edit: true,
|
|
64
|
+
glob: true,
|
|
65
|
+
grep: true,
|
|
66
|
+
webfetch: true,
|
|
67
|
+
task: false, // Cannot spawn sub-subagents
|
|
68
|
+
todoread: true,
|
|
69
|
+
todowrite: true,
|
|
70
|
+
question: true,
|
|
71
|
+
},
|
|
72
|
+
permission: {
|
|
73
|
+
edit: 'allow',
|
|
74
|
+
bash: 'allow',
|
|
75
|
+
webfetch: 'allow',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
explore: {
|
|
79
|
+
id: 'explore',
|
|
80
|
+
name: 'Explore',
|
|
81
|
+
description: 'Fast agent specialized for exploring codebases. Use for finding files by patterns, searching code, or answering questions about the codebase.',
|
|
82
|
+
mode: 'subagent',
|
|
83
|
+
maxSteps: 10,
|
|
84
|
+
tools: {
|
|
85
|
+
bash: false,
|
|
86
|
+
read: true,
|
|
87
|
+
write: false,
|
|
88
|
+
edit: false,
|
|
89
|
+
glob: true,
|
|
90
|
+
grep: true,
|
|
91
|
+
webfetch: false,
|
|
92
|
+
task: false,
|
|
93
|
+
todoread: true,
|
|
94
|
+
todowrite: true,
|
|
95
|
+
question: false,
|
|
96
|
+
},
|
|
97
|
+
permission: {
|
|
98
|
+
edit: 'deny',
|
|
99
|
+
bash: 'deny',
|
|
100
|
+
webfetch: 'deny',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Agent registry
|
|
106
|
+
const agents = new Map<string, AgentConfig>();
|
|
107
|
+
|
|
108
|
+
// Initialize with built-in agents
|
|
109
|
+
export function initializeAgents(customAgents?: Record<string, Partial<AgentConfig>>): void {
|
|
110
|
+
agents.clear();
|
|
111
|
+
|
|
112
|
+
// Add built-in agents
|
|
113
|
+
for (const [id, agent] of Object.entries(builtinAgents)) {
|
|
114
|
+
agents.set(id, agent);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Merge with custom agents
|
|
118
|
+
if (customAgents) {
|
|
119
|
+
for (const [id, customConfig] of Object.entries(customAgents)) {
|
|
120
|
+
const existingAgent = agents.get(id);
|
|
121
|
+
if (existingAgent) {
|
|
122
|
+
// Merge with existing agent
|
|
123
|
+
agents.set(id, mergeAgentConfig(existingAgent, customConfig));
|
|
124
|
+
} else {
|
|
125
|
+
// Create new agent
|
|
126
|
+
agents.set(id, {
|
|
127
|
+
id,
|
|
128
|
+
name: customConfig.name ?? id,
|
|
129
|
+
description: customConfig.description ?? '',
|
|
130
|
+
mode: customConfig.mode ?? 'all',
|
|
131
|
+
...customConfig,
|
|
132
|
+
} as AgentConfig);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function mergeAgentConfig(base: AgentConfig, override: Partial<AgentConfig>): AgentConfig {
|
|
139
|
+
return {
|
|
140
|
+
...base,
|
|
141
|
+
...override,
|
|
142
|
+
tools: {
|
|
143
|
+
...base.tools,
|
|
144
|
+
...override.tools,
|
|
145
|
+
},
|
|
146
|
+
permission: {
|
|
147
|
+
...base.permission,
|
|
148
|
+
...override.permission,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function getAgent(id: string): AgentConfig | undefined {
|
|
154
|
+
return agents.get(id);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function getPrimaryAgents(): AgentConfig[] {
|
|
158
|
+
return Array.from(agents.values()).filter(
|
|
159
|
+
(agent) => agent.mode === 'primary' || agent.mode === 'all'
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function getSubagents(): AgentConfig[] {
|
|
164
|
+
return Array.from(agents.values()).filter(
|
|
165
|
+
(agent) => (agent.mode === 'subagent' || agent.mode === 'all') && !agent.hidden
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function getAllAgents(): AgentConfig[] {
|
|
170
|
+
return Array.from(agents.values());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function isToolEnabled(agent: AgentConfig, toolName: string): boolean {
|
|
174
|
+
if (agent.disabled) return false;
|
|
175
|
+
if (agent.tools === undefined) return true;
|
|
176
|
+
return agent.tools[toolName] ?? true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Get system prompt for an agent
|
|
180
|
+
export function getAgentSystemPrompt(agent: AgentConfig): string {
|
|
181
|
+
// Load JARVIS brain (automatically created if doesn't exist)
|
|
182
|
+
let brain = '';
|
|
183
|
+
try {
|
|
184
|
+
const { loadBrain } = require('../brain/loader.js');
|
|
185
|
+
brain = loadBrain();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.warn('[Agent] Could not load brain:', error);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Load skills content
|
|
191
|
+
let skillsContent = '';
|
|
192
|
+
try {
|
|
193
|
+
const { loadSkills } = require('../utils/skills.js');
|
|
194
|
+
skillsContent = loadSkills();
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.warn('[Agent] Could not load skills:', error);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Combine: Brain + Skills + Agent-specific prompt
|
|
200
|
+
const parts: string[] = [];
|
|
201
|
+
|
|
202
|
+
// 1. Core brain (JARVIS.md)
|
|
203
|
+
if (brain) {
|
|
204
|
+
parts.push(brain);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 2. Active skills
|
|
208
|
+
if (skillsContent) {
|
|
209
|
+
parts.push('\n## Active Skills\n' + skillsContent);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 3. Agent-specific instructions
|
|
213
|
+
if (agent.description) {
|
|
214
|
+
parts.push('\n## Agent Role\n' + agent.description);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (agent.prompt) {
|
|
218
|
+
parts.push('\n## Additional Instructions\n' + agent.prompt);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// If no brain or skills loaded, fall back to basic prompt
|
|
222
|
+
if (parts.length === 0) {
|
|
223
|
+
const basePrompt = `You are ${agent.name}, an AI coding assistant.
|
|
224
|
+
Your name is ${agent.name}. You are JARVIS (Just A Rather Very Intelligent System).
|
|
225
|
+
|
|
226
|
+
${agent.description}
|
|
227
|
+
|
|
228
|
+
You help users with software engineering tasks including:
|
|
229
|
+
- Answering questions about code
|
|
230
|
+
- Debugging issues
|
|
231
|
+
- Adding new features
|
|
232
|
+
- Refactoring code
|
|
233
|
+
- Explaining complex concepts
|
|
234
|
+
|
|
235
|
+
Always be helpful, accurate, and thorough. When making changes, explain what you're doing and why.`;
|
|
236
|
+
|
|
237
|
+
if (agent.prompt) {
|
|
238
|
+
return `${basePrompt}\n\n${agent.prompt}`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return basePrompt;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return parts.join('\n\n');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Initialize agents on module load
|
|
248
|
+
initializeAgents();
|