@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.
Files changed (2) hide show
  1. package/dist/cli.js +106 -62
  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,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: false
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
- command: "npx",
508
- args: [
509
- "-y",
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
- p.intro(pc.green("\u{1F33F} Peppermint MCP Wizard"));
892
- const s = p.spinner();
893
- 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
+ }
894
905
  const hosts = await detectHosts();
895
- s.stop("Detection complete");
896
- if (hosts.length === 0) {
897
- p.log.error(
898
- "No supported AI hosts detected. Install Claude Code, Claude Desktop, Cursor, or Codex CLI and try again."
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
- for (const host of hosts) {
903
- const status = host.alreadyInstalled ? pc.yellow("already configured") : pc.dim("not configured");
904
- const version = host.version ? pc.dim(` (${host.version})`) : "";
905
- p.log.info(`${host.alreadyInstalled ? "\u26A0" : "\u2713"} ${host.name}${version} ${status}`);
906
- }
907
- const unconfigured = hosts.filter((h) => !h.alreadyInstalled);
908
- const toInstall = unconfigured.length > 0 ? unconfigured : hosts;
909
- const selected = await p.multiselect({
910
- message: "Install Peppermint MCP into which hosts?",
911
- options: toInstall.map((h) => ({
912
- value: h.id,
913
- label: h.name,
914
- hint: h.alreadyInstalled ? "will reinstall" : void 0
915
- })),
916
- initialValues: toInstall.map((h) => h.id)
917
- });
918
- if (p.isCancel(selected)) {
919
- p.cancel("Cancelled.");
920
- 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
+ );
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
- s.stop("Server unreachable");
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
- s.stop(
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
- 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)) {
940
973
  const base = serverBase(options.server);
941
974
  const existing = loadCredentials(base);
942
975
  if (existing) {
943
976
  apiKey = existing.api_key;
944
- 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);
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").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
+ }));
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 }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peppermint-mcp/wizard",
3
- "version": "0.2.2",
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": {