@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,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table Utilities for Jarvis Project
|
|
3
|
+
* Helper functions for creating and formatting tables
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// Terminal Table Utilities
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
export interface TableColumn {
|
|
13
|
+
key: string;
|
|
14
|
+
header: string;
|
|
15
|
+
width?: number;
|
|
16
|
+
align?: 'left' | 'center' | 'right';
|
|
17
|
+
color?: (value: any) => string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class TerminalTable {
|
|
21
|
+
private columns: TableColumn[];
|
|
22
|
+
private rows: any[] = [];
|
|
23
|
+
|
|
24
|
+
constructor(columns: TableColumn[]) {
|
|
25
|
+
this.columns = columns;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addRow(row: any) {
|
|
29
|
+
this.rows.push(row);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addRows(rows: any[]) {
|
|
33
|
+
this.rows.push(...rows);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private calculateColumnWidths(): number[] {
|
|
37
|
+
return this.columns.map((col, i) => {
|
|
38
|
+
if (col.width) return col.width;
|
|
39
|
+
|
|
40
|
+
const headerWidth = col.header.length;
|
|
41
|
+
const maxContentWidth = Math.max(
|
|
42
|
+
...this.rows.map(row => String(row[col.key] || '').length),
|
|
43
|
+
0
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return Math.max(headerWidth, maxContentWidth) + 2;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private formatCell(value: string, width: number, align: 'left' | 'center' | 'right' = 'left'): string {
|
|
51
|
+
const strValue = String(value);
|
|
52
|
+
const padding = width - strValue.length;
|
|
53
|
+
|
|
54
|
+
if (padding <= 0) return strValue.slice(0, width);
|
|
55
|
+
|
|
56
|
+
switch (align) {
|
|
57
|
+
case 'center':
|
|
58
|
+
const leftPad = Math.floor(padding / 2);
|
|
59
|
+
const rightPad = padding - leftPad;
|
|
60
|
+
return ' '.repeat(leftPad) + strValue + ' '.repeat(rightPad);
|
|
61
|
+
case 'right':
|
|
62
|
+
return ' '.repeat(padding) + strValue;
|
|
63
|
+
default:
|
|
64
|
+
return strValue + ' '.repeat(padding);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render(): string {
|
|
69
|
+
const widths = this.calculateColumnWidths();
|
|
70
|
+
const lines: string[] = [];
|
|
71
|
+
|
|
72
|
+
// Top border
|
|
73
|
+
lines.push('ā' + widths.map(w => 'ā'.repeat(w)).join('ā¬') + 'ā');
|
|
74
|
+
|
|
75
|
+
// Header
|
|
76
|
+
const headerCells = this.columns.map((col, i) =>
|
|
77
|
+
chalk.bold.cyan(this.formatCell(col.header, widths[i], 'center'))
|
|
78
|
+
);
|
|
79
|
+
lines.push('ā' + headerCells.join('ā') + 'ā');
|
|
80
|
+
|
|
81
|
+
// Header separator
|
|
82
|
+
lines.push('ā' + widths.map(w => 'ā'.repeat(w)).join('ā¼') + 'ā¤');
|
|
83
|
+
|
|
84
|
+
// Rows
|
|
85
|
+
this.rows.forEach((row, rowIndex) => {
|
|
86
|
+
const cells = this.columns.map((col, i) => {
|
|
87
|
+
const value = row[col.key] || '';
|
|
88
|
+
const formatted = this.formatCell(String(value), widths[i], col.align);
|
|
89
|
+
|
|
90
|
+
// Apply color if specified
|
|
91
|
+
if (col.color) {
|
|
92
|
+
return col.color(value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Alternate row colors for better readability
|
|
96
|
+
return rowIndex % 2 === 0 ? formatted : chalk.dim(formatted);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
lines.push('ā' + cells.join('ā') + 'ā');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Bottom border
|
|
103
|
+
lines.push('ā' + widths.map(w => 'ā'.repeat(w)).join('ā“') + 'ā');
|
|
104
|
+
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
print() {
|
|
109
|
+
console.log(this.render());
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================
|
|
114
|
+
// Quick Table Functions
|
|
115
|
+
// ============================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create a simple table from array of objects
|
|
119
|
+
*/
|
|
120
|
+
export function createTable(data: any[], columns?: string[]): TerminalTable {
|
|
121
|
+
if (data.length === 0) {
|
|
122
|
+
throw new Error('Cannot create table from empty data');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const keys = columns || Object.keys(data[0]);
|
|
126
|
+
const tableColumns: TableColumn[] = keys.map(key => ({
|
|
127
|
+
key,
|
|
128
|
+
header: key.toUpperCase().replace(/_/g, ' '),
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
const table = new TerminalTable(tableColumns);
|
|
132
|
+
table.addRows(data);
|
|
133
|
+
return table;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a comparison table
|
|
138
|
+
*/
|
|
139
|
+
export function createComparisonTable(
|
|
140
|
+
items: any[],
|
|
141
|
+
attributes: string[]
|
|
142
|
+
): TerminalTable {
|
|
143
|
+
const columns: TableColumn[] = [
|
|
144
|
+
{ key: 'attribute', header: 'Attribute', align: 'left' },
|
|
145
|
+
...items.map((item, i) => ({
|
|
146
|
+
key: `item${i}`,
|
|
147
|
+
header: item.name || `Item ${i + 1}`,
|
|
148
|
+
align: 'center' as const,
|
|
149
|
+
})),
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
const table = new TerminalTable(columns);
|
|
153
|
+
|
|
154
|
+
attributes.forEach(attr => {
|
|
155
|
+
const row: any = { attribute: attr };
|
|
156
|
+
items.forEach((item, i) => {
|
|
157
|
+
row[`item${i}`] = item[attr] || '-';
|
|
158
|
+
});
|
|
159
|
+
table.addRow(row);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return table;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Create a status table with colored status indicators
|
|
167
|
+
*/
|
|
168
|
+
export function createStatusTable(services: Array<{
|
|
169
|
+
name: string;
|
|
170
|
+
status: 'online' | 'degraded' | 'offline';
|
|
171
|
+
[key: string]: any;
|
|
172
|
+
}>): TerminalTable {
|
|
173
|
+
const statusColors = {
|
|
174
|
+
online: (text: string) => chalk.green('š¢ ' + text),
|
|
175
|
+
degraded: (text: string) => chalk.yellow('š” ' + text),
|
|
176
|
+
offline: (text: string) => chalk.red('š“ ' + text),
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const keys = Object.keys(services[0]).filter(k => k !== 'status');
|
|
180
|
+
const columns: TableColumn[] = [
|
|
181
|
+
...keys.map(key => ({
|
|
182
|
+
key,
|
|
183
|
+
header: key.toUpperCase(),
|
|
184
|
+
})),
|
|
185
|
+
{
|
|
186
|
+
key: 'status',
|
|
187
|
+
header: 'STATUS',
|
|
188
|
+
align: 'center' as const,
|
|
189
|
+
color: (value: any) => statusColors[value as keyof typeof statusColors]?.(value) || value,
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
const table = new TerminalTable(columns);
|
|
194
|
+
table.addRows(services);
|
|
195
|
+
return table;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ============================================
|
|
199
|
+
// Data Formatters
|
|
200
|
+
// ============================================
|
|
201
|
+
|
|
202
|
+
export const formatters = {
|
|
203
|
+
/**
|
|
204
|
+
* Format bytes to human-readable size
|
|
205
|
+
*/
|
|
206
|
+
bytes: (bytes: number): string => {
|
|
207
|
+
if (bytes === 0) return '0 B';
|
|
208
|
+
const k = 1024;
|
|
209
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
210
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
211
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Format milliseconds to human-readable duration
|
|
216
|
+
*/
|
|
217
|
+
duration: (ms: number): string => {
|
|
218
|
+
if (ms < 1000) return `${ms}ms`;
|
|
219
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`;
|
|
220
|
+
if (ms < 3600000) return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
|
|
221
|
+
return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`;
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Format number as currency
|
|
226
|
+
*/
|
|
227
|
+
currency: (amount: number, currency = 'USD'): string => {
|
|
228
|
+
return new Intl.NumberFormat('en-US', {
|
|
229
|
+
style: 'currency',
|
|
230
|
+
currency,
|
|
231
|
+
}).format(amount);
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Format date to ISO string
|
|
236
|
+
*/
|
|
237
|
+
date: (date: Date | string): string => {
|
|
238
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
239
|
+
return d.toISOString().split('T')[0];
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Format date and time
|
|
244
|
+
*/
|
|
245
|
+
datetime: (date: Date | string): string => {
|
|
246
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
247
|
+
return d.toLocaleString();
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Format percentage
|
|
252
|
+
*/
|
|
253
|
+
percent: (value: number, decimals = 1): string => {
|
|
254
|
+
return `${value.toFixed(decimals)}%`;
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Format number with thousand separators
|
|
259
|
+
*/
|
|
260
|
+
number: (value: number): string => {
|
|
261
|
+
return value.toLocaleString();
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Truncate string with ellipsis
|
|
266
|
+
*/
|
|
267
|
+
truncate: (str: string, maxLength: number): string => {
|
|
268
|
+
if (str.length <= maxLength) return str;
|
|
269
|
+
return str.slice(0, maxLength - 3) + '...';
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Format boolean as checkmark/cross
|
|
274
|
+
*/
|
|
275
|
+
boolean: (value: boolean): string => {
|
|
276
|
+
return value ? 'ā' : 'ā';
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// ============================================
|
|
281
|
+
// Export to CSV
|
|
282
|
+
// ============================================
|
|
283
|
+
|
|
284
|
+
export function exportToCSV(data: any[], filename = 'export.csv'): string {
|
|
285
|
+
if (data.length === 0) return '';
|
|
286
|
+
|
|
287
|
+
const headers = Object.keys(data[0]);
|
|
288
|
+
const csvContent = [
|
|
289
|
+
headers.join(','),
|
|
290
|
+
...data.map(row =>
|
|
291
|
+
headers.map(header => {
|
|
292
|
+
const value = row[header];
|
|
293
|
+
// Escape commas and quotes
|
|
294
|
+
if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
|
|
295
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
296
|
+
}
|
|
297
|
+
return value;
|
|
298
|
+
}).join(',')
|
|
299
|
+
),
|
|
300
|
+
].join('\n');
|
|
301
|
+
|
|
302
|
+
return csvContent;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ============================================
|
|
306
|
+
// Example Usage Functions
|
|
307
|
+
// ============================================
|
|
308
|
+
|
|
309
|
+
export function exampleUsage() {
|
|
310
|
+
console.log(chalk.bold.blue('\nš Jarvis Table Utilities Examples\n'));
|
|
311
|
+
|
|
312
|
+
// Example 1: Simple Data Table
|
|
313
|
+
console.log(chalk.yellow('1. Simple Data Table:'));
|
|
314
|
+
const users = [
|
|
315
|
+
{ id: 1, name: 'Alice', email: 'alice@example.com', role: 'Admin' },
|
|
316
|
+
{ id: 2, name: 'Bob', email: 'bob@example.com', role: 'User' },
|
|
317
|
+
{ id: 3, name: 'Carol', email: 'carol@example.com', role: 'Manager' },
|
|
318
|
+
];
|
|
319
|
+
createTable(users).print();
|
|
320
|
+
|
|
321
|
+
// Example 2: Comparison Table
|
|
322
|
+
console.log(chalk.yellow('\n2. Comparison Table:'));
|
|
323
|
+
const models = [
|
|
324
|
+
{ name: 'GPT-4', speed: 'āāā', cost: '$$$$', quality: 'āāāāā' },
|
|
325
|
+
{ name: 'Claude 3', speed: 'āāāā', cost: '$$$', quality: 'āāāāā' },
|
|
326
|
+
{ name: 'Gemini', speed: 'āāāā', cost: '$$', quality: 'āāāā' },
|
|
327
|
+
];
|
|
328
|
+
createComparisonTable(models, ['speed', 'cost', 'quality']).print();
|
|
329
|
+
|
|
330
|
+
// Example 3: Status Table
|
|
331
|
+
console.log(chalk.yellow('\n3. Status Table:'));
|
|
332
|
+
const services = [
|
|
333
|
+
{ name: 'API Server', status: 'online' as const, uptime: '99.9%' },
|
|
334
|
+
{ name: 'Database', status: 'online' as const, uptime: '99.8%' },
|
|
335
|
+
{ name: 'Cache', status: 'degraded' as const, uptime: '98.5%' },
|
|
336
|
+
];
|
|
337
|
+
createStatusTable(services).print();
|
|
338
|
+
|
|
339
|
+
// Example 4: Custom Formatted Table
|
|
340
|
+
console.log(chalk.yellow('\n4. Custom Formatted Table:'));
|
|
341
|
+
const files = [
|
|
342
|
+
{ name: 'document.pdf', size: 1048576, modified: new Date('2024-01-15') },
|
|
343
|
+
{ name: 'image.png', size: 524288, modified: new Date('2024-01-16') },
|
|
344
|
+
{ name: 'video.mp4', size: 10485760, modified: new Date('2024-01-17') },
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
const fileTable = new TerminalTable([
|
|
348
|
+
{ key: 'name', header: 'File Name' },
|
|
349
|
+
{ key: 'size', header: 'Size', align: 'right' },
|
|
350
|
+
{ key: 'modified', header: 'Modified' },
|
|
351
|
+
]);
|
|
352
|
+
|
|
353
|
+
fileTable.addRows(files.map(f => ({
|
|
354
|
+
name: f.name,
|
|
355
|
+
size: formatters.bytes(f.size),
|
|
356
|
+
modified: formatters.date(f.modified),
|
|
357
|
+
})));
|
|
358
|
+
|
|
359
|
+
fileTable.print();
|
|
360
|
+
|
|
361
|
+
console.log(chalk.green('\n⨠Examples Complete!\n'));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ============================================
|
|
365
|
+
// Performance Metrics Table
|
|
366
|
+
// ============================================
|
|
367
|
+
|
|
368
|
+
export function createMetricsTable(metrics: Array<{
|
|
369
|
+
metric: string;
|
|
370
|
+
value: number;
|
|
371
|
+
unit: string;
|
|
372
|
+
threshold?: number;
|
|
373
|
+
}>): TerminalTable {
|
|
374
|
+
const table = new TerminalTable([
|
|
375
|
+
{ key: 'metric', header: 'Metric' },
|
|
376
|
+
{ key: 'value', header: 'Value', align: 'right' },
|
|
377
|
+
{ key: 'unit', header: 'Unit' },
|
|
378
|
+
{ key: 'status', header: 'Status', align: 'center' },
|
|
379
|
+
]);
|
|
380
|
+
|
|
381
|
+
table.addRows(metrics.map(m => {
|
|
382
|
+
let status = 'ā';
|
|
383
|
+
if (m.threshold && m.value > m.threshold) {
|
|
384
|
+
status = chalk.yellow('ā ');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
metric: m.metric,
|
|
389
|
+
value: m.value,
|
|
390
|
+
unit: m.unit,
|
|
391
|
+
status,
|
|
392
|
+
};
|
|
393
|
+
}));
|
|
394
|
+
|
|
395
|
+
return table;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Run examples if this file is executed directly
|
|
399
|
+
if (import.meta.main) {
|
|
400
|
+
exampleUsage();
|
|
401
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { build } from 'bun';
|
|
2
|
+
|
|
3
|
+
async function buildUI() {
|
|
4
|
+
console.log('Building Web UI...');
|
|
5
|
+
|
|
6
|
+
const result = await build({
|
|
7
|
+
entrypoints: ['./src/web/ui/src/main.tsx'],
|
|
8
|
+
outdir: './src/web/ui/dist',
|
|
9
|
+
minify: true,
|
|
10
|
+
target: 'browser',
|
|
11
|
+
sourcemap: 'none',
|
|
12
|
+
naming: '[name].[ext]',
|
|
13
|
+
plugins: [],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
console.error('Build failed');
|
|
18
|
+
for (const message of result.logs) {
|
|
19
|
+
console.error(message);
|
|
20
|
+
}
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log('Build successful!');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
buildUI();
|