@peppermint-mcp/wizard 0.2.2 → 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 -62
- 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,11 +382,17 @@ 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";
|
|
@@ -504,23 +510,17 @@ function getConfigPath3() {
|
|
|
504
510
|
async function installClaudeDesktop(serverUrl, apiKey, dryRun) {
|
|
505
511
|
const configPath = getConfigPath3();
|
|
506
512
|
const serverConfig = {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
"mcp-remote@latest",
|
|
511
|
-
serverUrl,
|
|
512
|
-
"--header",
|
|
513
|
-
"Authorization:${PEPPERMINT_AUTH_HEADER}"
|
|
514
|
-
],
|
|
515
|
-
env: {
|
|
516
|
-
PEPPERMINT_AUTH_HEADER: `Bearer ${apiKey}`
|
|
513
|
+
url: serverUrl,
|
|
514
|
+
headers: {
|
|
515
|
+
Authorization: `Bearer ${apiKey}`
|
|
517
516
|
}
|
|
518
517
|
};
|
|
519
518
|
try {
|
|
519
|
+
removeServerFromConfig(configPath, "mcpServers", "peppermint", dryRun);
|
|
520
520
|
const result = writeServerToConfig({
|
|
521
521
|
filePath: configPath,
|
|
522
522
|
serverProperty: "mcpServers",
|
|
523
|
-
serverName: "peppermint",
|
|
523
|
+
serverName: "peppermint-memory",
|
|
524
524
|
serverConfig,
|
|
525
525
|
dryRun
|
|
526
526
|
});
|
|
@@ -539,7 +539,7 @@ async function removeClaudeDesktop(dryRun) {
|
|
|
539
539
|
const removed = removeServerFromConfig(
|
|
540
540
|
configPath,
|
|
541
541
|
"mcpServers",
|
|
542
|
-
"peppermint",
|
|
542
|
+
"peppermint-memory",
|
|
543
543
|
dryRun
|
|
544
544
|
);
|
|
545
545
|
return {
|
|
@@ -564,10 +564,11 @@ async function installCursor(serverUrl, apiKey, dryRun) {
|
|
|
564
564
|
}
|
|
565
565
|
};
|
|
566
566
|
try {
|
|
567
|
+
removeServerFromConfig(configPath, "mcpServers", "peppermint", dryRun);
|
|
567
568
|
const result = writeServerToConfig({
|
|
568
569
|
filePath: configPath,
|
|
569
570
|
serverProperty: "mcpServers",
|
|
570
|
-
serverName: "peppermint",
|
|
571
|
+
serverName: "peppermint-memory",
|
|
571
572
|
serverConfig,
|
|
572
573
|
dryRun
|
|
573
574
|
});
|
|
@@ -586,7 +587,7 @@ async function removeCursor(dryRun) {
|
|
|
586
587
|
const removed = removeServerFromConfig(
|
|
587
588
|
configPath,
|
|
588
589
|
"mcpServers",
|
|
589
|
-
"peppermint",
|
|
590
|
+
"peppermint-memory",
|
|
590
591
|
dryRun
|
|
591
592
|
);
|
|
592
593
|
return {
|
|
@@ -633,6 +634,10 @@ async function installCodex(serverUrl, apiKey, dryRun) {
|
|
|
633
634
|
if (apiKey) {
|
|
634
635
|
persistCodexEnvVar(apiKey);
|
|
635
636
|
}
|
|
637
|
+
try {
|
|
638
|
+
await exec4("codex", ["mcp", "remove", "peppermint-memory"], { timeout: 15e3 });
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
636
641
|
const env = { ...process.env };
|
|
637
642
|
if (apiKey) {
|
|
638
643
|
env.PEPPERMINT_TOKEN = apiKey;
|
|
@@ -708,12 +713,12 @@ function checkHostConfig(hostId, configPath) {
|
|
|
708
713
|
try {
|
|
709
714
|
const content = readFileSync6(configPath, "utf-8");
|
|
710
715
|
const parsed = jsonc4.parse(content);
|
|
711
|
-
const hasPeppermint = !!parsed?.mcpServers?.peppermint;
|
|
716
|
+
const hasPeppermint = !!parsed?.mcpServers?.["peppermint-memory"] || !!parsed?.mcpServers?.peppermint;
|
|
712
717
|
if (!hasPeppermint) {
|
|
713
718
|
return {
|
|
714
719
|
hostId,
|
|
715
720
|
status: "fail",
|
|
716
|
-
message: "peppermint entry not found in config"
|
|
721
|
+
message: "peppermint-memory entry not found in config"
|
|
717
722
|
};
|
|
718
723
|
}
|
|
719
724
|
return {
|
|
@@ -888,60 +893,92 @@ async function removeHost(host, dryRun) {
|
|
|
888
893
|
}
|
|
889
894
|
}
|
|
890
895
|
async function addCommand(options) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
}
|
|
894
905
|
const hosts = await detectHosts();
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
)
|
|
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.");
|
|
900
923
|
process.exit(6);
|
|
901
924
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
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
|
+
);
|
|
921
956
|
}
|
|
922
|
-
const selectedHosts = hosts.filter(
|
|
923
|
-
(h) => selected.includes(h.id)
|
|
924
|
-
);
|
|
925
|
-
s.start(`Checking server at ${options.server}...`);
|
|
926
957
|
const serverCheck = await checkServerReachable(options.server);
|
|
927
958
|
if (!serverCheck.reachable) {
|
|
928
|
-
|
|
929
|
-
p.log.error(
|
|
930
|
-
`Cannot reach ${options.server}: ${serverCheck.error}
|
|
931
|
-
Check your internet connection and try again.`
|
|
932
|
-
);
|
|
959
|
+
const msg = `Cannot reach ${options.server}: ${serverCheck.error}`;
|
|
960
|
+
nonInteractive ? console.error(msg) : p.log.error(msg);
|
|
933
961
|
process.exit(4);
|
|
934
962
|
}
|
|
935
|
-
|
|
936
|
-
`Server reachable ${pc.dim(`(${serverCheck.latencyMs}ms)`)}`
|
|
937
|
-
|
|
963
|
+
if (!nonInteractive) {
|
|
964
|
+
p.log.success(`Server reachable ${pc.dim(`(${serverCheck.latencyMs}ms)`)}`);
|
|
965
|
+
}
|
|
938
966
|
let apiKey;
|
|
939
|
-
|
|
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)) {
|
|
940
973
|
const base = serverBase(options.server);
|
|
941
974
|
const existing = loadCredentials(base);
|
|
942
975
|
if (existing) {
|
|
943
976
|
apiKey = existing.api_key;
|
|
944
|
-
|
|
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);
|
|
945
982
|
} else {
|
|
946
983
|
p.log.info("Opening browser for authentication...");
|
|
947
984
|
try {
|
|
@@ -1066,7 +1103,14 @@ async function removeCommand(options) {
|
|
|
1066
1103
|
p.outro("Removal complete");
|
|
1067
1104
|
}
|
|
1068
1105
|
var program = new Command().name("peppermint-mcp-wizard").description("One-command installer for Peppermint MCP").version("0.1.0");
|
|
1069
|
-
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
|
+
}));
|
|
1070
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 }));
|
|
1071
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 }));
|
|
1072
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 }));
|