@peppermint-mcp/wizard 0.2.3 → 0.3.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/cli.js +106 -65
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -69,7 +69,7 @@ async function detectClaudeDesktop() {
|
|
|
69
69
|
try {
|
|
70
70
|
const content = readFileSync(configPath, "utf-8");
|
|
71
71
|
const parsed = jsonc.parse(content);
|
|
72
|
-
alreadyInstalled = !!parsed?.mcpServers?.peppermint;
|
|
72
|
+
alreadyInstalled = !!parsed?.mcpServers?.["peppermint-memory"] || !!parsed?.mcpServers?.peppermint;
|
|
73
73
|
} catch {
|
|
74
74
|
warnings.push("Config file exists but could not be parsed");
|
|
75
75
|
}
|
|
@@ -77,7 +77,7 @@ async function detectClaudeDesktop() {
|
|
|
77
77
|
return {
|
|
78
78
|
id: "claude-desktop",
|
|
79
79
|
name: "Claude Desktop",
|
|
80
|
-
installMethod: "file-
|
|
80
|
+
installMethod: "file-native-http",
|
|
81
81
|
configPath,
|
|
82
82
|
alreadyInstalled,
|
|
83
83
|
needsRestart: true,
|
|
@@ -106,7 +106,7 @@ async function detectCursor() {
|
|
|
106
106
|
try {
|
|
107
107
|
const content = readFileSync2(configPath, "utf-8");
|
|
108
108
|
const parsed = jsonc2.parse(content);
|
|
109
|
-
alreadyInstalled = !!parsed?.mcpServers?.peppermint;
|
|
109
|
+
alreadyInstalled = !!parsed?.mcpServers?.["peppermint-memory"] || !!parsed?.mcpServers?.peppermint;
|
|
110
110
|
} catch {
|
|
111
111
|
warnings.push("Config file exists but could not be parsed");
|
|
112
112
|
}
|
|
@@ -382,17 +382,20 @@ async function installClaudeCode(serverUrl, apiKey, dryRun) {
|
|
|
382
382
|
};
|
|
383
383
|
}
|
|
384
384
|
try {
|
|
385
|
+
for (const name of ["peppermint-memory", "peppermint"]) {
|
|
386
|
+
try {
|
|
387
|
+
await exec3("claude", ["mcp", "remove", "--scope", "user", name], { timeout: 15e3 });
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
}
|
|
385
391
|
await exec3("claude", args, { timeout: 15e3 });
|
|
386
392
|
return {
|
|
387
393
|
success: true,
|
|
388
394
|
message: "Added peppermint-memory via claude mcp add",
|
|
389
|
-
needsRestart:
|
|
395
|
+
needsRestart: true
|
|
390
396
|
};
|
|
391
397
|
} catch (err) {
|
|
392
398
|
const message = err instanceof Error ? err.message : "claude mcp add failed";
|
|
393
|
-
if (message.includes("already exists")) {
|
|
394
|
-
return { success: true, message: "peppermint-memory already configured", needsRestart: false };
|
|
395
|
-
}
|
|
396
399
|
return { success: false, message, needsRestart: false };
|
|
397
400
|
}
|
|
398
401
|
}
|
|
@@ -507,23 +510,17 @@ function getConfigPath3() {
|
|
|
507
510
|
async function installClaudeDesktop(serverUrl, apiKey, dryRun) {
|
|
508
511
|
const configPath = getConfigPath3();
|
|
509
512
|
const serverConfig = {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
"mcp-remote@latest",
|
|
514
|
-
serverUrl,
|
|
515
|
-
"--header",
|
|
516
|
-
"Authorization:${PEPPERMINT_AUTH_HEADER}"
|
|
517
|
-
],
|
|
518
|
-
env: {
|
|
519
|
-
PEPPERMINT_AUTH_HEADER: `Bearer ${apiKey}`
|
|
513
|
+
url: serverUrl,
|
|
514
|
+
headers: {
|
|
515
|
+
Authorization: `Bearer ${apiKey}`
|
|
520
516
|
}
|
|
521
517
|
};
|
|
522
518
|
try {
|
|
519
|
+
removeServerFromConfig(configPath, "mcpServers", "peppermint", dryRun);
|
|
523
520
|
const result = writeServerToConfig({
|
|
524
521
|
filePath: configPath,
|
|
525
522
|
serverProperty: "mcpServers",
|
|
526
|
-
serverName: "peppermint",
|
|
523
|
+
serverName: "peppermint-memory",
|
|
527
524
|
serverConfig,
|
|
528
525
|
dryRun
|
|
529
526
|
});
|
|
@@ -542,7 +539,7 @@ async function removeClaudeDesktop(dryRun) {
|
|
|
542
539
|
const removed = removeServerFromConfig(
|
|
543
540
|
configPath,
|
|
544
541
|
"mcpServers",
|
|
545
|
-
"peppermint",
|
|
542
|
+
"peppermint-memory",
|
|
546
543
|
dryRun
|
|
547
544
|
);
|
|
548
545
|
return {
|
|
@@ -567,10 +564,11 @@ async function installCursor(serverUrl, apiKey, dryRun) {
|
|
|
567
564
|
}
|
|
568
565
|
};
|
|
569
566
|
try {
|
|
567
|
+
removeServerFromConfig(configPath, "mcpServers", "peppermint", dryRun);
|
|
570
568
|
const result = writeServerToConfig({
|
|
571
569
|
filePath: configPath,
|
|
572
570
|
serverProperty: "mcpServers",
|
|
573
|
-
serverName: "peppermint",
|
|
571
|
+
serverName: "peppermint-memory",
|
|
574
572
|
serverConfig,
|
|
575
573
|
dryRun
|
|
576
574
|
});
|
|
@@ -589,7 +587,7 @@ async function removeCursor(dryRun) {
|
|
|
589
587
|
const removed = removeServerFromConfig(
|
|
590
588
|
configPath,
|
|
591
589
|
"mcpServers",
|
|
592
|
-
"peppermint",
|
|
590
|
+
"peppermint-memory",
|
|
593
591
|
dryRun
|
|
594
592
|
);
|
|
595
593
|
return {
|
|
@@ -636,6 +634,10 @@ async function installCodex(serverUrl, apiKey, dryRun) {
|
|
|
636
634
|
if (apiKey) {
|
|
637
635
|
persistCodexEnvVar(apiKey);
|
|
638
636
|
}
|
|
637
|
+
try {
|
|
638
|
+
await exec4("codex", ["mcp", "remove", "peppermint-memory"], { timeout: 15e3 });
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
639
641
|
const env = { ...process.env };
|
|
640
642
|
if (apiKey) {
|
|
641
643
|
env.PEPPERMINT_TOKEN = apiKey;
|
|
@@ -711,12 +713,12 @@ function checkHostConfig(hostId, configPath) {
|
|
|
711
713
|
try {
|
|
712
714
|
const content = readFileSync6(configPath, "utf-8");
|
|
713
715
|
const parsed = jsonc4.parse(content);
|
|
714
|
-
const hasPeppermint = !!parsed?.mcpServers?.peppermint;
|
|
716
|
+
const hasPeppermint = !!parsed?.mcpServers?.["peppermint-memory"] || !!parsed?.mcpServers?.peppermint;
|
|
715
717
|
if (!hasPeppermint) {
|
|
716
718
|
return {
|
|
717
719
|
hostId,
|
|
718
720
|
status: "fail",
|
|
719
|
-
message: "peppermint entry not found in config"
|
|
721
|
+
message: "peppermint-memory entry not found in config"
|
|
720
722
|
};
|
|
721
723
|
}
|
|
722
724
|
return {
|
|
@@ -891,60 +893,92 @@ async function removeHost(host, dryRun) {
|
|
|
891
893
|
}
|
|
892
894
|
}
|
|
893
895
|
async function addCommand(options) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
896
|
+
const nonInteractive = options.yes || options.host?.length || options.authToken || !process.stdin.isTTY;
|
|
897
|
+
if (!process.stdin.isTTY && !nonInteractive) {
|
|
898
|
+
console.error("Error: peppermint-mcp-wizard requires an interactive terminal.");
|
|
899
|
+
console.error("For non-interactive installs, use: --host claude-code --yes");
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
902
|
+
if (!nonInteractive) {
|
|
903
|
+
p.intro(pc.green("\u{1F33F} Peppermint MCP Wizard"));
|
|
904
|
+
}
|
|
897
905
|
const hosts = await detectHosts();
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
)
|
|
906
|
+
if (!nonInteractive) {
|
|
907
|
+
const s = p.spinner();
|
|
908
|
+
s.start("Detecting AI hosts...");
|
|
909
|
+
s.stop("Detection complete");
|
|
910
|
+
if (hosts.length === 0) {
|
|
911
|
+
p.log.error(
|
|
912
|
+
"No supported AI hosts detected. Install Claude Code, Claude Desktop, Cursor, or Codex CLI and try again."
|
|
913
|
+
);
|
|
914
|
+
process.exit(6);
|
|
915
|
+
}
|
|
916
|
+
for (const host of hosts) {
|
|
917
|
+
const status = host.alreadyInstalled ? pc.yellow("already configured") : pc.dim("not configured");
|
|
918
|
+
const version = host.version ? pc.dim(` (${host.version})`) : "";
|
|
919
|
+
p.log.info(`${host.alreadyInstalled ? "\u26A0" : "\u2713"} ${host.name}${version} ${status}`);
|
|
920
|
+
}
|
|
921
|
+
} else if (hosts.length === 0) {
|
|
922
|
+
console.error("No supported AI hosts detected.");
|
|
903
923
|
process.exit(6);
|
|
904
924
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
925
|
+
let selectedHosts;
|
|
926
|
+
if (options.host?.length) {
|
|
927
|
+
const requestedIds = options.host;
|
|
928
|
+
selectedHosts = hosts.filter((h) => requestedIds.includes(h.id));
|
|
929
|
+
const missing = requestedIds.filter((id) => !hosts.find((h) => h.id === id));
|
|
930
|
+
if (missing.length > 0) {
|
|
931
|
+
const msg = `Host(s) not detected: ${missing.join(", ")}`;
|
|
932
|
+
nonInteractive ? console.error(msg) : p.log.error(msg);
|
|
933
|
+
process.exit(6);
|
|
934
|
+
}
|
|
935
|
+
} else if (nonInteractive) {
|
|
936
|
+
selectedHosts = hosts;
|
|
937
|
+
} else {
|
|
938
|
+
const unconfigured = hosts.filter((h) => !h.alreadyInstalled);
|
|
939
|
+
const toInstall = unconfigured.length > 0 ? unconfigured : hosts;
|
|
940
|
+
const selected = await p.multiselect({
|
|
941
|
+
message: "Install Peppermint MCP into which hosts?",
|
|
942
|
+
options: toInstall.map((h) => ({
|
|
943
|
+
value: h.id,
|
|
944
|
+
label: h.name,
|
|
945
|
+
hint: h.alreadyInstalled ? "will reinstall" : void 0
|
|
946
|
+
})),
|
|
947
|
+
initialValues: toInstall.map((h) => h.id)
|
|
948
|
+
});
|
|
949
|
+
if (p.isCancel(selected)) {
|
|
950
|
+
p.cancel("Cancelled.");
|
|
951
|
+
process.exit(0);
|
|
952
|
+
}
|
|
953
|
+
selectedHosts = hosts.filter(
|
|
954
|
+
(h) => selected.includes(h.id)
|
|
955
|
+
);
|
|
924
956
|
}
|
|
925
|
-
const selectedHosts = hosts.filter(
|
|
926
|
-
(h) => selected.includes(h.id)
|
|
927
|
-
);
|
|
928
|
-
s.start(`Checking server at ${options.server}...`);
|
|
929
957
|
const serverCheck = await checkServerReachable(options.server);
|
|
930
958
|
if (!serverCheck.reachable) {
|
|
931
|
-
|
|
932
|
-
p.log.error(
|
|
933
|
-
`Cannot reach ${options.server}: ${serverCheck.error}
|
|
934
|
-
Check your internet connection and try again.`
|
|
935
|
-
);
|
|
959
|
+
const msg = `Cannot reach ${options.server}: ${serverCheck.error}`;
|
|
960
|
+
nonInteractive ? console.error(msg) : p.log.error(msg);
|
|
936
961
|
process.exit(4);
|
|
937
962
|
}
|
|
938
|
-
|
|
939
|
-
`Server reachable ${pc.dim(`(${serverCheck.latencyMs}ms)`)}`
|
|
940
|
-
|
|
963
|
+
if (!nonInteractive) {
|
|
964
|
+
p.log.success(`Server reachable ${pc.dim(`(${serverCheck.latencyMs}ms)`)}`);
|
|
965
|
+
}
|
|
941
966
|
let apiKey;
|
|
942
|
-
|
|
967
|
+
const tokenFromFlag = options.authToken || process.env.PEPPERMINT_AUTH_TOKEN;
|
|
968
|
+
if (tokenFromFlag) {
|
|
969
|
+
apiKey = tokenFromFlag;
|
|
970
|
+
const msg = "Using provided auth token";
|
|
971
|
+
nonInteractive ? console.log(msg) : p.log.success(msg);
|
|
972
|
+
} else if (needsAuth(selectedHosts)) {
|
|
943
973
|
const base = serverBase(options.server);
|
|
944
974
|
const existing = loadCredentials(base);
|
|
945
975
|
if (existing) {
|
|
946
976
|
apiKey = existing.api_key;
|
|
947
|
-
|
|
977
|
+
const msg = `Authenticated as ${existing.email || "user"} (cached)`;
|
|
978
|
+
nonInteractive ? console.log(msg) : p.log.success(pc.bold(msg));
|
|
979
|
+
} else if (nonInteractive) {
|
|
980
|
+
console.error("Error: non-interactive mode requires --auth-token or PEPPERMINT_AUTH_TOKEN, or cached credentials.");
|
|
981
|
+
process.exit(3);
|
|
948
982
|
} else {
|
|
949
983
|
p.log.info("Opening browser for authentication...");
|
|
950
984
|
try {
|
|
@@ -1069,7 +1103,14 @@ async function removeCommand(options) {
|
|
|
1069
1103
|
p.outro("Removal complete");
|
|
1070
1104
|
}
|
|
1071
1105
|
var program = new Command().name("peppermint-mcp-wizard").description("One-command installer for Peppermint MCP").version("0.1.0");
|
|
1072
|
-
program.command("add", { isDefault: true }).description("Detect hosts, authenticate, install MCP config").option("--server <url>", "MCP server URL", DEFAULT_SERVER).option("--dry-run", "Print changes without writing", false).option("--no-verify", "Skip post-install verification").
|
|
1106
|
+
program.command("add", { isDefault: true }).description("Detect hosts, authenticate, install MCP config").option("--server <url>", "MCP server URL", DEFAULT_SERVER).option("--dry-run", "Print changes without writing", false).option("--no-verify", "Skip post-install verification").option("--host <id...>", "Install to specific hosts (claude-code, claude-desktop, cursor, codex)").option("--yes", "Skip all prompts (non-interactive)", false).option("--auth-token <token>", "API key or token for auth (skips browser OAuth)").action((opts) => addCommand({
|
|
1107
|
+
server: opts.server,
|
|
1108
|
+
dryRun: opts.dryRun,
|
|
1109
|
+
verify: opts.verify,
|
|
1110
|
+
host: opts.host,
|
|
1111
|
+
yes: opts.yes,
|
|
1112
|
+
authToken: opts.authToken
|
|
1113
|
+
}));
|
|
1073
1114
|
program.command("list").description("List detected AI hosts and their Peppermint status").option("--server <url>", "MCP server URL", DEFAULT_SERVER).action((opts) => listCommand({ server: opts.server }));
|
|
1074
1115
|
program.command("doctor").description("Run health checks on existing installation").option("--server <url>", "MCP server URL", DEFAULT_SERVER).action((opts) => doctorCommand({ server: opts.server }));
|
|
1075
1116
|
program.command("remove").description("Remove Peppermint MCP from selected hosts").option("--server <url>", "MCP server URL", DEFAULT_SERVER).option("--dry-run", "Print changes without writing", false).action((opts) => removeCommand({ server: opts.server, dryRun: opts.dryRun }));
|