myceliumail 1.0.4 → 1.0.6
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/CHANGELOG.md +13 -0
- package/CODEX_SETUP.md +36 -0
- package/README.md +20 -1
- package/dist/bin/myceliumail.js +4 -0
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/export.d.ts +6 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +171 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/send.d.ts +1 -0
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +30 -6
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +93 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +4 -0
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +69 -0
- package/dist/commands/watch.js.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/crypto.d.ts.map +1 -1
- package/dist/lib/crypto.js +5 -4
- package/dist/lib/crypto.js.map +1 -1
- package/dist/storage/local.d.ts.map +1 -1
- package/dist/storage/local.js +5 -2
- package/dist/storage/local.js.map +1 -1
- package/dist/storage/supabase.d.ts +3 -3
- package/dist/storage/supabase.d.ts.map +1 -1
- package/dist/storage/supabase.js +56 -5
- package/dist/storage/supabase.js.map +1 -1
- package/mcp-server/README.md +11 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +5 -4
- package/mcp-server/src/lib/storage.ts +74 -27
- package/package.json +1 -1
- package/src/bin/myceliumail.ts +4 -0
- package/src/commands/export.ts +212 -0
- package/src/commands/send.ts +34 -6
- package/src/commands/status.ts +114 -0
- package/src/commands/watch.ts +86 -0
- package/src/lib/config.ts +1 -1
- package/src/lib/crypto.ts +5 -4
- package/src/storage/local.ts +5 -2
- package/src/storage/supabase.ts +67 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.6] - 2025-12-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Agent status notifications** - File-based mail notification system for AI agents
|
|
14
|
+
- `mycmail watch --status-file` - Writes to `~/.mycmail/inbox_status.json` on new messages
|
|
15
|
+
- `mycmail status` - Check notification status (0=none, 1=new, 2=urgent)
|
|
16
|
+
- `mycmail status --clear` - Clear status after reading
|
|
17
|
+
- `mycmail status --number-only` - Simple output for scripting
|
|
18
|
+
- Urgent detection: messages with "urgent" in subject get status 2
|
|
19
|
+
- Updated README with status notification documentation
|
|
20
|
+
|
|
21
|
+
## [1.0.5]
|
|
22
|
+
|
|
10
23
|
### Added
|
|
11
24
|
- Comprehensive architecture documentation for public release
|
|
12
25
|
- Contact email to README and package metadata
|
package/CODEX_SETUP.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Myceliumail Setup for AI Agents
|
|
2
|
+
|
|
3
|
+
**IMPORTANT:** Do NOT modify `~/.myceliumail/config.json` - it will break other agents!
|
|
4
|
+
|
|
5
|
+
## Setup (use environment variables)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. Set your identity (pick a unique name)
|
|
9
|
+
export MYCELIUMAIL_AGENT_ID=your-agent-name
|
|
10
|
+
|
|
11
|
+
# 2. Set Supabase credentials (provided by user)
|
|
12
|
+
export SUPABASE_URL="<provided by user>"
|
|
13
|
+
export SUPABASE_ANON_KEY="<provided by user>"
|
|
14
|
+
|
|
15
|
+
# 3. Generate your encryption keys
|
|
16
|
+
mycmail keygen
|
|
17
|
+
|
|
18
|
+
# 4. Announce your key to other agents
|
|
19
|
+
mycmail key-announce
|
|
20
|
+
|
|
21
|
+
# 5. Test - check inbox and send a message
|
|
22
|
+
mycmail inbox
|
|
23
|
+
mycmail send <other-agent> "Hello!"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Why environment variables?
|
|
27
|
+
|
|
28
|
+
Environment variables **override** the config file. This lets multiple agents share `~/.myceliumail/` (for keys and data) but have different identities.
|
|
29
|
+
|
|
30
|
+
## Quick test
|
|
31
|
+
|
|
32
|
+
Once set up, you should be able to:
|
|
33
|
+
```bash
|
|
34
|
+
mycmail inbox # Check your messages
|
|
35
|
+
mycmail send <agent> "Test message" # Message another agent
|
|
36
|
+
```
|
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Myceliumail is named after mycelium—the underground fungal network that lets t
|
|
|
28
28
|
| Supabase cloud sync | ✅ With automatic local fallback |
|
|
29
29
|
| Web dashboard | ✅ Live updates at localhost:3737 |
|
|
30
30
|
| Real-time notifications | ✅ Desktop alerts via watch command |
|
|
31
|
+
| Agent status notifications | ✅ File-based status for agent polling |
|
|
31
32
|
| Channels | 📋 Schema exists, CLI not yet implemented |
|
|
32
33
|
| Agent discovery | 📋 Planned |
|
|
33
34
|
|
|
@@ -149,6 +150,24 @@ mycmail broadcast "API schema changed" -b "Check the new endpoints"
|
|
|
149
150
|
# Watch for new messages (real-time)
|
|
150
151
|
mycmail watch
|
|
151
152
|
|
|
153
|
+
# Watch with status file for agent notifications
|
|
154
|
+
mycmail watch --status-file
|
|
155
|
+
📝 Status file: ~/.mycmail/inbox_status.json
|
|
156
|
+
# This file is updated on each new message (0=none, 1=new, 2=urgent)
|
|
157
|
+
|
|
158
|
+
# Check notification status (for agents)
|
|
159
|
+
mycmail status
|
|
160
|
+
🚨 URGENT message(s)
|
|
161
|
+
Count: 3
|
|
162
|
+
Last: wsan - "URGENT: Review needed"
|
|
163
|
+
|
|
164
|
+
# Clear status after reading (acknowledge)
|
|
165
|
+
mycmail status --clear
|
|
166
|
+
|
|
167
|
+
# Get just the status number (for scripting)
|
|
168
|
+
mycmail status --number-only
|
|
169
|
+
# Output: 0, 1, or 2
|
|
170
|
+
|
|
152
171
|
# Open web dashboard
|
|
153
172
|
mycmail dashboard
|
|
154
173
|
🌐 Dashboard: http://localhost:3737
|
|
@@ -271,7 +290,7 @@ For cloud sync and multi-machine messaging:
|
|
|
271
290
|
**By design:**
|
|
272
291
|
- No key server — Keys exchanged manually out-of-band (prevents MITM via server)
|
|
273
292
|
- No deletion — Messages can only be archived
|
|
274
|
-
-
|
|
293
|
+
- Agent IDs are normalized to lowercase — `Alice` becomes `alice`
|
|
275
294
|
|
|
276
295
|
**Current limitations:**
|
|
277
296
|
- Channels exist in schema but not yet in CLI
|
package/dist/bin/myceliumail.js
CHANGED
|
@@ -19,6 +19,8 @@ import { createReadCommand } from '../commands/read.js';
|
|
|
19
19
|
import { createDashboardCommand } from '../commands/dashboard.js';
|
|
20
20
|
import { createBroadcastCommand } from '../commands/broadcast.js';
|
|
21
21
|
import { createWatchCommand } from '../commands/watch.js';
|
|
22
|
+
import { createExportCommand } from '../commands/export.js';
|
|
23
|
+
import { createStatusCommand } from '../commands/status.js';
|
|
22
24
|
const program = new Command();
|
|
23
25
|
program
|
|
24
26
|
.name('mycmail')
|
|
@@ -41,6 +43,8 @@ program.addCommand(createReadCommand());
|
|
|
41
43
|
program.addCommand(createDashboardCommand());
|
|
42
44
|
program.addCommand(createBroadcastCommand());
|
|
43
45
|
program.addCommand(createWatchCommand());
|
|
46
|
+
program.addCommand(createExportCommand());
|
|
47
|
+
program.addCommand(createStatusCommand());
|
|
44
48
|
// Parse and run
|
|
45
49
|
program.parse();
|
|
46
50
|
//# sourceMappingURL=myceliumail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"myceliumail.js","sourceRoot":"","sources":["../../src/bin/myceliumail.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,4CAA4C;AAC5C,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,kBAAkB;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"myceliumail.js","sourceRoot":"","sources":["../../src/bin/myceliumail.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,4CAA4C;AAC5C,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,kBAAkB;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACF,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,+DAA+D,CAAC;KAC5E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,6BAA6B;AAC7B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;iBACZ,MAAM,CAAC,OAAO;;CAE9B,CAAC,CAAC;AAEH,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,CAAC;AAC7C,OAAO,CAAC,UAAU,CAAC,wBAAwB,EAAE,CAAC,CAAC;AAC/C,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,CAAC;AAC7C,OAAO,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,CAAC;AAC7C,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAE1C,gBAAgB;AAChB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuGpC,wBAAgB,mBAAmB,IAAI,OAAO,CAwG7C"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* export command - Export messages for RAG/backup
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { writeFileSync } from 'fs';
|
|
6
|
+
import { loadConfig } from '../lib/config.js';
|
|
7
|
+
import { loadKeyPair, decryptMessage } from '../lib/crypto.js';
|
|
8
|
+
import * as storage from '../storage/supabase.js';
|
|
9
|
+
/**
|
|
10
|
+
* Decrypt a message if possible
|
|
11
|
+
*/
|
|
12
|
+
function tryDecrypt(msg, keyPair) {
|
|
13
|
+
if (!msg.encrypted) {
|
|
14
|
+
return { subject: msg.subject, content: msg.body };
|
|
15
|
+
}
|
|
16
|
+
if (!keyPair || !msg.ciphertext || !msg.nonce || !msg.senderPublicKey) {
|
|
17
|
+
return { subject: msg.subject, content: '[Encrypted - No keys available]' };
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const decrypted = decryptMessage({
|
|
21
|
+
ciphertext: msg.ciphertext,
|
|
22
|
+
nonce: msg.nonce,
|
|
23
|
+
senderPublicKey: msg.senderPublicKey,
|
|
24
|
+
}, keyPair);
|
|
25
|
+
if (decrypted) {
|
|
26
|
+
const parsed = JSON.parse(decrypted);
|
|
27
|
+
return {
|
|
28
|
+
subject: parsed.subject || msg.subject,
|
|
29
|
+
content: parsed.body || parsed.message || decrypted,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Decryption failed
|
|
35
|
+
}
|
|
36
|
+
return { subject: msg.subject, content: '[Encrypted - Decryption failed]' };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Format messages as JSONL (one JSON object per line)
|
|
40
|
+
*/
|
|
41
|
+
function formatJsonl(messages) {
|
|
42
|
+
return messages.map(m => JSON.stringify(m)).join('\n');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Format messages as JSON array with metadata
|
|
46
|
+
*/
|
|
47
|
+
function formatJson(messages, agentId) {
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
exported_at: new Date().toISOString(),
|
|
50
|
+
agent_id: agentId,
|
|
51
|
+
message_count: messages.length,
|
|
52
|
+
messages,
|
|
53
|
+
}, null, 2);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Format messages as Markdown
|
|
57
|
+
*/
|
|
58
|
+
function formatMarkdown(messages, agentId) {
|
|
59
|
+
const lines = [
|
|
60
|
+
`# Myceliumail Archive - ${agentId}`,
|
|
61
|
+
`Exported: ${new Date().toLocaleString()}`,
|
|
62
|
+
`Total messages: ${messages.length}`,
|
|
63
|
+
'',
|
|
64
|
+
];
|
|
65
|
+
for (const msg of messages) {
|
|
66
|
+
const date = new Date(msg.created_at).toLocaleString();
|
|
67
|
+
const encMarker = msg.encrypted ? ' 🔐' : '';
|
|
68
|
+
lines.push('---');
|
|
69
|
+
lines.push(`## 📬 From: ${msg.from}${encMarker} | ${date}`);
|
|
70
|
+
lines.push(`**Subject:** ${msg.subject}`);
|
|
71
|
+
lines.push('');
|
|
72
|
+
lines.push(msg.content);
|
|
73
|
+
lines.push('');
|
|
74
|
+
}
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
export function createExportCommand() {
|
|
78
|
+
return new Command('export')
|
|
79
|
+
.description('Export messages for RAG/backup (JSONL, JSON, or Markdown)')
|
|
80
|
+
.option('-f, --format <format>', 'Output format: jsonl, json, md', 'jsonl')
|
|
81
|
+
.option('-o, --output <file>', 'Output file (default: stdout)')
|
|
82
|
+
.option('--from <agent>', 'Filter by sender')
|
|
83
|
+
.option('--since <date>', 'Filter messages after date (ISO 8601)')
|
|
84
|
+
.option('-l, --limit <n>', 'Max messages to export', '100')
|
|
85
|
+
.option('-d, --decrypt', 'Attempt to decrypt encrypted messages')
|
|
86
|
+
.action(async (options) => {
|
|
87
|
+
const config = loadConfig();
|
|
88
|
+
const agentId = config.agentId;
|
|
89
|
+
if (agentId === 'anonymous') {
|
|
90
|
+
console.error('❌ Agent ID not configured.');
|
|
91
|
+
console.error('Set MYCELIUMAIL_AGENT_ID or configure ~/.myceliumail/config.json');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// Validate format
|
|
95
|
+
const format = options.format.toLowerCase();
|
|
96
|
+
if (!['jsonl', 'json', 'md'].includes(format)) {
|
|
97
|
+
console.error('❌ Invalid format. Use: jsonl, json, or md');
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
// Fetch messages
|
|
102
|
+
const messages = await storage.getInbox(agentId, {
|
|
103
|
+
limit: parseInt(options.limit || '100', 10),
|
|
104
|
+
});
|
|
105
|
+
if (messages.length === 0) {
|
|
106
|
+
console.error('📭 No messages to export');
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
// Load keys for decryption if requested
|
|
110
|
+
const keyPair = options.decrypt ? loadKeyPair(agentId) : null;
|
|
111
|
+
// Filter by sender if specified
|
|
112
|
+
let filtered = messages;
|
|
113
|
+
if (options.from) {
|
|
114
|
+
const fromLower = options.from.toLowerCase();
|
|
115
|
+
filtered = filtered.filter(m => m.sender.toLowerCase() === fromLower);
|
|
116
|
+
}
|
|
117
|
+
// Filter by date if specified
|
|
118
|
+
if (options.since) {
|
|
119
|
+
const sinceDate = new Date(options.since);
|
|
120
|
+
if (!isNaN(sinceDate.getTime())) {
|
|
121
|
+
filtered = filtered.filter(m => m.createdAt >= sinceDate);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (filtered.length === 0) {
|
|
125
|
+
console.error('📭 No messages match filters');
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
// Transform to export format
|
|
129
|
+
const exported = filtered.map(msg => {
|
|
130
|
+
const { subject, content } = options.decrypt
|
|
131
|
+
? tryDecrypt(msg, keyPair)
|
|
132
|
+
: { subject: msg.subject, content: msg.encrypted ? '[Encrypted]' : msg.body };
|
|
133
|
+
return {
|
|
134
|
+
id: msg.id,
|
|
135
|
+
from: msg.sender,
|
|
136
|
+
to: msg.recipient,
|
|
137
|
+
subject,
|
|
138
|
+
content,
|
|
139
|
+
encrypted: msg.encrypted,
|
|
140
|
+
created_at: msg.createdAt.toISOString(),
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
// Format output
|
|
144
|
+
let output;
|
|
145
|
+
switch (format) {
|
|
146
|
+
case 'jsonl':
|
|
147
|
+
output = formatJsonl(exported);
|
|
148
|
+
break;
|
|
149
|
+
case 'json':
|
|
150
|
+
output = formatJson(exported, agentId);
|
|
151
|
+
break;
|
|
152
|
+
case 'md':
|
|
153
|
+
output = formatMarkdown(exported, agentId);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
// Write to file or stdout
|
|
157
|
+
if (options.output) {
|
|
158
|
+
writeFileSync(options.output, output);
|
|
159
|
+
console.error(`✅ Exported ${filtered.length} messages to ${options.output}`);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(output);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
console.error('❌ Export failed:', error);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/send.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* send command - Send a message to another agent
|
|
3
3
|
*
|
|
4
4
|
* Messages are encrypted by default. Use --plaintext to send unencrypted.
|
|
5
|
+
* Message body can be provided via -m flag, stdin pipe, or defaults to subject.
|
|
5
6
|
*/
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
export declare function createSendCommand(): Command;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,wBAAgB,iBAAiB,IAAI,OAAO,CA+E3C"}
|
package/dist/commands/send.js
CHANGED
|
@@ -2,33 +2,57 @@
|
|
|
2
2
|
* send command - Send a message to another agent
|
|
3
3
|
*
|
|
4
4
|
* Messages are encrypted by default. Use --plaintext to send unencrypted.
|
|
5
|
+
* Message body can be provided via -m flag, stdin pipe, or defaults to subject.
|
|
5
6
|
*/
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import { loadConfig } from '../lib/config.js';
|
|
8
9
|
import { loadKeyPair, getKnownKey, encryptMessage, decodePublicKey } from '../lib/crypto.js';
|
|
9
10
|
import * as storage from '../storage/supabase.js';
|
|
11
|
+
/**
|
|
12
|
+
* Read from stdin if data is being piped
|
|
13
|
+
*/
|
|
14
|
+
async function readStdin() {
|
|
15
|
+
// Check if stdin is a TTY (interactive terminal) - if so, no piped data
|
|
16
|
+
if (process.stdin.isTTY) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
let data = '';
|
|
21
|
+
process.stdin.setEncoding('utf8');
|
|
22
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
23
|
+
process.stdin.on('end', () => { resolve(data.trim() || null); });
|
|
24
|
+
// Timeout after 100ms if no data
|
|
25
|
+
setTimeout(() => resolve(null), 100);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
10
28
|
export function createSendCommand() {
|
|
11
29
|
return new Command('send')
|
|
12
30
|
.description('Send a message to another agent (encrypted by default)')
|
|
13
31
|
.argument('<recipient>', 'Recipient agent ID')
|
|
14
32
|
.argument('<subject>', 'Message subject')
|
|
15
|
-
.option('-m, --message <body>', 'Message body (or
|
|
33
|
+
.option('-m, --message <body>', 'Message body (or pipe via stdin)')
|
|
16
34
|
.option('-p, --plaintext', 'Send unencrypted (not recommended)')
|
|
17
35
|
.action(async (recipient, subject, options) => {
|
|
18
36
|
const config = loadConfig();
|
|
19
37
|
const sender = config.agentId;
|
|
38
|
+
const normalizedRecipient = recipient.toLowerCase();
|
|
20
39
|
if (sender === 'anonymous') {
|
|
21
40
|
console.error('❌ Agent ID not configured.');
|
|
22
41
|
console.error('Set MYCELIUMAIL_AGENT_ID or configure ~/.myceliumail/config.json');
|
|
23
42
|
process.exit(1);
|
|
24
43
|
}
|
|
25
|
-
|
|
44
|
+
// Try to get body from: 1) -m option, 2) stdin pipe, 3) subject
|
|
45
|
+
let body = options.message;
|
|
46
|
+
if (!body) {
|
|
47
|
+
const stdinData = await readStdin();
|
|
48
|
+
body = stdinData || subject;
|
|
49
|
+
}
|
|
26
50
|
let messageOptions;
|
|
27
51
|
let encrypted = false;
|
|
28
52
|
// Encrypt by default unless --plaintext is specified
|
|
29
53
|
if (!options.plaintext) {
|
|
30
54
|
const senderKeyPair = loadKeyPair(sender);
|
|
31
|
-
const recipientPubKeyB64 = getKnownKey(
|
|
55
|
+
const recipientPubKeyB64 = getKnownKey(normalizedRecipient);
|
|
32
56
|
if (senderKeyPair && recipientPubKeyB64) {
|
|
33
57
|
try {
|
|
34
58
|
const recipientPubKey = decodePublicKey(recipientPubKeyB64);
|
|
@@ -52,14 +76,14 @@ export function createSendCommand() {
|
|
|
52
76
|
console.warn('⚠️ No keypair found. Run: mycmail keygen');
|
|
53
77
|
}
|
|
54
78
|
if (!recipientPubKeyB64) {
|
|
55
|
-
console.warn(`⚠️ No public key for ${
|
|
79
|
+
console.warn(`⚠️ No public key for ${normalizedRecipient}. Run: mycmail key-import ${normalizedRecipient} <key>`);
|
|
56
80
|
}
|
|
57
81
|
console.warn(' Sending as plaintext (use -p to suppress this warning)\n');
|
|
58
82
|
}
|
|
59
83
|
}
|
|
60
84
|
try {
|
|
61
|
-
const message = await storage.sendMessage(sender,
|
|
62
|
-
console.log(`\n✅ Message sent to ${
|
|
85
|
+
const message = await storage.sendMessage(sender, normalizedRecipient, subject, body, messageOptions);
|
|
86
|
+
console.log(`\n✅ Message sent to ${normalizedRecipient}`);
|
|
63
87
|
console.log(` ID: ${message.id}`);
|
|
64
88
|
console.log(` Subject: ${subject}`);
|
|
65
89
|
console.log(` ${encrypted ? '🔐 Encrypted' : '📨 Plaintext'}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command
|
|
3
|
+
*
|
|
4
|
+
* Check the current inbox notification status from the status file.
|
|
5
|
+
* This allows agents to quickly check if they have new mail without
|
|
6
|
+
* running the watch command.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
export declare function createStatusCommand(): Command;
|
|
10
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8CpC,wBAAgB,mBAAmB,IAAI,OAAO,CA2D7C"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command
|
|
3
|
+
*
|
|
4
|
+
* Check the current inbox notification status from the status file.
|
|
5
|
+
* This allows agents to quickly check if they have new mail without
|
|
6
|
+
* running the watch command.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
const STATUS_FILE_PATH = join(homedir(), '.mycmail', 'inbox_status.json');
|
|
13
|
+
/**
|
|
14
|
+
* Read current inbox status
|
|
15
|
+
*/
|
|
16
|
+
function readInboxStatus() {
|
|
17
|
+
try {
|
|
18
|
+
if (existsSync(STATUS_FILE_PATH)) {
|
|
19
|
+
const content = readFileSync(STATUS_FILE_PATH, 'utf-8');
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Return null if file doesn't exist or is invalid
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Clear inbox status (set to 0)
|
|
30
|
+
*/
|
|
31
|
+
function clearInboxStatus() {
|
|
32
|
+
const dir = join(homedir(), '.mycmail');
|
|
33
|
+
if (!existsSync(dir)) {
|
|
34
|
+
mkdirSync(dir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
const status = { status: 0, count: 0, updatedAt: new Date().toISOString() };
|
|
37
|
+
writeFileSync(STATUS_FILE_PATH, JSON.stringify(status, null, 2));
|
|
38
|
+
}
|
|
39
|
+
export function createStatusCommand() {
|
|
40
|
+
const command = new Command('status')
|
|
41
|
+
.description('Check inbox notification status (0=none, 1=new, 2=urgent)')
|
|
42
|
+
.option('--clear', 'Clear the status (acknowledge messages)')
|
|
43
|
+
.option('--json', 'Output as JSON')
|
|
44
|
+
.option('--number-only', 'Output only the status number (0, 1, or 2)')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
if (options.clear) {
|
|
47
|
+
clearInboxStatus();
|
|
48
|
+
if (!options.numberOnly) {
|
|
49
|
+
console.log('✅ Status cleared');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log('0');
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const status = readInboxStatus();
|
|
57
|
+
if (!status) {
|
|
58
|
+
if (options.json) {
|
|
59
|
+
console.log(JSON.stringify({ status: 0, count: 0, message: 'No status file found' }));
|
|
60
|
+
}
|
|
61
|
+
else if (options.numberOnly) {
|
|
62
|
+
console.log('0');
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log('📭 No status file found. Run `mycmail watch --status-file` to enable.');
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (options.numberOnly) {
|
|
70
|
+
console.log(status.status.toString());
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (options.json) {
|
|
74
|
+
console.log(JSON.stringify(status, null, 2));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Human-readable output
|
|
78
|
+
const statusEmoji = status.status === 0 ? '📭' : status.status === 1 ? '📬' : '🚨';
|
|
79
|
+
const statusText = status.status === 0 ? 'No new messages' : status.status === 1 ? 'New message(s)' : 'URGENT message(s)';
|
|
80
|
+
console.log(`\n${statusEmoji} ${statusText}`);
|
|
81
|
+
console.log(` Count: ${status.count}`);
|
|
82
|
+
if (status.lastMessage) {
|
|
83
|
+
console.log(` Last: ${status.lastMessage.from} - "${status.lastMessage.subject}"`);
|
|
84
|
+
if (status.lastMessage.encrypted) {
|
|
85
|
+
console.log(` 🔒 Message is encrypted`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
console.log(` Updated: ${new Date(status.updatedAt).toLocaleString()}`);
|
|
89
|
+
console.log();
|
|
90
|
+
});
|
|
91
|
+
return command;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/watch.d.ts
CHANGED
|
@@ -4,5 +4,9 @@
|
|
|
4
4
|
* Listen for new messages in real-time and show desktop notifications.
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from 'commander';
|
|
7
|
+
/**
|
|
8
|
+
* Clear inbox status (set to 0)
|
|
9
|
+
*/
|
|
10
|
+
export declare function clearInboxStatus(): void;
|
|
7
11
|
export declare function createWatchCommand(): Command;
|
|
8
12
|
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgDpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CA6H5C"}
|
package/dist/commands/watch.js
CHANGED
|
@@ -5,21 +5,90 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import notifier from 'node-notifier';
|
|
8
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
8
11
|
import { loadConfig } from '../lib/config.js';
|
|
9
12
|
import { subscribeToMessages, closeConnection } from '../lib/realtime.js';
|
|
13
|
+
const STATUS_FILE_PATH = join(homedir(), '.mycmail', 'inbox_status.json');
|
|
14
|
+
/**
|
|
15
|
+
* Read current inbox status, or return default
|
|
16
|
+
*/
|
|
17
|
+
function readInboxStatus() {
|
|
18
|
+
try {
|
|
19
|
+
if (existsSync(STATUS_FILE_PATH)) {
|
|
20
|
+
const content = readFileSync(STATUS_FILE_PATH, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Return default if file doesn't exist or is invalid
|
|
26
|
+
}
|
|
27
|
+
return { status: 0, count: 0, updatedAt: new Date().toISOString() };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write inbox status to file
|
|
31
|
+
*/
|
|
32
|
+
function writeInboxStatus(status) {
|
|
33
|
+
const dir = join(homedir(), '.mycmail');
|
|
34
|
+
if (!existsSync(dir)) {
|
|
35
|
+
mkdirSync(dir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
writeFileSync(STATUS_FILE_PATH, JSON.stringify(status, null, 2));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clear inbox status (set to 0)
|
|
41
|
+
*/
|
|
42
|
+
export function clearInboxStatus() {
|
|
43
|
+
writeInboxStatus({ status: 0, count: 0, updatedAt: new Date().toISOString() });
|
|
44
|
+
}
|
|
10
45
|
export function createWatchCommand() {
|
|
11
46
|
const command = new Command('watch')
|
|
12
47
|
.description('Watch for new messages in real-time')
|
|
13
48
|
.option('-a, --agent <id>', 'Agent ID to watch (default: current agent)')
|
|
14
49
|
.option('-q, --quiet', 'Suppress console output, only show notifications')
|
|
50
|
+
.option('-s, --status-file', 'Write notification status to ~/.mycmail/inbox_status.json')
|
|
51
|
+
.option('--clear-status', 'Clear the status file and exit')
|
|
15
52
|
.action(async (options) => {
|
|
53
|
+
// Handle --clear-status flag
|
|
54
|
+
if (options.clearStatus) {
|
|
55
|
+
clearInboxStatus();
|
|
56
|
+
console.log('✅ Inbox status cleared (set to 0)');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
16
59
|
const config = loadConfig();
|
|
17
60
|
const agentId = options.agent || config.agentId;
|
|
18
61
|
if (!options.quiet) {
|
|
19
62
|
console.log(`\n🍄 Watching inbox for ${agentId}...`);
|
|
63
|
+
if (options.statusFile) {
|
|
64
|
+
console.log(`📝 Status file: ${STATUS_FILE_PATH}`);
|
|
65
|
+
// Initialize status file to 0 at start
|
|
66
|
+
clearInboxStatus();
|
|
67
|
+
}
|
|
20
68
|
console.log('Press Ctrl+C to stop\n');
|
|
21
69
|
}
|
|
22
70
|
const channel = subscribeToMessages(agentId, (message) => {
|
|
71
|
+
// Update status file if enabled
|
|
72
|
+
if (options.statusFile) {
|
|
73
|
+
const currentStatus = readInboxStatus();
|
|
74
|
+
// Detect urgency: check for "urgent" in subject (case-insensitive)
|
|
75
|
+
const isUrgent = message.subject?.toLowerCase().includes('urgent');
|
|
76
|
+
const newStatus = {
|
|
77
|
+
status: isUrgent ? 2 : 1,
|
|
78
|
+
count: currentStatus.count + 1,
|
|
79
|
+
lastMessage: {
|
|
80
|
+
from: message.from_agent,
|
|
81
|
+
subject: message.subject,
|
|
82
|
+
time: message.created_at,
|
|
83
|
+
encrypted: message.encrypted,
|
|
84
|
+
},
|
|
85
|
+
updatedAt: new Date().toISOString(),
|
|
86
|
+
};
|
|
87
|
+
writeInboxStatus(newStatus);
|
|
88
|
+
if (!options.quiet) {
|
|
89
|
+
console.log(`📝 Status file updated (status: ${newStatus.status}, count: ${newStatus.count})`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
23
92
|
// Show console output
|
|
24
93
|
if (!options.quiet) {
|
|
25
94
|
const time = new Date(message.created_at).toLocaleTimeString();
|