@mcpilotx/intentorch 0.5.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/LICENSE +201 -0
- package/README.md +545 -0
- package/dist/ai/ai.d.ts +205 -0
- package/dist/ai/ai.js +1200 -0
- package/dist/ai/cloud-intent-engine.d.ts +270 -0
- package/dist/ai/cloud-intent-engine.js +956 -0
- package/dist/ai/command.d.ts +59 -0
- package/dist/ai/command.js +285 -0
- package/dist/ai/config.d.ts +66 -0
- package/dist/ai/config.js +211 -0
- package/dist/ai/enhanced-intent.d.ts +17 -0
- package/dist/ai/enhanced-intent.js +32 -0
- package/dist/ai/index.d.ts +29 -0
- package/dist/ai/index.js +44 -0
- package/dist/ai/intent.d.ts +16 -0
- package/dist/ai/intent.js +30 -0
- package/dist/core/ai-config.d.ts +25 -0
- package/dist/core/ai-config.js +326 -0
- package/dist/core/config-manager.d.ts +36 -0
- package/dist/core/config-manager.js +400 -0
- package/dist/core/config-validator.d.ts +9 -0
- package/dist/core/config-validator.js +184 -0
- package/dist/core/constants.d.ts +34 -0
- package/dist/core/constants.js +37 -0
- package/dist/core/error-ai.d.ts +23 -0
- package/dist/core/error-ai.js +217 -0
- package/dist/core/error-handler.d.ts +197 -0
- package/dist/core/error-handler.js +467 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +17 -0
- package/dist/core/logger.d.ts +27 -0
- package/dist/core/logger.js +108 -0
- package/dist/core/performance-monitor.d.ts +74 -0
- package/dist/core/performance-monitor.js +260 -0
- package/dist/core/providers.d.ts +36 -0
- package/dist/core/providers.js +304 -0
- package/dist/core/retry-manager.d.ts +41 -0
- package/dist/core/retry-manager.js +204 -0
- package/dist/core/types.d.ts +155 -0
- package/dist/core/types.js +2 -0
- package/dist/daemon/index.d.ts +10 -0
- package/dist/daemon/index.js +15 -0
- package/dist/daemon/intent-engine.d.ts +22 -0
- package/dist/daemon/intent-engine.js +50 -0
- package/dist/daemon/orchestrator.d.ts +24 -0
- package/dist/daemon/orchestrator.js +100 -0
- package/dist/daemon/pm.d.ts +33 -0
- package/dist/daemon/pm.js +127 -0
- package/dist/daemon/process.d.ts +11 -0
- package/dist/daemon/process.js +49 -0
- package/dist/daemon/server.d.ts +17 -0
- package/dist/daemon/server.js +435 -0
- package/dist/daemon/service.d.ts +36 -0
- package/dist/daemon/service.js +278 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +36 -0
- package/dist/mcp/client.d.ts +51 -0
- package/dist/mcp/client.js +276 -0
- package/dist/mcp/index.d.ts +162 -0
- package/dist/mcp/index.js +199 -0
- package/dist/mcp/tool-registry.d.ts +71 -0
- package/dist/mcp/tool-registry.js +308 -0
- package/dist/mcp/transport.d.ts +83 -0
- package/dist/mcp/transport.js +515 -0
- package/dist/mcp/types.d.ts +136 -0
- package/dist/mcp/types.js +31 -0
- package/dist/runtime/adapter-advanced.d.ts +184 -0
- package/dist/runtime/adapter-advanced.js +160 -0
- package/dist/runtime/adapter.d.ts +9 -0
- package/dist/runtime/adapter.js +2 -0
- package/dist/runtime/detector-advanced.d.ts +59 -0
- package/dist/runtime/detector-advanced.js +487 -0
- package/dist/runtime/detector.d.ts +5 -0
- package/dist/runtime/detector.js +56 -0
- package/dist/runtime/docker-adapter.d.ts +18 -0
- package/dist/runtime/docker-adapter.js +170 -0
- package/dist/runtime/docker.d.ts +17 -0
- package/dist/runtime/docker.js +71 -0
- package/dist/runtime/executable-analyzer.d.ts +56 -0
- package/dist/runtime/executable-analyzer.js +391 -0
- package/dist/runtime/go-adapter.d.ts +19 -0
- package/dist/runtime/go-adapter.js +190 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/node-adapter.d.ts +10 -0
- package/dist/runtime/node-adapter.js +23 -0
- package/dist/runtime/node.d.ts +20 -0
- package/dist/runtime/node.js +86 -0
- package/dist/runtime/python-adapter.d.ts +11 -0
- package/dist/runtime/python-adapter.js +102 -0
- package/dist/runtime/python.d.ts +17 -0
- package/dist/runtime/python.js +72 -0
- package/dist/runtime/rust-adapter.d.ts +21 -0
- package/dist/runtime/rust-adapter.js +267 -0
- package/dist/sdk.d.ts +500 -0
- package/dist/sdk.js +904 -0
- package/docs/README.ZH_CN.md +545 -0
- package/docs/api.md +888 -0
- package/docs/architecture.md +731 -0
- package/docs/development.md +744 -0
- package/package.json +112 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { CONFIG_PATH, MCPILOT_HOME, DEFAULT_CONFIG } from './constants.js';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
export class ConfigManager {
|
|
6
|
+
static CONFIG_DIR = MCPILOT_HOME;
|
|
7
|
+
static SERVICES_DIR = path.join(this.CONFIG_DIR, 'services');
|
|
8
|
+
static DOCKER_HOSTS_DIR = path.join(this.CONFIG_DIR, 'config', 'docker-hosts');
|
|
9
|
+
static RUNTIME_PROFILES_DIR = path.join(this.CONFIG_DIR, 'config', 'runtime-profiles');
|
|
10
|
+
static GLOBAL_CONFIG_PATH = CONFIG_PATH;
|
|
11
|
+
// Memory caches
|
|
12
|
+
static serviceConfigCache = new Map();
|
|
13
|
+
static servicesListCache = null;
|
|
14
|
+
static globalConfigCache = null;
|
|
15
|
+
static dockerHostsCache = new Map();
|
|
16
|
+
static runtimeProfilesCache = new Map();
|
|
17
|
+
static init() {
|
|
18
|
+
// Create configuration directory structure
|
|
19
|
+
const dirs = [
|
|
20
|
+
this.CONFIG_DIR,
|
|
21
|
+
path.join(this.CONFIG_DIR, 'config'),
|
|
22
|
+
this.SERVICES_DIR,
|
|
23
|
+
this.DOCKER_HOSTS_DIR,
|
|
24
|
+
this.RUNTIME_PROFILES_DIR,
|
|
25
|
+
];
|
|
26
|
+
for (const dir of dirs) {
|
|
27
|
+
if (!fs.existsSync(dir)) {
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Create default global configuration
|
|
32
|
+
if (!fs.existsSync(this.GLOBAL_CONFIG_PATH)) {
|
|
33
|
+
this.saveGlobalConfig(this.getDefaultGlobalConfig());
|
|
34
|
+
}
|
|
35
|
+
// Create default Docker host configuration
|
|
36
|
+
this.ensureDefaultDockerHosts();
|
|
37
|
+
// Create default runtime configuration templates
|
|
38
|
+
this.ensureDefaultRuntimeProfiles();
|
|
39
|
+
logger.info('Configuration system initialized');
|
|
40
|
+
}
|
|
41
|
+
// ==================== Service Configuration Management ====================
|
|
42
|
+
static getServiceConfig(serviceName) {
|
|
43
|
+
// Check cache first
|
|
44
|
+
if (this.serviceConfigCache.has(serviceName)) {
|
|
45
|
+
return this.serviceConfigCache.get(serviceName);
|
|
46
|
+
}
|
|
47
|
+
const configPath = this.getServiceConfigPath(serviceName);
|
|
48
|
+
if (!fs.existsSync(configPath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
53
|
+
const config = JSON.parse(content);
|
|
54
|
+
// Cache the result
|
|
55
|
+
this.serviceConfigCache.set(serviceName, config);
|
|
56
|
+
return config;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
logger.error(`Failed to read service config for ${serviceName}: ${error.message}`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static saveServiceConfig(serviceName, config) {
|
|
64
|
+
const configPath = this.getServiceConfigPath(serviceName);
|
|
65
|
+
const configDir = path.dirname(configPath);
|
|
66
|
+
if (!fs.existsSync(configDir)) {
|
|
67
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
// Ensure path is absolute
|
|
71
|
+
if (!path.isAbsolute(config.path)) {
|
|
72
|
+
config.path = path.resolve(config.path);
|
|
73
|
+
}
|
|
74
|
+
// Add/update metadata
|
|
75
|
+
config.installedAt = config.installedAt || new Date().toISOString();
|
|
76
|
+
config.lastDetectedAt = new Date().toISOString();
|
|
77
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
78
|
+
// Update cache
|
|
79
|
+
this.serviceConfigCache.set(serviceName, config);
|
|
80
|
+
this.servicesListCache = null; // Invalidate services list cache
|
|
81
|
+
logger.debug(`Service config saved: ${serviceName}`);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error(`Failed to save service config for ${serviceName}: ${error.message}`);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
static updateServiceDetection(serviceName, detection) {
|
|
89
|
+
const config = this.getServiceConfig(serviceName) || {
|
|
90
|
+
name: serviceName,
|
|
91
|
+
path: '', // Will be set by caller
|
|
92
|
+
};
|
|
93
|
+
config.detectedRuntime = detection.runtime;
|
|
94
|
+
config.detectionConfidence = detection.confidence;
|
|
95
|
+
config.detectionSource = detection.source;
|
|
96
|
+
config.detectionEvidence = detection.evidence;
|
|
97
|
+
config.detectionWarning = detection.warning;
|
|
98
|
+
config.lastDetectedAt = new Date().toISOString();
|
|
99
|
+
// If confidence is high, automatically update runtime
|
|
100
|
+
const globalConfig = this.getGlobalConfig();
|
|
101
|
+
if (detection.confidence >= globalConfig.detectionThreshold) {
|
|
102
|
+
config.runtime = detection.runtime;
|
|
103
|
+
logger.info(`Auto-updated runtime for ${serviceName}: ${detection.runtime} (confidence: ${detection.confidence})`);
|
|
104
|
+
}
|
|
105
|
+
this.saveServiceConfig(serviceName, config);
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
static setServiceRuntime(serviceName, runtime, runtimeConfig) {
|
|
109
|
+
const config = this.getServiceConfig(serviceName);
|
|
110
|
+
if (!config) {
|
|
111
|
+
throw new Error(`Service ${serviceName} not found`);
|
|
112
|
+
}
|
|
113
|
+
config.runtime = runtime;
|
|
114
|
+
config.detectionSource = 'explicit';
|
|
115
|
+
config.detectionConfidence = 1.0;
|
|
116
|
+
if (runtimeConfig) {
|
|
117
|
+
config.runtimeConfig = runtimeConfig;
|
|
118
|
+
}
|
|
119
|
+
this.saveServiceConfig(serviceName, config);
|
|
120
|
+
return config;
|
|
121
|
+
}
|
|
122
|
+
// ==================== Docker Host Configuration ====================
|
|
123
|
+
static getDockerHostConfig(hostName) {
|
|
124
|
+
const configPath = path.join(this.DOCKER_HOSTS_DIR, `${hostName}.json`);
|
|
125
|
+
if (!fs.existsSync(configPath)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
130
|
+
return JSON.parse(content);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
logger.error(`Failed to read Docker host config ${hostName}: ${error.message}`);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
static saveDockerHostConfig(hostName, config) {
|
|
138
|
+
const configPath = path.join(this.DOCKER_HOSTS_DIR, `${hostName}.json`);
|
|
139
|
+
try {
|
|
140
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
141
|
+
logger.debug(`Docker host config saved: ${hostName}`);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
logger.error(`Failed to save Docker host config ${hostName}: ${error.message}`);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
static deleteDockerHostConfig(hostName) {
|
|
149
|
+
const configPath = path.join(this.DOCKER_HOSTS_DIR, `${hostName}.json`);
|
|
150
|
+
try {
|
|
151
|
+
if (fs.existsSync(configPath)) {
|
|
152
|
+
fs.unlinkSync(configPath);
|
|
153
|
+
logger.debug(`Docker host config deleted: ${hostName}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
logger.error(`Failed to delete Docker host config ${hostName}: ${error.message}`);
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
static listDockerHosts() {
|
|
162
|
+
if (!fs.existsSync(this.DOCKER_HOSTS_DIR)) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
return fs.readdirSync(this.DOCKER_HOSTS_DIR)
|
|
166
|
+
.filter(file => file.endsWith('.json'))
|
|
167
|
+
.map(file => path.basename(file, '.json'));
|
|
168
|
+
}
|
|
169
|
+
// ==================== Runtime Configuration Templates ====================
|
|
170
|
+
static getRuntimeProfile(runtime) {
|
|
171
|
+
const profilePath = path.join(this.RUNTIME_PROFILES_DIR, `${runtime}.json`);
|
|
172
|
+
if (!fs.existsSync(profilePath)) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const content = fs.readFileSync(profilePath, 'utf-8');
|
|
177
|
+
return JSON.parse(content);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
logger.error(`Failed to read runtime profile for ${runtime}: ${error.message}`);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
static saveRuntimeProfile(runtime, config) {
|
|
185
|
+
const profilePath = path.join(this.RUNTIME_PROFILES_DIR, `${runtime}.json`);
|
|
186
|
+
try {
|
|
187
|
+
fs.writeFileSync(profilePath, JSON.stringify(config, null, 2));
|
|
188
|
+
logger.debug(`Runtime profile saved: ${runtime}`);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
logger.error(`Failed to save runtime profile for ${runtime}: ${error.message}`);
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// ==================== Global Configuration ====================
|
|
196
|
+
static getGlobalConfig() {
|
|
197
|
+
if (!fs.existsSync(this.GLOBAL_CONFIG_PATH)) {
|
|
198
|
+
return this.getDefaultGlobalConfig();
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const content = fs.readFileSync(this.GLOBAL_CONFIG_PATH, 'utf-8');
|
|
202
|
+
return JSON.parse(content);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
logger.error(`Failed to read global config: ${error.message}`);
|
|
206
|
+
return this.getDefaultGlobalConfig();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
static saveGlobalConfig(config) {
|
|
210
|
+
try {
|
|
211
|
+
fs.writeFileSync(this.GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
212
|
+
logger.debug('Global config saved');
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
logger.error(`Failed to save global config: ${error.message}`);
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// ==================== Helper Methods ====================
|
|
220
|
+
static getServiceConfigPath(serviceName) {
|
|
221
|
+
return path.join(this.SERVICES_DIR, serviceName, 'config.json');
|
|
222
|
+
}
|
|
223
|
+
static ensureDefaultDockerHosts() {
|
|
224
|
+
const defaultHosts = {
|
|
225
|
+
local: {
|
|
226
|
+
type: 'local',
|
|
227
|
+
socketPath: process.platform === 'win32'
|
|
228
|
+
? '//./pipe/docker_engine'
|
|
229
|
+
: '/var/run/docker.sock',
|
|
230
|
+
},
|
|
231
|
+
'localhost-tcp': {
|
|
232
|
+
type: 'remote',
|
|
233
|
+
host: 'localhost',
|
|
234
|
+
port: 2375,
|
|
235
|
+
},
|
|
236
|
+
'localhost-tls': {
|
|
237
|
+
type: 'remote',
|
|
238
|
+
host: 'localhost',
|
|
239
|
+
port: 2376,
|
|
240
|
+
useTLS: true,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
for (const [name, config] of Object.entries(defaultHosts)) {
|
|
244
|
+
const configPath = path.join(this.DOCKER_HOSTS_DIR, `${name}.json`);
|
|
245
|
+
if (!fs.existsSync(configPath)) {
|
|
246
|
+
this.saveDockerHostConfig(name, config);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
static ensureDefaultRuntimeProfiles() {
|
|
251
|
+
const defaultProfiles = {
|
|
252
|
+
node: {
|
|
253
|
+
node: {
|
|
254
|
+
npmRegistry: 'https://registry.npmmirror.com',
|
|
255
|
+
bun: false,
|
|
256
|
+
nodeVersion: '>=18.0.0',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
python: {
|
|
260
|
+
python: {
|
|
261
|
+
venv: true,
|
|
262
|
+
mirror: 'https://pypi.tuna.tsinghua.edu.cn/simple',
|
|
263
|
+
pythonVersion: '>=3.8',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
docker: {
|
|
267
|
+
docker: {
|
|
268
|
+
type: 'local',
|
|
269
|
+
ports: [8080],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
go: {
|
|
273
|
+
go: {
|
|
274
|
+
build: true,
|
|
275
|
+
goVersion: '>=1.20',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
rust: {
|
|
279
|
+
rust: {
|
|
280
|
+
release: true,
|
|
281
|
+
rustVersion: '>=1.70',
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
binary: {
|
|
285
|
+
// Binary runtime has no special configuration
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
for (const [runtime, config] of Object.entries(defaultProfiles)) {
|
|
289
|
+
const profilePath = path.join(this.RUNTIME_PROFILES_DIR, `${runtime}.json`);
|
|
290
|
+
if (!fs.existsSync(profilePath)) {
|
|
291
|
+
this.saveRuntimeProfile(runtime, config);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
static getDefaultGlobalConfig() {
|
|
296
|
+
return {
|
|
297
|
+
...DEFAULT_CONFIG,
|
|
298
|
+
defaultDockerHost: 'local',
|
|
299
|
+
detectionThreshold: 0.7,
|
|
300
|
+
requireExplicitRuntime: false,
|
|
301
|
+
autoSaveDetection: true,
|
|
302
|
+
interactiveMode: true,
|
|
303
|
+
logLevel: 'info',
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
// ==================== Configuration Parsing and Merging ====================
|
|
307
|
+
static resolveServiceConfig(userConfig, servicePath) {
|
|
308
|
+
const baseConfig = {
|
|
309
|
+
name: userConfig.name || path.basename(servicePath),
|
|
310
|
+
path: servicePath,
|
|
311
|
+
};
|
|
312
|
+
// Merge user configuration
|
|
313
|
+
const mergedConfig = { ...baseConfig, ...userConfig };
|
|
314
|
+
// Ensure path is absolute
|
|
315
|
+
if (!path.isAbsolute(mergedConfig.path)) {
|
|
316
|
+
mergedConfig.path = path.resolve(mergedConfig.path);
|
|
317
|
+
}
|
|
318
|
+
// If user specified runtime, set highest priority
|
|
319
|
+
if (mergedConfig.runtime) {
|
|
320
|
+
mergedConfig.detectionSource = 'explicit';
|
|
321
|
+
mergedConfig.detectionConfidence = 1.0;
|
|
322
|
+
}
|
|
323
|
+
// Apply runtime configuration template
|
|
324
|
+
if (mergedConfig.runtime && !mergedConfig.runtimeConfig) {
|
|
325
|
+
const profile = this.getRuntimeProfile(mergedConfig.runtime);
|
|
326
|
+
if (profile) {
|
|
327
|
+
mergedConfig.runtimeConfig = profile;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return mergedConfig;
|
|
331
|
+
}
|
|
332
|
+
// ==================== Configuration validation ====================
|
|
333
|
+
static validateServiceConfig(config) {
|
|
334
|
+
const errors = [];
|
|
335
|
+
if (!config.name) {
|
|
336
|
+
errors.push('Service name is required');
|
|
337
|
+
}
|
|
338
|
+
if (!config.path) {
|
|
339
|
+
errors.push('Service path is required');
|
|
340
|
+
}
|
|
341
|
+
else if (!fs.existsSync(config.path)) {
|
|
342
|
+
errors.push(`Service path does not exist: ${config.path}`);
|
|
343
|
+
}
|
|
344
|
+
if (!config.runtime && !config.detectedRuntime) {
|
|
345
|
+
errors.push('Runtime type is required (either explicit or detected)');
|
|
346
|
+
}
|
|
347
|
+
if (config.detectionConfidence !== undefined) {
|
|
348
|
+
if (config.detectionConfidence < 0 || config.detectionConfidence > 1) {
|
|
349
|
+
errors.push(`Detection confidence must be between 0 and 1, got ${config.detectionConfidence}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return errors;
|
|
353
|
+
}
|
|
354
|
+
// ==================== Configuration Utility Methods ====================
|
|
355
|
+
static getAllServices() {
|
|
356
|
+
// Check cache first
|
|
357
|
+
if (this.servicesListCache !== null) {
|
|
358
|
+
return this.servicesListCache;
|
|
359
|
+
}
|
|
360
|
+
if (!fs.existsSync(this.SERVICES_DIR)) {
|
|
361
|
+
this.servicesListCache = [];
|
|
362
|
+
return [];
|
|
363
|
+
}
|
|
364
|
+
const services = fs.readdirSync(this.SERVICES_DIR, { withFileTypes: true })
|
|
365
|
+
.filter(dirent => dirent.isDirectory())
|
|
366
|
+
.map(dirent => dirent.name);
|
|
367
|
+
// Cache the result
|
|
368
|
+
this.servicesListCache = services;
|
|
369
|
+
return services;
|
|
370
|
+
}
|
|
371
|
+
static getServiceDetectionCache(serviceName) {
|
|
372
|
+
const cachePath = path.join(this.SERVICES_DIR, serviceName, 'detection-cache.json');
|
|
373
|
+
if (!fs.existsSync(cachePath)) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const content = fs.readFileSync(cachePath, 'utf-8');
|
|
378
|
+
return JSON.parse(content);
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
logger.error(`Failed to read detection cache for ${serviceName}: ${error.message}`);
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
static saveServiceDetectionCache(serviceName, detection) {
|
|
386
|
+
const cachePath = path.join(this.SERVICES_DIR, serviceName, 'detection-cache.json');
|
|
387
|
+
const cacheDir = path.dirname(cachePath);
|
|
388
|
+
if (!fs.existsSync(cacheDir)) {
|
|
389
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
fs.writeFileSync(cachePath, JSON.stringify(detection, null, 2));
|
|
393
|
+
logger.debug(`Detection cache saved for ${serviceName}`);
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
logger.error(`Failed to save detection cache for ${serviceName}: ${error.message}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Config } from './types';
|
|
2
|
+
export declare class ConfigValidator {
|
|
3
|
+
static validate(config: any): Config;
|
|
4
|
+
private static checkRequiredConfig;
|
|
5
|
+
static getDefaultConfig(): Config;
|
|
6
|
+
static mergeWithDefaults(userConfig: any): Config;
|
|
7
|
+
static validateAIConfig(aiConfig: any): any;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=config-validator.d.ts.map
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { DEFAULT_CONFIG } from './constants.js';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
export class ConfigValidator {
|
|
4
|
+
static validate(config) {
|
|
5
|
+
const validated = {
|
|
6
|
+
ai: {
|
|
7
|
+
provider: 'deepseek',
|
|
8
|
+
model: 'deepseek-v3',
|
|
9
|
+
apiKey: '',
|
|
10
|
+
},
|
|
11
|
+
registry: {
|
|
12
|
+
preferred: 'gitee-mcp',
|
|
13
|
+
},
|
|
14
|
+
services: {
|
|
15
|
+
autoStart: [],
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
// Handle null or undefined config
|
|
19
|
+
if (!config) {
|
|
20
|
+
return validated;
|
|
21
|
+
}
|
|
22
|
+
// Validate AI configuration
|
|
23
|
+
if (config.ai) {
|
|
24
|
+
// Validate provider
|
|
25
|
+
if (typeof config.ai.provider === 'string') {
|
|
26
|
+
const validProviders = ['openai', 'anthropic', 'deepseek', 'cohere', 'ollama', 'local', 'custom'];
|
|
27
|
+
if (validProviders.includes(config.ai.provider)) {
|
|
28
|
+
validated.ai.provider = config.ai.provider;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logger.warn(`Invalid AI provider "${config.ai.provider}" in config, using default "deepseek"`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
logger.warn('Invalid AI provider in config, using default');
|
|
36
|
+
}
|
|
37
|
+
// Validate model
|
|
38
|
+
if (typeof config.ai.model === 'string') {
|
|
39
|
+
validated.ai.model = config.ai.model;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
logger.warn('Invalid AI model in config, using default');
|
|
43
|
+
}
|
|
44
|
+
// Validate apiKey
|
|
45
|
+
if (typeof config.ai.apiKey === 'string') {
|
|
46
|
+
validated.ai.apiKey = config.ai.apiKey;
|
|
47
|
+
}
|
|
48
|
+
// Validate apiEndpoint
|
|
49
|
+
if (typeof config.ai.apiEndpoint === 'string') {
|
|
50
|
+
validated.ai.apiEndpoint = config.ai.apiEndpoint;
|
|
51
|
+
}
|
|
52
|
+
// Validate timeout
|
|
53
|
+
if (typeof config.ai.timeout === 'number' && config.ai.timeout > 0) {
|
|
54
|
+
validated.ai.timeout = config.ai.timeout;
|
|
55
|
+
}
|
|
56
|
+
// Validate maxTokens
|
|
57
|
+
if (typeof config.ai.maxTokens === 'number' && config.ai.maxTokens > 0) {
|
|
58
|
+
validated.ai.maxTokens = config.ai.maxTokens;
|
|
59
|
+
}
|
|
60
|
+
// Validate temperature
|
|
61
|
+
if (typeof config.ai.temperature === 'number' && config.ai.temperature >= 0 && config.ai.temperature <= 2) {
|
|
62
|
+
validated.ai.temperature = config.ai.temperature;
|
|
63
|
+
}
|
|
64
|
+
// Validate embeddingProvider
|
|
65
|
+
if (typeof config.ai.embeddingProvider === 'string') {
|
|
66
|
+
validated.ai.embeddingProvider = config.ai.embeddingProvider;
|
|
67
|
+
}
|
|
68
|
+
// Validate embeddingApiKey
|
|
69
|
+
if (typeof config.ai.embeddingApiKey === 'string') {
|
|
70
|
+
validated.ai.embeddingApiKey = config.ai.embeddingApiKey;
|
|
71
|
+
}
|
|
72
|
+
// Validate embeddingModel
|
|
73
|
+
if (typeof config.ai.embeddingModel === 'string') {
|
|
74
|
+
validated.ai.embeddingModel = config.ai.embeddingModel;
|
|
75
|
+
}
|
|
76
|
+
// Validate embeddingEndpoint
|
|
77
|
+
if (typeof config.ai.embeddingEndpoint === 'string') {
|
|
78
|
+
validated.ai.embeddingEndpoint = config.ai.embeddingEndpoint;
|
|
79
|
+
}
|
|
80
|
+
// Validate localModelPath
|
|
81
|
+
if (typeof config.ai.localModelPath === 'string') {
|
|
82
|
+
validated.ai.localModelPath = config.ai.localModelPath;
|
|
83
|
+
}
|
|
84
|
+
// Validate ollamaHost
|
|
85
|
+
if (typeof config.ai.ollamaHost === 'string') {
|
|
86
|
+
validated.ai.ollamaHost = config.ai.ollamaHost;
|
|
87
|
+
}
|
|
88
|
+
// Validate customConfig
|
|
89
|
+
if (config.ai.customConfig && typeof config.ai.customConfig === 'object') {
|
|
90
|
+
validated.ai.customConfig = config.ai.customConfig;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Validate registry configuration
|
|
94
|
+
if (config.registry) {
|
|
95
|
+
if (typeof config.registry.preferred === 'string') {
|
|
96
|
+
validated.registry.preferred = config.registry.preferred;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
logger.warn('Invalid registry preference in config, using default');
|
|
100
|
+
}
|
|
101
|
+
// Validate customRegistries
|
|
102
|
+
if (config.registry.customRegistries && typeof config.registry.customRegistries === 'object') {
|
|
103
|
+
validated.registry.customRegistries = config.registry.customRegistries;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Validate service configuration
|
|
107
|
+
if (config.services) {
|
|
108
|
+
if (Array.isArray(config.services.autoStart)) {
|
|
109
|
+
validated.services.autoStart = config.services.autoStart.filter((service) => typeof service === 'string');
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
logger.warn('Invalid autoStart configuration, using empty array');
|
|
113
|
+
}
|
|
114
|
+
// Validate defaultTimeout
|
|
115
|
+
if (typeof config.services.defaultTimeout === 'number' && config.services.defaultTimeout > 0) {
|
|
116
|
+
validated.services.defaultTimeout = config.services.defaultTimeout;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Check required configuration
|
|
120
|
+
this.checkRequiredConfig(validated);
|
|
121
|
+
return validated;
|
|
122
|
+
}
|
|
123
|
+
static checkRequiredConfig(config) {
|
|
124
|
+
// Check AI configuration
|
|
125
|
+
const aiConfig = config.ai;
|
|
126
|
+
// Check AI API key (if using providers that require API key)
|
|
127
|
+
const providersRequiringKey = ['openai', 'anthropic', 'deepseek', 'cohere'];
|
|
128
|
+
if (providersRequiringKey.includes(aiConfig.provider) && !aiConfig.apiKey) {
|
|
129
|
+
logger.warn(`AI provider ${aiConfig.provider} requires an API key but none was provided`);
|
|
130
|
+
}
|
|
131
|
+
// Check local model configuration
|
|
132
|
+
if (aiConfig.provider === 'local' && !aiConfig.localModelPath) {
|
|
133
|
+
logger.warn('Local AI provider selected but no localModelPath specified');
|
|
134
|
+
}
|
|
135
|
+
// Check Ollama configuration
|
|
136
|
+
if (aiConfig.provider === 'ollama') {
|
|
137
|
+
if (!aiConfig.ollamaHost) {
|
|
138
|
+
logger.info('Ollama provider selected, using default host: http://localhost:11434');
|
|
139
|
+
aiConfig.ollamaHost = 'http://localhost:11434';
|
|
140
|
+
}
|
|
141
|
+
if (!aiConfig.model) {
|
|
142
|
+
logger.warn('Ollama provider selected but no model specified');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Check custom provider configuration
|
|
146
|
+
if (aiConfig.provider === 'custom' && !aiConfig.apiEndpoint) {
|
|
147
|
+
logger.warn('Custom AI provider selected but no apiEndpoint specified');
|
|
148
|
+
}
|
|
149
|
+
// Check if auto-start services are valid
|
|
150
|
+
if (config.services.autoStart.length > 0) {
|
|
151
|
+
logger.info(`Services configured for auto-start: ${config.services.autoStart.join(', ')}`);
|
|
152
|
+
}
|
|
153
|
+
// Check registry configuration
|
|
154
|
+
if (config.registry.customRegistries) {
|
|
155
|
+
const customRegistryCount = Object.keys(config.registry.customRegistries).length;
|
|
156
|
+
if (customRegistryCount > 0) {
|
|
157
|
+
logger.info(`Loaded ${customRegistryCount} custom registry configuration(s)`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
static getDefaultConfig() {
|
|
162
|
+
return DEFAULT_CONFIG;
|
|
163
|
+
}
|
|
164
|
+
static mergeWithDefaults(userConfig) {
|
|
165
|
+
const defaultConfig = this.getDefaultConfig();
|
|
166
|
+
const merged = {
|
|
167
|
+
ai: { ...defaultConfig.ai, ...(userConfig.ai || {}) },
|
|
168
|
+
registry: { ...defaultConfig.registry, ...(userConfig.registry || {}) },
|
|
169
|
+
services: { ...defaultConfig.services, ...(userConfig.services || {}) },
|
|
170
|
+
};
|
|
171
|
+
return this.validate(merged);
|
|
172
|
+
}
|
|
173
|
+
static validateAIConfig(aiConfig) {
|
|
174
|
+
// Create a mock config with just the AI config for validation
|
|
175
|
+
const mockConfig = {
|
|
176
|
+
ai: aiConfig,
|
|
177
|
+
registry: { preferred: 'gitee-mcp' },
|
|
178
|
+
services: { autoStart: [] },
|
|
179
|
+
};
|
|
180
|
+
const validated = this.validate(mockConfig);
|
|
181
|
+
return validated.ai;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=config-validator.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const MCPILOT_HOME: string;
|
|
2
|
+
export declare const MCPILOT_DIR: string;
|
|
3
|
+
export declare const SOCKET_PATH: string;
|
|
4
|
+
export declare const LOGS_DIR: string;
|
|
5
|
+
export declare const SERVERS_DIR: string;
|
|
6
|
+
export declare const VENVS_DIR: string;
|
|
7
|
+
export declare const CONFIG_PATH: string;
|
|
8
|
+
export declare const DEFAULT_CONFIG: {
|
|
9
|
+
ai: {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
provider: string;
|
|
12
|
+
model: string;
|
|
13
|
+
apiKey: string;
|
|
14
|
+
timeout: number;
|
|
15
|
+
maxTokens: number;
|
|
16
|
+
temperature: number;
|
|
17
|
+
embeddingProvider: string;
|
|
18
|
+
embeddingApiKey: string;
|
|
19
|
+
embeddingModel: string;
|
|
20
|
+
embeddingEndpoint: string;
|
|
21
|
+
useLocalEmbeddings: boolean;
|
|
22
|
+
useVectorSearch: boolean;
|
|
23
|
+
transformersTimeout: number;
|
|
24
|
+
fallbackMode: string;
|
|
25
|
+
};
|
|
26
|
+
registry: {
|
|
27
|
+
preferred: string;
|
|
28
|
+
};
|
|
29
|
+
services: {
|
|
30
|
+
autoStart: string[];
|
|
31
|
+
defaultTimeout: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export const MCPILOT_HOME = path.join(os.homedir(), '.mcpilot');
|
|
4
|
+
export const MCPILOT_DIR = MCPILOT_HOME; // Alias for backward compatibility
|
|
5
|
+
export const SOCKET_PATH = path.join(MCPILOT_HOME, 'run', 'mcp.sock');
|
|
6
|
+
export const LOGS_DIR = path.join(MCPILOT_HOME, 'logs');
|
|
7
|
+
export const SERVERS_DIR = path.join(MCPILOT_HOME, 'servers');
|
|
8
|
+
export const VENVS_DIR = path.join(MCPILOT_HOME, 'venvs');
|
|
9
|
+
export const CONFIG_PATH = path.join(MCPILOT_HOME, 'config.json');
|
|
10
|
+
export const DEFAULT_CONFIG = {
|
|
11
|
+
ai: {
|
|
12
|
+
enabled: true, // Whether to enable AI functionality
|
|
13
|
+
provider: 'deepseek',
|
|
14
|
+
model: 'deepseek-v3',
|
|
15
|
+
apiKey: '',
|
|
16
|
+
timeout: 30000, // 30 second timeout
|
|
17
|
+
maxTokens: 2048,
|
|
18
|
+
temperature: 0.7,
|
|
19
|
+
// Embedding-specific configuration
|
|
20
|
+
embeddingProvider: '',
|
|
21
|
+
embeddingApiKey: '',
|
|
22
|
+
embeddingModel: '',
|
|
23
|
+
embeddingEndpoint: '',
|
|
24
|
+
useLocalEmbeddings: false, // Whether to use local transformers for text embedding
|
|
25
|
+
useVectorSearch: true, // Whether to use vector search
|
|
26
|
+
transformersTimeout: 5000, // Transformers loading timeout (milliseconds)
|
|
27
|
+
fallbackMode: 'lightweight', // Fallback mode: 'lightweight' | 'simple' | 'disabled'
|
|
28
|
+
},
|
|
29
|
+
registry: {
|
|
30
|
+
preferred: 'gitee-mcp',
|
|
31
|
+
},
|
|
32
|
+
services: {
|
|
33
|
+
autoStart: ['filesystem'],
|
|
34
|
+
defaultTimeout: 60000, // 60 second default timeout
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AIProvider } from './types';
|
|
2
|
+
export interface AIError {
|
|
3
|
+
type: 'config' | 'connection' | 'validation' | 'authentication' | 'unknown';
|
|
4
|
+
message: string;
|
|
5
|
+
provider?: AIProvider;
|
|
6
|
+
details?: any;
|
|
7
|
+
}
|
|
8
|
+
export declare class AIErrorHandler {
|
|
9
|
+
static handleError(error: AIError): void;
|
|
10
|
+
private static getSuggestions;
|
|
11
|
+
private static printNextSteps;
|
|
12
|
+
private static getProviderWebsite;
|
|
13
|
+
static handleProviderError(input: string, similarProviders?: Array<{
|
|
14
|
+
provider: AIProvider;
|
|
15
|
+
similarity: number;
|
|
16
|
+
distance: number;
|
|
17
|
+
}>): void;
|
|
18
|
+
static handleModelError(provider: AIProvider, model: string, availableModels?: string[]): void;
|
|
19
|
+
static handleApiKeyError(provider: AIProvider): void;
|
|
20
|
+
private static getEnvVarName;
|
|
21
|
+
static handleTestResult(success: boolean, provider?: AIProvider, details?: any): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=error-ai.d.ts.map
|