ai-account-switch 1.11.0 → 1.12.0
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/package.json +45 -45
- package/src/accounts/base-account.js +39 -0
- package/src/accounts/ccr-account.js +118 -0
- package/src/accounts/claude-account.js +62 -0
- package/src/accounts/codex-account.js +192 -0
- package/src/accounts/droids-account.js +80 -0
- package/src/accounts/index.js +29 -0
- package/src/config/global-config.js +266 -0
- package/src/config/project-config.js +255 -0
- package/src/config.js +126 -1478
- package/src/config.js.bak +1593 -0
- package/src/constants.js +86 -0
- package/src/generators/base-generator.js +124 -0
- package/src/generators/ccr-generator.js +113 -0
- package/src/generators/claude-generator.js +124 -0
- package/src/generators/codex-generator.js +207 -0
- package/src/generators/droids-generator.js +49 -0
- package/src/generators/index.js +29 -0
- package/src/mcp/mcp-manager.js +309 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Configuration Manager
|
|
3
|
+
* Handles global configuration operations (accounts, MCP servers in home directory)
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { CONFIG_FILES } = require('../constants');
|
|
9
|
+
|
|
10
|
+
class GlobalConfigManager {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.globalConfigDir = path.join(os.homedir(), CONFIG_FILES.GLOBAL_DIR);
|
|
13
|
+
this.globalConfigFile = path.join(this.globalConfigDir, CONFIG_FILES.GLOBAL_CONFIG);
|
|
14
|
+
this.projectConfigFilename = '.ais-project-config';
|
|
15
|
+
this.ensureConfigExists();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Ensure configuration directories and files exist
|
|
20
|
+
*/
|
|
21
|
+
ensureConfigExists() {
|
|
22
|
+
if (!fs.existsSync(this.globalConfigDir)) {
|
|
23
|
+
fs.mkdirSync(this.globalConfigDir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(this.globalConfigFile)) {
|
|
27
|
+
this.save({ accounts: {}, mcpServers: {}, nextAccountId: 1 });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.migrateAccountIds();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Find project root by searching upwards for .ais-project-config file
|
|
35
|
+
*/
|
|
36
|
+
findProjectRoot(startDir = process.cwd()) {
|
|
37
|
+
let currentDir = path.resolve(startDir);
|
|
38
|
+
const rootDir = path.parse(currentDir).root;
|
|
39
|
+
|
|
40
|
+
while (currentDir !== rootDir) {
|
|
41
|
+
const configPath = path.join(currentDir, this.projectConfigFilename);
|
|
42
|
+
if (fs.existsSync(configPath)) {
|
|
43
|
+
return currentDir;
|
|
44
|
+
}
|
|
45
|
+
currentDir = path.dirname(currentDir);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const configPath = path.join(rootDir, this.projectConfigFilename);
|
|
49
|
+
if (fs.existsSync(configPath)) {
|
|
50
|
+
return rootDir;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read global configuration
|
|
58
|
+
*/
|
|
59
|
+
read() {
|
|
60
|
+
try {
|
|
61
|
+
const data = fs.readFileSync(this.globalConfigFile, 'utf8');
|
|
62
|
+
const config = JSON.parse(data);
|
|
63
|
+
if (!config.nextAccountId) {
|
|
64
|
+
config.nextAccountId = 1;
|
|
65
|
+
}
|
|
66
|
+
return config;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return { accounts: {}, mcpServers: {}, nextAccountId: 1 };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Save global configuration
|
|
74
|
+
*/
|
|
75
|
+
save(config) {
|
|
76
|
+
fs.writeFileSync(this.globalConfigFile, JSON.stringify(config, null, 2), 'utf8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Migrate existing accounts to have IDs
|
|
81
|
+
*/
|
|
82
|
+
migrateAccountIds() {
|
|
83
|
+
const config = this.read();
|
|
84
|
+
let needsSave = false;
|
|
85
|
+
|
|
86
|
+
if (!config.nextAccountId) {
|
|
87
|
+
config.nextAccountId = 1;
|
|
88
|
+
needsSave = true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Object.keys(config.accounts || {}).forEach(name => {
|
|
92
|
+
if (!config.accounts[name].id) {
|
|
93
|
+
config.accounts[name].id = config.nextAccountId;
|
|
94
|
+
config.nextAccountId++;
|
|
95
|
+
needsSave = true;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (needsSave) {
|
|
100
|
+
this.save(config);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get account by ID or name
|
|
106
|
+
*/
|
|
107
|
+
getAccountByIdOrName(idOrName) {
|
|
108
|
+
const accounts = this.getAllAccounts();
|
|
109
|
+
|
|
110
|
+
const id = parseInt(idOrName, 10);
|
|
111
|
+
if (!isNaN(id)) {
|
|
112
|
+
for (const [name, account] of Object.entries(accounts)) {
|
|
113
|
+
if (account.id === id) {
|
|
114
|
+
return { name, ...account };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const account = accounts[idOrName];
|
|
120
|
+
if (account) {
|
|
121
|
+
return { name: idOrName, ...account };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Add or update an account
|
|
129
|
+
*/
|
|
130
|
+
addAccount(name, accountData) {
|
|
131
|
+
const config = this.read();
|
|
132
|
+
|
|
133
|
+
const isNewAccount = !config.accounts[name];
|
|
134
|
+
const accountId = isNewAccount ? config.nextAccountId : config.accounts[name].id;
|
|
135
|
+
|
|
136
|
+
config.accounts[name] = {
|
|
137
|
+
...accountData,
|
|
138
|
+
id: accountId,
|
|
139
|
+
createdAt: config.accounts[name]?.createdAt || new Date().toISOString(),
|
|
140
|
+
updatedAt: new Date().toISOString()
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (isNewAccount) {
|
|
144
|
+
config.nextAccountId++;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.save(config);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get all accounts
|
|
153
|
+
*/
|
|
154
|
+
getAllAccounts() {
|
|
155
|
+
const config = this.read();
|
|
156
|
+
return config.accounts || {};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a specific account
|
|
161
|
+
*/
|
|
162
|
+
getAccount(name) {
|
|
163
|
+
const accounts = this.getAllAccounts();
|
|
164
|
+
return accounts[name] || null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Remove an account
|
|
169
|
+
*/
|
|
170
|
+
removeAccount(name) {
|
|
171
|
+
const config = this.read();
|
|
172
|
+
if (config.accounts[name]) {
|
|
173
|
+
delete config.accounts[name];
|
|
174
|
+
this.save(config);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if an account exists
|
|
182
|
+
*/
|
|
183
|
+
accountExists(name) {
|
|
184
|
+
const accounts = this.getAllAccounts();
|
|
185
|
+
return !!accounts[name];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// MCP Server methods
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Add or update an MCP server
|
|
192
|
+
*/
|
|
193
|
+
addMcpServer(name, serverData) {
|
|
194
|
+
const config = this.read();
|
|
195
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
196
|
+
|
|
197
|
+
const { DEFAULT_MCP_SCOPE } = require('../constants');
|
|
198
|
+
if (!serverData.scope) {
|
|
199
|
+
serverData.scope = DEFAULT_MCP_SCOPE;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
config.mcpServers[name] = {
|
|
203
|
+
...serverData,
|
|
204
|
+
createdAt: config.mcpServers[name]?.createdAt || new Date().toISOString(),
|
|
205
|
+
updatedAt: new Date().toISOString()
|
|
206
|
+
};
|
|
207
|
+
this.save(config);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get all MCP servers
|
|
213
|
+
*/
|
|
214
|
+
getAllMcpServers() {
|
|
215
|
+
const config = this.read();
|
|
216
|
+
return config.mcpServers || {};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get a specific MCP server
|
|
221
|
+
*/
|
|
222
|
+
getMcpServer(name) {
|
|
223
|
+
const servers = this.getAllMcpServers();
|
|
224
|
+
return servers[name] || null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Update an MCP server
|
|
229
|
+
*/
|
|
230
|
+
updateMcpServer(name, serverData) {
|
|
231
|
+
const config = this.read();
|
|
232
|
+
if (!config.mcpServers || !config.mcpServers[name]) return false;
|
|
233
|
+
config.mcpServers[name] = {
|
|
234
|
+
...serverData,
|
|
235
|
+
createdAt: config.mcpServers[name].createdAt,
|
|
236
|
+
updatedAt: new Date().toISOString()
|
|
237
|
+
};
|
|
238
|
+
this.save(config);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Remove an MCP server
|
|
244
|
+
*/
|
|
245
|
+
removeMcpServer(name) {
|
|
246
|
+
const config = this.read();
|
|
247
|
+
if (config.mcpServers && config.mcpServers[name]) {
|
|
248
|
+
delete config.mcpServers[name];
|
|
249
|
+
this.save(config);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get configuration file paths
|
|
257
|
+
*/
|
|
258
|
+
getConfigPaths() {
|
|
259
|
+
return {
|
|
260
|
+
global: this.globalConfigFile,
|
|
261
|
+
globalDir: this.globalConfigDir
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
module.exports = GlobalConfigManager;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Configuration Manager
|
|
3
|
+
* Handles project-specific configuration operations
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
class ProjectConfigManager {
|
|
9
|
+
constructor(globalConfig) {
|
|
10
|
+
this.globalConfig = globalConfig;
|
|
11
|
+
this.projectConfigFilename = '.ais-project-config';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get project configuration file path
|
|
16
|
+
*/
|
|
17
|
+
getProjectConfigPath(projectRoot = process.cwd()) {
|
|
18
|
+
return path.join(projectRoot, this.projectConfigFilename);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Read project configuration
|
|
23
|
+
*/
|
|
24
|
+
read(projectRoot = process.cwd()) {
|
|
25
|
+
const projectConfigFile = this.getProjectConfigPath(projectRoot);
|
|
26
|
+
if (!fs.existsSync(projectConfigFile)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const data = fs.readFileSync(projectConfigFile, 'utf8');
|
|
32
|
+
return JSON.parse(data);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Save project configuration
|
|
40
|
+
*/
|
|
41
|
+
save(projectConfig, projectRoot = process.cwd()) {
|
|
42
|
+
const projectConfigFile = this.getProjectConfigPath(projectRoot);
|
|
43
|
+
fs.writeFileSync(projectConfigFile, JSON.stringify(projectConfig, null, 2), 'utf8');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Set current project's active account
|
|
48
|
+
*/
|
|
49
|
+
setAccount(accountName, projectRoot = process.cwd()) {
|
|
50
|
+
const projectConfigFile = this.getProjectConfigPath(projectRoot);
|
|
51
|
+
|
|
52
|
+
// Read existing project config to preserve enabledMcpServers
|
|
53
|
+
let existingConfig = {};
|
|
54
|
+
if (fs.existsSync(projectConfigFile)) {
|
|
55
|
+
try {
|
|
56
|
+
const data = fs.readFileSync(projectConfigFile, 'utf8');
|
|
57
|
+
existingConfig = JSON.parse(data);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// If parsing fails, start fresh
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const projectConfig = {
|
|
64
|
+
activeAccount: accountName,
|
|
65
|
+
projectPath: projectRoot,
|
|
66
|
+
setAt: new Date().toISOString(),
|
|
67
|
+
enabledMcpServers: existingConfig.enabledMcpServers || []
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
this.save(projectConfig, projectRoot);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get current project's active account with full details
|
|
76
|
+
*/
|
|
77
|
+
getAccount(projectRoot = process.cwd()) {
|
|
78
|
+
try {
|
|
79
|
+
const projectConfig = this.read(projectRoot);
|
|
80
|
+
if (!projectConfig) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get the full account details from global config
|
|
85
|
+
const account = this.globalConfig.getAccount(projectConfig.activeAccount);
|
|
86
|
+
if (account) {
|
|
87
|
+
return {
|
|
88
|
+
name: projectConfig.activeAccount,
|
|
89
|
+
...account,
|
|
90
|
+
setAt: projectConfig.setAt,
|
|
91
|
+
projectRoot: projectRoot
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// MCP Server methods for project
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get project's enabled MCP servers
|
|
104
|
+
*/
|
|
105
|
+
getMcpServers(projectRoot = process.cwd()) {
|
|
106
|
+
try {
|
|
107
|
+
const projectConfig = this.read(projectRoot);
|
|
108
|
+
if (!projectConfig) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
return projectConfig.enabledMcpServers || [];
|
|
112
|
+
} catch (error) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if MCP server is enabled in current project
|
|
119
|
+
*/
|
|
120
|
+
isMcpServerEnabled(serverName, projectRoot = process.cwd()) {
|
|
121
|
+
try {
|
|
122
|
+
const projectConfig = this.read(projectRoot);
|
|
123
|
+
if (!projectConfig) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return projectConfig.enabledMcpServers &&
|
|
128
|
+
projectConfig.enabledMcpServers.includes(serverName);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Enable MCP server for current project with scope
|
|
136
|
+
*/
|
|
137
|
+
enableMcpServer(serverName, scope, projectRoot = process.cwd()) {
|
|
138
|
+
const projectConfigFile = this.getProjectConfigPath(projectRoot);
|
|
139
|
+
if (!fs.existsSync(projectConfigFile)) {
|
|
140
|
+
throw new Error('Project not configured. Run "ais use" first.');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const data = fs.readFileSync(projectConfigFile, 'utf8');
|
|
144
|
+
const projectConfig = JSON.parse(data);
|
|
145
|
+
|
|
146
|
+
// Update server scope in global config
|
|
147
|
+
const globalConfig = this.globalConfig.read();
|
|
148
|
+
if (globalConfig.mcpServers[serverName]) {
|
|
149
|
+
globalConfig.mcpServers[serverName].scope = scope;
|
|
150
|
+
this.globalConfig.save(globalConfig);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Handle different scopes
|
|
154
|
+
const { MCP_SCOPES } = require('../constants');
|
|
155
|
+
if (scope === MCP_SCOPES.LOCAL) {
|
|
156
|
+
if (!projectConfig.enabledMcpServers) projectConfig.enabledMcpServers = [];
|
|
157
|
+
if (!projectConfig.enabledMcpServers.includes(serverName)) {
|
|
158
|
+
projectConfig.enabledMcpServers.push(serverName);
|
|
159
|
+
}
|
|
160
|
+
} else if (scope === MCP_SCOPES.PROJECT) {
|
|
161
|
+
if (!projectConfig.projectMcpServers) projectConfig.projectMcpServers = {};
|
|
162
|
+
const server = this.globalConfig.getMcpServer(serverName);
|
|
163
|
+
projectConfig.projectMcpServers[serverName] = {
|
|
164
|
+
...server,
|
|
165
|
+
scope: MCP_SCOPES.PROJECT
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
if (!projectConfig.enabledMcpServers) projectConfig.enabledMcpServers = [];
|
|
169
|
+
if (!projectConfig.enabledMcpServers.includes(serverName)) {
|
|
170
|
+
projectConfig.enabledMcpServers.push(serverName);
|
|
171
|
+
}
|
|
172
|
+
} else if (scope === MCP_SCOPES.USER) {
|
|
173
|
+
if (!projectConfig.enabledMcpServers) projectConfig.enabledMcpServers = [];
|
|
174
|
+
if (!projectConfig.enabledMcpServers.includes(serverName)) {
|
|
175
|
+
projectConfig.enabledMcpServers.push(serverName);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.save(projectConfig, projectRoot);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Disable MCP server for current project
|
|
185
|
+
*/
|
|
186
|
+
disableMcpServer(serverName, projectRoot = process.cwd()) {
|
|
187
|
+
const projectConfig = this.read(projectRoot);
|
|
188
|
+
if (!projectConfig) {
|
|
189
|
+
throw new Error('Project not configured. Run "ais use" first.');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!projectConfig.enabledMcpServers) return false;
|
|
193
|
+
|
|
194
|
+
const index = projectConfig.enabledMcpServers.indexOf(serverName);
|
|
195
|
+
if (index > -1) {
|
|
196
|
+
projectConfig.enabledMcpServers.splice(index, 1);
|
|
197
|
+
this.save(projectConfig, projectRoot);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Remove MCP server from current project's enabled list
|
|
205
|
+
*/
|
|
206
|
+
removeMcpServer(serverName, projectRoot = process.cwd()) {
|
|
207
|
+
try {
|
|
208
|
+
const projectConfig = this.read(projectRoot);
|
|
209
|
+
if (!projectConfig) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!projectConfig.enabledMcpServers) return false;
|
|
214
|
+
|
|
215
|
+
const index = projectConfig.enabledMcpServers.indexOf(serverName);
|
|
216
|
+
if (index > -1) {
|
|
217
|
+
projectConfig.enabledMcpServers.splice(index, 1);
|
|
218
|
+
this.save(projectConfig, projectRoot);
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
return false;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get all available MCP servers including project-scoped ones
|
|
229
|
+
*/
|
|
230
|
+
getAllMcpServers(projectRoot = process.cwd()) {
|
|
231
|
+
const globalServers = this.globalConfig.getAllMcpServers();
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const projectConfig = this.read(projectRoot);
|
|
235
|
+
if (!projectConfig) {
|
|
236
|
+
return globalServers;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Merge global and project servers
|
|
240
|
+
const allServers = { ...globalServers };
|
|
241
|
+
|
|
242
|
+
if (projectConfig.projectMcpServers) {
|
|
243
|
+
Object.entries(projectConfig.projectMcpServers).forEach(([name, server]) => {
|
|
244
|
+
allServers[name] = server;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return allServers;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return globalServers;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
module.exports = ProjectConfigManager;
|