bashbros 0.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +453 -0
  3. package/dist/audit-MCFNGOIM.js +11 -0
  4. package/dist/audit-MCFNGOIM.js.map +1 -0
  5. package/dist/chunk-43W3RVEL.js +2910 -0
  6. package/dist/chunk-43W3RVEL.js.map +1 -0
  7. package/dist/chunk-4R4GV5V2.js +213 -0
  8. package/dist/chunk-4R4GV5V2.js.map +1 -0
  9. package/dist/chunk-7OCVIDC7.js +12 -0
  10. package/dist/chunk-7OCVIDC7.js.map +1 -0
  11. package/dist/chunk-CSRPOGHY.js +354 -0
  12. package/dist/chunk-CSRPOGHY.js.map +1 -0
  13. package/dist/chunk-DEAF6PYM.js +212 -0
  14. package/dist/chunk-DEAF6PYM.js.map +1 -0
  15. package/dist/chunk-DLP2O6PN.js +273 -0
  16. package/dist/chunk-DLP2O6PN.js.map +1 -0
  17. package/dist/chunk-GD5VNHIN.js +519 -0
  18. package/dist/chunk-GD5VNHIN.js.map +1 -0
  19. package/dist/chunk-ID2O2QTI.js +269 -0
  20. package/dist/chunk-ID2O2QTI.js.map +1 -0
  21. package/dist/chunk-J37RHCFJ.js +357 -0
  22. package/dist/chunk-J37RHCFJ.js.map +1 -0
  23. package/dist/chunk-SB4JS3GU.js +456 -0
  24. package/dist/chunk-SB4JS3GU.js.map +1 -0
  25. package/dist/chunk-SG752FZC.js +200 -0
  26. package/dist/chunk-SG752FZC.js.map +1 -0
  27. package/dist/cli.d.ts +2 -0
  28. package/dist/cli.js +2448 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/config-CZMIGNPF.js +13 -0
  31. package/dist/config-CZMIGNPF.js.map +1 -0
  32. package/dist/config-parser-XHE7BC7H.js +13 -0
  33. package/dist/config-parser-XHE7BC7H.js.map +1 -0
  34. package/dist/db-EHQDB5OL.js +11 -0
  35. package/dist/db-EHQDB5OL.js.map +1 -0
  36. package/dist/display-IN4NRJJS.js +18 -0
  37. package/dist/display-IN4NRJJS.js.map +1 -0
  38. package/dist/engine-PKLXW6OF.js +9 -0
  39. package/dist/engine-PKLXW6OF.js.map +1 -0
  40. package/dist/index.d.ts +1498 -0
  41. package/dist/index.js +552 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/moltbot-DXZFVK3X.js +11 -0
  44. package/dist/moltbot-DXZFVK3X.js.map +1 -0
  45. package/dist/ollama-HY35OHW4.js +9 -0
  46. package/dist/ollama-HY35OHW4.js.map +1 -0
  47. package/dist/risk-scorer-Y6KF2XCZ.js +9 -0
  48. package/dist/risk-scorer-Y6KF2XCZ.js.map +1 -0
  49. package/dist/static/index.html +410 -0
  50. package/package.json +68 -0
