terminator-mcp-agent 0.5.12 → 0.5.13

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/config.js +280 -0
  2. package/package.json +7 -6
package/config.js ADDED
@@ -0,0 +1,280 @@
1
+ const fs = require("fs");
2
+ const os = require("os");
3
+ const path = require("path");
4
+ const { execFileSync } = require("child_process");
5
+
6
+ /**
7
+ * @typedef {Object} ClientConfig
8
+ * @property {Object.<string, any>} mcpServers
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} ClientFileTarget
13
+ * @property {"file"} type
14
+ * @property {string} path
15
+ */
16
+
17
+ /**
18
+ * @typedef {Object} ClientCommandTarget
19
+ * @property {"command"} type
20
+ * @property {string} command
21
+ */
22
+
23
+ // Initialize platform-specific paths
24
+ const homeDir = os.homedir();
25
+
26
+ const platformPaths = {
27
+ win32: {
28
+ baseDir: process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"),
29
+ vscodePath: path.join("Code", "User", "globalStorage"),
30
+ },
31
+ darwin: {
32
+ baseDir: path.join(homeDir, "Library", "Application Support"),
33
+ vscodePath: path.join("Code", "User", "globalStorage"),
34
+ },
35
+ linux: {
36
+ baseDir: process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"),
37
+ vscodePath: path.join("Code/User/globalStorage"),
38
+ },
39
+ };
40
+
41
+ const platform = process.platform;
42
+ const { baseDir, vscodePath } = platformPaths[platform] || platformPaths.linux;
43
+ const defaultClaudePath = path.join(
44
+ baseDir,
45
+ "Claude",
46
+ "claude_desktop_config.json",
47
+ );
48
+
49
+ // Define client paths using the platform-specific base directories
50
+ const clientPaths = {
51
+ claude: { type: "file", path: defaultClaudePath },
52
+ cline: {
53
+ type: "file",
54
+ path: path.join(
55
+ baseDir,
56
+ vscodePath,
57
+ "saoudrizwan.claude-dev",
58
+ "settings",
59
+ "cline_mcp_settings.json",
60
+ ),
61
+ },
62
+ roocode: {
63
+ type: "file",
64
+ path: path.join(
65
+ baseDir,
66
+ vscodePath,
67
+ "rooveterinaryinc.roo-cline",
68
+ "settings",
69
+ "mcp_settings.json",
70
+ ),
71
+ },
72
+ windsurf: {
73
+ type: "file",
74
+ path: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json"),
75
+ },
76
+ witsy: { type: "file", path: path.join(baseDir, "Witsy", "settings.json") },
77
+ enconvo: {
78
+ type: "file",
79
+ path: path.join(homeDir, ".config", "enconvo", "mcp_config.json"),
80
+ },
81
+ cursor: { type: "file", path: path.join(homeDir, ".cursor", "mcp.json") },
82
+ vscode: {
83
+ type: "command",
84
+ command: process.platform === "win32" ? "code.cmd" : "code",
85
+ },
86
+ "vscode-insiders": {
87
+ type: "command",
88
+ command:
89
+ process.platform === "win32" ? "code-insiders.cmd" : "code-insiders",
90
+ },
91
+ boltai: { type: "file", path: path.join(homeDir, ".boltai", "mcp.json") },
92
+ "amazon-bedrock": {
93
+ type: "file",
94
+ path: path.join(homeDir, "Amazon Bedrock Client", "mcp_config.json"),
95
+ },
96
+ amazonq: {
97
+ type: "file",
98
+ path: path.join(homeDir, ".aws", "amazonq", "mcp.json"),
99
+ },
100
+ };
101
+
102
+ /**
103
+ * @param {string} [client]
104
+ * @returns {ClientFileTarget|ClientCommandTarget}
105
+ */
106
+ function getConfigPath(client) {
107
+ const normalizedClient = client ? client.toLowerCase() : "claude";
108
+ verbose(`Getting config path for client: ${normalizedClient}`);
109
+
110
+ const configTarget = clientPaths[normalizedClient] || {
111
+ type: "file",
112
+ path: path.join(
113
+ path.dirname(defaultClaudePath),
114
+ "..",
115
+ client || "claude",
116
+ `${normalizedClient}_config.json`,
117
+ ),
118
+ };
119
+
120
+ verbose(`Config path resolved to: ${JSON.stringify(configTarget)}`);
121
+ return configTarget;
122
+ }
123
+
124
+ /**
125
+ * @param {string} client
126
+ * @returns {ClientConfig}
127
+ */
128
+ function readConfig(client) {
129
+ verbose(`Reading config for client: ${client}`);
130
+ try {
131
+ const configPath = getConfigPath(client);
132
+
133
+ // Command-based installers (i.e. VS Code) do not currently support listing servers
134
+ if (configPath.type === "command") {
135
+ return { mcpServers: {} };
136
+ }
137
+
138
+ verbose(`Checking if config file exists at: ${configPath.path}`);
139
+ if (!fs.existsSync(configPath.path)) {
140
+ verbose(`Config file not found, returning default empty config`);
141
+ return { mcpServers: {} };
142
+ }
143
+
144
+ verbose(`Reading config file content`);
145
+ const rawConfig = JSON.parse(fs.readFileSync(configPath.path, "utf8"));
146
+ verbose(
147
+ `Config loaded successfully: ${JSON.stringify(rawConfig, null, 2)}`,
148
+ );
149
+
150
+ return {
151
+ ...rawConfig,
152
+ mcpServers: rawConfig.mcpServers || {},
153
+ };
154
+ } catch (error) {
155
+ verbose(
156
+ `Error reading config: ${error instanceof Error ? error.stack : JSON.stringify(error)}`,
157
+ );
158
+ return { mcpServers: {} };
159
+ }
160
+ }
161
+
162
+ /**
163
+ * @param {ClientConfig} config
164
+ * @param {string} [client]
165
+ */
166
+ function writeConfig(configObj, client) {
167
+ verbose(`Writing config for client: ${client || "default"}`);
168
+ verbose(`Config data: ${JSON.stringify(configObj, null, 2)}`);
169
+
170
+ if (!configObj.mcpServers || typeof configObj.mcpServers !== "object") {
171
+ verbose(`Invalid mcpServers structure in config`);
172
+ throw new Error("Invalid mcpServers structure");
173
+ }
174
+
175
+ const configPath = getConfigPath(client);
176
+ if (configPath.type === "command") {
177
+ writeConfigCommand(configObj, configPath);
178
+ } else {
179
+ writeConfigFile(configObj, configPath);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * @param {ClientConfig} config
185
+ * @param {ClientCommandTarget} target
186
+ */
187
+ function writeConfigCommand(config, target) {
188
+ const args = [];
189
+ for (const [name, server] of Object.entries(config.mcpServers)) {
190
+ args.push("--add-mcp", JSON.stringify({ ...server, name }));
191
+ }
192
+
193
+ verbose(`Running command: ${JSON.stringify([target.command, ...args])}`);
194
+
195
+ try {
196
+ const output = execFileSync(target.command, args);
197
+ verbose(`Executed command successfully: ${output.toString()}`);
198
+ } catch (error) {
199
+ verbose(
200
+ `Error executing command: ${error instanceof Error ? error.message : String(error)}`,
201
+ );
202
+
203
+ if (error && error.code === "ENOENT") {
204
+ throw new Error(
205
+ `Command '${target.command}' not found. Make sure ${target.command} is installed and on your PATH`,
206
+ );
207
+ }
208
+
209
+ throw error;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * @param {ClientConfig} config
215
+ * @param {ClientFileTarget} target
216
+ */
217
+ function writeConfigFile(config, target) {
218
+ const configDir = path.dirname(target.path);
219
+
220
+ verbose(`Ensuring config directory exists: ${configDir}`);
221
+ if (!fs.existsSync(configDir)) {
222
+ verbose(`Creating directory: ${configDir}`);
223
+ fs.mkdirSync(configDir, { recursive: true });
224
+ }
225
+
226
+ let existingConfig = { mcpServers: {} };
227
+ try {
228
+ if (fs.existsSync(target.path)) {
229
+ verbose(`Reading existing config file for merging`);
230
+ existingConfig = JSON.parse(fs.readFileSync(target.path, "utf8"));
231
+ verbose(
232
+ `Existing config loaded: ${JSON.stringify(existingConfig, null, 2)}`,
233
+ );
234
+ }
235
+ } catch (error) {
236
+ verbose(
237
+ `Error reading existing config for merge: ${error instanceof Error ? error.message : String(error)}`,
238
+ );
239
+ // If reading fails, continue with empty existing config
240
+ }
241
+
242
+ verbose(`Merging configs`);
243
+ const mergedConfig = {
244
+ ...existingConfig,
245
+ ...config,
246
+ };
247
+ verbose(`Merged config: ${JSON.stringify(mergedConfig, null, 2)}`);
248
+
249
+ verbose(`Writing config to file: ${target.path}`);
250
+ fs.writeFileSync(target.path, JSON.stringify(mergedConfig, null, 2));
251
+ verbose(`Config successfully written`);
252
+ }
253
+
254
+ function verbose(msg) {
255
+ if (process.env.MCP_VERBOSE) {
256
+ console.log(`[config] ${msg}`);
257
+ }
258
+ }
259
+
260
+ const supportedClients = [
261
+ { key: "cursor", label: "Cursor" },
262
+ { key: "claude", label: "Claude" },
263
+ { key: "vscode", label: "VS Code" },
264
+ { key: "insiders", label: "VS Code Insiders" },
265
+ { key: "windsurf", label: "Windsurf" },
266
+ { key: "cline", label: "Cline" },
267
+ { key: "roocode", label: "RooCode" },
268
+ { key: "witsy", label: "Witsy" },
269
+ { key: "enconvo", label: "Enconvo" },
270
+ { key: "boltai", label: "BoltAI" },
271
+ { key: "amazon-bedrock", label: "Amazon Bedrock" },
272
+ { key: "amazonq", label: "Amazon Q" },
273
+ ];
274
+
275
+ module.exports = {
276
+ getConfigPath,
277
+ readConfig,
278
+ writeConfig,
279
+ supportedClients,
280
+ };
package/package.json CHANGED
@@ -7,14 +7,15 @@
7
7
  "node": ">= 10"
8
8
  },
9
9
  "files": [
10
- "index.js"
10
+ "index.js",
11
+ "config.js"
11
12
  ],
12
13
  "name": "terminator-mcp-agent",
13
14
  "optionalDependencies": {
14
- "terminator-mcp-darwin-arm64": "0.5.12",
15
- "terminator-mcp-darwin-x64": "0.5.12",
16
- "terminator-mcp-linux-x64-gnu": "0.5.12",
17
- "terminator-mcp-win32-x64-msvc": "0.5.12"
15
+ "terminator-mcp-darwin-arm64": "0.5.13",
16
+ "terminator-mcp-darwin-x64": "0.5.13",
17
+ "terminator-mcp-linux-x64-gnu": "0.5.13",
18
+ "terminator-mcp-win32-x64-msvc": "0.5.13"
18
19
  },
19
20
  "repository": {
20
21
  "type": "git",
@@ -26,5 +27,5 @@
26
27
  "sync-version": "node ./utils/sync-version.js",
27
28
  "update-badges": "node ./utils/update-badges.js"
28
29
  },
29
- "version": "0.5.12"
30
+ "version": "0.5.13"
30
31
  }