myceliumail 1.0.9 β 1.0.13
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/.mappersan/outbox.json +15 -0
- package/.spidersan/registry.json +39 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +29 -0
- package/README.md +23 -2
- package/dist/bin/myceliumail.js +17 -1
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/close.d.ts +9 -0
- package/dist/commands/close.d.ts.map +1 -0
- package/dist/commands/close.js +153 -0
- package/dist/commands/close.js.map +1 -0
- package/dist/commands/collab.d.ts +8 -0
- package/dist/commands/collab.d.ts.map +1 -0
- package/dist/commands/collab.js +112 -0
- package/dist/commands/collab.js.map +1 -0
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +105 -26
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/tags.d.ts +6 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +90 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/wake.d.ts +9 -0
- package/dist/commands/wake.d.ts.map +1 -0
- package/dist/commands/wake.js +198 -0
- package/dist/commands/wake.js.map +1 -0
- package/dist/dashboard/public/app.js +117 -0
- package/dist/dashboard/public/index.html +63 -5
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +31 -2
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/lib/update-check.d.ts.map +1 -1
- package/dist/lib/update-check.js +6 -4
- package/dist/lib/update-check.js.map +1 -1
- package/dist/lib/watson-digest.d.ts +40 -0
- package/dist/lib/watson-digest.d.ts.map +1 -0
- package/dist/lib/watson-digest.js +164 -0
- package/dist/lib/watson-digest.js.map +1 -0
- package/dist/storage/supabase.d.ts +4 -0
- package/dist/storage/supabase.d.ts.map +1 -1
- package/dist/storage/supabase.js +57 -0
- package/dist/storage/supabase.js.map +1 -1
- package/docs/COLLAB_mappersan_mycmail_setup.md +115 -0
- package/docs/COLLAB_wake_close_commands.md +518 -0
- package/docs/CROSS_TOOL_INTEGRATION_PLAN.md +246 -0
- package/docs/JSON_SCHEMA_WAKE_CLOSE.md +246 -0
- package/docs/MYCMAIL_QUICKSTART.md +103 -0
- package/docs/WAKE_AGENTS_SHARED_DOC.md +1215 -0
- package/mcp-server/README.md +75 -69
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +5 -1
- package/mcp-server/postinstall.js +14 -0
- package/mcp-server/src/server.ts +39 -0
- package/mobile-app/README.md +36 -0
- package/mobile-app/app/compose/page.tsx +140 -0
- package/mobile-app/app/favicon.ico +0 -0
- package/mobile-app/app/globals.css +26 -0
- package/mobile-app/app/layout.tsx +42 -0
- package/mobile-app/app/message/[id]/page.tsx +126 -0
- package/mobile-app/app/page.tsx +131 -0
- package/mobile-app/components/MessageCard.tsx +60 -0
- package/mobile-app/eslint.config.mjs +18 -0
- package/mobile-app/lib/supabase.ts +87 -0
- package/mobile-app/next.config.ts +7 -0
- package/mobile-app/package-lock.json +6674 -0
- package/mobile-app/package.json +27 -0
- package/mobile-app/postcss.config.mjs +7 -0
- package/mobile-app/public/file.svg +1 -0
- package/mobile-app/public/globe.svg +1 -0
- package/mobile-app/public/next.svg +1 -0
- package/mobile-app/public/vercel.svg +1 -0
- package/mobile-app/public/window.svg +1 -0
- package/mobile-app/tsconfig.json +34 -0
- package/package.json +2 -1
- package/postinstall.js +14 -0
- package/src/bin/myceliumail.ts +19 -1
- package/src/commands/close.ts +172 -0
- package/src/commands/collab.ts +125 -0
- package/src/commands/inbox.ts +120 -29
- package/src/commands/tags.ts +102 -0
- package/src/commands/wake.ts +228 -0
- package/src/dashboard/public/app.js +117 -0
- package/src/dashboard/public/index.html +63 -5
- package/src/dashboard/routes.ts +31 -2
- package/src/lib/update-check.ts +7 -4
- package/src/lib/watson-digest.ts +217 -0
- package/src/storage/supabase.ts +71 -0
- package/vscode-extension/README.md +107 -0
- package/vscode-extension/package-lock.json +1941 -0
- package/vscode-extension/package.json +117 -0
- package/vscode-extension/src/chatParticipant.ts +179 -0
- package/vscode-extension/src/extension.ts +262 -0
- package/vscode-extension/src/handlers.ts +265 -0
- package/vscode-extension/src/realtime.ts +302 -0
- package/vscode-extension/src/types.ts +41 -0
- package/vscode-extension/tsconfig.json +26 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watson Digest - Generate and send summary reports to watsan
|
|
3
|
+
*
|
|
4
|
+
* Creates summarized digests of unread messages and collaboration docs
|
|
5
|
+
* to keep the orchestrator informed.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { loadConfig, Config } from './config.js';
|
|
9
|
+
import { loadKeyPair, decryptMessage } from './crypto.js';
|
|
10
|
+
import * as storage from '../storage/supabase.js';
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import * as os from 'os';
|
|
14
|
+
|
|
15
|
+
interface DigestMessage {
|
|
16
|
+
from: string;
|
|
17
|
+
subject: string;
|
|
18
|
+
preview: string;
|
|
19
|
+
tag?: string;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface DigestReport {
|
|
24
|
+
type: 'wake' | 'close';
|
|
25
|
+
agentId: string;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
inbox: {
|
|
28
|
+
total: number;
|
|
29
|
+
unread: number;
|
|
30
|
+
};
|
|
31
|
+
urgentMessages: DigestMessage[];
|
|
32
|
+
taggedMessages: DigestMessage[];
|
|
33
|
+
activeCollabs: string[];
|
|
34
|
+
sessionDuration?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Extract hashtag from subject line
|
|
39
|
+
*/
|
|
40
|
+
function extractTag(subject: string | null): string | null {
|
|
41
|
+
if (!subject) return null;
|
|
42
|
+
const match = subject.match(/^#([a-zA-Z0-9_-]+):/);
|
|
43
|
+
return match ? match[1].toLowerCase() : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get preview of message body (first 100 chars)
|
|
48
|
+
*/
|
|
49
|
+
function getPreview(body: string | null): string {
|
|
50
|
+
if (!body) return '(no body)';
|
|
51
|
+
const clean = body.replace(/\n/g, ' ').trim();
|
|
52
|
+
return clean.length > 100 ? clean.slice(0, 97) + '...' : clean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generate a digest of unread messages
|
|
57
|
+
*/
|
|
58
|
+
export async function generateDigest(
|
|
59
|
+
agentId: string,
|
|
60
|
+
type: 'wake' | 'close',
|
|
61
|
+
sessionDuration?: string
|
|
62
|
+
): Promise<DigestReport> {
|
|
63
|
+
const keyPair = loadKeyPair(agentId);
|
|
64
|
+
const messages = await storage.getInbox(agentId, { limit: 100 });
|
|
65
|
+
const unreadMessages = messages.filter(m => !m.read);
|
|
66
|
+
|
|
67
|
+
const urgentMessages: DigestMessage[] = [];
|
|
68
|
+
const taggedMessages: DigestMessage[] = [];
|
|
69
|
+
|
|
70
|
+
for (const msg of unreadMessages.slice(0, 20)) { // Cap at 20 for digest
|
|
71
|
+
let subject = msg.subject || '(no subject)';
|
|
72
|
+
let body = msg.body || '';
|
|
73
|
+
|
|
74
|
+
// Decrypt if needed
|
|
75
|
+
if (msg.encrypted && keyPair && msg.ciphertext && msg.nonce && msg.senderPublicKey) {
|
|
76
|
+
try {
|
|
77
|
+
const decrypted = decryptMessage({
|
|
78
|
+
ciphertext: msg.ciphertext,
|
|
79
|
+
nonce: msg.nonce,
|
|
80
|
+
senderPublicKey: msg.senderPublicKey,
|
|
81
|
+
}, keyPair);
|
|
82
|
+
|
|
83
|
+
if (decrypted) {
|
|
84
|
+
const parsed = JSON.parse(decrypted);
|
|
85
|
+
subject = parsed.subject || subject;
|
|
86
|
+
body = parsed.body || body;
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
// Keep original
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const tag = extractTag(subject);
|
|
94
|
+
const digestMsg: DigestMessage = {
|
|
95
|
+
from: msg.sender || 'unknown',
|
|
96
|
+
subject,
|
|
97
|
+
preview: getPreview(body),
|
|
98
|
+
tag: tag || undefined,
|
|
99
|
+
timestamp: msg.createdAt?.toISOString() || new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Categorize: urgent keywords or tagged
|
|
103
|
+
const isUrgent = /urgent|important|asap|critical|blocked/i.test(subject + body);
|
|
104
|
+
if (isUrgent) {
|
|
105
|
+
urgentMessages.push(digestMsg);
|
|
106
|
+
} else if (tag) {
|
|
107
|
+
taggedMessages.push(digestMsg);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Load session for active collabs
|
|
112
|
+
const sessionPath = path.join(os.homedir(), '.mycmail', 'session.json');
|
|
113
|
+
let activeCollabs: string[] = [];
|
|
114
|
+
try {
|
|
115
|
+
if (fs.existsSync(sessionPath)) {
|
|
116
|
+
const session = JSON.parse(fs.readFileSync(sessionPath, 'utf-8'));
|
|
117
|
+
activeCollabs = session.activeCollabs || [];
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// Ignore
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
type,
|
|
125
|
+
agentId,
|
|
126
|
+
timestamp: new Date().toISOString(),
|
|
127
|
+
inbox: {
|
|
128
|
+
total: messages.length,
|
|
129
|
+
unread: unreadMessages.length
|
|
130
|
+
},
|
|
131
|
+
urgentMessages,
|
|
132
|
+
taggedMessages,
|
|
133
|
+
activeCollabs,
|
|
134
|
+
sessionDuration
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Format digest as readable text for watsan
|
|
140
|
+
*/
|
|
141
|
+
export function formatDigestText(digest: DigestReport): string {
|
|
142
|
+
const lines: string[] = [];
|
|
143
|
+
|
|
144
|
+
lines.push(`π MYCM ${digest.type.toUpperCase()} DIGEST`);
|
|
145
|
+
lines.push(`Time: ${new Date(digest.timestamp).toLocaleString()}`);
|
|
146
|
+
lines.push(`Inbox: ${digest.inbox.unread} unread / ${digest.inbox.total} total`);
|
|
147
|
+
|
|
148
|
+
if (digest.sessionDuration) {
|
|
149
|
+
lines.push(`Session: ${digest.sessionDuration}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (digest.urgentMessages.length > 0) {
|
|
153
|
+
lines.push('');
|
|
154
|
+
lines.push('π¨ URGENT:');
|
|
155
|
+
for (const msg of digest.urgentMessages.slice(0, 5)) {
|
|
156
|
+
lines.push(` β’ ${msg.from}: ${msg.subject}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (digest.taggedMessages.length > 0) {
|
|
161
|
+
lines.push('');
|
|
162
|
+
lines.push('π·οΈ TAGGED:');
|
|
163
|
+
for (const msg of digest.taggedMessages.slice(0, 5)) {
|
|
164
|
+
lines.push(` β’ ${msg.from}: ${msg.subject}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (digest.activeCollabs.length > 0) {
|
|
169
|
+
lines.push('');
|
|
170
|
+
lines.push('π ACTIVE COLLABS:');
|
|
171
|
+
for (const collab of digest.activeCollabs) {
|
|
172
|
+
lines.push(` β’ ${collab}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (digest.urgentMessages.length === 0 && digest.taggedMessages.length === 0) {
|
|
177
|
+
lines.push('');
|
|
178
|
+
lines.push('β
No urgent or tagged messages');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return lines.join('\n');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Send digest to watson (unencrypted) and wsan (encrypted)
|
|
186
|
+
*/
|
|
187
|
+
export async function sendDigestToWatsan(digest: DigestReport): Promise<void> {
|
|
188
|
+
const config = loadConfig();
|
|
189
|
+
const content = formatDigestText(digest);
|
|
190
|
+
const subject = `[DIGEST] ${digest.agentId} ${digest.type} @ ${new Date().toLocaleTimeString()}`;
|
|
191
|
+
|
|
192
|
+
// Send to watson (unencrypted)
|
|
193
|
+
try {
|
|
194
|
+
await storage.sendMessage(
|
|
195
|
+
digest.agentId,
|
|
196
|
+
'watson',
|
|
197
|
+
subject,
|
|
198
|
+
content,
|
|
199
|
+
{ encrypted: false }
|
|
200
|
+
);
|
|
201
|
+
} catch {
|
|
202
|
+
// Silent fail
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Send to wsan (encrypted - archiver)
|
|
206
|
+
try {
|
|
207
|
+
await storage.sendMessage(
|
|
208
|
+
digest.agentId,
|
|
209
|
+
'wsan',
|
|
210
|
+
subject,
|
|
211
|
+
content,
|
|
212
|
+
{ encrypted: true }
|
|
213
|
+
);
|
|
214
|
+
} catch {
|
|
215
|
+
// Silent fail
|
|
216
|
+
}
|
|
217
|
+
}
|
package/src/storage/supabase.ts
CHANGED
|
@@ -220,6 +220,77 @@ export async function getInbox(agentId: string, options?: InboxOptions): Promise
|
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Get inbox messages for multiple agents from Supabase
|
|
225
|
+
*/
|
|
226
|
+
export async function getMultiAgentInbox(agentIds: string[], options?: InboxOptions): Promise<Message[]> {
|
|
227
|
+
const client = createClient();
|
|
228
|
+
|
|
229
|
+
if (!client || agentIds.length === 0) {
|
|
230
|
+
// For local storage, aggregate from all agents
|
|
231
|
+
if (agentIds.length === 0) return [];
|
|
232
|
+
const allMessages: Message[] = [];
|
|
233
|
+
for (const agentId of agentIds) {
|
|
234
|
+
const msgs = await local.getInbox(agentId, options);
|
|
235
|
+
allMessages.push(...msgs);
|
|
236
|
+
}
|
|
237
|
+
// Sort by date descending and apply limit
|
|
238
|
+
allMessages.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
239
|
+
return options?.limit ? allMessages.slice(0, options.limit) : allMessages;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Build query with IN clause for multiple agents
|
|
243
|
+
const agentList = agentIds.map(id => `"${id}"`).join(',');
|
|
244
|
+
let query = `/agent_messages?to_agent=in.(${agentList})&order=created_at.desc`;
|
|
245
|
+
|
|
246
|
+
if (options?.unreadOnly) {
|
|
247
|
+
query += '&read=eq.false';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (options?.limit) {
|
|
251
|
+
query += `&limit=${options.limit}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const results = await supabaseRequest<Array<{
|
|
255
|
+
id: string;
|
|
256
|
+
from_agent: string;
|
|
257
|
+
to_agent: string;
|
|
258
|
+
subject: string;
|
|
259
|
+
message: string;
|
|
260
|
+
encrypted: boolean;
|
|
261
|
+
read: boolean;
|
|
262
|
+
created_at: string;
|
|
263
|
+
}>>(client, query);
|
|
264
|
+
|
|
265
|
+
return results.map(r => {
|
|
266
|
+
// Parse encrypted message
|
|
267
|
+
let ciphertext, nonce, senderPublicKey, body = r.message;
|
|
268
|
+
if (r.encrypted && r.message) {
|
|
269
|
+
try {
|
|
270
|
+
const enc = JSON.parse(r.message);
|
|
271
|
+
ciphertext = enc.ciphertext;
|
|
272
|
+
nonce = enc.nonce;
|
|
273
|
+
senderPublicKey = enc.sender_public_key;
|
|
274
|
+
body = '';
|
|
275
|
+
} catch { }
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
id: r.id,
|
|
279
|
+
sender: r.from_agent,
|
|
280
|
+
recipient: r.to_agent,
|
|
281
|
+
subject: r.subject || '',
|
|
282
|
+
body,
|
|
283
|
+
encrypted: r.encrypted,
|
|
284
|
+
ciphertext,
|
|
285
|
+
nonce,
|
|
286
|
+
senderPublicKey,
|
|
287
|
+
read: r.read,
|
|
288
|
+
archived: false,
|
|
289
|
+
createdAt: new Date(r.created_at),
|
|
290
|
+
};
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
223
294
|
/**
|
|
224
295
|
* Get a specific message (supports partial ID lookup)
|
|
225
296
|
*/
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Myceliumail Wake Agent
|
|
2
|
+
|
|
3
|
+
Real-time agent wake-up extension for VS Code and Antigravity. Listens to Myceliumail messages via Supabase Realtime and wakes your agent through notifications, sidebar UI, or chat participant integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- π¬ **Real-time Notifications** - Get instant notifications when messages arrive
|
|
8
|
+
- π¬ **Chat Integration** - `@mycelium` chat participant for AI-powered message handling
|
|
9
|
+
- π **Auto-reconnect** - Automatic reconnection with exponential backoff
|
|
10
|
+
- π **Status Bar** - Connection status always visible
|
|
11
|
+
|
|
12
|
+
## Setup
|
|
13
|
+
|
|
14
|
+
### 1. Configure Settings
|
|
15
|
+
|
|
16
|
+
Open VS Code settings and configure:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"myceliumail.agentId": "your-agent-id",
|
|
21
|
+
"myceliumail.supabaseUrl": "https://your-project.supabase.co",
|
|
22
|
+
"myceliumail.supabaseKey": "your-anon-key"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or use the Settings UI:
|
|
27
|
+
1. Open Command Palette (`Cmd+Shift+P`)
|
|
28
|
+
2. Search "Preferences: Open Settings (UI)"
|
|
29
|
+
3. Search "myceliumail"
|
|
30
|
+
|
|
31
|
+
### 2. Verify Connection
|
|
32
|
+
|
|
33
|
+
1. Check the status bar - should show `π¬ Myceliumail`
|
|
34
|
+
2. Run command: **Myceliumail: Show Status**
|
|
35
|
+
3. Send a test: **Myceliumail: Test Wake Notification**
|
|
36
|
+
|
|
37
|
+
## Commands
|
|
38
|
+
|
|
39
|
+
| Command | Description |
|
|
40
|
+
|---------|-------------|
|
|
41
|
+
| `Myceliumail: Test Wake` | Send a test notification |
|
|
42
|
+
| `Myceliumail: Open Inbox` | View cached messages |
|
|
43
|
+
| `Myceliumail: Reconnect` | Force reconnection |
|
|
44
|
+
| `Myceliumail: Disconnect` | Disconnect from Supabase |
|
|
45
|
+
| `Myceliumail: Show Status` | Show connection status |
|
|
46
|
+
|
|
47
|
+
## Chat Participant
|
|
48
|
+
|
|
49
|
+
Use `@mycelium` in VS Code Chat:
|
|
50
|
+
|
|
51
|
+
- `@mycelium show inbox` - List recent messages
|
|
52
|
+
- `@mycelium status` - Show connection status
|
|
53
|
+
- `@mycelium how to send` - Help with sending messages
|
|
54
|
+
|
|
55
|
+
## Configuration Options
|
|
56
|
+
|
|
57
|
+
| Setting | Type | Default | Description |
|
|
58
|
+
|---------|------|---------|-------------|
|
|
59
|
+
| `myceliumail.agentId` | string | - | Your agent ID |
|
|
60
|
+
| `myceliumail.supabaseUrl` | string | - | Supabase project URL |
|
|
61
|
+
| `myceliumail.supabaseKey` | string | - | Supabase anon key |
|
|
62
|
+
| `myceliumail.enableNotifications` | boolean | true | Show notifications |
|
|
63
|
+
| `myceliumail.enableChatParticipant` | boolean | true | Enable @mycelium |
|
|
64
|
+
| `myceliumail.autoConnect` | boolean | true | Connect on startup |
|
|
65
|
+
|
|
66
|
+
## Development
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Install dependencies
|
|
70
|
+
npm install
|
|
71
|
+
|
|
72
|
+
# Compile
|
|
73
|
+
npm run compile
|
|
74
|
+
|
|
75
|
+
# Watch mode
|
|
76
|
+
npm run watch
|
|
77
|
+
|
|
78
|
+
# Package extension
|
|
79
|
+
npm run package
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Architecture
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
βββββββββββββββββββ WebSocket ββββββββββββββββββββ
|
|
86
|
+
β Supabase RT β ββββββββββββββββΆ β Wake Extension β
|
|
87
|
+
β agent_messages β β β
|
|
88
|
+
βββββββββββββββββββ ββββββββββ¬ββββββββββ
|
|
89
|
+
β
|
|
90
|
+
βββββββββββββββββΌββββββββββββββββ
|
|
91
|
+
β β β
|
|
92
|
+
βΌ βΌ βΌ
|
|
93
|
+
ββββββββββββ ββββββββββββ ββββββββββββ
|
|
94
|
+
β Notify β β Webview β β @myceliumβ
|
|
95
|
+
β Popup β β Panel β β Chat β
|
|
96
|
+
ββββββββββββ ββββββββββββ ββββββββββββ
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
- VS Code 1.85.0 or later (for Chat Participant API)
|
|
102
|
+
- Supabase account with Myceliumail tables
|
|
103
|
+
- Myceliumail agent configured
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|