@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,148 @@
|
|
|
1
|
+
// Plugin system for Jarvis
|
|
2
|
+
// Compatible with opencode plugins like opencode-antigravity-auth
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { existsSync, readFileSync } from 'fs';
|
|
5
|
+
import { getConfigDir } from '../config';
|
|
6
|
+
import type { Plugin, JarvisInstance, ProviderConfig, Tool, AgentConfig } from '../core/types';
|
|
7
|
+
|
|
8
|
+
// Plugin registry
|
|
9
|
+
const plugins = new Map<string, Plugin>();
|
|
10
|
+
|
|
11
|
+
export interface PluginLoader {
|
|
12
|
+
name: string;
|
|
13
|
+
load: () => Promise<Plugin>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Load plugins from config
|
|
17
|
+
export async function loadPlugins(pluginNames: string[]): Promise<Plugin[]> {
|
|
18
|
+
const loadedPlugins: Plugin[] = [];
|
|
19
|
+
|
|
20
|
+
for (const name of pluginNames) {
|
|
21
|
+
try {
|
|
22
|
+
const plugin = await loadPlugin(name);
|
|
23
|
+
if (plugin) {
|
|
24
|
+
plugins.set(name, plugin);
|
|
25
|
+
loadedPlugins.push(plugin);
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn(`Failed to load plugin ${name}:`, error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return loadedPlugins;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Load a single plugin
|
|
36
|
+
async function loadPlugin(name: string): Promise<Plugin | undefined> {
|
|
37
|
+
// Parse plugin name (supports @scope/name@version format)
|
|
38
|
+
const { packageName, version } = parsePluginName(name);
|
|
39
|
+
|
|
40
|
+
// Check if it's an opencode plugin that needs compatibility
|
|
41
|
+
if (packageName.includes('opencode-antigravity-auth')) {
|
|
42
|
+
return createAntigravityCompatPlugin(packageName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Try to dynamically import the plugin
|
|
46
|
+
try {
|
|
47
|
+
const module = await import(packageName);
|
|
48
|
+
if (module.default && typeof module.default === 'object') {
|
|
49
|
+
return module.default as Plugin;
|
|
50
|
+
}
|
|
51
|
+
return module as Plugin;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.warn(`Could not load plugin ${packageName}:`, error);
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Parse plugin name to extract package and version
|
|
59
|
+
function parsePluginName(name: string): { packageName: string; version?: string } {
|
|
60
|
+
// Handle @scope/package@version format
|
|
61
|
+
const atIndex = name.lastIndexOf('@');
|
|
62
|
+
if (atIndex > 0) {
|
|
63
|
+
return {
|
|
64
|
+
packageName: name.substring(0, atIndex),
|
|
65
|
+
version: name.substring(atIndex + 1),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { packageName: name };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Create a compatibility layer for opencode-antigravity-auth
|
|
72
|
+
function createAntigravityCompatPlugin(packageName: string): Plugin {
|
|
73
|
+
return {
|
|
74
|
+
name: 'antigravity-auth-compat',
|
|
75
|
+
version: '1.0.0',
|
|
76
|
+
|
|
77
|
+
async init(jarvis: JarvisInstance) {
|
|
78
|
+
console.log('Antigravity Auth compatibility plugin initialized');
|
|
79
|
+
|
|
80
|
+
// Check for existing accounts file
|
|
81
|
+
const accountsPath = join(getConfigDir(), 'antigravity-accounts.json');
|
|
82
|
+
if (existsSync(accountsPath)) {
|
|
83
|
+
try {
|
|
84
|
+
const accounts = JSON.parse(readFileSync(accountsPath, 'utf-8'));
|
|
85
|
+
console.log(`Found ${accounts.accounts?.length || 0} Antigravity account(s)`);
|
|
86
|
+
} catch {
|
|
87
|
+
// Ignore parse errors
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
console.log('No Antigravity accounts found. Run "jarvis auth login" to add an account.');
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// Antigravity models are already configured in default config
|
|
95
|
+
providers: [],
|
|
96
|
+
tools: [],
|
|
97
|
+
agents: [],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Initialize all loaded plugins
|
|
102
|
+
export async function initializePlugins(jarvis: JarvisInstance): Promise<void> {
|
|
103
|
+
for (const [name, plugin] of plugins) {
|
|
104
|
+
try {
|
|
105
|
+
if (plugin.init) {
|
|
106
|
+
await plugin.init(jarvis);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Register plugin providers
|
|
110
|
+
if (plugin.providers) {
|
|
111
|
+
for (const provider of plugin.providers) {
|
|
112
|
+
jarvis.providers.set(provider.id, provider);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Register plugin tools
|
|
117
|
+
if (plugin.tools) {
|
|
118
|
+
for (const tool of plugin.tools) {
|
|
119
|
+
jarvis.tools.set(tool.name, tool);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Register plugin agents
|
|
124
|
+
if (plugin.agents) {
|
|
125
|
+
for (const agent of plugin.agents) {
|
|
126
|
+
jarvis.agents.set(agent.id, agent);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error(`Error initializing plugin ${name}:`, error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Get a loaded plugin
|
|
136
|
+
export function getPlugin(name: string): Plugin | undefined {
|
|
137
|
+
return plugins.get(name);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// List all loaded plugins
|
|
141
|
+
export function listPlugins(): Plugin[] {
|
|
142
|
+
return Array.from(plugins.values());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Unload a plugin
|
|
146
|
+
export function unloadPlugin(name: string): boolean {
|
|
147
|
+
return plugins.delete(name);
|
|
148
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// Core types for Jarvis AI Agent
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export type AgentMode = 'primary' | 'subagent' | 'all';
|
|
5
|
+
|
|
6
|
+
export type PermissionLevel = 'ask' | 'allow' | 'deny';
|
|
7
|
+
|
|
8
|
+
export interface AgentConfig {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
mode: AgentMode;
|
|
13
|
+
model?: string;
|
|
14
|
+
prompt?: string;
|
|
15
|
+
temperature?: number;
|
|
16
|
+
top_p?: number;
|
|
17
|
+
maxSteps?: number;
|
|
18
|
+
steps?: number;
|
|
19
|
+
tools?: Record<string, boolean>;
|
|
20
|
+
permission?: PermissionConfig;
|
|
21
|
+
hidden?: boolean;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
color?: string;
|
|
24
|
+
options?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type PermissionRuleConfig = PermissionLevel | Record<string, PermissionLevel>;
|
|
28
|
+
|
|
29
|
+
export interface PermissionConfig {
|
|
30
|
+
read?: PermissionRuleConfig;
|
|
31
|
+
edit?: PermissionRuleConfig;
|
|
32
|
+
glob?: PermissionRuleConfig;
|
|
33
|
+
grep?: PermissionRuleConfig;
|
|
34
|
+
list?: PermissionRuleConfig;
|
|
35
|
+
bash?: PermissionRuleConfig;
|
|
36
|
+
task?: PermissionRuleConfig;
|
|
37
|
+
external_directory?: PermissionRuleConfig;
|
|
38
|
+
todowrite?: PermissionLevel;
|
|
39
|
+
todoread?: PermissionLevel;
|
|
40
|
+
question?: PermissionLevel;
|
|
41
|
+
webfetch?: PermissionLevel;
|
|
42
|
+
websearch?: PermissionLevel;
|
|
43
|
+
codesearch?: PermissionLevel;
|
|
44
|
+
lsp?: PermissionRuleConfig;
|
|
45
|
+
doom_loop?: PermissionLevel;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ProviderConfig {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
apiKey?: string;
|
|
52
|
+
baseUrl?: string;
|
|
53
|
+
models: Record<string, ModelConfig>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ModelConfig {
|
|
57
|
+
name: string;
|
|
58
|
+
limit: {
|
|
59
|
+
context: number;
|
|
60
|
+
output: number;
|
|
61
|
+
};
|
|
62
|
+
modalities?: {
|
|
63
|
+
input: string[];
|
|
64
|
+
output: string[];
|
|
65
|
+
};
|
|
66
|
+
variants?: Record<string, Record<string, unknown>>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface JarvisConfig {
|
|
70
|
+
$schema?: string;
|
|
71
|
+
model?: string;
|
|
72
|
+
small_model?: string;
|
|
73
|
+
default_agent?: string;
|
|
74
|
+
theme?: string;
|
|
75
|
+
username?: string;
|
|
76
|
+
snapshot?: boolean;
|
|
77
|
+
share?: 'manual' | 'auto' | 'disabled';
|
|
78
|
+
autoupdate?: boolean | 'notify';
|
|
79
|
+
logLevel?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
80
|
+
provider?: Record<string, Partial<ProviderConfig>>;
|
|
81
|
+
agent?: Record<string, Partial<AgentConfig>>;
|
|
82
|
+
plugin?: string[];
|
|
83
|
+
tools?: Record<string, boolean>;
|
|
84
|
+
permission?: PermissionConfig;
|
|
85
|
+
keybinds?: Record<string, string>;
|
|
86
|
+
command?: Record<string, CommandConfig>;
|
|
87
|
+
watcher?: {
|
|
88
|
+
ignore?: string[];
|
|
89
|
+
};
|
|
90
|
+
tui?: {
|
|
91
|
+
scroll_speed?: number;
|
|
92
|
+
scroll_acceleration?: { enabled: boolean };
|
|
93
|
+
diff_style?: 'auto' | 'stacked';
|
|
94
|
+
};
|
|
95
|
+
server?: {
|
|
96
|
+
port?: number;
|
|
97
|
+
hostname?: string;
|
|
98
|
+
mdns?: boolean;
|
|
99
|
+
cors?: string[];
|
|
100
|
+
};
|
|
101
|
+
oauth?: {
|
|
102
|
+
callbackUrl?: string; // Custom OAuth callback URL for container deployments
|
|
103
|
+
callbackHost?: string; // Bind host for callback server (default: '0.0.0.0')
|
|
104
|
+
callbackPort?: number; // Port for callback server (default: 51121)
|
|
105
|
+
};
|
|
106
|
+
disabled_providers?: string[];
|
|
107
|
+
enabled_providers?: string[];
|
|
108
|
+
workspaces?: Array<{
|
|
109
|
+
id: string;
|
|
110
|
+
name: string;
|
|
111
|
+
path: string;
|
|
112
|
+
icon: string;
|
|
113
|
+
}>;
|
|
114
|
+
persona?: string;
|
|
115
|
+
instructions?: string;
|
|
116
|
+
restrictedPaths?: string[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface CommandConfig {
|
|
120
|
+
template: string;
|
|
121
|
+
description?: string;
|
|
122
|
+
agent?: string;
|
|
123
|
+
model?: string;
|
|
124
|
+
subtask?: boolean;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface Message {
|
|
128
|
+
id: string;
|
|
129
|
+
role: 'user' | 'assistant' | 'system';
|
|
130
|
+
content: string;
|
|
131
|
+
parts?: MessagePart[];
|
|
132
|
+
timestamp: Date;
|
|
133
|
+
thinking?: string;
|
|
134
|
+
toolCalls?: Array<{
|
|
135
|
+
name: string;
|
|
136
|
+
args: any;
|
|
137
|
+
result?: any;
|
|
138
|
+
}>;
|
|
139
|
+
attachments?: any[];
|
|
140
|
+
metadata?: Record<string, unknown>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface MessagePart {
|
|
144
|
+
type: 'text' | 'tool_call' | 'tool_result' | 'thinking' | 'image';
|
|
145
|
+
content: string;
|
|
146
|
+
toolName?: string;
|
|
147
|
+
toolArgs?: Record<string, unknown>;
|
|
148
|
+
toolResult?: unknown;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface Session {
|
|
152
|
+
id: string;
|
|
153
|
+
title?: string;
|
|
154
|
+
agentId: string;
|
|
155
|
+
workdir?: string;
|
|
156
|
+
messages: Message[];
|
|
157
|
+
createdAt: Date;
|
|
158
|
+
updatedAt: Date;
|
|
159
|
+
parentId?: string;
|
|
160
|
+
metadata?: Record<string, unknown>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface Tool {
|
|
164
|
+
name: string;
|
|
165
|
+
description: string;
|
|
166
|
+
parameters: z.ZodType<any> | Record<string, unknown>;
|
|
167
|
+
execute: (args: Record<string, unknown>, context: ToolContext) => Promise<ToolResult>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface ToolContext {
|
|
171
|
+
workdir: string;
|
|
172
|
+
session: Session;
|
|
173
|
+
signal?: AbortSignal;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface ToolResult {
|
|
177
|
+
success: boolean;
|
|
178
|
+
content: string;
|
|
179
|
+
error?: string;
|
|
180
|
+
metadata?: Record<string, unknown>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface Plugin {
|
|
184
|
+
name: string;
|
|
185
|
+
version: string;
|
|
186
|
+
init?: (jarvis: JarvisInstance) => Promise<void>;
|
|
187
|
+
providers?: ProviderConfig[];
|
|
188
|
+
tools?: Tool[];
|
|
189
|
+
agents?: AgentConfig[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface JarvisInstance {
|
|
193
|
+
config: JarvisConfig;
|
|
194
|
+
providers: Map<string, ProviderConfig>;
|
|
195
|
+
agents: Map<string, AgentConfig>;
|
|
196
|
+
tools: Map<string, Tool>;
|
|
197
|
+
sessions: Map<string, Session>;
|
|
198
|
+
activeSession?: Session;
|
|
199
|
+
activeAgent?: AgentConfig;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type EventType =
|
|
203
|
+
| 'session.created'
|
|
204
|
+
| 'session.updated'
|
|
205
|
+
| 'session.deleted'
|
|
206
|
+
| 'message.created'
|
|
207
|
+
| 'message.updated'
|
|
208
|
+
| 'tool.started'
|
|
209
|
+
| 'tool.completed'
|
|
210
|
+
| 'agent.switched'
|
|
211
|
+
| 'error';
|
|
212
|
+
|
|
213
|
+
export interface JarvisEvent {
|
|
214
|
+
type: EventType;
|
|
215
|
+
timestamp: Date;
|
|
216
|
+
data: unknown;
|
|
217
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
|
|
2
|
+
import { spawn, ChildProcess } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
let mainWindow: BrowserWindow | null = null;
|
|
10
|
+
let bunServer: ChildProcess | null = null;
|
|
11
|
+
let serverPort: number = 5533;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Start Bun server in background
|
|
15
|
+
*/
|
|
16
|
+
async function startBunServer(): Promise<string> {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
console.log('[Electron] Starting Bun server...');
|
|
19
|
+
|
|
20
|
+
// Find project root (go up from dist/electron/main.js to project root)
|
|
21
|
+
const projectRoot = path.join(__dirname, '..', '..');
|
|
22
|
+
const cliPath = path.join(projectRoot, 'src', 'cli.ts');
|
|
23
|
+
|
|
24
|
+
// Start Bun server
|
|
25
|
+
bunServer = spawn('bun', ['run', cliPath, 'web', '--port', String(serverPort)], {
|
|
26
|
+
cwd: projectRoot,
|
|
27
|
+
stdio: 'pipe'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
bunServer.stdout?.on('data', (data) => {
|
|
31
|
+
const output = data.toString();
|
|
32
|
+
console.log('[Bun Server]', output);
|
|
33
|
+
|
|
34
|
+
// Look for server ready message
|
|
35
|
+
if (output.includes('Server running') || output.includes('localhost')) {
|
|
36
|
+
resolve(`http://localhost:${serverPort}`);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
bunServer.stderr?.on('data', (data) => {
|
|
41
|
+
console.error('[Bun Server Error]', data.toString());
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
bunServer.on('error', (error) => {
|
|
45
|
+
console.error('[Bun Server] Failed to start:', error);
|
|
46
|
+
reject(error);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Timeout after 10 seconds
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
resolve(`http://localhost:${serverPort}`);
|
|
52
|
+
}, 3000);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create main Electron window
|
|
58
|
+
*/
|
|
59
|
+
async function createWindow() {
|
|
60
|
+
console.log('[Electron] Creating main window...');
|
|
61
|
+
|
|
62
|
+
// Start Bun server first
|
|
63
|
+
const serverUrl = await startBunServer();
|
|
64
|
+
console.log('[Electron] Server URL:', serverUrl);
|
|
65
|
+
|
|
66
|
+
// Create browser window
|
|
67
|
+
mainWindow = new BrowserWindow({
|
|
68
|
+
width: 1400,
|
|
69
|
+
height: 900,
|
|
70
|
+
minWidth: 1024,
|
|
71
|
+
minHeight: 768,
|
|
72
|
+
title: 'JARVIS - AI Coding Assistant',
|
|
73
|
+
backgroundColor: '#09090b', // zinc-950
|
|
74
|
+
autoHideMenuBar: true, // Hide menu bar but allow Alt to show it
|
|
75
|
+
webPreferences: {
|
|
76
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
77
|
+
contextIsolation: true,
|
|
78
|
+
nodeIntegration: false,
|
|
79
|
+
sandbox: false
|
|
80
|
+
},
|
|
81
|
+
show: false // Don't show until ready
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Show window when ready
|
|
85
|
+
mainWindow.once('ready-to-show', () => {
|
|
86
|
+
mainWindow?.show();
|
|
87
|
+
console.log('[Electron] Window ready');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Load the Bun server URL
|
|
91
|
+
await mainWindow.loadURL(serverUrl);
|
|
92
|
+
|
|
93
|
+
// Open DevTools in development
|
|
94
|
+
if (process.env.NODE_ENV === 'development') {
|
|
95
|
+
mainWindow.webContents.openDevTools();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle window closed
|
|
99
|
+
mainWindow.on('closed', () => {
|
|
100
|
+
mainWindow = null;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Setup IPC handlers
|
|
106
|
+
*/
|
|
107
|
+
function setupIPC() {
|
|
108
|
+
// Handle folder selection
|
|
109
|
+
ipcMain.handle('select-folder', async () => {
|
|
110
|
+
const result = await dialog.showOpenDialog({
|
|
111
|
+
properties: ['openDirectory'],
|
|
112
|
+
title: 'Select Workspace Folder'
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result.filePaths[0];
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Handle file selection
|
|
123
|
+
ipcMain.handle('select-files', async () => {
|
|
124
|
+
const result = await dialog.showOpenDialog({
|
|
125
|
+
properties: ['openFile', 'multiSelections'],
|
|
126
|
+
title: 'Select Files'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (result.canceled) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return result.filePaths;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Get app version
|
|
137
|
+
ipcMain.handle('get-app-version', () => {
|
|
138
|
+
return app.getVersion();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Get app mode
|
|
142
|
+
ipcMain.handle('get-app-mode', () => {
|
|
143
|
+
return 'electron';
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Cleanup on app quit
|
|
149
|
+
*/
|
|
150
|
+
function cleanup() {
|
|
151
|
+
console.log('[Electron] Cleaning up...');
|
|
152
|
+
|
|
153
|
+
if (bunServer) {
|
|
154
|
+
console.log('[Electron] Stopping Bun server...');
|
|
155
|
+
bunServer.kill();
|
|
156
|
+
bunServer = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* App lifecycle
|
|
162
|
+
*/
|
|
163
|
+
app.whenReady().then(() => {
|
|
164
|
+
console.log('[Electron] App ready');
|
|
165
|
+
setupIPC();
|
|
166
|
+
createWindow();
|
|
167
|
+
|
|
168
|
+
// On macOS, re-create window when dock icon is clicked
|
|
169
|
+
app.on('activate', () => {
|
|
170
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
171
|
+
createWindow();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Quit when all windows are closed (except on macOS)
|
|
177
|
+
app.on('window-all-closed', () => {
|
|
178
|
+
if (process.platform !== 'darwin') {
|
|
179
|
+
cleanup();
|
|
180
|
+
app.quit();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Cleanup before quit
|
|
185
|
+
app.on('before-quit', () => {
|
|
186
|
+
cleanup();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Handle uncaught errors
|
|
190
|
+
process.on('uncaughtException', (error) => {
|
|
191
|
+
console.error('[Electron] Uncaught exception:', error);
|
|
192
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Electron Preload Script
|
|
5
|
+
* Bridges main process and renderer process securely
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Expose safe APIs to renderer process
|
|
9
|
+
contextBridge.exposeInMainWorld('electron', {
|
|
10
|
+
// Folder selection
|
|
11
|
+
selectFolder: () => ipcRenderer.invoke('select-folder'),
|
|
12
|
+
|
|
13
|
+
// File selection
|
|
14
|
+
selectFiles: () => ipcRenderer.invoke('select-files'),
|
|
15
|
+
|
|
16
|
+
// App info
|
|
17
|
+
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
|
|
18
|
+
getAppMode: () => ipcRenderer.invoke('get-app-mode'),
|
|
19
|
+
|
|
20
|
+
// Environment detection
|
|
21
|
+
isElectron: true,
|
|
22
|
+
platform: process.platform
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log('[Preload] Electron APIs exposed to renderer');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for Electron APIs exposed to renderer
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ElectronAPI {
|
|
6
|
+
selectFolder: () => Promise<string | null>;
|
|
7
|
+
selectFiles: () => Promise<string[]>;
|
|
8
|
+
getAppVersion: () => Promise<string>;
|
|
9
|
+
getAppMode: () => Promise<'electron' | 'web'>;
|
|
10
|
+
isElectron: boolean;
|
|
11
|
+
platform: NodeJS.Platform;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
electron?: ElectronAPI;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Jarvis AI - Main Entry Point
|
|
2
|
+
// This file exports all modules for SDK/library usage
|
|
3
|
+
|
|
4
|
+
export * from './core/types.js';
|
|
5
|
+
export * from './config/index.js';
|
|
6
|
+
export * from './providers/index.js';
|
|
7
|
+
export * from './agents/index.js';
|
|
8
|
+
export * from './tools/index.js';
|
|
9
|
+
export * from './sessions/index.js';
|
|
10
|
+
export * from './core/executor.js';
|
|
11
|
+
export * from './core/plugins.js';
|
|
12
|
+
export * from './utils/index.js';
|