mrmainspring 0.2.0 → 0.2.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 CHANGED
@@ -71,14 +71,23 @@ export async function runCliCommand(args) {
71
71
  }
72
72
  else {
73
73
  process.stdout.write("\nNo MCP clients detected automatically.\n" +
74
- "Add this to your MCP client config (Claude Desktop, Cursor, Windsurf, Zed, VS Code, Continue, or any MCP host):\n\n");
74
+ "Add this to your MCP client config:\n\n");
75
75
  process.stdout.write(`${formatMcpConfig()}\n`);
76
76
  process.stdout.write("\nConfig file locations:\n" +
77
- " Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json\n" +
78
- " Cursor ~/.cursor/mcp.json\n" +
79
- " Windsurf ~/.codeium/windsurf/mcp_config.json\n" +
80
- " Zed ~/.config/zed/settings.json (context_servers format)\n" +
81
- " VS Code ~/.vscode/mcp.json\n\n");
77
+ " Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json\n" +
78
+ " Claude Code ~/.claude/settings.json\n" +
79
+ " Cursor ~/.cursor/mcp.json\n" +
80
+ " Windsurf ~/.codeium/windsurf/mcp_config.json\n" +
81
+ " Zed ~/.config/zed/settings.json (context_servers format)\n" +
82
+ " VS Code ~/.vscode/mcp.json\n" +
83
+ " Cline ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n" +
84
+ " Roo Code ~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json\n" +
85
+ " Kilo Code ~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json\n" +
86
+ " OpenCode ~/.config/opencode/config.json\n" +
87
+ " Amazon Q ~/.aws/amazonq/mcp.json\n" +
88
+ " Gemini CLI ~/.gemini/settings.json\n" +
89
+ " Codex CLI ~/.codex/config.json\n" +
90
+ " Continue.dev ~/.continue/config.json (array format)\n\n");
82
91
  }
83
92
  }
84
93
  return true;
@@ -98,42 +107,37 @@ export async function runCliCommand(args) {
98
107
  process.exitCode = 1;
99
108
  return true;
100
109
  }
