@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.
Files changed (2) hide show
  1. package/dist/cli.js +106 -65
  2. 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-stdio-shim",
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: false
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
- command: "npx",
511
- args: [
512
- "-y",
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
- p.intro(pc.green("\u{1F33F} Peppermint MCP Wizard"));
895
- const s = p.spinner();
896
- s.start("Detecting AI hosts...");
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
- s.stop("Detection complete");
899
- if (hosts.length === 0) {
900
- p.log.error(
901
- "No supported AI hosts detected. Install Claude Code, Claude Desktop, Cursor, or Codex CLI and try again."
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
- for (const host of hosts) {
906
- const status = host.alreadyInstalled ? pc.yellow("already configured") : pc.dim("not configured");
907
- const version = host.version ? pc.dim(` (${host.version})`) : "";
908
- p.log.info(`${host.alreadyInstalled ? "\u26A0" : "\u2713"} ${host.name}${version} ${status}`);
909
- }
910
- const unconfigured = hosts.filter((h) => !h.alreadyInstalled);
911
- const toInstall = unconfigured.length > 0 ? unconfigured : hosts;
912
- const selected = await p.multiselect({
913
- message: "Install Peppermint MCP into which hosts?",
914
- options: toInstall.map((h) => ({
915
- value: h.id,
916
- label: h.name,
917
- hint: h.alreadyInstalled ? "will reinstall" : void 0
918
- })),
919
- initialValues: toInstall.map((h) => h.id)
920
- });
921
- if (p.isCancel(selected)) {
922
- p.cancel("Cancelled.");
923
- process.exit(0);
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
- s.stop("Server unreachable");
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
- s.stop(
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
- if (needsAuth(selectedHosts)) {
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
- p.log.success(`Authenticated as ${pc.bold(existing.email || "user")} (cached)`);
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").action((opts) => addCommand({ server: opts.server, dryRun: opts.dryRun, verify: opts.verify }));
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 }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peppermint-mcp/wizard",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "description": "One-command installer for Peppermint MCP across AI coding hosts",
5
5
  "type": "module",
6
6
  "bin": {