@@ -0,0 +1,410 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>BashBros Dashboard</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
16
+ background: #1a1a2e;
17
+ color: #eaeaea;
18
+ min-height: 100vh;
19
+ padding: 20px;
20
+ }
21
+
22
+ .header {
23
+ display: flex;
24
+ justify-content: space-between;
25
+ align-items: center;
26
+ margin-bottom: 30px;
27
+ padding-bottom: 20px;
28
+ border-bottom: 1px solid #2d2d44;
29
+ }
30
+
31
+ .header h1 {
32
+ font-size: 24px;
33
+ font-weight: 600;
34
+ color: #fff;
35
+ }
36
+
37
+ .connection-status {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 8px;
41
+ font-size: 14px;
42
+ color: #888;
43
+ }
44
+
45
+ .status-dot {
46
+ width: 10px;
47
+ height: 10px;
48
+ border-radius: 50%;
49
+ background: #666;
50
+ }
51
+
52
+ .status-dot.connected {
53
+ background: #4ade80;
54
+ }
55
+
56
+ .status-dot.disconnected {
57
+ background: #ef4444;
58
+ }
59
+
60
+ .stats-grid {
61
+ display: grid;
62
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
63
+ gap: 20px;
64
+ margin-bottom: 30px;
65
+ }
66
+
67
+ .stat-card {
68
+ background: #16213e;
69
+ border-radius: 12px;
70
+ padding: 20px;
71
+ border: 1px solid #2d2d44;
72
+ }
73
+
74
+ .stat-card .label {
75
+ font-size: 14px;
76
+ color: #888;
77
+ margin-bottom: 8px;
78
+ }
79
+
80
+ .stat-card .value {
81
+ font-size: 32px;
82
+ font-weight: 700;
83
+ color: #fff;
84
+ }
85
+
86
+ .stat-card.warning .value {
87
+ color: #fbbf24;
88
+ }
89
+
90
+ .stat-card.error .value {
91
+ color: #ef4444;
92
+ }
93
+
94
+ .stat-card.success .value {
95
+ color: #4ade80;
96
+ }
97
+
98
+ .section {
99
+ background: #16213e;
100
+ border-radius: 12px;
101
+ padding: 20px;
102
+ border: 1px solid #2d2d44;
103
+ margin-bottom: 20px;
104
+ }
105
+
106
+ .section h2 {
107
+ font-size: 18px;
108
+ font-weight: 600;
109
+ margin-bottom: 16px;
110
+ color: #fff;
111
+ }
112
+
113
+ .activity-list {
114
+ list-style: none;
115
+ }
116
+
117
+ .activity-item {
118
+ display: flex;
119
+ align-items: flex-start;
120
+ gap: 12px;
121
+ padding: 12px 0;
122
+ border-bottom: 1px solid #2d2d44;
123
+ }
124
+
125
+ .activity-item:last-child {
126
+ border-bottom: none;
127
+ }
128
+
129
+ .activity-icon {
130
+ width: 32px;
131
+ height: 32px;
132
+ border-radius: 8px;
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ font-size: 14px;
137
+ flex-shrink: 0;
138
+ }
139
+
140
+ .activity-icon.info {
141
+ background: #1e40af;
142
+ color: #60a5fa;
143
+ }
144
+
145
+ .activity-icon.warning {
146
+ background: #854d0e;
147
+ color: #fbbf24;
148
+ }
149
+
150
+ .activity-icon.error {
151
+ background: #7f1d1d;
152
+ color: #ef4444;
153
+ }
154
+
155
+ .activity-icon.debug {
156
+ background: #374151;
157
+ color: #9ca3af;
158
+ }
159
+
160
+ .activity-content {
161
+ flex: 1;
162
+ min-width: 0;
163
+ }
164
+
165
+ .activity-message {
166
+ font-size: 14px;
167
+ color: #eaeaea;
168
+ word-break: break-word;
169
+ }
170
+
171
+ .activity-meta {
172
+ display: flex;
173
+ gap: 16px;
174
+ margin-top: 4px;
175
+ font-size: 12px;
176
+ color: #666;
177
+ }
178
+
179
+ .activity-meta span {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 4px;
183
+ }
184
+
185
+ .empty-state {
186
+ text-align: center;
187
+ padding: 40px 20px;
188
+ color: #666;
189
+ }
190
+
191
+ .empty-state p {
192
+ font-size: 14px;
193
+ }
194
+ </style>
195
+ </head>
196
+ <body>
197
+ <div class="header">
198
+ <h1>BashBros Dashboard</h1>
199
+ <div class="connection-status">
200
+ <span class="status-dot" id="connectionDot"></span>
201
+ <span id="connectionText">Connecting...</span>
202
+ </div>
203
+ </div>
204
+
205
+ <div class="stats-grid">
206
+ <div class="stat-card">
207
+ <div class="label">Total Events</div>
208
+ <div class="value" id="totalEvents">0</div>
209
+ </div>
210
+ <div class="stat-card warning">
211
+ <div class="label">Pending Blocks</div>
212
+ <div class="value" id="pendingBlocks">0</div>
213
+ </div>
214
+ <div class="stat-card success">
215
+ <div class="label">Active Connectors</div>
216
+ <div class="value" id="activeConnectors">0</div>
217
+ </div>
218
+ <div class="stat-card error">
219
+ <div class="label">Errors</div>
220
+ <div class="value" id="errors">0</div>
221
+ </div>
222
+ </div>
223
+
224
+ <div class="section">
225
+ <h2>Recent Activity</h2>
226
+ <ul class="activity-list" id="activityList">
227
+ <li class="empty-state">
228
+ <p>No recent activity</p>
229
+ </li>
230
+ </ul>
231
+ </div>
232
+
233
+ <script>
234
+ // Dashboard state
235
+ let ws = null;
236
+ let reconnectTimeout = null;
237
+
238
+ // DOM elements
239
+ const connectionDot = document.getElementById('connectionDot');
240
+ const connectionText = document.getElementById('connectionText');
241
+ const totalEventsEl = document.getElementById('totalEvents');
242
+ const pendingBlocksEl = document.getElementById('pendingBlocks');
243
+ const activeConnectorsEl = document.getElementById('activeConnectors');
244
+ const errorsEl = document.getElementById('errors');
245
+ const activityList = document.getElementById('activityList');
246
+
247
+ // Update connection status
248
+ function setConnectionStatus(connected) {
249
+ connectionDot.className = 'status-dot ' + (connected ? 'connected' : 'disconnected');
250
+ connectionText.textContent = connected ? 'Connected' : 'Disconnected';
251
+ }
252
+
253
+ // Update stats display
254
+ function updateStats(stats) {
255
+ totalEventsEl.textContent = stats.totalEvents || 0;
256
+ pendingBlocksEl.textContent = stats.pendingBlocks || 0;
257
+ activeConnectorsEl.textContent = stats.connectorCount || 0;
258
+ errorsEl.textContent = (stats.eventsByLevel && stats.eventsByLevel.error) || 0;
259
+ }
260
+
261
+ // Format timestamp
262
+ function formatTime(timestamp) {
263
+ const date = new Date(timestamp);
264
+ return date.toLocaleTimeString();
265
+ }
266
+
267
+ // Get icon class based on level
268
+ function getIconClass(level) {
269
+ switch (level) {
270
+ case 'error': return 'error';
271
+ case 'warning': return 'warning';
272
+ case 'debug': return 'debug';
273
+ default: return 'info';
274
+ }
275
+ }
276
+
277
+ // Get icon symbol based on level
278
+ function getIconSymbol(level) {
279
+ switch (level) {
280
+ case 'error': return '!';
281
+ case 'warning': return '!';
282
+ case 'debug': return '#';
283
+ default: return 'i';
284
+ }
285
+ }
286
+
287
+ // Update activity list
288
+ function updateActivity(events) {
289
+ if (!events || events.length === 0) {
290
+ activityList.innerHTML = '<li class="empty-state"><p>No recent activity</p></li>';
291
+ return;
292
+ }
293
+
294
+ activityList.innerHTML = events.slice(0, 20).map(event => `
295
+ <li class="activity-item">
296
+ <div class="activity-icon ${getIconClass(event.level)}">
297
+ ${getIconSymbol(event.level)}
298
+ </div>
299
+ <div class="activity-content">
300
+ <div class="activity-message">${escapeHtml(event.message)}</div>
301
+ <div class="activity-meta">
302
+ <span>${event.source}</span>
303
+ <span>${event.category}</span>
304
+ <span>${formatTime(event.timestamp)}</span>
305
+ </div>
306
+ </div>
307
+ </li>
308
+ `).join('');
309
+ }
310
+
311
+ // Escape HTML to prevent XSS
312
+ function escapeHtml(text) {
313
+ const div = document.createElement('div');
314
+ div.textContent = text;
315
+ return div.innerHTML;
316
+ }
317
+
318
+ // Fetch stats from API
319
+ async function fetchStats() {
320
+ try {
321
+ const response = await fetch('/api/stats');
322
+ if (response.ok) {
323
+ const stats = await response.json();
324
+ updateStats(stats);
325
+ }
326
+ } catch (error) {
327
+ console.error('Failed to fetch stats:', error);
328
+ }
329
+ }
330
+
331
+ // Fetch events from API
332
+ async function fetchEvents() {
333
+ try {
334
+ const response = await fetch('/api/events?limit=20');
335
+ if (response.ok) {
336
+ const events = await response.json();
337
+ updateActivity(events);
338
+ }
339
+ } catch (error) {
340
+ console.error('Failed to fetch events:', error);
341
+ }
342
+ }
343
+
344
+ // Connect to WebSocket
345
+ function connectWebSocket() {
346
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
347
+ const wsUrl = `${protocol}//${window.location.host}`;
348
+
349
+ try {
350
+ ws = new WebSocket(wsUrl);
351
+
352
+ ws.onopen = function() {
353
+ setConnectionStatus(true);
354
+ if (reconnectTimeout) {
355
+ clearTimeout(reconnectTimeout);
356
+ reconnectTimeout = null;
357
+ }
358
+ };
359
+
360
+ ws.onmessage = function(event) {
361
+ try {
362
+ const message = JSON.parse(event.data);
363
+ if (message.type === 'stats') {
364
+ updateStats(message.data);
365
+ } else if (message.type === 'event') {
366
+ fetchEvents();
367
+ fetchStats();
368
+ } else if (message.type === 'block-approved' || message.type === 'block-denied') {
369
+ fetchStats();
370
+ }
371
+ } catch (error) {
372
+ console.error('Failed to parse WebSocket message:', error);
373
+ }
374
+ };
375
+
376
+ ws.onclose = function() {
377
+ setConnectionStatus(false);
378
+ ws = null;
379
+ // Attempt to reconnect after 5 seconds
380
+ reconnectTimeout = setTimeout(connectWebSocket, 5000);
381
+ };
382
+
383
+ ws.onerror = function() {
384
+ setConnectionStatus(false);
385
+ };
386
+ } catch (error) {
387
+ console.error('Failed to connect WebSocket:', error);
388
+ setConnectionStatus(false);
389
+ reconnectTimeout = setTimeout(connectWebSocket, 5000);
390
+ }
391
+ }
392
+
393
+ // Initialize dashboard
394
+ function init() {
395
+ fetchStats();
396
+ fetchEvents();
397
+ connectWebSocket();
398
+
399
+ // Auto-refresh every 30 seconds
400
+ setInterval(() => {
401
+ fetchStats();
402
+ fetchEvents();
403
+ }, 30000);
404
+ }
405
+
406
+ // Start when DOM is ready
407
+ document.addEventListener('DOMContentLoaded', init);
408
+ </script>
409
+ </body>
410
+ </html>
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "bashbros",
3
+ "version": "0.1.0",
4
+ "description": "The Bash Agent Helper",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "bashbros": "dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup && npm run copy-static",
18
+ "copy-static": "node -e \"const fs=require('fs');fs.mkdirSync('dist/static',{recursive:true});fs.cpSync('src/dashboard/static','dist/static',{recursive:true})\"",
19
+ "dev": "tsup --watch",
20
+ "test": "vitest",
21
+ "lint": "eslint src/",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "bash",
26
+ "cli",
27
+ "agent",
28
+ "security",
29
+ "pty",
30
+ "claude",
31
+ "ai",
32
+ "automation"
33
+ ],
34
+ "author": "GhostPeony",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/GhostPeony/bashbros.git"
39
+ },
40
+ "homepage": "https://bashbros.ai",
41
+ "bugs": {
42
+ "url": "https://github.com/GhostPeony/bashbros/issues"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "better-sqlite3": "^12.6.2",
49
+ "chalk": "^5.3.0",
50
+ "commander": "^12.1.0",
51
+ "express": "^5.2.1",
52
+ "inquirer": "^9.2.0",
53
+ "node-pty": "^1.0.0",
54
+ "winston": "^3.13.0",
55
+ "ws": "^8.19.0",
56
+ "yaml": "^2.4.0"
57
+ },
58
+ "devDependencies": {
59
+ "@types/better-sqlite3": "^7.6.13",
60
+ "@types/express": "^5.0.6",
61
+ "@types/node": "^20.0.0",
62
+ "@types/ws": "^8.18.1",
63
+ "eslint": "^9.0.0",
64
+ "tsup": "^8.0.0",
65
+ "typescript": "^5.4.0",
66
+ "vitest": "^1.6.0"
67
+ }
68
+ }