ai-account-switch 1.9.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.
@@ -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;