myceliumail 1.0.2 → 1.0.4

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 (69) hide show
  1. package/.context7 +87 -0
  2. package/.eslintrc.json +29 -0
  3. package/.github/workflows/publish.yml +108 -0
  4. package/CHANGELOG.md +85 -0
  5. package/README.md +295 -162
  6. package/desktop/README.md +102 -0
  7. package/desktop/assets/icon.icns +0 -0
  8. package/desktop/assets/icon.iconset/icon_128x128.png +0 -0
  9. package/desktop/assets/icon.iconset/icon_128x128@2x.png +0 -0
  10. package/desktop/assets/icon.iconset/icon_16x16.png +0 -0
  11. package/desktop/assets/icon.iconset/icon_16x16@2x.png +0 -0
  12. package/desktop/assets/icon.iconset/icon_256x256.png +0 -0
  13. package/desktop/assets/icon.iconset/icon_256x256@2x.png +0 -0
  14. package/desktop/assets/icon.iconset/icon_32x32.png +0 -0
  15. package/desktop/assets/icon.iconset/icon_32x32@2x.png +0 -0
  16. package/desktop/assets/icon.iconset/icon_512x512.png +0 -0
  17. package/desktop/assets/icon.iconset/icon_512x512@2x.png +0 -0
  18. package/desktop/assets/icon.png +0 -0
  19. package/desktop/assets/tray-icon.png +0 -0
  20. package/desktop/main.js +257 -0
  21. package/desktop/package-lock.json +4198 -0
  22. package/desktop/package.json +48 -0
  23. package/desktop/preload.js +11 -0
  24. package/dist/bin/myceliumail.js +2 -0
  25. package/dist/bin/myceliumail.js.map +1 -1
  26. package/dist/commands/key-announce.d.ts +6 -0
  27. package/dist/commands/key-announce.d.ts.map +1 -0
  28. package/dist/commands/key-announce.js +63 -0
  29. package/dist/commands/key-announce.js.map +1 -0
  30. package/docs/AGENT_STARTER_KIT.md +145 -0
  31. package/docs/DEPLOYMENT.md +59 -0
  32. package/docs/LESSONS_LEARNED.md +127 -0
  33. package/docs/MCP_STARTER_KIT.md +117 -0
  34. package/mcp-server/README.md +143 -0
  35. package/mcp-server/assets/icon.png +0 -0
  36. package/mcp-server/myceliumail-mcp-1.0.0.tgz +0 -0
  37. package/mcp-server/package-lock.json +1141 -0
  38. package/mcp-server/package.json +50 -0
  39. package/mcp-server/src/lib/config.ts +55 -0
  40. package/mcp-server/src/lib/crypto.ts +150 -0
  41. package/mcp-server/src/lib/storage.ts +267 -0
  42. package/mcp-server/src/server.ts +387 -0
  43. package/mcp-server/tsconfig.json +26 -0
  44. package/package.json +13 -4
  45. package/src/bin/myceliumail.ts +54 -0
  46. package/src/commands/broadcast.ts +70 -0
  47. package/src/commands/dashboard.ts +19 -0
  48. package/src/commands/inbox.ts +75 -0
  49. package/src/commands/key-announce.ts +70 -0
  50. package/src/commands/key-import.ts +35 -0
  51. package/src/commands/keygen.ts +44 -0
  52. package/src/commands/keys.ts +55 -0
  53. package/src/commands/read.ts +97 -0
  54. package/src/commands/send.ts +89 -0
  55. package/src/commands/watch.ts +101 -0
  56. package/src/dashboard/public/app.js +523 -0
  57. package/src/dashboard/public/index.html +75 -0
  58. package/src/dashboard/public/styles.css +68 -0
  59. package/src/dashboard/routes.ts +128 -0
  60. package/src/dashboard/server.ts +33 -0
  61. package/src/lib/config.ts +104 -0
  62. package/src/lib/crypto.ts +210 -0
  63. package/src/lib/realtime.ts +109 -0
  64. package/src/storage/local.ts +209 -0
  65. package/src/storage/supabase.ts +336 -0
  66. package/src/types/index.ts +53 -0
  67. package/supabase/migrations/000_myceliumail_setup.sql +93 -0
  68. package/supabase/migrations/001_enable_realtime.sql +10 -0
  69. package/tsconfig.json +28 -0
