@marlinjai/email-mcp 1.4.0 → 1.4.1
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/dist/index.js +592 -572
- package/dist/index.js.map +4 -4
- package/dist/setup/wizard.js +139 -126
- package/dist/setup/wizard.js.map +3 -3
- package/package.json +1 -2
package/dist/setup/wizard.js
CHANGED
|
@@ -4,7 +4,101 @@
|
|
|
4
4
|
// src/setup/wizard.ts
|
|
5
5
|
import crypto3 from "node:crypto";
|
|
6
6
|
import { exec } from "node:child_process";
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
// src/setup/prompts.ts
|
|
9
|
+
import readline from "node:readline/promises";
|
|
10
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
11
|
+
var CTRL_C = "";
|
|
12
|
+
var CTRL_D = "";
|
|
13
|
+
var BACKSPACE = "\x7F";
|
|
14
|
+
var sharedInterface = null;
|
|
15
|
+
function getInterface() {
|
|
16
|
+
if (!sharedInterface) {
|
|
17
|
+
sharedInterface = readline.createInterface({ input, output });
|
|
18
|
+
}
|
|
19
|
+
return sharedInterface;
|
|
20
|
+
}
|
|
21
|
+
function closePrompts() {
|
|
22
|
+
sharedInterface?.close();
|
|
23
|
+
sharedInterface = null;
|
|
24
|
+
}
|
|
25
|
+
async function askText(message, defaultValue) {
|
|
26
|
+
const rl = getInterface();
|
|
27
|
+
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
28
|
+
const answer = await rl.question(`${message}${suffix} `);
|
|
29
|
+
const trimmed = answer.trim();
|
|
30
|
+
return trimmed.length > 0 ? trimmed : defaultValue ?? "";
|
|
31
|
+
}
|
|
32
|
+
async function askValidated(message, defaultValue, validate) {
|
|
33
|
+
for (; ; ) {
|
|
34
|
+
const value = await askText(message, defaultValue);
|
|
35
|
+
const result = validate(value);
|
|
36
|
+
if (result === true) return value;
|
|
37
|
+
console.log(` ${result}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function askConfirm(message, defaultValue = false) {
|
|
41
|
+
const suffix = defaultValue ? "Y/n" : "y/N";
|
|
42
|
+
const answer = await askText(`${message} (${suffix})`);
|
|
43
|
+
if (!answer) return defaultValue;
|
|
44
|
+
return /^y/i.test(answer);
|
|
45
|
+
}
|
|
46
|
+
async function askChoice(message, choices) {
|
|
47
|
+
console.log(message);
|
|
48
|
+
choices.forEach((c, i) => console.log(` ${i + 1}) ${c.name}`));
|
|
49
|
+
for (; ; ) {
|
|
50
|
+
const answer = await askText("Enter a number:");
|
|
51
|
+
const idx = parseInt(answer, 10) - 1;
|
|
52
|
+
if (idx >= 0 && idx < choices.length) return choices[idx].value;
|
|
53
|
+
console.log(` Please enter a number between 1 and ${choices.length}.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function askPassword(message) {
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
output.write(`${message} `);
|
|
59
|
+
if (!input.isTTY || typeof input.setRawMode !== "function") {
|
|
60
|
+
const rl = getInterface();
|
|
61
|
+
rl.question("").then(resolve);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let value = "";
|
|
65
|
+
input.setRawMode(true);
|
|
66
|
+
input.resume();
|
|
67
|
+
input.setEncoding("utf8");
|
|
68
|
+
const cleanup = () => {
|
|
69
|
+
input.setRawMode(false);
|
|
70
|
+
input.pause();
|
|
71
|
+
input.removeListener("data", onData);
|
|
72
|
+
};
|
|
73
|
+
const onData = (char) => {
|
|
74
|
+
switch (char) {
|
|
75
|
+
case "\n":
|
|
76
|
+
case "\r":
|
|
77
|
+
case CTRL_D:
|
|
78
|
+
cleanup();
|
|
79
|
+
output.write("\n");
|
|
80
|
+
resolve(value);
|
|
81
|
+
break;
|
|
82
|
+
case CTRL_C:
|
|
83
|
+
cleanup();
|
|
84
|
+
output.write("\n");
|
|
85
|
+
process.exit(130);
|
|
86
|
+
break;
|
|
87
|
+
case BACKSPACE:
|
|
88
|
+
case "\b":
|
|
89
|
+
if (value.length > 0) {
|
|
90
|
+
value = value.slice(0, -1);
|
|
91
|
+
output.write("\b \b");
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
value += char;
|
|
96
|
+
output.write("*");
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
input.on("data", onData);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
8
102
|
|
|
9
103
|
// src/auth/credential-store.ts
|
|
10
104
|
import crypto from "node:crypto";
|
|
@@ -2527,15 +2621,7 @@ async function testAndSave(creds) {
|
|
|
2527
2621
|
}
|
|
2528
2622
|
}
|
|
2529
2623
|
async function promptAccountName(defaultName) {
|
|
2530
|
-
|
|
2531
|
-
{
|
|
2532
|
-
type: "input",
|
|
2533
|
-
name: "name",
|
|
2534
|
-
message: "Account name:",
|
|
2535
|
-
default: defaultName
|
|
2536
|
-
}
|
|
2537
|
-
]);
|
|
2538
|
-
return name;
|
|
2624
|
+
return askText("Account name:", defaultName);
|
|
2539
2625
|
}
|
|
2540
2626
|
async function setupGmail() {
|
|
2541
2627
|
console.log("\n--- Gmail Setup ---");
|
|
@@ -2627,30 +2713,25 @@ async function setupICloud() {
|
|
|
2627
2713
|
console.log(
|
|
2628
2714
|
"You need an app-specific password for iCloud Mail.\nGenerate one at https://appleid.apple.com/account/manage\n(Sign In & Security > App-Specific Passwords)\n"
|
|
2629
2715
|
);
|
|
2630
|
-
const
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
message: "App-specific password:",
|
|
2641
|
-
mask: "*",
|
|
2642
|
-
validate: (v) => v.trim().length > 0 || "Password is required"
|
|
2643
|
-
}
|
|
2644
|
-
]);
|
|
2716
|
+
const email = await askValidated(
|
|
2717
|
+
"iCloud email address:",
|
|
2718
|
+
void 0,
|
|
2719
|
+
(v) => v.includes("@") || "Enter a valid email address"
|
|
2720
|
+
);
|
|
2721
|
+
let password = await askPassword("App-specific password:");
|
|
2722
|
+
while (password.trim().length === 0) {
|
|
2723
|
+
console.log(" Password is required");
|
|
2724
|
+
password = await askPassword("App-specific password:");
|
|
2725
|
+
}
|
|
2645
2726
|
const name = await promptAccountName("iCloud");
|
|
2646
2727
|
const id = crypto3.randomUUID();
|
|
2647
2728
|
const creds = {
|
|
2648
2729
|
id,
|
|
2649
2730
|
name,
|
|
2650
2731
|
provider: ProviderType.ICloud,
|
|
2651
|
-
email:
|
|
2732
|
+
email: email.trim(),
|
|
2652
2733
|
password: {
|
|
2653
|
-
password
|
|
2734
|
+
password,
|
|
2654
2735
|
host: "imap.mail.me.com",
|
|
2655
2736
|
port: 993,
|
|
2656
2737
|
tls: true,
|
|
@@ -2662,72 +2743,26 @@ async function setupICloud() {
|
|
|
2662
2743
|
}
|
|
2663
2744
|
async function setupIMAP() {
|
|
2664
2745
|
console.log("\n--- Generic IMAP Setup ---\n");
|
|
2665
|
-
const
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
type: "input",
|
|
2680
|
-
name: "port",
|
|
2681
|
-
message: "IMAP port:",
|
|
2682
|
-
default: "993",
|
|
2683
|
-
validate: (v) => {
|
|
2684
|
-
const n = parseInt(v, 10);
|
|
2685
|
-
return n > 0 && n <= 65535 || "Enter a valid port number (1-65535)";
|
|
2686
|
-
}
|
|
2687
|
-
},
|
|
2688
|
-
{
|
|
2689
|
-
type: "confirm",
|
|
2690
|
-
name: "tls",
|
|
2691
|
-
message: "Use TLS?",
|
|
2692
|
-
default: true
|
|
2693
|
-
},
|
|
2694
|
-
{
|
|
2695
|
-
type: "password",
|
|
2696
|
-
name: "password",
|
|
2697
|
-
message: "Password:",
|
|
2698
|
-
mask: "*",
|
|
2699
|
-
validate: (v) => v.trim().length > 0 || "Password is required"
|
|
2700
|
-
},
|
|
2701
|
-
{
|
|
2702
|
-
type: "confirm",
|
|
2703
|
-
name: "configureSmtp",
|
|
2704
|
-
message: "Configure SMTP (for sending)?",
|
|
2705
|
-
default: false
|
|
2706
|
-
}
|
|
2707
|
-
]);
|
|
2746
|
+
const portValidator = (v) => {
|
|
2747
|
+
const n = parseInt(v, 10);
|
|
2748
|
+
return n > 0 && n <= 65535 || "Enter a valid port number (1-65535)";
|
|
2749
|
+
};
|
|
2750
|
+
const email = await askValidated("Email address:", void 0, (v) => v.includes("@") || "Enter a valid email address");
|
|
2751
|
+
const host = await askValidated("IMAP host:", void 0, (v) => v.trim().length > 0 || "Host is required");
|
|
2752
|
+
const portStr = await askValidated("IMAP port:", "993", portValidator);
|
|
2753
|
+
const tls = await askConfirm("Use TLS?", true);
|
|
2754
|
+
let password = await askPassword("Password:");
|
|
2755
|
+
while (password.trim().length === 0) {
|
|
2756
|
+
console.log(" Password is required");
|
|
2757
|
+
password = await askPassword("Password:");
|
|
2758
|
+
}
|
|
2759
|
+
const configureSmtp = await askConfirm("Configure SMTP (for sending)?", false);
|
|
2708
2760
|
let smtpHost;
|
|
2709
2761
|
let smtpPort;
|
|
2710
|
-
if (
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
name: "smtpHost",
|
|
2715
|
-
message: "SMTP host:",
|
|
2716
|
-
validate: (v) => v.trim().length > 0 || "SMTP host is required"
|
|
2717
|
-
},
|
|
2718
|
-
{
|
|
2719
|
-
type: "input",
|
|
2720
|
-
name: "smtpPort",
|
|
2721
|
-
message: "SMTP port:",
|
|
2722
|
-
default: "587",
|
|
2723
|
-
validate: (v) => {
|
|
2724
|
-
const n = parseInt(v, 10);
|
|
2725
|
-
return n > 0 && n <= 65535 || "Enter a valid port number (1-65535)";
|
|
2726
|
-
}
|
|
2727
|
-
}
|
|
2728
|
-
]);
|
|
2729
|
-
smtpHost = smtp.smtpHost.trim();
|
|
2730
|
-
smtpPort = parseInt(smtp.smtpPort, 10);
|
|
2762
|
+
if (configureSmtp) {
|
|
2763
|
+
smtpHost = await askValidated("SMTP host:", void 0, (v) => v.trim().length > 0 || "SMTP host is required");
|
|
2764
|
+
const smtpPortStr = await askValidated("SMTP port:", "587", portValidator);
|
|
2765
|
+
smtpPort = parseInt(smtpPortStr, 10);
|
|
2731
2766
|
}
|
|
2732
2767
|
const name = await promptAccountName("IMAP");
|
|
2733
2768
|
const id = crypto3.randomUUID();
|
|
@@ -2735,12 +2770,12 @@ async function setupIMAP() {
|
|
|
2735
2770
|
id,
|
|
2736
2771
|
name,
|
|
2737
2772
|
provider: ProviderType.IMAP,
|
|
2738
|
-
email:
|
|
2773
|
+
email: email.trim(),
|
|
2739
2774
|
password: {
|
|
2740
|
-
password
|
|
2741
|
-
host:
|
|
2742
|
-
port: parseInt(
|
|
2743
|
-
tls
|
|
2775
|
+
password,
|
|
2776
|
+
host: host.trim(),
|
|
2777
|
+
port: parseInt(portStr, 10),
|
|
2778
|
+
tls,
|
|
2744
2779
|
smtpHost,
|
|
2745
2780
|
smtpPort
|
|
2746
2781
|
}
|
|
@@ -2770,14 +2805,7 @@ async function removeAccount(id) {
|
|
|
2770
2805
|
console.error(`Account not found: ${id}`);
|
|
2771
2806
|
process.exit(1);
|
|
2772
2807
|
}
|
|
2773
|
-
const
|
|
2774
|
-
{
|
|
2775
|
-
type: "confirm",
|
|
2776
|
-
name: "confirm",
|
|
2777
|
-
message: `Remove account "${acct.name}" (${acct.email})?`,
|
|
2778
|
-
default: false
|
|
2779
|
-
}
|
|
2780
|
-
]);
|
|
2808
|
+
const confirm = await askConfirm(`Remove account "${acct.name}" (${acct.email})?`, false);
|
|
2781
2809
|
if (confirm) {
|
|
2782
2810
|
await store.remove(id);
|
|
2783
2811
|
console.log(`Account "${acct.name}" removed.`);
|
|
@@ -2804,18 +2832,11 @@ async function main() {
|
|
|
2804
2832
|
console.log("@marlinjai/email-mcp Account Setup\n");
|
|
2805
2833
|
let addMore = true;
|
|
2806
2834
|
while (addMore) {
|
|
2807
|
-
const
|
|
2808
|
-
{
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
choices: [
|
|
2813
|
-
{ name: "Gmail", value: "gmail" },
|
|
2814
|
-
{ name: "Outlook", value: "outlook" },
|
|
2815
|
-
{ name: "iCloud", value: "icloud" },
|
|
2816
|
-
{ name: "Other IMAP", value: "imap" }
|
|
2817
|
-
]
|
|
2818
|
-
}
|
|
2835
|
+
const provider = await askChoice("Select provider:", [
|
|
2836
|
+
{ name: "Gmail", value: "gmail" },
|
|
2837
|
+
{ name: "Outlook", value: "outlook" },
|
|
2838
|
+
{ name: "iCloud", value: "icloud" },
|
|
2839
|
+
{ name: "Other IMAP", value: "imap" }
|
|
2819
2840
|
]);
|
|
2820
2841
|
switch (provider) {
|
|
2821
2842
|
case ProviderType.Gmail:
|
|
@@ -2834,15 +2855,7 @@ async function main() {
|
|
|
2834
2855
|
console.error(`Unknown provider: ${provider}`);
|
|
2835
2856
|
process.exit(1);
|
|
2836
2857
|
}
|
|
2837
|
-
|
|
2838
|
-
{
|
|
2839
|
-
type: "confirm",
|
|
2840
|
-
name: "another",
|
|
2841
|
-
message: "Would you like to add another email account?",
|
|
2842
|
-
default: false
|
|
2843
|
-
}
|
|
2844
|
-
]);
|
|
2845
|
-
addMore = another;
|
|
2858
|
+
addMore = await askConfirm("Would you like to add another email account?", false);
|
|
2846
2859
|
}
|
|
2847
2860
|
console.log("\nSetup complete! You can now use the email tools in Claude Code.");
|
|
2848
2861
|
}
|
|
@@ -2850,5 +2863,5 @@ main().catch((err) => {
|
|
|
2850
2863
|
console.error(`
|
|
2851
2864
|
Setup failed: ${err.message}`);
|
|
2852
2865
|
process.exit(1);
|
|
2853
|
-
});
|
|
2866
|
+
}).finally(closePrompts);
|
|
2854
2867
|
//# sourceMappingURL=wizard.js.map
|