mrmainspring 0.1.5 → 0.1.7

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)));
@@ -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,132 @@
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
+ // Windsurf (also on Windows via AppData)
21
+ { name: "Windsurf", path: "%APPDATA%/Windsurf/User/globalStorage/codeium.windsurf/mcp_config.json", platforms: ["win32"], format: "standard" },
22
+ // Zed
23
+ { name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed" },
24
+ // Continue.dev
25
+ { name: "Continue", path: "~/.continue/config.json", platforms: ["darwin", "linux", "win32"], format: "continue" },
26
+ // VS Code (workspace-agnostic user MCP config — requires MCP extension)
27
+ { name: "VS Code", path: "~/.vscode/mcp.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
28
+ ];
29
+ function expandPath(p, env) {
30
+ const home = env.HOME ?? env.USERPROFILE ?? homedir();
31
+ return p
32
+ .replace(/^~/, home)
33
+ .replace(/%APPDATA%/gi, env.APPDATA ?? "")
34
+ .replace(/%USERPROFILE%/gi, env.USERPROFILE ?? home);
35
+ }
36
+ function isInstalled(configPath) {
37
+ return existsSync(dirname(configPath)) || existsSync(configPath);
38
+ }
39
+ function readJson(path) {
40
+ if (!existsSync(path))
41
+ return {};
42
+ try {
43
+ return JSON.parse(readFileSync(path, "utf8"));
44
+ }
45
+ catch {
46
+ return {};
47
+ }
48
+ }
49
+ function alreadySet(json, format) {
50
+ if (format === "zed") {
51
+ return !!json.context_servers?.mainspring;
52
+ }
53
+ if (format === "continue") {
54
+ const servers = json.mcpServers;
55
+ return !!servers?.some(s => s.name === "mainspring");
56
+ }
57
+ return !!json.mcpServers?.mainspring;
58
+ }
59
+ function mergeConfig(json, format) {
60
+ if (format === "zed") {
61
+ return {
62
+ ...json,
63
+ context_servers: {
64
+ ...(json.context_servers ?? {}),
65
+ mainspring: { command: { path: "npx", args: ["-y", "mrmainspring"] } }
66
+ }
67
+ };
68
+ }
69
+ if (format === "continue") {
70
+ const existing = (json.mcpServers ?? [])
71
+ .filter((s) => s.name !== "mainspring");
72
+ return {
73
+ ...json,
74
+ mcpServers: [...existing, { name: "mainspring", command: "npx", args: ["-y", "mrmainspring"] }]
75
+ };
76
+ }
77
+ return {
78
+ ...json,
79
+ mcpServers: {
80
+ ...(json.mcpServers ?? {}),
81
+ mainspring: MAINSPRING_ENTRY
82
+ }
83
+ };
84
+ }
85
+ export function setupAllClients(env = process.env) {
86
+ const plat = process.platform;
87
+ const results = [];
88
+ const seen = new Set();
89
+ for (const client of CLIENTS) {
90
+ if (!client.platforms.includes(plat))
91
+ continue;
92
+ const configPath = expandPath(client.path, env);
93
+ const key = `${client.name}:${configPath}`;
94
+ if (seen.has(key))
95
+ continue;
96
+ seen.add(key);
97
+ if (!isInstalled(configPath)) {
98
+ results.push({ name: client.name, configPath, status: "not-installed" });
99
+ continue;
100
+ }
101
+ try {
102
+ const json = readJson(configPath);
103
+ if (alreadySet(json, client.format)) {
104
+ results.push({ name: client.name, configPath, status: "already-set" });
105
+ continue;
106
+ }
107
+ mkdirSync(dirname(configPath), { recursive: true });
108
+ writeFileSync(configPath, JSON.stringify(mergeConfig(json, client.format), null, 2) + "\n", "utf8");
109
+ results.push({ name: client.name, configPath, status: "written" });
110
+ }
111
+ catch (e) {
112
+ results.push({ name: client.name, configPath, status: "error", error: String(e) });
113
+ }
114
+ }
115
+ return results;
116
+ }
117
+ export function formatClientSetupReport(results) {
118
+ const active = results.filter(r => r.status !== "not-installed");
119
+ if (active.length === 0)
120
+ return "";
121
+ const lines = ["\nMCP clients configured:"];
122
+ for (const r of active) {
123
+ if (r.status === "written")
124
+ lines.push(` [ok] ${r.name} → ${r.configPath}`);
125
+ else if (r.status === "already-set")
126
+ lines.push(` [ok] ${r.name} → already configured`);
127
+ else
128
+ lines.push(` [warn] ${r.name} → ${r.error}`);
129
+ }
130
+ lines.push("\nRestart any open MCP clients to load the server.");
131
+ return lines.join("\n") + "\n";
132
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmainspring",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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",