@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.
Files changed (55) hide show
  1. package/README.md +5 -0
  2. package/bin/{jarvis.js → jarvis} +1 -1
  3. package/dist/cli.js +476 -350
  4. package/dist/electron/main.js +160 -0
  5. package/dist/electron/preload.js +19 -0
  6. package/package.json +21 -8
  7. package/skills.md +147 -0
  8. package/src/agents/index.ts +248 -0
  9. package/src/brain/loader.ts +136 -0
  10. package/src/cli.ts +411 -0
  11. package/src/config/index.ts +363 -0
  12. package/src/core/executor.ts +222 -0
  13. package/src/core/plugins.ts +148 -0
  14. package/src/core/types.ts +217 -0
  15. package/src/electron/main.ts +192 -0
  16. package/src/electron/preload.ts +25 -0
  17. package/src/electron/types.d.ts +20 -0
  18. package/src/index.ts +12 -0
  19. package/src/providers/antigravity-loader.ts +233 -0
  20. package/src/providers/antigravity.ts +585 -0
  21. package/src/providers/index.ts +523 -0
  22. package/src/sessions/index.ts +194 -0
  23. package/src/tools/index.ts +436 -0
  24. package/src/tui/index.tsx +784 -0
  25. package/src/utils/auth-prompt.ts +394 -0
  26. package/src/utils/index.ts +180 -0
  27. package/src/utils/native-picker.ts +71 -0
  28. package/src/utils/skills.ts +99 -0
  29. package/src/utils/table-integration-examples.ts +617 -0
  30. package/src/utils/table-utils.ts +401 -0
  31. package/src/web/build-ui.ts +27 -0
  32. package/src/web/server.ts +674 -0
  33. package/src/web/ui/dist/.gitkeep +0 -0
  34. package/src/web/ui/dist/main.css +1 -0
  35. package/src/web/ui/dist/main.js +320 -0
  36. package/src/web/ui/dist/main.js.map +20 -0
  37. package/src/web/ui/index.html +46 -0
  38. package/src/web/ui/src/App.tsx +143 -0
  39. package/src/web/ui/src/Modules/Safety/GuardianModal.tsx +83 -0
  40. package/src/web/ui/src/components/Layout/ContextPanel.tsx +243 -0
  41. package/src/web/ui/src/components/Layout/Header.tsx +91 -0
  42. package/src/web/ui/src/components/Layout/ModelSelector.tsx +235 -0
  43. package/src/web/ui/src/components/Layout/SessionStats.tsx +369 -0
  44. package/src/web/ui/src/components/Layout/Sidebar.tsx +895 -0
  45. package/src/web/ui/src/components/Modules/Chat/ChatStage.tsx +620 -0
  46. package/src/web/ui/src/components/Modules/Chat/MessageItem.tsx +446 -0
  47. package/src/web/ui/src/components/Modules/Editor/CommandInspector.tsx +71 -0
  48. package/src/web/ui/src/components/Modules/Editor/DiffViewer.tsx +83 -0
  49. package/src/web/ui/src/components/Modules/Terminal/TabbedTerminal.tsx +202 -0
  50. package/src/web/ui/src/components/Settings/SettingsModal.tsx +935 -0
  51. package/src/web/ui/src/config/models.ts +70 -0
  52. package/src/web/ui/src/main.tsx +13 -0
  53. package/src/web/ui/src/store/agentStore.ts +41 -0
  54. package/src/web/ui/src/store/uiStore.ts +64 -0
  55. 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();