myceliumail 1.0.6 → 1.0.8
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 +38 -1
- package/CODEX_SETUP.md +13 -2
- package/README.md +85 -1
- package/dist/bin/myceliumail.js +4 -0
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/activate.d.ts +10 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +77 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/key-import.d.ts.map +1 -1
- package/dist/commands/key-import.js +5 -0
- package/dist/commands/key-import.js.map +1 -1
- package/dist/lib/license.d.ts +61 -0
- package/dist/lib/license.d.ts.map +1 -0
- package/dist/lib/license.js +173 -0
- package/dist/lib/license.js.map +1 -0
- package/mcp-server/CHANGELOG.md +68 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/lib/license.ts +147 -0
- package/mcp-server/src/server.ts +4 -0
- package/package.json +1 -1
- package/src/bin/myceliumail.ts +6 -0
- package/src/commands/activate.ts +85 -0
- package/src/commands/key-import.ts +7 -0
- package/src/lib/license.ts +215 -0
package/CHANGELOG.md
CHANGED
|
@@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
18
|
- Urgent detection: messages with "urgent" in subject get status 2
|
|
19
19
|
- Updated README with status notification documentation
|
|
20
20
|
|
|
21
|
-
## [1.0.5]
|
|
21
|
+
## [1.0.5] - 2025-12-20
|
|
22
22
|
|
|
23
23
|
### Added
|
|
24
24
|
- Comprehensive architecture documentation for public release
|
|
@@ -27,6 +27,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
27
27
|
### Changed
|
|
28
28
|
- Complete README rewrite for public release messaging
|
|
29
29
|
|
|
30
|
+
## [1.0.4] - 2025-12-20
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Partial ID lookup bug in `mycmail read` command for Supabase storage
|
|
34
|
+
- Applied same fix to `myceliumail-mcp` server
|
|
35
|
+
|
|
36
|
+
## [1.0.3] - 2025-12-18
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- Agent ID case normalization (all IDs now lowercase)
|
|
40
|
+
- Key import and send commands now handle case correctly
|
|
41
|
+
|
|
42
|
+
## [1.0.2] - 2025-12-18
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- Desktop notification sound and click behavior
|
|
46
|
+
- Dashboard real-time connection stability
|
|
47
|
+
|
|
48
|
+
## [1.0.1] - 2025-12-18
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- npm package bin paths corrected
|
|
52
|
+
- Missing dependencies in published package
|
|
53
|
+
|
|
30
54
|
## [1.0.0] - 2025-12-18
|
|
31
55
|
|
|
32
56
|
### Added
|
|
@@ -78,6 +102,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
78
102
|
|
|
79
103
|
## MCP Server Releases
|
|
80
104
|
|
|
105
|
+
> See [mcp-server/CHANGELOG.md](mcp-server/CHANGELOG.md) for full history.
|
|
106
|
+
|
|
107
|
+
### [myceliumail-mcp@1.0.11] - 2025-12-21
|
|
108
|
+
|
|
109
|
+
#### Fixed
|
|
110
|
+
- DMG installer and desktop app fixes
|
|
111
|
+
- Improved error handling in MCP tools
|
|
112
|
+
|
|
113
|
+
### [myceliumail-mcp@1.0.9] - 2025-12-20
|
|
114
|
+
|
|
115
|
+
#### Fixed
|
|
116
|
+
- Partial ID lookup for message reading
|
|
117
|
+
|
|
81
118
|
### [myceliumail-mcp@1.0.7] - 2025-12-18
|
|
82
119
|
|
|
83
120
|
#### Fixed
|
package/CODEX_SETUP.md
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
export MYCELIUMAIL_AGENT_ID=your-agent-name
|
|
10
10
|
|
|
11
11
|
# 2. Set Supabase credentials (provided by user)
|
|
12
|
-
export SUPABASE_URL="
|
|
13
|
-
export SUPABASE_ANON_KEY="
|
|
12
|
+
export SUPABASE_URL="https://your-project.supabase.co"
|
|
13
|
+
export SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # JWT format!
|
|
14
14
|
|
|
15
15
|
# 3. Generate your encryption keys
|
|
16
16
|
mycmail keygen
|
|
@@ -23,6 +23,17 @@ mycmail inbox
|
|
|
23
23
|
mycmail send <other-agent> "Hello!"
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## ⚠️ Key Format Warning
|
|
27
|
+
|
|
28
|
+
**Use JWT anon keys, NOT publishable keys:**
|
|
29
|
+
|
|
30
|
+
| Format | Example | Works? |
|
|
31
|
+
|--------|---------|--------|
|
|
32
|
+
| ✅ JWT anon | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` | Yes |
|
|
33
|
+
| ❌ Publishable | `sb_publishable_...` | No |
|
|
34
|
+
|
|
35
|
+
Find the correct key in Supabase Dashboard → Settings → API → "anon public" (the long JWT string).
|
|
36
|
+
|
|
26
37
|
## Why environment variables?
|
|
27
38
|
|
|
28
39
|
Environment variables **override** the config file. This lets multiple agents share `~/.myceliumail/` (for keys and data) but have different identities.
|
package/README.md
CHANGED
|
@@ -34,6 +34,43 @@ Myceliumail is named after mycelium—the underground fungal network that lets t
|
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
+
## 💎 Free vs Pro
|
|
38
|
+
|
|
39
|
+
Myceliumail works as a **generous free tier** — upgrade when you need more power.
|
|
40
|
+
|
|
41
|
+
| Feature | Free | Pro ($9/mo) |
|
|
42
|
+
|---------|------|-------------|
|
|
43
|
+
| Core messaging | ✅ Unlimited | ✅ Unlimited |
|
|
44
|
+
| Encryption | ✅ Full E2E | ✅ Full E2E |
|
|
45
|
+
| Imported keys | 5 max | ✅ Unlimited |
|
|
46
|
+
| MCP Server | ❌ | ✅ |
|
|
47
|
+
| Cloud key backup | ❌ | ✅ Coming soon |
|
|
48
|
+
| Priority support | ❌ | ✅ |
|
|
49
|
+
|
|
50
|
+
**Activate Pro:**
|
|
51
|
+
```bash
|
|
52
|
+
mycmail activate <your-license-key>
|
|
53
|
+
mycmail license # Check status
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Get a license: [myceliumail.dev/pro](https://myceliumail.dev/pro)
|
|
57
|
+
|
|
58
|
+
> **Note:** One Pro license unlocks the entire Treebird ecosystem (Myceliumail + Spidersan).
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 🗣️ Feedback & Support
|
|
63
|
+
|
|
64
|
+
We're building this in public and want to hear from you!
|
|
65
|
+
|
|
66
|
+
- **Issues & Features:** [GitHub Issues](https://github.com/treebird7/myceliumail/issues)
|
|
67
|
+
- **Email:** treebird7@proton.me
|
|
68
|
+
- **Twitter/X:** [@treebird7](https://twitter.com/treebird7)
|
|
69
|
+
|
|
70
|
+
Tell us what's working, what's broken, and what you'd love to see next.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
37
74
|
## Quick Start
|
|
38
75
|
|
|
39
76
|
### CLI Installation
|
|
@@ -98,10 +135,12 @@ Create `~/.myceliumail/config.json`:
|
|
|
98
135
|
{
|
|
99
136
|
"agent_id": "my-agent",
|
|
100
137
|
"supabase_url": "https://xxx.supabase.co",
|
|
101
|
-
"supabase_key": "
|
|
138
|
+
"supabase_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
102
139
|
}
|
|
103
140
|
```
|
|
104
141
|
|
|
142
|
+
> **⚠️ Key Format:** Use the JWT anon key (starts with `eyJ...`), NOT the publishable key (`sb_publishable_...`). Find it in Supabase Dashboard → Settings → API → "anon public".
|
|
143
|
+
|
|
105
144
|
### Storage Modes
|
|
106
145
|
|
|
107
146
|
| Mode | Backend | Use Case |
|
|
@@ -303,6 +342,51 @@ For cloud sync and multi-machine messaging:
|
|
|
303
342
|
|
|
304
343
|
---
|
|
305
344
|
|
|
345
|
+
## Troubleshooting
|
|
346
|
+
|
|
347
|
+
### "Invalid API key" Error
|
|
348
|
+
|
|
349
|
+
**Cause:** Using the wrong key format.
|
|
350
|
+
|
|
351
|
+
| Key Type | Format | Works? |
|
|
352
|
+
|----------|--------|--------|
|
|
353
|
+
| ✅ JWT anon key | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` | Yes |
|
|
354
|
+
| ❌ Publishable key | `sb_publishable_...` | No |
|
|
355
|
+
|
|
356
|
+
**Fix:** Go to Supabase Dashboard → Settings → API → copy the "anon public" key (the long JWT string starting with `eyJ...`).
|
|
357
|
+
|
|
358
|
+
### Version Mismatch (`-V` shows old version)
|
|
359
|
+
|
|
360
|
+
**Cause:** npm global install caching.
|
|
361
|
+
|
|
362
|
+
**Fix:**
|
|
363
|
+
```bash
|
|
364
|
+
npm uninstall -g myceliumail
|
|
365
|
+
npm install -g myceliumail@latest
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### "Connection refused" or timeout errors
|
|
369
|
+
|
|
370
|
+
**Cause:** Supabase project paused or incorrect URL.
|
|
371
|
+
|
|
372
|
+
**Fix:**
|
|
373
|
+
1. Verify your `SUPABASE_URL` is correct
|
|
374
|
+
2. Check if the project is active at [supabase.com/dashboard](https://supabase.com/dashboard)
|
|
375
|
+
3. Try `mycmail inbox` with `MYCELIUMAIL_STORAGE=local` to test locally
|
|
376
|
+
|
|
377
|
+
### Encryption errors
|
|
378
|
+
|
|
379
|
+
**Cause:** Missing or mismatched keys.
|
|
380
|
+
|
|
381
|
+
**Fix:**
|
|
382
|
+
```bash
|
|
383
|
+
mycmail keygen # Generate your keypair
|
|
384
|
+
mycmail key-announce # Share your public key
|
|
385
|
+
mycmail keys # Verify keys are present
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
306
390
|
## Roadmap
|
|
307
391
|
|
|
308
392
|
Myceliumail is part of the **Treebird ecosystem**—a suite of tools for AI agent coordination.
|
package/dist/bin/myceliumail.js
CHANGED
|
@@ -21,6 +21,7 @@ import { createBroadcastCommand } from '../commands/broadcast.js';
|
|
|
21
21
|
import { createWatchCommand } from '../commands/watch.js';
|
|
22
22
|
import { createExportCommand } from '../commands/export.js';
|
|
23
23
|
import { createStatusCommand } from '../commands/status.js';
|
|
24
|
+
import { createActivateCommand, createLicenseStatusCommand } from '../commands/activate.js';
|
|
24
25
|
const program = new Command();
|
|
25
26
|
program
|
|
26
27
|
.name('mycmail')
|
|
@@ -45,6 +46,9 @@ program.addCommand(createBroadcastCommand());
|
|
|
45
46
|
program.addCommand(createWatchCommand());
|
|
46
47
|
program.addCommand(createExportCommand());
|
|
47
48
|
program.addCommand(createStatusCommand());
|
|
49
|
+
// License management
|
|
50
|
+
program.addCommand(createActivateCommand());
|
|
51
|
+
program.addCommand(createLicenseStatusCommand());
|
|
48
52
|
// Parse and run
|
|
49
53
|
program.parse();
|
|
50
54
|
//# 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;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,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;AAC5D,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE5F,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,qBAAqB;AACrB,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAC;AAC5C,OAAO,CAAC,UAAU,CAAC,0BAA0B,EAAE,CAAC,CAAC;AAEjD,gBAAgB;AAChB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Activation Command
|
|
3
|
+
*
|
|
4
|
+
* Activates a Pro license key.
|
|
5
|
+
* Usage: mycmail activate <license-key>
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function createActivateCommand(): Command;
|
|
9
|
+
export declare function createLicenseStatusCommand(): Command;
|
|
10
|
+
//# sourceMappingURL=activate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activate.d.ts","sourceRoot":"","sources":["../../src/commands/activate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,qBAAqB,IAAI,OAAO,CA0C/C;AAED,wBAAgB,0BAA0B,IAAI,OAAO,CA6BpD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Activation Command
|
|
3
|
+
*
|
|
4
|
+
* Activates a Pro license key.
|
|
5
|
+
* Usage: mycmail activate <license-key>
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { verifyLicense, saveLicense, getLicenseStatus, FREE_TIER_LIMITS } from '../lib/license.js';
|
|
9
|
+
import { loadKnownKeys } from '../lib/crypto.js';
|
|
10
|
+
export function createActivateCommand() {
|
|
11
|
+
return new Command('activate')
|
|
12
|
+
.description('Activate a Pro license key')
|
|
13
|
+
.argument('<license-key>', 'Your license key from myceliumail.dev/pro')
|
|
14
|
+
.action(async (licenseKey) => {
|
|
15
|
+
console.log('🍄 Activating license...\n');
|
|
16
|
+
// Verify the license
|
|
17
|
+
const license = verifyLicense(licenseKey);
|
|
18
|
+
if (!license) {
|
|
19
|
+
console.error('❌ Invalid license key');
|
|
20
|
+
console.error(' Please check your key and try again.');
|
|
21
|
+
console.error(' Get a license at: myceliumail.dev/pro');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
if (license.isExpired) {
|
|
25
|
+
console.error('❌ This license has expired');
|
|
26
|
+
console.error(` Expired on: ${new Date(license.data.expiresAt).toLocaleDateString()}`);
|
|
27
|
+
console.error(' Renew at: myceliumail.dev/pro');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Save the license
|
|
31
|
+
const saved = saveLicense(licenseKey);
|
|
32
|
+
if (!saved) {
|
|
33
|
+
console.error('❌ Failed to save license');
|
|
34
|
+
console.error(' Please check file permissions for ~/.myceliumail/');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
// Show success
|
|
38
|
+
const status = getLicenseStatus();
|
|
39
|
+
console.log('✅ Pro License activated!\n');
|
|
40
|
+
console.log(` Email: ${status.email}`);
|
|
41
|
+
console.log(` Plan: ${status.plan.toUpperCase()}`);
|
|
42
|
+
console.log(` Expires: ${new Date(status.expiresAt).toLocaleDateString()}`);
|
|
43
|
+
console.log(` Features: ${status.features.join(', ')}`);
|
|
44
|
+
console.log('');
|
|
45
|
+
console.log('🍄 Thank you for supporting Myceliumail!');
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function createLicenseStatusCommand() {
|
|
49
|
+
return new Command('license')
|
|
50
|
+
.description('Show license status and plan details')
|
|
51
|
+
.action(async () => {
|
|
52
|
+
const status = getLicenseStatus();
|
|
53
|
+
const knownKeys = loadKnownKeys();
|
|
54
|
+
const keyCount = Object.keys(knownKeys).length;
|
|
55
|
+
console.log('🍄 Myceliumail License Status\n');
|
|
56
|
+
if (status.plan === 'pro') {
|
|
57
|
+
console.log(` Plan: 💎 Pro`);
|
|
58
|
+
console.log(` Email: ${status.email}`);
|
|
59
|
+
console.log(` Expires: ${new Date(status.expiresAt).toLocaleDateString()} (${status.daysRemaining} days)`);
|
|
60
|
+
console.log(` Features: ${status.features.join(', ')}`);
|
|
61
|
+
console.log(` Keys: ${keyCount} imported (unlimited)`);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.log(` Plan: Free`);
|
|
65
|
+
console.log(` Keys: ${keyCount}/${FREE_TIER_LIMITS.maxImportedKeys} imported`);
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(' 💎 Upgrade to Pro for:');
|
|
68
|
+
console.log(' • Unlimited imported keys');
|
|
69
|
+
console.log(' • MCP Server integration');
|
|
70
|
+
console.log(' • Cloud key backup/restore');
|
|
71
|
+
console.log(' • Real-time notifications');
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log(' Get Pro: myceliumail.dev/pro');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=activate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activate.js","sourceRoot":"","sources":["../../src/commands/activate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-import.d.ts","sourceRoot":"","sources":["../../src/commands/key-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"key-import.d.ts","sourceRoot":"","sources":["../../src/commands/key-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,sBAAsB,IAAI,OAAO,CAgChD"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { saveKnownKey, getKnownKey } from '../lib/crypto.js';
|
|
6
|
+
import { checkKeyLimit } from '../lib/license.js';
|
|
6
7
|
export function createKeyImportCommand() {
|
|
7
8
|
return new Command('key-import')
|
|
8
9
|
.description('Import a peer agent\'s public key')
|
|
@@ -22,6 +23,10 @@ export function createKeyImportCommand() {
|
|
|
22
23
|
console.log('\nUse --force to overwrite');
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
26
|
+
// Check key limit for free tier (only for new keys)
|
|
27
|
+
if (!existing) {
|
|
28
|
+
checkKeyLimit();
|
|
29
|
+
}
|
|
25
30
|
saveKnownKey(agentId, publicKey);
|
|
26
31
|
console.log(`✅ Imported public key for ${agentId}`);
|
|
27
32
|
console.log(`Key: ${publicKey.slice(0, 20)}...`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-import.js","sourceRoot":"","sources":["../../src/commands/key-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"key-import.js","sourceRoot":"","sources":["../../src/commands/key-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,UAAU,sBAAsB;IAClC,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;SAC3B,WAAW,CAAC,mCAAmC,CAAC;SAChD,QAAQ,CAAC,SAAS,EAAE,4BAA4B,CAAC;SACjD,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;SAC9C,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;SAC/C,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,SAAiB,EAAE,OAAO,EAAE,EAAE;QAC1D,oCAAoC;QACpC,IAAI,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,OAAO;QACX,CAAC;QAED,oDAAoD;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,aAAa,EAAE,CAAC;QACpB,CAAC;QAED,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEjC,OAAO,CAAC,GAAG,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,QAAQ,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for Pro features.
|
|
5
|
+
* Public key is embedded; private key is kept by treebird for signing.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FREE_TIER_LIMITS: {
|
|
8
|
+
maxImportedKeys: number;
|
|
9
|
+
};
|
|
10
|
+
export type ProFeature = 'unlimited_keys' | 'mcp_server' | 'cloud_sync' | 'key_backup' | 'realtime_watch';
|
|
11
|
+
export interface LicenseData {
|
|
12
|
+
email: string;
|
|
13
|
+
plan: 'free' | 'pro';
|
|
14
|
+
expiresAt: string;
|
|
15
|
+
issuedAt: string;
|
|
16
|
+
features: ProFeature[];
|
|
17
|
+
}
|
|
18
|
+
export interface License {
|
|
19
|
+
data: LicenseData;
|
|
20
|
+
isValid: boolean;
|
|
21
|
+
isExpired: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Verify a license string using Ed25519 detached signature
|
|
25
|
+
*/
|
|
26
|
+
export declare function verifyLicense(licenseString: string): License | null;
|
|
27
|
+
/**
|
|
28
|
+
* Save a license key to disk
|
|
29
|
+
*/
|
|
30
|
+
export declare function saveLicense(licenseString: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Load the saved license from disk
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadLicense(): License | null;
|
|
35
|
+
/**
|
|
36
|
+
* Check if user has a valid Pro license
|
|
37
|
+
*/
|
|
38
|
+
export declare function isPro(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a specific Pro feature is enabled
|
|
41
|
+
*/
|
|
42
|
+
export declare function hasFeature(feature: ProFeature): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get license status summary
|
|
45
|
+
*/
|
|
46
|
+
export declare function getLicenseStatus(): {
|
|
47
|
+
plan: 'free' | 'pro';
|
|
48
|
+
email?: string;
|
|
49
|
+
expiresAt?: string;
|
|
50
|
+
features: ProFeature[];
|
|
51
|
+
daysRemaining?: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Check imported key limit and throw if exceeded (for free tier)
|
|
55
|
+
*/
|
|
56
|
+
export declare function checkKeyLimit(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Print Pro upsell message (soft sell)
|
|
59
|
+
*/
|
|
60
|
+
export declare function printProUpsell(feature: string): void;
|
|
61
|
+
//# sourceMappingURL=license.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,eAAO,MAAM,gBAAgB;;CAE5B,CAAC;AAGF,MAAM,MAAM,UAAU,GAChB,gBAAgB,GAChB,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,gBAAgB,CAAC;AAEvB,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACtB;AAyBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CA6BnE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,GAAG,IAAI,CAS5C;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAM/B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAIvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI;IAChC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B,CAqBA;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAepC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMpD"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for Pro features.
|
|
5
|
+
* Public key is embedded; private key is kept by treebird for signing.
|
|
6
|
+
*/
|
|
7
|
+
import nacl from 'tweetnacl';
|
|
8
|
+
import util from 'tweetnacl-util';
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
import { loadKnownKeys } from './crypto.js';
|
|
13
|
+
// License storage location
|
|
14
|
+
const LICENSE_DIR = join(homedir(), '.myceliumail');
|
|
15
|
+
const LICENSE_FILE = join(LICENSE_DIR, 'license.key');
|
|
16
|
+
// Treebird's public key for license verification (Ed25519)
|
|
17
|
+
// Use the same key as Spidersan for unified licensing
|
|
18
|
+
const TREEBIRD_PUBLIC_KEY = 'XqIqSlybZGKkKemgLKKl8P9MepnObhcJcxxZHtgG8/o=';
|
|
19
|
+
// Free tier limits
|
|
20
|
+
export const FREE_TIER_LIMITS = {
|
|
21
|
+
maxImportedKeys: 5,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Ensure license directory exists
|
|
25
|
+
*/
|
|
26
|
+
function ensureLicenseDir() {
|
|
27
|
+
if (!existsSync(LICENSE_DIR)) {
|
|
28
|
+
mkdirSync(LICENSE_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse a license string into components
|
|
33
|
+
* Format: LICENSE_V1.BASE64_DATA.BASE64_SIGNATURE
|
|
34
|
+
*/
|
|
35
|
+
function parseLicenseString(licenseString) {
|
|
36
|
+
const parts = licenseString.trim().split('.');
|
|
37
|
+
if (parts.length !== 3)
|
|
38
|
+
return null;
|
|
39
|
+
const [version, data, signature] = parts;
|
|
40
|
+
if (version !== 'LICENSE_V1')
|
|
41
|
+
return null;
|
|
42
|
+
return { version, data, signature };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify a license string using Ed25519 detached signature
|
|
46
|
+
*/
|
|
47
|
+
export function verifyLicense(licenseString) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = parseLicenseString(licenseString);
|
|
50
|
+
if (!parsed)
|
|
51
|
+
return null;
|
|
52
|
+
const dataBytes = util.decodeBase64(parsed.data);
|
|
53
|
+
// Verify detached Ed25519 signature
|
|
54
|
+
const publicKey = util.decodeBase64(TREEBIRD_PUBLIC_KEY);
|
|
55
|
+
const signatureBytes = util.decodeBase64(parsed.signature);
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
const isValid = nacl.sign.detached.verify(dataBytes, signatureBytes, publicKey);
|
|
58
|
+
if (!isValid)
|
|
59
|
+
return null;
|
|
60
|
+
const dataString = util.encodeUTF8(dataBytes);
|
|
61
|
+
const data = JSON.parse(dataString);
|
|
62
|
+
const expiresAt = new Date(data.expiresAt);
|
|
63
|
+
const isExpired = expiresAt < new Date();
|
|
64
|
+
return {
|
|
65
|
+
data,
|
|
66
|
+
isValid: true,
|
|
67
|
+
isExpired,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Save a license key to disk
|
|
76
|
+
*/
|
|
77
|
+
export function saveLicense(licenseString) {
|
|
78
|
+
try {
|
|
79
|
+
ensureLicenseDir();
|
|
80
|
+
writeFileSync(LICENSE_FILE, licenseString.trim(), { mode: 0o600 });
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Load the saved license from disk
|
|
89
|
+
*/
|
|
90
|
+
export function loadLicense() {
|
|
91
|
+
if (!existsSync(LICENSE_FILE))
|
|
92
|
+
return null;
|
|
93
|
+
try {
|
|
94
|
+
const licenseString = readFileSync(LICENSE_FILE, 'utf-8');
|
|
95
|
+
return verifyLicense(licenseString);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if user has a valid Pro license
|
|
103
|
+
*/
|
|
104
|
+
export function isPro() {
|
|
105
|
+
const license = loadLicense();
|
|
106
|
+
if (!license)
|
|
107
|
+
return false;
|
|
108
|
+
if (!license.isValid)
|
|
109
|
+
return false;
|
|
110
|
+
if (license.isExpired)
|
|
111
|
+
return false;
|
|
112
|
+
return license.data.plan === 'pro';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if a specific Pro feature is enabled
|
|
116
|
+
*/
|
|
117
|
+
export function hasFeature(feature) {
|
|
118
|
+
const license = loadLicense();
|
|
119
|
+
if (!license || !license.isValid || license.isExpired)
|
|
120
|
+
return false;
|
|
121
|
+
return license.data.features.includes(feature);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get license status summary
|
|
125
|
+
*/
|
|
126
|
+
export function getLicenseStatus() {
|
|
127
|
+
const license = loadLicense();
|
|
128
|
+
if (!license || !license.isValid || license.isExpired) {
|
|
129
|
+
return {
|
|
130
|
+
plan: 'free',
|
|
131
|
+
features: [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const expiresAt = new Date(license.data.expiresAt);
|
|
135
|
+
const now = new Date();
|
|
136
|
+
const daysRemaining = Math.ceil((expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
137
|
+
return {
|
|
138
|
+
plan: license.data.plan,
|
|
139
|
+
email: license.data.email,
|
|
140
|
+
expiresAt: license.data.expiresAt,
|
|
141
|
+
features: license.data.features,
|
|
142
|
+
daysRemaining,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check imported key limit and throw if exceeded (for free tier)
|
|
147
|
+
*/
|
|
148
|
+
export function checkKeyLimit() {
|
|
149
|
+
if (isPro())
|
|
150
|
+
return; // Pro has unlimited
|
|
151
|
+
const knownKeys = loadKnownKeys();
|
|
152
|
+
const keyCount = Object.keys(knownKeys).length;
|
|
153
|
+
if (keyCount >= FREE_TIER_LIMITS.maxImportedKeys) {
|
|
154
|
+
console.error(`\n🍄 Free tier limit reached: ${keyCount}/${FREE_TIER_LIMITS.maxImportedKeys} imported keys`);
|
|
155
|
+
console.error('');
|
|
156
|
+
console.error(' Options:');
|
|
157
|
+
console.error(' • Remove unused keys from ~/.myceliumail/keys/known_keys.json');
|
|
158
|
+
console.error(' • Upgrade: myceliumail.dev/pro for unlimited keys');
|
|
159
|
+
console.error('');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Print Pro upsell message (soft sell)
|
|
165
|
+
*/
|
|
166
|
+
export function printProUpsell(feature) {
|
|
167
|
+
if (isPro())
|
|
168
|
+
return;
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(`💎 Pro tip: Upgrade for ${feature}`);
|
|
171
|
+
console.log(' myceliumail.dev/pro');
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog - Myceliumail MCP Server
|
|
2
|
+
|
|
3
|
+
All notable changes to the MCP server will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.11] - 2025-12-21
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- DMG installer and desktop app fixes
|
|
9
|
+
- Improved error handling in MCP tools
|
|
10
|
+
|
|
11
|
+
## [1.0.9] - 2025-12-20
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Partial ID lookup for message reading (matches main CLI fix)
|
|
15
|
+
|
|
16
|
+
## [1.0.8] - 2025-12-20
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Sync with main myceliumail package updates
|
|
20
|
+
|
|
21
|
+
## [1.0.7] - 2025-12-18
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Supabase column names to match actual schema (`to_agent` vs `recipient`)
|
|
25
|
+
- Added error logging (removed silent catch blocks)
|
|
26
|
+
- Config file support (`~/.myceliumail/config.json`)
|
|
27
|
+
|
|
28
|
+
## [1.0.6] - 2025-12-18
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- Agent ID case normalization (all lowercase)
|
|
32
|
+
|
|
33
|
+
## [1.0.5] - 2025-12-18
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- Key import handling improvements
|
|
37
|
+
|
|
38
|
+
## [1.0.4] - 2025-12-18
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
- Encryption/decryption edge cases
|
|
42
|
+
|
|
43
|
+
## [1.0.3] - 2025-12-17
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- Message sending reliability improvements
|
|
47
|
+
|
|
48
|
+
## [1.0.2] - 2025-12-16
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- Initial bug fixes after launch
|
|
52
|
+
|
|
53
|
+
## [1.0.0] - 2025-12-16
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
- Initial MCP server release
|
|
57
|
+
- 8 messaging tools for Claude Desktop:
|
|
58
|
+
- `check_inbox` - List received messages
|
|
59
|
+
- `read_message` - Read and decrypt messages
|
|
60
|
+
- `send_message` - Send messages to other agents
|
|
61
|
+
- `reply_message` - Reply to messages
|
|
62
|
+
- `generate_keys` - Create encryption keypair
|
|
63
|
+
- `list_keys` - Show available keys
|
|
64
|
+
- `import_key` - Import peer public keys
|
|
65
|
+
- `archive_message` - Archive messages
|
|
66
|
+
- End-to-end encryption support (NaCl/TweetNaCl.js)
|
|
67
|
+
- Local and Supabase storage backends
|
|
68
|
+
- Automatic fallback from cloud to local storage
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myceliumail-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "myceliumail-mcp",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.12",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
package/mcp-server/package.json
CHANGED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for MCP Pro features.
|
|
5
|
+
* MCP server is a Pro feature - requires valid license to start.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import nacl from 'tweetnacl';
|
|
9
|
+
import util from 'tweetnacl-util';
|
|
10
|
+
import { existsSync, readFileSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
|
|
14
|
+
// License storage location (shared with CLI)
|
|
15
|
+
const LICENSE_FILE = join(homedir(), '.myceliumail', 'license.key');
|
|
16
|
+
|
|
17
|
+
// Treebird's public key for license verification (Ed25519)
|
|
18
|
+
const TREEBIRD_PUBLIC_KEY = 'XqIqSlybZGKkKemgLKKl8P9MepnObhcJcxxZHtgG8/o=';
|
|
19
|
+
|
|
20
|
+
export interface LicenseData {
|
|
21
|
+
email: string;
|
|
22
|
+
plan: 'free' | 'pro';
|
|
23
|
+
expiresAt: string;
|
|
24
|
+
issuedAt: string;
|
|
25
|
+
features: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface License {
|
|
29
|
+
data: LicenseData;
|
|
30
|
+
isValid: boolean;
|
|
31
|
+
isExpired: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parse a license string into components
|
|
36
|
+
*/
|
|
37
|
+
function parseLicenseString(licenseString: string): { version: string; data: string; signature: string } | null {
|
|
38
|
+
const parts = licenseString.trim().split('.');
|
|
39
|
+
if (parts.length !== 3) return null;
|
|
40
|
+
|
|
41
|
+
const [version, data, signature] = parts;
|
|
42
|
+
if (version !== 'LICENSE_V1') return null;
|
|
43
|
+
|
|
44
|
+
return { version, data, signature };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Verify a license string using Ed25519 detached signature
|
|
49
|
+
*/
|
|
50
|
+
export function verifyLicense(licenseString: string): License | null {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = parseLicenseString(licenseString);
|
|
53
|
+
if (!parsed) return null;
|
|
54
|
+
|
|
55
|
+
const dataBytes = util.decodeBase64(parsed.data);
|
|
56
|
+
const publicKey = util.decodeBase64(TREEBIRD_PUBLIC_KEY);
|
|
57
|
+
const signatureBytes = util.decodeBase64(parsed.signature);
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
const isValid = (nacl as any).sign.detached.verify(dataBytes, signatureBytes, publicKey);
|
|
61
|
+
if (!isValid) return null;
|
|
62
|
+
|
|
63
|
+
const dataString = util.encodeUTF8(dataBytes);
|
|
64
|
+
const data = JSON.parse(dataString) as LicenseData;
|
|
65
|
+
|
|
66
|
+
const expiresAt = new Date(data.expiresAt);
|
|
67
|
+
const isExpired = expiresAt < new Date();
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
data,
|
|
71
|
+
isValid: true,
|
|
72
|
+
isExpired,
|
|
73
|
+
};
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Load and verify license from disk
|
|
81
|
+
*/
|
|
82
|
+
export function loadLicense(): License | null {
|
|
83
|
+
if (!existsSync(LICENSE_FILE)) return null;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const licenseString = readFileSync(LICENSE_FILE, 'utf-8');
|
|
87
|
+
return verifyLicense(licenseString);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if user has a valid Pro license
|
|
95
|
+
*/
|
|
96
|
+
export function isPro(): boolean {
|
|
97
|
+
const license = loadLicense();
|
|
98
|
+
if (!license) return false;
|
|
99
|
+
if (!license.isValid) return false;
|
|
100
|
+
if (license.isExpired) return false;
|
|
101
|
+
return license.data.plan === 'pro';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if MCP feature is enabled
|
|
106
|
+
*/
|
|
107
|
+
export function hasMcpAccess(): boolean {
|
|
108
|
+
const license = loadLicense();
|
|
109
|
+
if (!license || !license.isValid || license.isExpired) return false;
|
|
110
|
+
return license.data.features.includes('mcp_server');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Verify Pro license or exit with upgrade message
|
|
115
|
+
*/
|
|
116
|
+
export function requireProLicense(): void {
|
|
117
|
+
const license = loadLicense();
|
|
118
|
+
|
|
119
|
+
if (!license) {
|
|
120
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
121
|
+
console.error('🍄 Myceliumail MCP Server - Pro Feature');
|
|
122
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
123
|
+
console.error('');
|
|
124
|
+
console.error('This feature requires a Pro license.');
|
|
125
|
+
console.error('');
|
|
126
|
+
console.error('Activate with: mycmail activate <license-key>');
|
|
127
|
+
console.error('Get a license: myceliumail.dev/pro');
|
|
128
|
+
console.error('');
|
|
129
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!license.isValid) {
|
|
134
|
+
console.error('❌ Invalid license. Please re-activate.');
|
|
135
|
+
console.error(' mycmail activate <license-key>');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (license.isExpired) {
|
|
140
|
+
console.error('❌ License expired on', new Date(license.data.expiresAt).toLocaleDateString());
|
|
141
|
+
console.error(' Renew at: myceliumail.dev/pro');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Valid Pro license - show confirmation
|
|
146
|
+
console.error(`🍄 Myceliumail MCP (Pro) - ${license.data.email}`);
|
|
147
|
+
}
|
package/mcp-server/src/server.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { z } from 'zod';
|
|
|
14
14
|
import * as crypto from './lib/crypto.js';
|
|
15
15
|
import * as storage from './lib/storage.js';
|
|
16
16
|
import { getAgentId } from './lib/config.js';
|
|
17
|
+
import { requireProLicense } from './lib/license.js';
|
|
17
18
|
|
|
18
19
|
// Create the MCP server
|
|
19
20
|
const server = new McpServer({
|
|
@@ -379,6 +380,9 @@ server.tool(
|
|
|
379
380
|
|
|
380
381
|
// Start the server
|
|
381
382
|
async function main() {
|
|
383
|
+
// Verify Pro license before starting
|
|
384
|
+
requireProLicense();
|
|
385
|
+
|
|
382
386
|
const transport = new StdioServerTransport();
|
|
383
387
|
await server.connect(transport);
|
|
384
388
|
console.error('Myceliumail MCP server running');
|
package/package.json
CHANGED
package/src/bin/myceliumail.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { createBroadcastCommand } from '../commands/broadcast.js';
|
|
|
25
25
|
import { createWatchCommand } from '../commands/watch.js';
|
|
26
26
|
import { createExportCommand } from '../commands/export.js';
|
|
27
27
|
import { createStatusCommand } from '../commands/status.js';
|
|
28
|
+
import { createActivateCommand, createLicenseStatusCommand } from '../commands/activate.js';
|
|
28
29
|
|
|
29
30
|
const program = new Command();
|
|
30
31
|
|
|
@@ -54,5 +55,10 @@ program.addCommand(createWatchCommand());
|
|
|
54
55
|
program.addCommand(createExportCommand());
|
|
55
56
|
program.addCommand(createStatusCommand());
|
|
56
57
|
|
|
58
|
+
// License management
|
|
59
|
+
program.addCommand(createActivateCommand());
|
|
60
|
+
program.addCommand(createLicenseStatusCommand());
|
|
61
|
+
|
|
57
62
|
// Parse and run
|
|
58
63
|
program.parse();
|
|
64
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Activation Command
|
|
3
|
+
*
|
|
4
|
+
* Activates a Pro license key.
|
|
5
|
+
* Usage: mycmail activate <license-key>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { verifyLicense, saveLicense, getLicenseStatus, FREE_TIER_LIMITS } from '../lib/license.js';
|
|
10
|
+
import { loadKnownKeys } from '../lib/crypto.js';
|
|
11
|
+
|
|
12
|
+
export function createActivateCommand(): Command {
|
|
13
|
+
return new Command('activate')
|
|
14
|
+
.description('Activate a Pro license key')
|
|
15
|
+
.argument('<license-key>', 'Your license key from myceliumail.dev/pro')
|
|
16
|
+
.action(async (licenseKey: string) => {
|
|
17
|
+
console.log('🍄 Activating license...\n');
|
|
18
|
+
|
|
19
|
+
// Verify the license
|
|
20
|
+
const license = verifyLicense(licenseKey);
|
|
21
|
+
|
|
22
|
+
if (!license) {
|
|
23
|
+
console.error('❌ Invalid license key');
|
|
24
|
+
console.error(' Please check your key and try again.');
|
|
25
|
+
console.error(' Get a license at: myceliumail.dev/pro');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (license.isExpired) {
|
|
30
|
+
console.error('❌ This license has expired');
|
|
31
|
+
console.error(` Expired on: ${new Date(license.data.expiresAt).toLocaleDateString()}`);
|
|
32
|
+
console.error(' Renew at: myceliumail.dev/pro');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Save the license
|
|
37
|
+
const saved = saveLicense(licenseKey);
|
|
38
|
+
if (!saved) {
|
|
39
|
+
console.error('❌ Failed to save license');
|
|
40
|
+
console.error(' Please check file permissions for ~/.myceliumail/');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Show success
|
|
45
|
+
const status = getLicenseStatus();
|
|
46
|
+
console.log('✅ Pro License activated!\n');
|
|
47
|
+
console.log(` Email: ${status.email}`);
|
|
48
|
+
console.log(` Plan: ${status.plan.toUpperCase()}`);
|
|
49
|
+
console.log(` Expires: ${new Date(status.expiresAt!).toLocaleDateString()}`);
|
|
50
|
+
console.log(` Features: ${status.features.join(', ')}`);
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log('🍄 Thank you for supporting Myceliumail!');
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createLicenseStatusCommand(): Command {
|
|
57
|
+
return new Command('license')
|
|
58
|
+
.description('Show license status and plan details')
|
|
59
|
+
.action(async () => {
|
|
60
|
+
const status = getLicenseStatus();
|
|
61
|
+
const knownKeys = loadKnownKeys();
|
|
62
|
+
const keyCount = Object.keys(knownKeys).length;
|
|
63
|
+
|
|
64
|
+
console.log('🍄 Myceliumail License Status\n');
|
|
65
|
+
|
|
66
|
+
if (status.plan === 'pro') {
|
|
67
|
+
console.log(` Plan: 💎 Pro`);
|
|
68
|
+
console.log(` Email: ${status.email}`);
|
|
69
|
+
console.log(` Expires: ${new Date(status.expiresAt!).toLocaleDateString()} (${status.daysRemaining} days)`);
|
|
70
|
+
console.log(` Features: ${status.features.join(', ')}`);
|
|
71
|
+
console.log(` Keys: ${keyCount} imported (unlimited)`);
|
|
72
|
+
} else {
|
|
73
|
+
console.log(` Plan: Free`);
|
|
74
|
+
console.log(` Keys: ${keyCount}/${FREE_TIER_LIMITS.maxImportedKeys} imported`);
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log(' 💎 Upgrade to Pro for:');
|
|
77
|
+
console.log(' • Unlimited imported keys');
|
|
78
|
+
console.log(' • MCP Server integration');
|
|
79
|
+
console.log(' • Cloud key backup/restore');
|
|
80
|
+
console.log(' • Real-time notifications');
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(' Get Pro: myceliumail.dev/pro');
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import { saveKnownKey, getKnownKey } from '../lib/crypto.js';
|
|
7
|
+
import { checkKeyLimit } from '../lib/license.js';
|
|
7
8
|
|
|
8
9
|
export function createKeyImportCommand(): Command {
|
|
9
10
|
return new Command('key-import')
|
|
@@ -26,6 +27,11 @@ export function createKeyImportCommand(): Command {
|
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
// Check key limit for free tier (only for new keys)
|
|
31
|
+
if (!existing) {
|
|
32
|
+
checkKeyLimit();
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
saveKnownKey(agentId, publicKey);
|
|
30
36
|
|
|
31
37
|
console.log(`✅ Imported public key for ${agentId}`);
|
|
@@ -33,3 +39,4 @@ export function createKeyImportCommand(): Command {
|
|
|
33
39
|
console.log('\n🔐 You can now send encrypted messages to this agent');
|
|
34
40
|
});
|
|
35
41
|
}
|
|
42
|
+
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for Pro features.
|
|
5
|
+
* Public key is embedded; private key is kept by treebird for signing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import nacl from 'tweetnacl';
|
|
9
|
+
import util from 'tweetnacl-util';
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
import { loadKnownKeys } from './crypto.js';
|
|
14
|
+
|
|
15
|
+
// License storage location
|
|
16
|
+
const LICENSE_DIR = join(homedir(), '.myceliumail');
|
|
17
|
+
const LICENSE_FILE = join(LICENSE_DIR, 'license.key');
|
|
18
|
+
|
|
19
|
+
// Treebird's public key for license verification (Ed25519)
|
|
20
|
+
// Use the same key as Spidersan for unified licensing
|
|
21
|
+
const TREEBIRD_PUBLIC_KEY = 'XqIqSlybZGKkKemgLKKl8P9MepnObhcJcxxZHtgG8/o=';
|
|
22
|
+
|
|
23
|
+
// Free tier limits
|
|
24
|
+
export const FREE_TIER_LIMITS = {
|
|
25
|
+
maxImportedKeys: 5,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Pro features
|
|
29
|
+
export type ProFeature =
|
|
30
|
+
| 'unlimited_keys'
|
|
31
|
+
| 'mcp_server'
|
|
32
|
+
| 'cloud_sync'
|
|
33
|
+
| 'key_backup'
|
|
34
|
+
| 'realtime_watch';
|
|
35
|
+
|
|
36
|
+
export interface LicenseData {
|
|
37
|
+
email: string;
|
|
38
|
+
plan: 'free' | 'pro';
|
|
39
|
+
expiresAt: string; // ISO date
|
|
40
|
+
issuedAt: string; // ISO date
|
|
41
|
+
features: ProFeature[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface License {
|
|
45
|
+
data: LicenseData;
|
|
46
|
+
isValid: boolean;
|
|
47
|
+
isExpired: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Ensure license directory exists
|
|
52
|
+
*/
|
|
53
|
+
function ensureLicenseDir(): void {
|
|
54
|
+
if (!existsSync(LICENSE_DIR)) {
|
|
55
|
+
mkdirSync(LICENSE_DIR, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse a license string into components
|
|
61
|
+
* Format: LICENSE_V1.BASE64_DATA.BASE64_SIGNATURE
|
|
62
|
+
*/
|
|
63
|
+
function parseLicenseString(licenseString: string): { version: string; data: string; signature: string } | null {
|
|
64
|
+
const parts = licenseString.trim().split('.');
|
|
65
|
+
if (parts.length !== 3) return null;
|
|
66
|
+
|
|
67
|
+
const [version, data, signature] = parts;
|
|
68
|
+
if (version !== 'LICENSE_V1') return null;
|
|
69
|
+
|
|
70
|
+
return { version, data, signature };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Verify a license string using Ed25519 detached signature
|
|
75
|
+
*/
|
|
76
|
+
export function verifyLicense(licenseString: string): License | null {
|
|
77
|
+
try {
|
|
78
|
+
const parsed = parseLicenseString(licenseString);
|
|
79
|
+
if (!parsed) return null;
|
|
80
|
+
|
|
81
|
+
const dataBytes = util.decodeBase64(parsed.data);
|
|
82
|
+
|
|
83
|
+
// Verify detached Ed25519 signature
|
|
84
|
+
const publicKey = util.decodeBase64(TREEBIRD_PUBLIC_KEY);
|
|
85
|
+
const signatureBytes = util.decodeBase64(parsed.signature);
|
|
86
|
+
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
+
const isValid = (nacl as any).sign.detached.verify(dataBytes, signatureBytes, publicKey);
|
|
89
|
+
if (!isValid) return null;
|
|
90
|
+
|
|
91
|
+
const dataString = util.encodeUTF8(dataBytes);
|
|
92
|
+
const data = JSON.parse(dataString) as LicenseData;
|
|
93
|
+
|
|
94
|
+
const expiresAt = new Date(data.expiresAt);
|
|
95
|
+
const isExpired = expiresAt < new Date();
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
data,
|
|
99
|
+
isValid: true,
|
|
100
|
+
isExpired,
|
|
101
|
+
};
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Save a license key to disk
|
|
109
|
+
*/
|
|
110
|
+
export function saveLicense(licenseString: string): boolean {
|
|
111
|
+
try {
|
|
112
|
+
ensureLicenseDir();
|
|
113
|
+
writeFileSync(LICENSE_FILE, licenseString.trim(), { mode: 0o600 });
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Load the saved license from disk
|
|
122
|
+
*/
|
|
123
|
+
export function loadLicense(): License | null {
|
|
124
|
+
if (!existsSync(LICENSE_FILE)) return null;
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const licenseString = readFileSync(LICENSE_FILE, 'utf-8');
|
|
128
|
+
return verifyLicense(licenseString);
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if user has a valid Pro license
|
|
136
|
+
*/
|
|
137
|
+
export function isPro(): boolean {
|
|
138
|
+
const license = loadLicense();
|
|
139
|
+
if (!license) return false;
|
|
140
|
+
if (!license.isValid) return false;
|
|
141
|
+
if (license.isExpired) return false;
|
|
142
|
+
return license.data.plan === 'pro';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Check if a specific Pro feature is enabled
|
|
147
|
+
*/
|
|
148
|
+
export function hasFeature(feature: ProFeature): boolean {
|
|
149
|
+
const license = loadLicense();
|
|
150
|
+
if (!license || !license.isValid || license.isExpired) return false;
|
|
151
|
+
return license.data.features.includes(feature);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get license status summary
|
|
156
|
+
*/
|
|
157
|
+
export function getLicenseStatus(): {
|
|
158
|
+
plan: 'free' | 'pro';
|
|
159
|
+
email?: string;
|
|
160
|
+
expiresAt?: string;
|
|
161
|
+
features: ProFeature[];
|
|
162
|
+
daysRemaining?: number;
|
|
163
|
+
} {
|
|
164
|
+
const license = loadLicense();
|
|
165
|
+
|
|
166
|
+
if (!license || !license.isValid || license.isExpired) {
|
|
167
|
+
return {
|
|
168
|
+
plan: 'free',
|
|
169
|
+
features: [],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const expiresAt = new Date(license.data.expiresAt);
|
|
174
|
+
const now = new Date();
|
|
175
|
+
const daysRemaining = Math.ceil((expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
plan: license.data.plan,
|
|
179
|
+
email: license.data.email,
|
|
180
|
+
expiresAt: license.data.expiresAt,
|
|
181
|
+
features: license.data.features,
|
|
182
|
+
daysRemaining,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check imported key limit and throw if exceeded (for free tier)
|
|
188
|
+
*/
|
|
189
|
+
export function checkKeyLimit(): void {
|
|
190
|
+
if (isPro()) return; // Pro has unlimited
|
|
191
|
+
|
|
192
|
+
const knownKeys = loadKnownKeys();
|
|
193
|
+
const keyCount = Object.keys(knownKeys).length;
|
|
194
|
+
|
|
195
|
+
if (keyCount >= FREE_TIER_LIMITS.maxImportedKeys) {
|
|
196
|
+
console.error(`\n🍄 Free tier limit reached: ${keyCount}/${FREE_TIER_LIMITS.maxImportedKeys} imported keys`);
|
|
197
|
+
console.error('');
|
|
198
|
+
console.error(' Options:');
|
|
199
|
+
console.error(' • Remove unused keys from ~/.myceliumail/keys/known_keys.json');
|
|
200
|
+
console.error(' • Upgrade: myceliumail.dev/pro for unlimited keys');
|
|
201
|
+
console.error('');
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Print Pro upsell message (soft sell)
|
|
208
|
+
*/
|
|
209
|
+
export function printProUpsell(feature: string): void {
|
|
210
|
+
if (isPro()) return;
|
|
211
|
+
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log(`💎 Pro tip: Upgrade for ${feature}`);
|
|
214
|
+
console.log(' myceliumail.dev/pro');
|
|
215
|
+
}
|