@benzsiangco/jarvis 1.0.2 → 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/dist/cli.js +478 -347
- package/dist/electron/main.js +160 -0
- package/dist/electron/preload.js +19 -0
- package/package.json +19 -6
- 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,136 @@
|
|
|
1
|
+
// Brain loader utilities for JARVIS
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_BRAIN = `# JARVIS - Just A Rather Very Intelligent System
|
|
6
|
+
|
|
7
|
+
You are JARVIS, an advanced AI coding assistant designed to help developers with software engineering tasks.
|
|
8
|
+
|
|
9
|
+
## Core Identity
|
|
10
|
+
|
|
11
|
+
JARVIS (Just A Rather Very Intelligent System) is a powerful, technical AI assistant specializing in:
|
|
12
|
+
- Software architecture and system design
|
|
13
|
+
- Full-stack development and implementation
|
|
14
|
+
- DevOps, infrastructure, and containerization
|
|
15
|
+
- Security analysis and hardening
|
|
16
|
+
- Technical decision-making and best practices
|
|
17
|
+
|
|
18
|
+
## Core Principles
|
|
19
|
+
|
|
20
|
+
1. **Technical Precision** - Be accurate, thorough, and technically sound in all recommendations
|
|
21
|
+
2. **Explain Reasoning** - Always explain the "why" behind decisions and approaches
|
|
22
|
+
3. **Security First** - Prioritize security best practices and potential vulnerabilities
|
|
23
|
+
4. **Pragmatic Solutions** - Balance ideal solutions with practical constraints
|
|
24
|
+
5. **Context Awareness** - Adapt communication style based on user expertise and situation
|
|
25
|
+
|
|
26
|
+
## Communication Style
|
|
27
|
+
|
|
28
|
+
- Direct and professional tone
|
|
29
|
+
- Technical depth appropriate to context
|
|
30
|
+
- Code examples when relevant
|
|
31
|
+
- Clear explanations of complex concepts
|
|
32
|
+
- Proactive error prevention and edge case handling
|
|
33
|
+
|
|
34
|
+
## Technical Capabilities
|
|
35
|
+
|
|
36
|
+
### Programming Languages
|
|
37
|
+
- TypeScript/JavaScript (Node.js, Bun, Deno)
|
|
38
|
+
- Python (async, FastAPI, Django)
|
|
39
|
+
- Go (concurrency, microservices)
|
|
40
|
+
- Rust (systems programming, performance)
|
|
41
|
+
- Shell scripting (Bash, PowerShell)
|
|
42
|
+
|
|
43
|
+
### Frontend Development
|
|
44
|
+
- React ecosystem (Next.js, Remix, hooks, context)
|
|
45
|
+
- Modern CSS (TailwindCSS, CSS-in-JS, animations)
|
|
46
|
+
- State management (Zustand, Redux, Context)
|
|
47
|
+
- Build tools (Vite, esbuild, Webpack)
|
|
48
|
+
- Performance optimization
|
|
49
|
+
|
|
50
|
+
### Backend Development
|
|
51
|
+
- API design (REST, GraphQL, WebSockets)
|
|
52
|
+
- Database design (PostgreSQL, MySQL, MongoDB, Redis)
|
|
53
|
+
- Authentication & authorization (OAuth, JWT, session management)
|
|
54
|
+
- Message queues (RabbitMQ, Redis Pub/Sub)
|
|
55
|
+
- Microservices architecture
|
|
56
|
+
|
|
57
|
+
### DevOps & Infrastructure
|
|
58
|
+
- Containerization (Docker, Docker Compose)
|
|
59
|
+
- Orchestration (Kubernetes, Docker Swarm)
|
|
60
|
+
- CI/CD (GitHub Actions, GitLab CI, Jenkins)
|
|
61
|
+
- Cloud platforms (AWS, GCP, Azure)
|
|
62
|
+
- Infrastructure as Code (Terraform, Ansible)
|
|
63
|
+
- Proxmox virtualization (LXC, VMs)
|
|
64
|
+
|
|
65
|
+
### Security
|
|
66
|
+
- Web application security (OWASP Top 10)
|
|
67
|
+
- Network security (firewalls, VPNs, SSL/TLS)
|
|
68
|
+
- Container security and hardening
|
|
69
|
+
- SSH key management and hardening
|
|
70
|
+
- Penetration testing basics
|
|
71
|
+
- Secure coding practices
|
|
72
|
+
|
|
73
|
+
### Databases
|
|
74
|
+
- SQL query optimization and indexing
|
|
75
|
+
- Schema design and normalization
|
|
76
|
+
- Replication and backup strategies
|
|
77
|
+
- NoSQL patterns and use cases
|
|
78
|
+
- Database performance tuning
|
|
79
|
+
|
|
80
|
+
## Problem-Solving Approach
|
|
81
|
+
|
|
82
|
+
1. **Understand Context** - Gather requirements and constraints
|
|
83
|
+
2. **Analyze Options** - Consider multiple approaches with trade-offs
|
|
84
|
+
3. **Recommend Solution** - Provide clear recommendation with reasoning
|
|
85
|
+
4. **Implement Carefully** - Write clean, tested, documented code
|
|
86
|
+
5. **Verify Results** - Test thoroughly and handle edge cases
|
|
87
|
+
|
|
88
|
+
## Code Quality Standards
|
|
89
|
+
|
|
90
|
+
- Write self-documenting code with clear naming
|
|
91
|
+
- Add comments for complex logic only
|
|
92
|
+
- Follow language-specific best practices
|
|
93
|
+
- Handle errors gracefully
|
|
94
|
+
- Consider performance implications
|
|
95
|
+
- Test edge cases and error paths
|
|
96
|
+
- Maintain backward compatibility when possible
|
|
97
|
+
|
|
98
|
+
## When to Ask for Clarification
|
|
99
|
+
|
|
100
|
+
- Requirements are ambiguous or incomplete
|
|
101
|
+
- Multiple valid approaches exist with different trade-offs
|
|
102
|
+
- Breaking changes might be introduced
|
|
103
|
+
- Security implications are significant
|
|
104
|
+
- Destructive operations are requested
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
This is your core brain. Skills from skills.md and agent-specific instructions will be combined with this foundation.
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
export function getBrainPath(): string {
|
|
112
|
+
return join(process.cwd(), 'JARVIS.md');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function loadBrain(): string {
|
|
116
|
+
const path = getBrainPath();
|
|
117
|
+
|
|
118
|
+
// Create default if doesn't exist
|
|
119
|
+
if (!existsSync(path)) {
|
|
120
|
+
writeFileSync(path, DEFAULT_BRAIN, 'utf-8');
|
|
121
|
+
console.log('[Brain] Created default JARVIS.md');
|
|
122
|
+
return DEFAULT_BRAIN;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return readFileSync(path, 'utf-8');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function saveBrain(content: string): void {
|
|
129
|
+
const path = getBrainPath();
|
|
130
|
+
writeFileSync(path, content, 'utf-8');
|
|
131
|
+
console.log('[Brain] JARVIS.md updated');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function hasBrain(): boolean {
|
|
135
|
+
return existsSync(getBrainPath());
|
|
136
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Jarvis CLI Entry Point
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import { loadConfig, saveGlobalConfig, getGlobalConfigPath } from './config/index.js';
|
|
5
|
+
import { initializeProviders, getAvailableModels, getProvidersWithStatus } from './providers/index.js';
|
|
6
|
+
import { initializeAgents, getAllAgents } from './agents/index.js';
|
|
7
|
+
import { initializeTools } from './tools/index.js';
|
|
8
|
+
import { listSessions } from './sessions/index.js';
|
|
9
|
+
import { existsSync, writeFileSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import {
|
|
12
|
+
startAntigravityLogin,
|
|
13
|
+
listAccountsWithStatus,
|
|
14
|
+
removeAccount,
|
|
15
|
+
setRotationStrategy,
|
|
16
|
+
togglePidOffset,
|
|
17
|
+
getAccountStats,
|
|
18
|
+
type RotationStrategy,
|
|
19
|
+
} from './providers/antigravity.js';
|
|
20
|
+
|
|
21
|
+
const VERSION = '0.1.0';
|
|
22
|
+
|
|
23
|
+
interface CommandOptions {
|
|
24
|
+
model?: string;
|
|
25
|
+
variant?: string;
|
|
26
|
+
prompt?: string;
|
|
27
|
+
json?: boolean;
|
|
28
|
+
show?: boolean;
|
|
29
|
+
path?: boolean;
|
|
30
|
+
init?: boolean;
|
|
31
|
+
list?: boolean;
|
|
32
|
+
clear?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Default command - launch TUI
|
|
36
|
+
program
|
|
37
|
+
.command('tui', { isDefault: true })
|
|
38
|
+
.description('Launch the Terminal User Interface')
|
|
39
|
+
.option('-m, --model <model>', 'Model to use')
|
|
40
|
+
.option('-v, --variant <variant>', 'Model variant')
|
|
41
|
+
.option('-p, --prompt <prompt>', 'Initial prompt to send')
|
|
42
|
+
.action(async (options: CommandOptions) => {
|
|
43
|
+
try {
|
|
44
|
+
const { model, variant, prompt } = options;
|
|
45
|
+
|
|
46
|
+
console.log('Starting Jarvis TUI...');
|
|
47
|
+
const { startTui } = await import('./tui/index.js');
|
|
48
|
+
await startTui({
|
|
49
|
+
initialPrompt: prompt,
|
|
50
|
+
model,
|
|
51
|
+
variant,
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Error starting TUI:', error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Run command - single prompt execution
|
|
60
|
+
program
|
|
61
|
+
.command('run <prompt>')
|
|
62
|
+
.description('Run a single prompt and exit')
|
|
63
|
+
.option('-m, --model <model>', 'Model to use')
|
|
64
|
+
.option('-v, --variant <variant>', 'Model variant')
|
|
65
|
+
.option('--json', 'Output as JSON')
|
|
66
|
+
.action(async (prompt: string, options: CommandOptions) => {
|
|
67
|
+
const { executeAgentSync } = await import('./core/executor.js');
|
|
68
|
+
const { getAgent } = await import('./agents/index.js');
|
|
69
|
+
const { createSession } = await import('./sessions/index.js');
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const config = loadConfig();
|
|
73
|
+
await initializeProviders(config);
|
|
74
|
+
initializeAgents(config.agent);
|
|
75
|
+
initializeTools();
|
|
76
|
+
|
|
77
|
+
const agent = getAgent('build');
|
|
78
|
+
if (!agent) {
|
|
79
|
+
console.error('Agent not found');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const session = createSession(agent.id);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
if (!options.json) {
|
|
87
|
+
console.log('Thinking...');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const result = await executeAgentSync(prompt, {
|
|
91
|
+
session,
|
|
92
|
+
agent: {
|
|
93
|
+
...agent,
|
|
94
|
+
model: options.model || agent.model,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!options.json) {
|
|
99
|
+
console.log('\n' + result.message.content);
|
|
100
|
+
|
|
101
|
+
if (result.toolCalls.length > 0) {
|
|
102
|
+
console.log(`\n🛠 Used ${result.toolCalls.length} tools.`);
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
console.log(JSON.stringify(result, null, 2));
|
|
106
|
+
}
|
|
107
|
+
} catch (execError) {
|
|
108
|
+
console.error('\nExecution Error:', (execError as Error).message);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Initialization Error:', (error as Error).message);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Auth command group
|
|
118
|
+
const authCmd = program
|
|
119
|
+
.command('auth')
|
|
120
|
+
.description('Authentication and account management');
|
|
121
|
+
|
|
122
|
+
// Auth login
|
|
123
|
+
authCmd
|
|
124
|
+
.command('login')
|
|
125
|
+
.description('Interactive login with provider selection and multi-account support')
|
|
126
|
+
.option('--quick', 'Skip provider selection, go directly to Google OAuth')
|
|
127
|
+
.action(async (options: { quick?: boolean }) => {
|
|
128
|
+
try {
|
|
129
|
+
if (options.quick) {
|
|
130
|
+
await startAntigravityLogin();
|
|
131
|
+
} else {
|
|
132
|
+
const { runInteractiveAuth } = await import('./utils/auth-prompt.js');
|
|
133
|
+
await runInteractiveAuth();
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('Login failed:', (error as Error).message);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Auth list
|
|
142
|
+
authCmd
|
|
143
|
+
.command('list')
|
|
144
|
+
.description('List all authenticated accounts')
|
|
145
|
+
.action(() => {
|
|
146
|
+
const accounts = listAccountsWithStatus();
|
|
147
|
+
const stats = getAccountStats();
|
|
148
|
+
|
|
149
|
+
if (accounts.length === 0) {
|
|
150
|
+
console.log('No accounts configured.');
|
|
151
|
+
console.log('Run "jarvis auth login" to add a Google account.');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log('Authenticated Accounts:\n');
|
|
156
|
+
|
|
157
|
+
accounts.forEach((item) => {
|
|
158
|
+
const { account, status, rateLimitRemaining } = item;
|
|
159
|
+
const statusIcon = status === 'available' ? '✓' : status === 'rate-limited' ? '⏳' : '✗';
|
|
160
|
+
const statusColor = status === 'available' ? '\x1b[32m' : status === 'rate-limited' ? '\x1b[33m' : '\x1b[31m';
|
|
161
|
+
|
|
162
|
+
console.log(`${statusColor}${statusIcon}\x1b[0m ${account.email || account.id}`);
|
|
163
|
+
console.log(` ID: ${account.id}`);
|
|
164
|
+
console.log(` Status: ${status}`);
|
|
165
|
+
if (rateLimitRemaining) {
|
|
166
|
+
console.log(` Rate limit expires in: ${Math.ceil(rateLimitRemaining / 1000)}s`);
|
|
167
|
+
}
|
|
168
|
+
console.log(` Requests: ${account.requestCount || 0}`);
|
|
169
|
+
console.log('');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
console.log(`Strategy: ${stats.strategy}`);
|
|
173
|
+
console.log(`Available: ${stats.available}/${stats.total}`);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Auth remove
|
|
177
|
+
authCmd
|
|
178
|
+
.command('remove <email-or-id>')
|
|
179
|
+
.description('Remove an authenticated account')
|
|
180
|
+
.action((emailOrId: string) => {
|
|
181
|
+
if (removeAccount(emailOrId)) {
|
|
182
|
+
console.log('Account removed successfully.');
|
|
183
|
+
} else {
|
|
184
|
+
console.error('Account not found.');
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Auth strategy
|
|
190
|
+
authCmd
|
|
191
|
+
.command('strategy <strategy>')
|
|
192
|
+
.description('Set account rotation strategy: round-robin, sticky, least-used, random')
|
|
193
|
+
.action((strategy: string) => {
|
|
194
|
+
const valid: RotationStrategy[] = ['round-robin', 'sticky', 'least-used', 'random'];
|
|
195
|
+
if (!valid.includes(strategy as RotationStrategy)) {
|
|
196
|
+
console.error(`Invalid strategy. Choose from: ${valid.join(', ')}`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
setRotationStrategy(strategy as RotationStrategy);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Auth pid-offset
|
|
203
|
+
authCmd
|
|
204
|
+
.command('pid-offset <enabled>')
|
|
205
|
+
.description('Enable/disable PID offset for parallel agents (true/false)')
|
|
206
|
+
.action((enabled: string) => {
|
|
207
|
+
togglePidOffset(enabled === 'true');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Providers command
|
|
211
|
+
program
|
|
212
|
+
.command('providers')
|
|
213
|
+
.description('List all supported providers and their status')
|
|
214
|
+
.action(async () => {
|
|
215
|
+
const config = loadConfig();
|
|
216
|
+
await initializeProviders(config);
|
|
217
|
+
|
|
218
|
+
const providers = getProvidersWithStatus();
|
|
219
|
+
|
|
220
|
+
console.log('AI Providers:\n');
|
|
221
|
+
|
|
222
|
+
providers.forEach(p => {
|
|
223
|
+
const icon = p.isAvailable ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
|
|
224
|
+
console.log(`${icon} ${p.name}`);
|
|
225
|
+
console.log(` ID: ${p.id}`);
|
|
226
|
+
console.log(` Env: ${p.envVar}`);
|
|
227
|
+
console.log('');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
console.log('To enable a provider, set its environment variable.');
|
|
231
|
+
console.log('For Google Antigravity (free), run: jarvis auth login');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Config command
|
|
235
|
+
program
|
|
236
|
+
.command('config')
|
|
237
|
+
.description('Configuration management')
|
|
238
|
+
.option('--show', 'Show current configuration')
|
|
239
|
+
.option('--path', 'Show config file path')
|
|
240
|
+
.option('--init', 'Initialize default configuration')
|
|
241
|
+
.action((options: CommandOptions) => {
|
|
242
|
+
if (options.path) {
|
|
243
|
+
console.log(getGlobalConfigPath());
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (options.init) {
|
|
248
|
+
const config = loadConfig();
|
|
249
|
+
saveGlobalConfig(config);
|
|
250
|
+
console.log('Configuration initialized at:', getGlobalConfigPath());
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (options.show) {
|
|
255
|
+
const config = loadConfig();
|
|
256
|
+
console.log(JSON.stringify(config, null, 2));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log('Usage: jarvis config [--show|--path|--init]');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Models command
|
|
264
|
+
program
|
|
265
|
+
.command('models')
|
|
266
|
+
.description('List available models')
|
|
267
|
+
.action(async () => {
|
|
268
|
+
const config = loadConfig();
|
|
269
|
+
await initializeProviders(config);
|
|
270
|
+
|
|
271
|
+
const models = getAvailableModels(config);
|
|
272
|
+
|
|
273
|
+
console.log('Available Models:\n');
|
|
274
|
+
|
|
275
|
+
const byProvider: Record<string, typeof models> = {};
|
|
276
|
+
for (const model of models) {
|
|
277
|
+
if (!byProvider[model.provider]) {
|
|
278
|
+
byProvider[model.provider] = [];
|
|
279
|
+
}
|
|
280
|
+
byProvider[model.provider]!.push(model);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
for (const [provider, providerModels] of Object.entries(byProvider)) {
|
|
284
|
+
console.log(`${provider}:`);
|
|
285
|
+
for (const model of providerModels) {
|
|
286
|
+
console.log(` ${model.id} - ${model.name}`);
|
|
287
|
+
}
|
|
288
|
+
console.log('');
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Agents command
|
|
293
|
+
program
|
|
294
|
+
.command('agents')
|
|
295
|
+
.description('List available agents')
|
|
296
|
+
.action(() => {
|
|
297
|
+
const config = loadConfig();
|
|
298
|
+
initializeAgents(config.agent);
|
|
299
|
+
|
|
300
|
+
const agents = getAllAgents();
|
|
301
|
+
|
|
302
|
+
console.log('Available Agents:\n');
|
|
303
|
+
|
|
304
|
+
for (const agent of agents) {
|
|
305
|
+
const mode = agent.mode === 'primary' ? '[PRIMARY]' : '[SUBAGENT]';
|
|
306
|
+
console.log(`${agent.name} ${mode}`);
|
|
307
|
+
console.log(` ${agent.description}`);
|
|
308
|
+
console.log('');
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Sessions command
|
|
313
|
+
program
|
|
314
|
+
.command('sessions')
|
|
315
|
+
.description('List or manage sessions')
|
|
316
|
+
.option('--list', 'List all sessions')
|
|
317
|
+
.option('--clear', 'Clear all sessions')
|
|
318
|
+
.action(async (options: CommandOptions) => {
|
|
319
|
+
if (options.clear) {
|
|
320
|
+
const { clearAllSessions } = await import('./sessions/index.js');
|
|
321
|
+
clearAllSessions();
|
|
322
|
+
console.log('All sessions cleared.');
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const sessions = listSessions();
|
|
327
|
+
|
|
328
|
+
if (sessions.length === 0) {
|
|
329
|
+
console.log('No sessions found.');
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
console.log('Sessions:\n');
|
|
334
|
+
for (const session of sessions) {
|
|
335
|
+
const date = new Date(session.updatedAt).toLocaleString();
|
|
336
|
+
console.log(`${session.id.substring(0, 8)}... - ${session.title || 'Untitled'}`);
|
|
337
|
+
console.log(` Agent: ${session.agentId} | Messages: ${session.messages.length} | Updated: ${date}`);
|
|
338
|
+
console.log('');
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Web command
|
|
343
|
+
program
|
|
344
|
+
.command('web')
|
|
345
|
+
.description('Start the Jarvis Web interface')
|
|
346
|
+
.option('-p, --port <number>', 'Port to run on', '1138')
|
|
347
|
+
.action(async (options: { port: string }) => {
|
|
348
|
+
console.log(`Starting Jarvis Web on http://0.0.0.0:${options.port}...`);
|
|
349
|
+
try {
|
|
350
|
+
const server = await import('./web/server.js');
|
|
351
|
+
const port = parseInt(options.port);
|
|
352
|
+
|
|
353
|
+
if (typeof Bun === 'undefined') {
|
|
354
|
+
throw new Error('Jarvis Web requires the Bun runtime.');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
Bun.serve({
|
|
358
|
+
port,
|
|
359
|
+
fetch: server.default.fetch,
|
|
360
|
+
websocket: server.default.websocket,
|
|
361
|
+
idleTimeout: 120, // 2 minutes - allows time for folder selection dialog
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
console.log(`Jarvis Web is ready!`);
|
|
365
|
+
} catch (error) {
|
|
366
|
+
console.error('Failed to start web server:', error);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Init command
|
|
371
|
+
program
|
|
372
|
+
.command('init')
|
|
373
|
+
.description('Initialize Jarvis for a project')
|
|
374
|
+
.action(() => {
|
|
375
|
+
const cwd = process.cwd();
|
|
376
|
+
const agentsPath = join(cwd, 'AGENTS.md');
|
|
377
|
+
|
|
378
|
+
if (existsSync(agentsPath)) {
|
|
379
|
+
console.log('AGENTS.md already exists in this project.');
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const template = `# Project Agents
|
|
384
|
+
|
|
385
|
+
This file helps AI agents understand your project.
|
|
386
|
+
|
|
387
|
+
## Project Structure
|
|
388
|
+
|
|
389
|
+
Describe your project structure here.
|
|
390
|
+
|
|
391
|
+
## Key Files
|
|
392
|
+
|
|
393
|
+
- \`src/\` - Source code
|
|
394
|
+
- \`package.json\` - Project configuration
|
|
395
|
+
|
|
396
|
+
## Coding Conventions
|
|
397
|
+
|
|
398
|
+
Describe your coding conventions here.
|
|
399
|
+
|
|
400
|
+
## Common Tasks
|
|
401
|
+
|
|
402
|
+
Describe common development tasks here.
|
|
403
|
+
`;
|
|
404
|
+
|
|
405
|
+
writeFileSync(agentsPath, template);
|
|
406
|
+
console.log('Created AGENTS.md in project root.');
|
|
407
|
+
console.log('Edit this file to help AI understand your project better.');
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Parse and execute
|
|
411
|
+
program.version(VERSION).parse();
|