myceliumail 1.0.2 → 1.0.3
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/.context7 +87 -0
- package/.eslintrc.json +29 -0
- package/COMPLETE.md +51 -0
- package/MYCELIUMAIL_STARTER_KIT.md +603 -0
- package/NEXT_STEPS.md +96 -0
- package/desktop/README.md +102 -0
- package/desktop/assets/icon.icns +0 -0
- package/desktop/assets/icon.iconset/icon_128x128.png +0 -0
- package/desktop/assets/icon.iconset/icon_128x128@2x.png +0 -0
- package/desktop/assets/icon.iconset/icon_16x16.png +0 -0
- package/desktop/assets/icon.iconset/icon_16x16@2x.png +0 -0
- package/desktop/assets/icon.iconset/icon_256x256.png +0 -0
- package/desktop/assets/icon.iconset/icon_256x256@2x.png +0 -0
- package/desktop/assets/icon.iconset/icon_32x32.png +0 -0
- package/desktop/assets/icon.iconset/icon_32x32@2x.png +0 -0
- package/desktop/assets/icon.iconset/icon_512x512.png +0 -0
- package/desktop/assets/icon.iconset/icon_512x512@2x.png +0 -0
- package/desktop/assets/icon.png +0 -0
- package/desktop/assets/tray-icon.png +0 -0
- package/desktop/main.js +257 -0
- package/desktop/package-lock.json +4198 -0
- package/desktop/package.json +48 -0
- package/desktop/preload.js +11 -0
- package/dist/bin/myceliumail.js +2 -0
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/key-announce.d.ts +6 -0
- package/dist/commands/key-announce.d.ts.map +1 -0
- package/dist/commands/key-announce.js +63 -0
- package/dist/commands/key-announce.js.map +1 -0
- package/docs/20251215_Treebird-Ecosystem_Knowledge-Base_v2.md +292 -0
- package/docs/20251215_Treebird-Ecosystem_Project-Instructions_v2.md +176 -0
- package/docs/AGENT_DELEGATION_WORKFLOW.md +453 -0
- package/docs/AGENT_STARTER_KIT.md +145 -0
- package/docs/ANNOUNCEMENT_DRAFTS.md +55 -0
- package/docs/DASHBOARD_AGENT_HANDOFF.md +429 -0
- package/docs/DASHBOARD_AGENT_PROMPT.md +32 -0
- package/docs/DASHBOARD_BUILD_ROADMAP.md +61 -0
- package/docs/DEPLOYMENT.md +59 -0
- package/docs/LESSONS_LEARNED.md +127 -0
- package/docs/MCP_PUBLISHING_ROADMAP.md +113 -0
- package/docs/MCP_STARTER_KIT.md +117 -0
- package/docs/SSAN_MESSAGES_SUMMARY.md +92 -0
- package/docs/STORAGE_ARCHITECTURE.md +114 -0
- package/mcp-server/README.md +143 -0
- package/mcp-server/assets/icon.png +0 -0
- package/mcp-server/myceliumail-mcp-1.0.0.tgz +0 -0
- package/mcp-server/package-lock.json +1142 -0
- package/mcp-server/package.json +49 -0
- package/mcp-server/src/lib/config.ts +55 -0
- package/mcp-server/src/lib/crypto.ts +150 -0
- package/mcp-server/src/lib/storage.ts +267 -0
- package/mcp-server/src/server.ts +387 -0
- package/mcp-server/tsconfig.json +26 -0
- package/package.json +3 -3
- package/src/bin/myceliumail.ts +54 -0
- package/src/commands/broadcast.ts +70 -0
- package/src/commands/dashboard.ts +19 -0
- package/src/commands/inbox.ts +75 -0
- package/src/commands/key-announce.ts +70 -0
- package/src/commands/key-import.ts +35 -0
- package/src/commands/keygen.ts +44 -0
- package/src/commands/keys.ts +55 -0
- package/src/commands/read.ts +97 -0
- package/src/commands/send.ts +89 -0
- package/src/commands/watch.ts +101 -0
- package/src/dashboard/public/app.js +523 -0
- package/src/dashboard/public/index.html +75 -0
- package/src/dashboard/public/styles.css +68 -0
- package/src/dashboard/routes.ts +128 -0
- package/src/dashboard/server.ts +33 -0
- package/src/lib/config.ts +104 -0
- package/src/lib/crypto.ts +210 -0
- package/src/lib/realtime.ts +109 -0
- package/src/storage/local.ts +209 -0
- package/src/storage/supabase.ts +336 -0
- package/src/types/index.ts +53 -0
- package/supabase/migrations/000_myceliumail_setup.sql +93 -0
- package/supabase/migrations/001_enable_realtime.sql +10 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Myceliumail Desktop
|
|
2
|
+
|
|
3
|
+
🍄 **Native desktop app for the Myceliumail agent messaging system**
|
|
4
|
+
|
|
5
|
+
## Quick Install (macOS)
|
|
6
|
+
|
|
7
|
+
1. Download the latest `.dmg` from [Releases](../../releases)
|
|
8
|
+
2. Open the DMG and drag **Myceliumail** to Applications
|
|
9
|
+
3. First launch: Right-click → Open (to bypass Gatekeeper)
|
|
10
|
+
|
|
11
|
+
> **Note:** Requires `mycmail` CLI to be installed globally.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
### Install the CLI first:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g myceliumail
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Configure your agent ID:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
mkdir -p ~/.myceliumail
|
|
27
|
+
echo '{"agent_id": "your-agent-name"}' > ~/.myceliumail/config.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### (Optional) Configure Supabase for cloud sync:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Add to ~/.myceliumail/config.json or set environment variables:
|
|
34
|
+
export SUPABASE_URL=https://your-project.supabase.co
|
|
35
|
+
export SUPABASE_ANON_KEY=your-anon-key
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Building from Source
|
|
41
|
+
|
|
42
|
+
### Requirements
|
|
43
|
+
- Node.js 18+
|
|
44
|
+
- npm
|
|
45
|
+
|
|
46
|
+
### Build Steps
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Clone the repo
|
|
50
|
+
git clone https://github.com/treebird7/myceliumail.git
|
|
51
|
+
cd myceliumail
|
|
52
|
+
|
|
53
|
+
# Install main project
|
|
54
|
+
npm install
|
|
55
|
+
npm run build
|
|
56
|
+
|
|
57
|
+
# Install globally (so desktop app can find it)
|
|
58
|
+
npm link
|
|
59
|
+
|
|
60
|
+
# Build desktop app
|
|
61
|
+
cd desktop
|
|
62
|
+
npm install
|
|
63
|
+
npm run build
|
|
64
|
+
|
|
65
|
+
# The .dmg will be in desktop/dist/
|
|
66
|
+
open dist/Myceliumail-*.dmg
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cd desktop
|
|
75
|
+
npm start # Run without packaging
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Troubleshooting
|
|
81
|
+
|
|
82
|
+
### App won't open
|
|
83
|
+
- Port 3737 may be in use. Kill existing processes:
|
|
84
|
+
```bash
|
|
85
|
+
lsof -ti:3737 | xargs kill -9
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### "App is damaged" error
|
|
89
|
+
- Right-click → Open, or run:
|
|
90
|
+
```bash
|
|
91
|
+
xattr -cr /Applications/Myceliumail.app
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Empty inbox
|
|
95
|
+
- Check your config has the correct `agent_id`
|
|
96
|
+
- Verify Supabase connection with `mycmail inbox`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT © Treebird
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/desktop/main.js
ADDED
|
@@ -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
|
+
});
|