110
+ const CLOCK_ART = [
111
+ " ╷ ",
112
+ " ╭────┴────╮ ",
113
+ " ╭╯ 12 ╰╮ ",
114
+ " │ 11 │ 1 │ ",
115
+ " │ │ │ ",
116
+ " 9 ─┤ ──◎ ├─ 3 ",
117
+ " │ │ ",
118
+ " │ 8 4 │ ",
119
+ " ╰╮ 7 5 ╭╯ ",
120
+ " ╰╮ 6 ╭╯ ",
121
+ " ╰────────╯ ",
122
+ " ",
123
+ " Mr Mainspring ",
124
+ " Memory · Anchor · Pay ",
125
+ ].join("\n");
101
126
  async function runInteractiveSetup() {
102
- clack.intro("Mr Mainspring — setup");
127
+ process.stdout.write(`\n${CLOCK_ART}\n\n`);
128
+ clack.intro("setup");
103
129
  const result = initializeLocalSetup();
104
130
  clack.log.success(`Local files ready\n Config: ${result.envFile}\n Data: ${result.dataDir}`);
105
131
  const clients = detectClients();
106
132
  const installed = clients.filter(c => c.installed);
107
- const notInstalled = clients.filter(c => !c.installed);
108
- let selected;
109
- if (installed.length === 0) {
110
- clack.log.warn("No MCP clients detected on this machine.");
111
- clack.log.info("Add this JSON to your client config manually:\n\n" +
112
- formatMcpConfig() + "\n\n" +
113
- " Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json\n" +
114
- " Cursor ~/.cursor/mcp.json\n" +
115
- " Windsurf ~/.codeium/windsurf/mcp_config.json\n" +
116
- " Zed ~/.config/zed/settings.json\n" +
117
- " VS Code ~/.vscode/mcp.json");
118
- clack.outro("Restart your client after updating the config.");
119
- return;
120
- }
121
133
  const choices = await clack.multiselect({
122
134
  message: "Which MCP clients should we configure?",
123
- options: [
124
- ...installed.map(c => ({
125
- value: c,
126
- label: c.name,
127
- hint: c.configPath,
128
- selected: true
129
- })),
130
- ...notInstalled.map(c => ({
131
- value: c,
132
- label: c.name,
133
- hint: "not found",
134
- selected: false
135
- }))
136
- ],
135
+ options: clients.map(c => ({
136
+ value: c,
137
+ label: c.name,
138
+ hint: c.installed ? c.configPath : "not detected — config will be created"
139
+ })),
140
+ initialValues: installed,
137
141
  required: false
138
142
  });
139
143
  if (clack.isCancel(choices)) {
@@ -141,13 +145,34 @@ async function runInteractiveSetup() {
141
145
  process.exitCode = 1;
142
146
  return;
143
147
  }
144
- selected = choices;
148
+ const selected = choices;
145
149
  if (selected.length === 0) {
146
- clack.log.warn("No clients selected — nothing configured.");
147
- clack.outro("Run mainspring setup again when ready.");
150
+ clack.log.warn("No clients selected.");
151
+ const customPath = await clack.text({
152
+ message: "Enter a config file path to configure manually (or press Enter to skip):",
153
+ placeholder: "~/.config/myapp/mcp.json",
154
+ validate: () => undefined
155
+ });
156
+ if (!clack.isCancel(customPath) && customPath && customPath.trim()) {
157
+ const expandedPath = customPath.replace(/^~/, process.env.HOME ?? "");
158
+ const configResults = configureClients([
159
+ { name: "Custom", configPath: expandedPath, installed: true, format: "standard" }
160
+ ]);
161
+ const r = configResults[0];
162
+ if (r?.status === "written")
163
+ clack.log.success(`Configured: ${expandedPath}`);
164
+ else if (r?.status === "already-set")
165
+ clack.log.info(`Already configured: ${expandedPath}`);
166
+ else if (r?.error)
167
+ clack.log.error(`Failed: ${r.error}`);
168
+ }
169
+ else {
170
+ clack.log.info("Add this JSON to your MCP client config:\n\n" + formatMcpConfig());
171
+ }
172
+ clack.outro("Restart your MCP client after updating the config.");
148
173
  return;
149
174
  }
150
- const configResults = configureClients(selected.filter(c => c.installed));
175
+ const configResults = configureClients(selected);
151
176
  const written = configResults.filter(r => r.status === "written").map(r => r.name);
152
177
  const alreadySet = configResults.filter(r => r.status === "already-set").map(r => r.name);
153
178
  const errors = configResults.filter(r => r.status === "error");
@@ -17,14 +17,81 @@ const CLIENTS = [
17
17
  { name: "Cursor", path: "%USERPROFILE%/.cursor/mcp.json", platforms: ["win32"], format: "standard" },
18
18
  // Windsurf
19
19
  { name: "Windsurf", path: "~/.codeium/windsurf/mcp_config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
20
- // Windsurf (also on Windows via AppData)
21
20
  { name: "Windsurf", path: "%APPDATA%/Windsurf/User/globalStorage/codeium.windsurf/mcp_config.json", platforms: ["win32"], format: "standard" },
22
21
  // Zed
23
22
  { name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed" },
24
23
  // Continue.dev
25
24
  { name: "Continue", path: "~/.continue/config.json", platforms: ["darwin", "linux", "win32"], format: "continue" },
26
- // VS Code (workspace-agnostic user MCP config — requires MCP extension)
25
+ // VS Code (user-level MCP config — requires GitHub Copilot or MCP extension)
27
26
  { name: "VS Code", path: "~/.vscode/mcp.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
27
+ // Cline (VS Code extension by saoudrizwan)
28
+ {
29
+ name: "Cline",
30
+ path: "~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
31
+ detectDir: "~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev",
32
+ platforms: ["darwin"], format: "standard"
33
+ },
34
+ {
35
+ name: "Cline",
36
+ path: "~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
37
+ detectDir: "~/.config/Code/User/globalStorage/saoudrizwan.claude-dev",
38
+ platforms: ["linux"], format: "standard"
39
+ },
40
+ {
41
+ name: "Cline",
42
+ path: "%APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
43
+ detectDir: "%APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev",
44
+ platforms: ["win32"], format: "standard"
45
+ },
46
+ // Roo Code (VS Code extension, fork of Cline)
47
+ {
48
+ name: "Roo Code",
49
+ path: "~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
50
+ detectDir: "~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline",
51
+ platforms: ["darwin"], format: "standard"
52
+ },
53
+ {
54
+ name: "Roo Code",
55
+ path: "~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
56
+ detectDir: "~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline",
57
+ platforms: ["linux"], format: "standard"
58
+ },
59
+ {
60
+ name: "Roo Code",
61
+ path: "%APPDATA%/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
62
+ detectDir: "%APPDATA%/Code/User/globalStorage/rooveterinaryinc.roo-cline",
63
+ platforms: ["win32"], format: "standard"
64
+ },
65
+ // Kilo Code (VS Code extension)
66
+ {
67
+ name: "Kilo Code",
68
+ path: "~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
69
+ detectDir: "~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code",
70
+ platforms: ["darwin"], format: "standard"
71
+ },
72
+ {
73
+ name: "Kilo Code",
74
+ path: "~/.config/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
75
+ detectDir: "~/.config/Code/User/globalStorage/kilocode.kilo-code",
76
+ platforms: ["linux"], format: "standard"
77
+ },
78
+ {
79
+ name: "Kilo Code",
80
+ path: "%APPDATA%/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
81
+ detectDir: "%APPDATA%/Code/User/globalStorage/kilocode.kilo-code",
82
+ platforms: ["win32"], format: "standard"
83
+ },
84
+ // OpenCode (terminal AI coding assistant)
85
+ { name: "OpenCode", path: "~/.config/opencode/config.json", platforms: ["darwin", "linux"], format: "standard" },
86
+ { name: "OpenCode", path: "%APPDATA%/opencode/config.json", platforms: ["win32"], format: "standard" },
87
+ // Amazon Q Developer
88
+ { name: "Amazon Q", path: "~/.aws/amazonq/mcp.json", platforms: ["darwin", "linux"], format: "standard" },
89
+ { name: "Amazon Q", path: "%USERPROFILE%/.aws/amazonq/mcp.json", platforms: ["win32"], format: "standard" },
90
+ // Gemini CLI (Google)
91
+ { name: "Gemini CLI", path: "~/.gemini/settings.json", platforms: ["darwin", "linux"], format: "standard" },
92
+ { name: "Gemini CLI", path: "%USERPROFILE%/.gemini/settings.json", platforms: ["win32"], format: "standard" },
93
+ // Codex CLI (OpenAI)
94
+ { name: "Codex CLI", path: "~/.codex/config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
28
95
  ];
29
96
  function expandPath(p, env) {
30
97
  const home = env.HOME ?? env.USERPROFILE ?? homedir();
@@ -33,8 +100,9 @@ function expandPath(p, env) {
33
100
  .replace(/%APPDATA%/gi, env.APPDATA ?? "")
34
101
  .replace(/%USERPROFILE%/gi, env.USERPROFILE ?? home);
35
102
  }
36
- function isInstalled(configPath) {
37
- return existsSync(dirname(configPath)) || existsSync(configPath);
103
+ function isInstalled(configPath, detectDir) {
104
+ const dir = detectDir ?? dirname(configPath);
105
+ return existsSync(dir) || existsSync(configPath);
38
106
  }
39
107
  function readJson(path) {
40
108
  if (!existsSync(path))
@@ -94,17 +162,14 @@ export function detectClients(env = process.env) {
94
162
  if (seen.has(key))
95
163
  continue;
96
164
  seen.add(key);
97
- results.push({ name: client.name, configPath, installed: isInstalled(configPath), format: client.format });
165
+ const detectDir = client.detectDir ? expandPath(client.detectDir, env) : undefined;
166
+ results.push({ name: client.name, configPath, installed: isInstalled(configPath, detectDir), format: client.format });
98
167
  }
99
168
  return results;
100
169
  }
101
170
  export function configureClients(selected, env = process.env) {
102
171
  const results = [];
103
172
  for (const client of selected) {
104
- if (!client.installed) {
105
- results.push({ name: client.name, configPath: client.configPath, status: "not-installed" });
106
- continue;
107
- }
108
173
  try {
109
174
  const json = readJson(client.configPath);
110
175
  if (alreadySet(json, client.format)) {
@@ -133,7 +198,8 @@ export function setupAllClients(env = process.env) {
133
198
  if (seen.has(key))
134
199
  continue;
135
200
  seen.add(key);
136
- if (!isInstalled(configPath)) {
201
+ const detectDir = client.detectDir ? expandPath(client.detectDir, env) : undefined;
202
+ if (!isInstalled(configPath, detectDir)) {
137
203
  results.push({ name: client.name, configPath, status: "not-installed" });
138
204
  continue;
139
205
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmainspring",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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",