@@ -0,0 +1,257 @@
1
+ const { app, BrowserWindow, Menu, Tray, shell, Notification } = require('electron');
2
+ const { spawn } = require('child_process');
3
+ const path = require('path');
4
+ const { createClient } = require('@supabase/supabase-js');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+
8
+ let mainWindow;
9
+ let tray;
10
+ let dashboardProcess;
11
+ let supabaseClient;
12
+ let realtimeChannel;
13
+ const DASHBOARD_PORT = 3737;
14
+
15
+ // Load config from ~/.myceliumail/config.json
16
+ function loadConfig() {
17
+ const configPath = path.join(os.homedir(), '.myceliumail', 'config.json');
18
+ try {
19
+ if (fs.existsSync(configPath)) {
20
+ const raw = fs.readFileSync(configPath, 'utf-8');
21
+ return JSON.parse(raw);
22
+ }
23
+ } catch (err) {
24
+ console.error('Failed to load config:', err);
25
+ }
26
+ return {};
27
+ }
28
+
29
+ // Setup Supabase Realtime subscription
30
+ function setupRealtimeNotifications(config) {
31
+ if (!config.supabase_url || !config.supabase_key) {
32
+ console.log('Supabase not configured, skipping realtime notifications');
33
+ return;
34
+ }
35
+
36
+ const agentId = config.agent_id || 'anonymous';
37
+ console.log(`🍄 Setting up Realtime notifications for ${agentId}...`);
38
+
39
+ supabaseClient = createClient(config.supabase_url, config.supabase_key, {
40
+ realtime: {
41
+ params: { eventsPerSecond: 10 }
42
+ }
43
+ });
44
+
45
+ realtimeChannel = supabaseClient
46
+ .channel('desktop-notifications')
47
+ .on(
48
+ 'postgres_changes',
49
+ {
50
+ event: 'INSERT',
51
+ schema: 'public',
52
+ table: 'agent_messages',
53
+ filter: `to_agent=eq.${agentId}`
54
+ },
55
+ (payload) => {
56
+ const message = payload.new;
57
+ showNotification(message);
58
+ }
59
+ )
60
+ .subscribe((status, err) => {
61
+ if (status === 'SUBSCRIBED') {
62
+ console.log('✅ Connected to Supabase Realtime');
63
+ } else if (status === 'CHANNEL_ERROR') {
64
+ console.error('❌ Realtime channel error:', err);
65
+ }
66
+ });
67
+ }
68
+
69
+ // Show native Electron notification
70
+ function showNotification(message) {
71
+ const preview = message.encrypted
72
+ ? '🔒 Encrypted message'
73
+ : message.message?.substring(0, 100) || '';
74
+
75
+ const notification = new Notification({
76
+ title: `📬 ${message.from_agent}: ${message.subject}`,
77
+ body: preview,
78
+ silent: false,
79
+ urgency: 'normal'
80
+ });
81
+
82
+ notification.on('click', () => {
83
+ if (mainWindow) {
84
+ mainWindow.show();
85
+ mainWindow.focus();
86
+ }
87
+ });
88
+
89
+ notification.show();
90
+ console.log(`📬 Notification: ${message.from_agent} - ${message.subject}`);
91
+ }
92
+
93
+ // Wait for dashboard to be ready
94
+ function waitForDashboard(url, timeout = 15000) {
95
+ return new Promise((resolve, reject) => {
96
+ const startTime = Date.now();
97
+
98
+ const check = () => {
99
+ const http = require('http');
100
+ // Use 127.0.0.1 to match the server binding
101
+ const checkUrl = url.replace('localhost', '127.0.0.1');
102
+ const req = http.get(checkUrl, (res) => {
103
+ resolve(true);
104
+ });
105
+ req.on('error', () => {
106
+ if (Date.now() - startTime > timeout) {
107
+ reject(new Error('Dashboard startup timeout'));
108
+ } else {
109
+ setTimeout(check, 300);
110
+ }
111
+ });
112
+ req.end();
113
+ };
114
+
115
+ // Give the server a moment to start
116
+ setTimeout(check, 500);
117
+ });
118
+ }
119
+
120
+ // Start the dashboard server
121
+ function startDashboard() {
122
+ return new Promise((resolve, reject) => {
123
+ const mycmailCmd = process.platform === 'win32' ? 'mycmail.cmd' : 'mycmail';
124
+
125
+ console.log('🍄 Starting Myceliumail dashboard...');
126
+
127
+ dashboardProcess = spawn(mycmailCmd, ['dashboard'], {
128
+ env: { ...process.env },
129
+ shell: true,
130
+ detached: false
131
+ });
132
+
133
+ dashboardProcess.stdout.on('data', (data) => {
134
+ console.log(`Dashboard: ${data}`);
135
+ });
136
+
137
+ dashboardProcess.stderr.on('data', (data) => {
138
+ console.error(`Dashboard error: ${data}`);
139
+ });
140
+
141
+ dashboardProcess.on('error', (err) => {
142
+ console.error('Failed to start dashboard:', err);
143
+ reject(err);
144
+ });
145
+
146
+ waitForDashboard(`http://localhost:${DASHBOARD_PORT}`)
147
+ .then(resolve)
148
+ .catch(reject);
149
+ });
150
+ }
151
+
152
+ function createWindow() {
153
+ mainWindow = new BrowserWindow({
154
+ width: 1200,
155
+ height: 800,
156
+ minWidth: 800,
157
+ minHeight: 600,
158
+ title: 'Myceliumail',
159
+ icon: path.join(__dirname, 'assets', 'icon.png'),
160
+ webPreferences: {
161
+ nodeIntegration: false,
162
+ contextIsolation: true,
163
+ preload: path.join(__dirname, 'preload.js')
164
+ },
165
+ titleBarStyle: 'hiddenInset',
166
+ backgroundColor: '#030712',
167
+ });
168
+
169
+ mainWindow.loadURL(`http://127.0.0.1:${DASHBOARD_PORT}`);
170
+ mainWindow.webContents.setZoomFactor(0.9);
171
+
172
+ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
173
+ shell.openExternal(url);
174
+ return { action: 'deny' };
175
+ });
176
+
177
+ mainWindow.on('closed', () => {
178
+ mainWindow = null;
179
+ });
180
+
181
+ mainWindow.on('close', (event) => {
182
+ if (!app.isQuitting) {
183
+ event.preventDefault();
184
+ mainWindow.hide();
185
+ }
186
+ });
187
+ }
188
+
189
+ function createTray() {
190
+ tray = new Tray(path.join(__dirname, 'assets', 'tray-icon.png'));
191
+
192
+ const contextMenu = Menu.buildFromTemplate([
193
+ {
194
+ label: 'Open Myceliumail',
195
+ click: () => mainWindow.show()
196
+ },
197
+ { type: 'separator' },
198
+ {
199
+ label: 'Quit',
200
+ click: () => {
201
+ app.isQuitting = true;
202
+ app.quit();
203
+ }
204
+ }
205
+ ]);
206
+
207
+ tray.setToolTip('Myceliumail');
208
+ tray.setContextMenu(contextMenu);
209
+
210
+ tray.on('click', () => {
211
+ mainWindow.show();
212
+ });
213
+ }
214
+
215
+ app.whenReady().then(async () => {
216
+ try {
217
+ // Load config and setup notifications
218
+ const config = loadConfig();
219
+ setupRealtimeNotifications(config);
220
+
221
+ await startDashboard();
222
+ createWindow();
223
+ // createTray(); // Uncomment to enable tray icon
224
+
225
+ app.on('activate', () => {
226
+ if (mainWindow === null) {
227
+ createWindow();
228
+ } else {
229
+ mainWindow.show();
230
+ }
231
+ });
232
+ } catch (err) {
233
+ console.error('Failed to start:', err);
234
+ app.quit();
235
+ }
236
+ });
237
+
238
+ app.on('window-all-closed', () => {
239
+ if (process.platform !== 'darwin') {
240
+ app.quit();
241
+ }
242
+ });
243
+
244
+ app.on('before-quit', () => {
245
+ app.isQuitting = true;
246
+
247
+ // Cleanup realtime subscription
248
+ if (realtimeChannel && supabaseClient) {
249
+ supabaseClient.removeChannel(realtimeChannel);
250
+ }
251
+
252
+ // Kill the dashboard process
253
+ if (dashboardProcess) {
254
+ console.log('Stopping dashboard...');
255
+ dashboardProcess.kill();
256
+ }
257
+ });