mrmainspring 0.1.4 → 0.1.6

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 CHANGED
@@ -3,6 +3,7 @@ import { dirname, join } from "node:path";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { loadConfig } from "./config.js";
6
+ import { setupAllClients, formatClientSetupReport } from "./client-setup.js";
6
7
  import { ensureGrimoireMasterKey, loadLocalEnvFile, resolveEnvPath } from "./env-file.js";
7
8
  import { getDefaultMainspringPaths } from "./paths.js";
8
9
  const _pkgRoot = dirname(dirname(fileURLToPath(import.meta.url)));
@@ -15,7 +16,7 @@ Usage:
15
16
  mainspring --version Show the installed version
16
17
  mainspring init Create local config, data, and logs directories
17
18
  mainspring config Print MCP client config JSON
18
- mainspring setup [client] Initialize local files and print MCP config
19
+ mainspring setup Initialize local files and print MCP config
19
20
  mainspring doctor Check the local setup
20
21
  mainspring update Show how to update to the latest version
21
22
 
@@ -58,8 +59,15 @@ export function runCliCommand(args) {
58
59
  if (command === "setup") {
59
60
  const result = initializeLocalSetup();
60
61
  process.stdout.write(formatInitResult(result));
61
- process.stdout.write(`\nPaste this into ${formatClientName(target)} MCP config:\n\n`);
62
- process.stdout.write(`${formatMcpConfig()}\n`);
62
+ const clientResults = setupAllClients();
63
+ const report = formatClientSetupReport(clientResults);
64
+ if (report) {
65
+ process.stdout.write(report);
66
+ }
67
+ else {
68
+ process.stdout.write("\nNo MCP clients detected. Paste this into your client config manually:\n\n");
69
+ process.stdout.write(`${formatMcpConfig()}\n`);
70
+ }
63
71
  return true;
64
72
  }
65
73
  if (command === "doctor") {
@@ -0,0 +1,8 @@
1
+ export type ClientSetupResult = {
2
+ name: string;
3
+ configPath: string;
4
+ status: "written" | "already-set" | "not-installed" | "error";
5
+ error?: string;
6
+ };
7
+ export declare function setupAllClients(env?: NodeJS.ProcessEnv): ClientSetupResult[];
8
+ export declare function formatClientSetupReport(results: ClientSetupResult[]): string;
@@ -0,0 +1,113 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const MAINSPRING_ENTRY = {
5
+ command: "npx",
6
+ args: ["-y", "mrmainspring"]
7
+ };
8
+ const CLIENTS = [
9
+ // Claude Desktop
10
+ { name: "Claude Desktop", path: "~/Library/Application Support/Claude/claude_desktop_config.json", platforms: ["darwin"], format: "standard" },
11
+ { name: "Claude Desktop", path: "%APPDATA%/Claude/claude_desktop_config.json", platforms: ["win32"], format: "standard" },
12
+ { name: "Claude Desktop", path: "~/.config/Claude/claude_desktop_config.json", platforms: ["linux"], format: "standard" },
13
+ // Claude Code CLI
14
+ { name: "Claude Code", path: "~/.claude/settings.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
15
+ // Cursor
16
+ { name: "Cursor", path: "~/.cursor/mcp.json", platforms: ["darwin", "linux"], format: "standard" },
17
+ { name: "Cursor", path: "%USERPROFILE%/.cursor/mcp.json", platforms: ["win32"], format: "standard" },
18
+ // Windsurf
19
+ { name: "Windsurf", path: "~/.codeium/windsurf/mcp_config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
20
+ // Zed
21
+ { name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed" },
22
+ ];
23
+ function expandPath(p, env) {
24
+ return p
25
+ .replace(/^~/, homedir())
26
+ .replace(/%APPDATA%/gi, env.APPDATA ?? "")
27
+ .replace(/%USERPROFILE%/gi, env.USERPROFILE ?? homedir());
28
+ }
29
+ function isInstalled(configPath) {
30
+ return existsSync(dirname(configPath)) || existsSync(configPath);
31
+ }
32
+ function readJson(path) {
33
+ if (!existsSync(path))
34
+ return {};
35
+ try {
36
+ return JSON.parse(readFileSync(path, "utf8"));
37
+ }
38
+ catch {
39
+ return {};
40
+ }
41
+ }
42
+ function alreadySet(json, format) {
43
+ if (format === "zed") {
44
+ return !!json.context_servers?.mainspring;
45
+ }
46
+ return !!json.mcpServers?.mainspring;
47
+ }
48
+ function mergeConfig(json, format) {
49
+ if (format === "zed") {
50
+ return {
51
+ ...json,
52
+ context_servers: {
53
+ ...(json.context_servers ?? {}),
54
+ mainspring: { command: { path: "npx", args: ["-y", "mrmainspring"] } }
55
+ }
56
+ };
57
+ }
58
+ return {
59
+ ...json,
60
+ mcpServers: {
61
+ ...(json.mcpServers ?? {}),
62
+ mainspring: MAINSPRING_ENTRY
63
+ }
64
+ };
65
+ }
66
+ export function setupAllClients(env = process.env) {
67
+ const plat = process.platform;
68
+ const results = [];
69
+ const seen = new Set();
70
+ for (const client of CLIENTS) {
71
+ if (!client.platforms.includes(plat))
72
+ continue;
73
+ const configPath = expandPath(client.path, env);
74
+ const key = `${client.name}:${configPath}`;
75
+ if (seen.has(key))
76
+ continue;
77
+ seen.add(key);
78
+ if (!isInstalled(configPath)) {
79
+ results.push({ name: client.name, configPath, status: "not-installed" });
80
+ continue;
81
+ }
82
+ try {
83
+ const json = readJson(configPath);
84
+ if (alreadySet(json, client.format)) {
85
+ results.push({ name: client.name, configPath, status: "already-set" });
86
+ continue;
87
+ }
88
+ mkdirSync(dirname(configPath), { recursive: true });
89
+ writeFileSync(configPath, JSON.stringify(mergeConfig(json, client.format), null, 2) + "\n", "utf8");
90
+ results.push({ name: client.name, configPath, status: "written" });
91
+ }
92
+ catch (e) {
93
+ results.push({ name: client.name, configPath, status: "error", error: String(e) });
94
+ }
95
+ }
96
+ return results;
97
+ }
98
+ export function formatClientSetupReport(results) {
99
+ const active = results.filter(r => r.status !== "not-installed");
100
+ if (active.length === 0)
101
+ return "";
102
+ const lines = ["\nMCP clients configured:"];
103
+ for (const r of active) {
104
+ if (r.status === "written")
105
+ lines.push(` [ok] ${r.name} → ${r.configPath}`);
106
+ else if (r.status === "already-set")
107
+ lines.push(` [ok] ${r.name} → already configured`);
108
+ else
109
+ lines.push(` [warn] ${r.name} → ${r.error}`);
110
+ }
111
+ lines.push("\nRestart any open MCP clients to load the server.");
112
+ return lines.join("\n") + "\n";
113
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmainspring",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Mr Mainspring MCP backend with memory, Grimoire policies, audit, Casper anchoring, and x402 settlement boundaries.",
5
5
  "license": "MIT",
6
6
  "type": "module",