@marlinjai/email-mcp 1.4.0 → 1.4.2
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/README.md +8 -6
- package/dist/index.js +600 -571
- package/dist/index.js.map +4 -4
- package/dist/setup/wizard.js +147 -125
- package/dist/setup/wizard.js.map +3 -3
- package/package.json +1 -2
package/dist/setup/wizard.js
CHANGED
|
@@ -4,7 +4,107 @@
|
|
|
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
|
+
closePrompts();
|
|
60
|
+
let rawModeOk = true;
|
|
61
|
+
try {
|
|
62
|
+
input.setRawMode(true);
|
|
63
|
+
} catch {
|
|
64
|
+
rawModeOk = false;
|
|
65
|
+
}
|
|
66
|
+
if (!rawModeOk) {
|
|
67
|
+
const rl = getInterface();
|
|
68
|
+
rl.question("").then(resolve);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let value = "";
|
|
72
|
+
input.resume();
|
|
73
|
+
input.setEncoding("utf8");
|
|
74
|
+
const cleanup = () => {
|
|
75
|
+
input.setRawMode(false);
|
|
76
|
+
input.pause();
|
|
77
|
+
input.removeListener("data", onData);
|
|
78
|
+
};
|
|
79
|
+
const onData = (char) => {
|
|
80
|
+
switch (char) {
|
|
81
|
+
case "\n":
|
|
82
|
+
case "\r":
|
|
83
|
+
case CTRL_D:
|
|
84
|
+
cleanup();
|
|
85
|
+
output.write("\n");
|
|
86
|
+
resolve(value);
|
|
87
|
+
break;
|
|
88
|
+
case CTRL_C:
|
|
89
|
+
cleanup();
|
|
90
|
+
output.write("\n");
|
|
91
|
+
process.exit(130);
|
|
92
|
+
break;
|
|
93
|
+
case BACKSPACE:
|
|
94
|
+
case "\b":
|
|
95
|
+
if (value.length > 0) {
|
|
96
|
+
value = value.slice(0, -1);
|
|
97
|
+
output.write("\b \b");
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
value += char;
|
|
102
|
+
output.write("*");
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
input.on("data", onData);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
8
108
|
|
|
9
109
|
// src/auth/credential-store.ts
|
|
10
110
|
import crypto from "node:crypto";
|
|
@@ -2527,15 +2627,7 @@ async function testAndSave(creds) {
|
|
|
2527
2627
|
}
|
|
2528
2628
|
}
|
|
2529
2629
|
async function promptAccountName(defaultName) {
|
|
2530
|
-
|
|
2531
|
-
{
|
|
2532
|
-
type: "input",
|
|
2533
|
-
name: "name",
|
|
2534
|
-
message: "Account name:",
|
|
2535
|
-
default: defaultName
|
|
2536
|
-
}
|
|
2537
|
-
]);
|
|
2538
|
-
return name;
|
|
2630
|
+
return askText("Account name:", defaultName);
|
|
2539
2631
|
}
|
|
2540
2632
|
async function setupGmail() {
|
|
2541
2633
|
console.log("\n--- Gmail Setup ---");
|
|
@@ -2627,30 +2719,25 @@ async function setupICloud() {
|
|
|
2627
2719
|
console.log(
|
|
2628
2720
|
"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
2721
|
);
|
|
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
|
-
]);
|
|
2722
|
+
const email = await askValidated(
|
|
2723
|
+
"iCloud email address:",
|
|
2724
|
+
void 0,
|
|
2725
|
+
(v) => v.includes("@") || "Enter a valid email address"
|
|
2726
|
+
);
|
|
2727
|
+
let password = await askPassword("App-specific password:");
|
|
2728
|
+
while (password.trim().length === 0) {
|
|
2729
|
+
console.log(" Password is required");
|
|
2730
|
+
password = await askPassword("App-specific password:");
|
|
2731
|
+
}
|
|
2645
2732
|
const name = await promptAccountName("iCloud");
|
|
2646
2733
|
const id = crypto3.randomUUID();
|
|
2647
2734
|
const creds = {
|
|
2648
2735
|
id,
|
|
2649
2736
|
name,
|
|
2650
2737
|
provider: ProviderType.ICloud,
|
|
2651
|
-
email:
|
|
2738
|
+
email: email.trim(),
|
|
2652
2739
|
password: {
|
|
2653
|
-
password
|
|
2740
|
+
password,
|
|
2654
2741
|
host: "imap.mail.me.com",
|
|
2655
2742
|
port: 993,
|
|
2656
2743
|
tls: true,
|
|
@@ -2662,72 +2749,26 @@ async function setupICloud() {
|
|
|
2662
2749
|
}
|
|
2663
2750
|
async function setupIMAP() {
|
|
2664
2751
|
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
|
-
]);
|
|
2752
|
+
const portValidator = (v) => {
|
|
2753
|
+
const n = parseInt(v, 10);
|
|
2754
|
+
return n > 0 && n <= 65535 || "Enter a valid port number (1-65535)";
|
|
2755
|
+
};
|
|
2756
|
+
const email = await askValidated("Email address:", void 0, (v) => v.includes("@") || "Enter a valid email address");
|
|
2757
|
+
const host = await askValidated("IMAP host:", void 0, (v) => v.trim().length > 0 || "Host is required");
|
|
2758
|
+
const portStr = await askValidated("IMAP port:", "993", portValidator);
|
|
2759
|
+
const tls = await askConfirm("Use TLS?", true);
|
|
2760
|
+
let password = await askPassword("Password:");
|
|
2761
|
+
while (password.trim().length === 0) {
|
|
2762
|
+
console.log(" Password is required");
|
|
2763
|
+
password = await askPassword("Password:");
|
|
2764
|
+
}
|
|
2765
|
+
const configureSmtp = await askConfirm("Configure SMTP (for sending)?", false);
|
|
2708
2766
|
let smtpHost;
|
|
2709
2767
|
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);
|
|
2768
|
+
if (configureSmtp) {
|
|
2769
|
+
smtpHost = await askValidated("SMTP host:", void 0, (v) => v.trim().length > 0 || "SMTP host is required");
|
|
2770
|
+
const smtpPortStr = await askValidated("SMTP port:", "587", portValidator);
|
|
2771
|
+
smtpPort = parseInt(smtpPortStr, 10);
|
|
2731
2772
|
}
|
|
2732
2773
|
const name = await promptAccountName("IMAP");
|
|
2733
2774
|
const id = crypto3.randomUUID();
|
|
@@ -2735,12 +2776,12 @@ async function setupIMAP() {
|
|
|
2735
2776
|
id,
|
|
2736
2777
|
name,
|
|
2737
2778
|
provider: ProviderType.IMAP,
|
|
2738
|
-
email:
|
|
2779
|
+
email: email.trim(),
|
|
2739
2780
|
password: {
|
|
2740
|
-
password
|
|
2741
|
-
host:
|
|
2742
|
-
port: parseInt(
|
|
2743
|
-
tls
|
|
2781
|
+
password,
|
|
2782
|
+
host: host.trim(),
|
|
2783
|
+
port: parseInt(portStr, 10),
|
|
2784
|
+
tls,
|
|
2744
2785
|
smtpHost,
|
|
2745
2786
|
smtpPort
|
|
2746
2787
|
}
|
|
@@ -2770,14 +2811,7 @@ async function removeAccount(id) {
|
|
|
2770
2811
|
console.error(`Account not found: ${id}`);
|
|
2771
2812
|
process.exit(1);
|
|
2772
2813
|
}
|
|
2773
|
-
const
|
|
2774
|
-
{
|
|
2775
|
-
type: "confirm",
|
|
2776
|
-
name: "confirm",
|
|
2777
|
-
message: `Remove account "${acct.name}" (${acct.email})?`,
|
|
2778
|
-
default: false
|
|
2779
|
-
}
|
|
2780
|
-
]);
|
|
2814
|
+
const confirm = await askConfirm(`Remove account "${acct.name}" (${acct.email})?`, false);
|
|
2781
2815
|
if (confirm) {
|
|
2782
2816
|
await store.remove(id);
|
|
2783
2817
|
console.log(`Account "${acct.name}" removed.`);
|
|
@@ -2804,18 +2838,11 @@ async function main() {
|
|
|
2804
2838
|
console.log("@marlinjai/email-mcp Account Setup\n");
|
|
2805
2839
|
let addMore = true;
|
|
2806
2840
|
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
|
-
}
|
|
2841
|
+
const provider = await askChoice("Select provider:", [
|
|
2842
|
+
{ name: "Gmail", value: "gmail" },
|
|
2843
|
+
{ name: "Outlook", value: "outlook" },
|
|
2844
|
+
{ name: "iCloud", value: "icloud" },
|
|
2845
|
+
{ name: "Other IMAP", value: "imap" }
|
|
2819
2846
|
]);
|
|
2820
2847
|
switch (provider) {
|
|
2821
2848
|
case ProviderType.Gmail:
|
|
@@ -2834,15 +2861,7 @@ async function main() {
|
|
|
2834
2861
|
console.error(`Unknown provider: ${provider}`);
|
|
2835
2862
|
process.exit(1);
|
|
2836
2863
|
}
|
|
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;
|
|
2864
|
+
addMore = await askConfirm("Would you like to add another email account?", false);
|
|
2846
2865
|
}
|
|
2847
2866
|
console.log("\nSetup complete! You can now use the email tools in Claude Code.");
|
|
2848
2867
|
}
|
|
@@ -2850,5 +2869,8 @@ main().catch((err) => {
|
|
|
2850
2869
|
console.error(`
|
|
2851
2870
|
Setup failed: ${err.message}`);
|
|
2852
2871
|
process.exit(1);
|
|
2872
|
+
}).finally(() => {
|
|
2873
|
+
closePrompts();
|
|
2874
|
+
process.exit(0);
|
|
2853
2875
|
});
|
|
2854
2876
|
//# sourceMappingURL=wizard.js.map
|