fraim-framework 2.0.81 → 2.0.83
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/src/cli/api/get-provider-client.js +41 -0
- package/dist/src/cli/api/provider-client.js +107 -0
- package/dist/src/cli/commands/add-ide.js +144 -77
- package/dist/src/cli/commands/add-provider.js +223 -0
- package/dist/src/cli/commands/doctor.js +131 -111
- package/dist/src/cli/commands/init-project.js +67 -31
- package/dist/src/cli/commands/setup.js +247 -563
- package/dist/src/cli/commands/sync.js +2 -2
- package/dist/src/cli/commands/test-mcp.js +35 -1
- package/dist/src/cli/doctor/check-runner.js +199 -0
- package/dist/src/cli/doctor/checks/global-setup-checks.js +220 -0
- package/dist/src/cli/doctor/checks/ide-config-checks.js +250 -0
- package/dist/src/cli/doctor/checks/mcp-connectivity-checks.js +381 -0
- package/dist/src/cli/doctor/checks/project-setup-checks.js +282 -0
- package/dist/src/cli/doctor/checks/scripts-checks.js +157 -0
- package/dist/src/cli/doctor/checks/workflow-checks.js +247 -0
- package/dist/src/cli/doctor/reporters/console-reporter.js +96 -0
- package/dist/src/cli/doctor/reporters/json-reporter.js +11 -0
- package/dist/src/cli/doctor/types.js +6 -0
- package/dist/src/cli/fraim.js +44 -3
- package/dist/src/cli/mcp/ide-formats.js +243 -0
- package/dist/src/cli/mcp/mcp-server-builder.js +48 -0
- package/dist/src/cli/mcp/mcp-server-registry.js +159 -0
- package/dist/src/cli/mcp/types.js +3 -0
- package/dist/src/cli/providers/local-provider-registry.js +145 -0
- package/dist/src/cli/providers/provider-registry.js +230 -0
- package/dist/src/cli/setup/auto-mcp-setup.js +56 -118
- package/dist/src/cli/setup/mcp-config-generator.js +64 -321
- package/dist/src/cli/setup/provider-prompts.js +300 -0
- package/dist/src/cli/utils/remote-sync.js +22 -2
- package/package.json +4 -2
- package/dist/src/cli/commands/install.js +0 -86
- package/dist/src/cli/setup/token-validator.js +0 -57
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Console reporter for FRAIM doctor command
|
|
4
|
+
* Formats output with colors and emojis
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.formatConsoleOutput = formatConsoleOutput;
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const CATEGORY_NAMES = {
|
|
14
|
+
globalSetup: 'Global Setup',
|
|
15
|
+
projectSetup: 'Project Setup',
|
|
16
|
+
workflows: 'Workflows',
|
|
17
|
+
ideConfiguration: 'IDE Configuration',
|
|
18
|
+
mcpConnectivity: 'MCP Server Connectivity',
|
|
19
|
+
scripts: 'Scripts'
|
|
20
|
+
};
|
|
21
|
+
function getStatusIcon(status) {
|
|
22
|
+
switch (status) {
|
|
23
|
+
case 'passed': return '✅';
|
|
24
|
+
case 'warning': return '⚠️';
|
|
25
|
+
case 'error': return '❌';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function formatLatency(latency) {
|
|
29
|
+
if (!latency)
|
|
30
|
+
return '';
|
|
31
|
+
return chalk_1.default.gray(` (${latency}ms)`);
|
|
32
|
+
}
|
|
33
|
+
function formatConsoleOutput(result, options) {
|
|
34
|
+
const lines = [];
|
|
35
|
+
// Header
|
|
36
|
+
lines.push(chalk_1.default.blue('🩺 FRAIM Doctor - Comprehensive Health Check\n'));
|
|
37
|
+
// Categories
|
|
38
|
+
for (const [categoryKey, categoryResult] of Object.entries(result.categories)) {
|
|
39
|
+
// Skip empty categories
|
|
40
|
+
if (categoryResult.checks.length === 0)
|
|
41
|
+
continue;
|
|
42
|
+
const categoryName = CATEGORY_NAMES[categoryKey] || categoryKey;
|
|
43
|
+
lines.push(chalk_1.default.bold(`━━━ ${categoryName} ━━━`));
|
|
44
|
+
for (const check of categoryResult.checks) {
|
|
45
|
+
const icon = getStatusIcon(check.status);
|
|
46
|
+
const latency = formatLatency(check.latency);
|
|
47
|
+
lines.push(`${icon} ${check.message}${latency}`);
|
|
48
|
+
// Show details in verbose mode
|
|
49
|
+
if (options.verbose && check.details) {
|
|
50
|
+
for (const [key, value] of Object.entries(check.details)) {
|
|
51
|
+
lines.push(chalk_1.default.gray(` ${key}: ${value}`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Show suggestions for warnings and errors
|
|
55
|
+
if (check.suggestion) {
|
|
56
|
+
lines.push(chalk_1.default.blue(` 💡 ${check.suggestion}`));
|
|
57
|
+
if (check.command) {
|
|
58
|
+
lines.push(chalk_1.default.gray(` Run: ${check.command}`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
lines.push(''); // Empty line between categories
|
|
63
|
+
}
|
|
64
|
+
// Summary
|
|
65
|
+
lines.push(chalk_1.default.bold('━━━ Summary ━━━'));
|
|
66
|
+
lines.push(`${chalk_1.default.green('✅')} ${result.summary.passed} checks passed`);
|
|
67
|
+
if (result.summary.warnings > 0) {
|
|
68
|
+
lines.push(`${chalk_1.default.yellow('⚠️')} ${result.summary.warnings} warnings`);
|
|
69
|
+
}
|
|
70
|
+
if (result.summary.errors > 0) {
|
|
71
|
+
lines.push(`${chalk_1.default.red('❌')} ${result.summary.errors} errors`);
|
|
72
|
+
}
|
|
73
|
+
lines.push('');
|
|
74
|
+
// Final message
|
|
75
|
+
if (result.summary.errors === 0 && result.summary.warnings === 0) {
|
|
76
|
+
lines.push(chalk_1.default.green('✨ Everything looks great! Your FRAIM setup is healthy.'));
|
|
77
|
+
}
|
|
78
|
+
else if (result.summary.errors === 0) {
|
|
79
|
+
lines.push(chalk_1.default.yellow('⚠️ Some warnings found. See suggestions below.'));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
lines.push(chalk_1.default.red('❌ Issues found. See suggestions below.'));
|
|
83
|
+
}
|
|
84
|
+
// Suggestions
|
|
85
|
+
if (result.suggestions && result.suggestions.length > 0) {
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(chalk_1.default.blue('💡 Suggested fixes:'));
|
|
88
|
+
for (const suggestion of result.suggestions.slice(0, 5)) { // Show top 5
|
|
89
|
+
lines.push(chalk_1.default.blue(` ${suggestion.priority}. ${suggestion.message}`));
|
|
90
|
+
if (suggestion.command) {
|
|
91
|
+
lines.push(chalk_1.default.gray(` Run: ${suggestion.command}`));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return lines.join('\n');
|
|
96
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSON reporter for FRAIM doctor command
|
|
4
|
+
* Formats output as JSON for automation
|
|
5
|
+
* Issue #144: Enhanced doctor command
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.formatJsonOutput = formatJsonOutput;
|
|
9
|
+
function formatJsonOutput(result) {
|
|
10
|
+
return JSON.stringify(result, null, 2);
|
|
11
|
+
}
|
package/dist/src/cli/fraim.js
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
38
|
};
|
|
@@ -12,9 +45,9 @@ const setup_1 = require("./commands/setup");
|
|
|
12
45
|
const init_project_1 = require("./commands/init-project");
|
|
13
46
|
const test_mcp_1 = require("./commands/test-mcp");
|
|
14
47
|
const add_ide_1 = require("./commands/add-ide");
|
|
48
|
+
const add_provider_1 = require("./commands/add-provider");
|
|
15
49
|
const override_1 = require("./commands/override");
|
|
16
50
|
const list_overridable_1 = require("./commands/list-overridable");
|
|
17
|
-
const install_1 = require("./commands/install");
|
|
18
51
|
const fs_1 = __importDefault(require("fs"));
|
|
19
52
|
const path_1 = __importDefault(require("path"));
|
|
20
53
|
const program = new commander_1.Command();
|
|
@@ -49,7 +82,15 @@ program.addCommand(setup_1.setupCommand);
|
|
|
49
82
|
program.addCommand(init_project_1.initProjectCommand);
|
|
50
83
|
program.addCommand(test_mcp_1.testMCPCommand);
|
|
51
84
|
program.addCommand(add_ide_1.addIDECommand);
|
|
85
|
+
program.addCommand(add_provider_1.addProviderCommand);
|
|
52
86
|
program.addCommand(override_1.overrideCommand);
|
|
53
87
|
program.addCommand(list_overridable_1.listOverridableCommand);
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
// Wait for async command initialization before parsing
|
|
89
|
+
(async () => {
|
|
90
|
+
// Import the initialization promise from setup command
|
|
91
|
+
const { setupCommandInitialization } = await Promise.resolve().then(() => __importStar(require('./commands/setup')));
|
|
92
|
+
if (setupCommandInitialization) {
|
|
93
|
+
await setupCommandInitialization;
|
|
94
|
+
}
|
|
95
|
+
program.parse(process.argv);
|
|
96
|
+
})();
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// IDE Format Adapters - transform logical server structure to IDE-specific formats
|
|
3
|
+
// Uses the centralized registry to determine server types
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.IDE_FORMATS = exports.CodexFormat = exports.WindsurfFormat = exports.ClaudeCodeFormat = exports.ClaudeFormat = exports.VSCodeFormat = exports.KiroFormat = exports.StandardFormat = void 0;
|
|
6
|
+
exports.getIDEFormat = getIDEFormat;
|
|
7
|
+
const mcp_server_registry_1 = require("./mcp-server-registry");
|
|
8
|
+
const provider_registry_1 = require("../providers/provider-registry");
|
|
9
|
+
// Standard format (Cursor, Kiro, Antigravity, etc.)
|
|
10
|
+
class StandardFormat {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.name = 'standard';
|
|
13
|
+
}
|
|
14
|
+
transform(servers) {
|
|
15
|
+
const mcpServers = {};
|
|
16
|
+
for (const [key, server] of servers) {
|
|
17
|
+
if (server.url) {
|
|
18
|
+
// HTTP server - use serverUrl for standard format
|
|
19
|
+
mcpServers[key] = {
|
|
20
|
+
serverUrl: server.url,
|
|
21
|
+
headers: server.headers
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// stdio server
|
|
26
|
+
mcpServers[key] = {
|
|
27
|
+
command: server.command,
|
|
28
|
+
...(server.args && { args: server.args }),
|
|
29
|
+
...(server.env && { env: server.env })
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { mcpServers };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.StandardFormat = StandardFormat;
|
|
37
|
+
// Kiro format (also used by Cursor)
|
|
38
|
+
class KiroFormat {
|
|
39
|
+
constructor() {
|
|
40
|
+
this.name = 'kiro';
|
|
41
|
+
}
|
|
42
|
+
transform(servers) {
|
|
43
|
+
const mcpServers = {};
|
|
44
|
+
for (const [key, server] of servers) {
|
|
45
|
+
if (server.url) {
|
|
46
|
+
// HTTP server - use url (not serverUrl)
|
|
47
|
+
mcpServers[key] = {
|
|
48
|
+
url: server.url,
|
|
49
|
+
headers: server.headers
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// stdio server
|
|
54
|
+
mcpServers[key] = {
|
|
55
|
+
command: server.command,
|
|
56
|
+
...(server.args && { args: server.args }),
|
|
57
|
+
...(server.env && { env: server.env })
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { mcpServers };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.KiroFormat = KiroFormat;
|
|
65
|
+
// VSCode format
|
|
66
|
+
class VSCodeFormat {
|
|
67
|
+
constructor() {
|
|
68
|
+
this.name = 'vscode';
|
|
69
|
+
}
|
|
70
|
+
transform(servers) {
|
|
71
|
+
const vscodeServers = {};
|
|
72
|
+
for (const [key, server] of servers) {
|
|
73
|
+
if (server.url) {
|
|
74
|
+
// HTTP server
|
|
75
|
+
vscodeServers[key] = {
|
|
76
|
+
type: 'http',
|
|
77
|
+
url: server.url,
|
|
78
|
+
headers: server.headers
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// stdio server
|
|
83
|
+
vscodeServers[key] = {
|
|
84
|
+
type: 'stdio',
|
|
85
|
+
command: server.command,
|
|
86
|
+
...(server.args && { args: server.args }),
|
|
87
|
+
...(server.env && { env: server.env })
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { servers: vscodeServers };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.VSCodeFormat = VSCodeFormat;
|
|
95
|
+
// Claude Desktop format (excludes provider servers - Issue #132)
|
|
96
|
+
class ClaudeFormat {
|
|
97
|
+
constructor() {
|
|
98
|
+
this.name = 'claude';
|
|
99
|
+
}
|
|
100
|
+
async transform(servers) {
|
|
101
|
+
const mcpServers = {};
|
|
102
|
+
for (const [key, server] of servers) {
|
|
103
|
+
// Skip all provider servers - they break Claude Desktop
|
|
104
|
+
// See: https://github.com/mathursrus/FRAIM/issues/132
|
|
105
|
+
if (await (0, mcp_server_registry_1.isProviderServer)(key)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// Only include base servers (git, playwright, fraim)
|
|
109
|
+
mcpServers[key] = {
|
|
110
|
+
command: server.command,
|
|
111
|
+
...(server.args && { args: server.args }),
|
|
112
|
+
...(server.env && { env: server.env })
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return { mcpServers };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.ClaudeFormat = ClaudeFormat;
|
|
119
|
+
// Claude Code format (supports HTTP servers with VSCode-style format)
|
|
120
|
+
class ClaudeCodeFormat {
|
|
121
|
+
constructor() {
|
|
122
|
+
this.name = 'claude-code';
|
|
123
|
+
}
|
|
124
|
+
transform(servers) {
|
|
125
|
+
const mcpServers = {};
|
|
126
|
+
for (const [key, server] of servers) {
|
|
127
|
+
if (server.url) {
|
|
128
|
+
// HTTP server - use VSCode-style format
|
|
129
|
+
mcpServers[key] = {
|
|
130
|
+
type: 'http',
|
|
131
|
+
url: server.url,
|
|
132
|
+
headers: server.headers
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// stdio server
|
|
137
|
+
mcpServers[key] = {
|
|
138
|
+
command: server.command,
|
|
139
|
+
...(server.args && { args: server.args }),
|
|
140
|
+
...(server.env && { env: server.env })
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { mcpServers };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.ClaudeCodeFormat = ClaudeCodeFormat;
|
|
148
|
+
// Windsurf format (uses server-fetch wrapper for HTTP servers)
|
|
149
|
+
class WindsurfFormat {
|
|
150
|
+
constructor() {
|
|
151
|
+
this.name = 'windsurf';
|
|
152
|
+
}
|
|
153
|
+
async transform(servers) {
|
|
154
|
+
const mcpServers = {};
|
|
155
|
+
for (const [key, server] of servers) {
|
|
156
|
+
if (server.url) {
|
|
157
|
+
// HTTP server - wrap with server-fetch
|
|
158
|
+
const provider = await (0, provider_registry_1.getProvider)(key);
|
|
159
|
+
const tokenEnvVar = provider?.id ? `${provider.id.toUpperCase()}_TOKEN` : undefined;
|
|
160
|
+
if (tokenEnvVar && server.headers?.Authorization) {
|
|
161
|
+
const token = server.headers.Authorization.replace('Bearer ', '');
|
|
162
|
+
mcpServers[key] = {
|
|
163
|
+
command: 'npx',
|
|
164
|
+
args: ['-y', '@modelcontextprotocol/server-fetch', server.url],
|
|
165
|
+
env: {
|
|
166
|
+
[tokenEnvVar]: token
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// stdio server
|
|
173
|
+
mcpServers[key] = {
|
|
174
|
+
command: server.command,
|
|
175
|
+
...(server.args && { args: server.args }),
|
|
176
|
+
...(server.env && { env: server.env })
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { mcpServers };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.WindsurfFormat = WindsurfFormat;
|
|
184
|
+
// Codex format (TOML)
|
|
185
|
+
class CodexFormat {
|
|
186
|
+
constructor() {
|
|
187
|
+
this.name = 'codex';
|
|
188
|
+
}
|
|
189
|
+
transform(servers) {
|
|
190
|
+
const sections = [];
|
|
191
|
+
for (const [key, server] of servers) {
|
|
192
|
+
if (server.url) {
|
|
193
|
+
// HTTP server
|
|
194
|
+
const token = server.headers?.Authorization?.replace('Bearer ', '') || '';
|
|
195
|
+
const escapedToken = this.escapeToml(token);
|
|
196
|
+
const escapedUrl = this.escapeToml(server.url);
|
|
197
|
+
sections.push(`[mcp_servers.${key}]`);
|
|
198
|
+
sections.push(`url = "${escapedUrl}"`);
|
|
199
|
+
sections.push(`http_headers = { Authorization = "Bearer ${escapedToken}" }`);
|
|
200
|
+
sections.push('');
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// stdio server
|
|
204
|
+
sections.push(`[mcp_servers.${key}]`);
|
|
205
|
+
sections.push(`command = "${this.escapeToml(server.command || '')}"`);
|
|
206
|
+
if (server.args && server.args.length > 0) {
|
|
207
|
+
const argsStr = server.args.map(arg => `"${this.escapeToml(arg)}"`).join(', ');
|
|
208
|
+
sections.push(`args = [${argsStr}]`);
|
|
209
|
+
}
|
|
210
|
+
if (server.env) {
|
|
211
|
+
sections.push('');
|
|
212
|
+
sections.push(`[mcp_servers.${key}.env]`);
|
|
213
|
+
for (const [envKey, envValue] of Object.entries(server.env)) {
|
|
214
|
+
sections.push(`${envKey} = "${this.escapeToml(envValue)}"`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
sections.push('');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return sections.join('\n');
|
|
221
|
+
}
|
|
222
|
+
escapeToml(value) {
|
|
223
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.CodexFormat = CodexFormat;
|
|
227
|
+
// Format registry
|
|
228
|
+
exports.IDE_FORMATS = {
|
|
229
|
+
standard: new StandardFormat(),
|
|
230
|
+
kiro: new KiroFormat(),
|
|
231
|
+
vscode: new VSCodeFormat(),
|
|
232
|
+
claude: new ClaudeFormat(),
|
|
233
|
+
'claude-code': new ClaudeCodeFormat(),
|
|
234
|
+
windsurf: new WindsurfFormat(),
|
|
235
|
+
codex: new CodexFormat()
|
|
236
|
+
};
|
|
237
|
+
function getIDEFormat(configType) {
|
|
238
|
+
const format = exports.IDE_FORMATS[configType];
|
|
239
|
+
if (!format) {
|
|
240
|
+
throw new Error(`Unsupported IDE format: ${configType}`);
|
|
241
|
+
}
|
|
242
|
+
return format;
|
|
243
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// MCP Server Builder - builds logical server structure (format-agnostic)
|
|
3
|
+
// Uses the centralized registry for all server definitions
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.MCPServerBuilder = void 0;
|
|
6
|
+
const mcp_server_registry_1 = require("./mcp-server-registry");
|
|
7
|
+
class MCPServerBuilder {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.servers = new Map();
|
|
10
|
+
}
|
|
11
|
+
addBaseServers(fraimKey) {
|
|
12
|
+
const baseServers = (0, mcp_server_registry_1.buildAllBaseServers)(fraimKey);
|
|
13
|
+
for (const [id, server] of baseServers) {
|
|
14
|
+
this.servers.set(id, server);
|
|
15
|
+
}
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
async addProvider(providerId, token, config) {
|
|
19
|
+
try {
|
|
20
|
+
const server = await (0, mcp_server_registry_1.buildProviderMCPServer)(providerId, token, config);
|
|
21
|
+
this.servers.set(providerId, server);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
// Always warn user when MCP server can't be built
|
|
25
|
+
// Common case: Jira without baseUrl/email config
|
|
26
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
27
|
+
console.warn(`⚠️ Skipping ${providerId} MCP server: ${errorMessage}`);
|
|
28
|
+
}
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
// Legacy methods for backward compatibility - delegate to addProvider
|
|
32
|
+
async addGitHub(token) {
|
|
33
|
+
return await this.addProvider('github', token);
|
|
34
|
+
}
|
|
35
|
+
async addGitLab(token) {
|
|
36
|
+
return await this.addProvider('gitlab', token);
|
|
37
|
+
}
|
|
38
|
+
async addJira(token, config) {
|
|
39
|
+
return await this.addProvider('jira', token, config);
|
|
40
|
+
}
|
|
41
|
+
getServers() {
|
|
42
|
+
return new Map(this.servers);
|
|
43
|
+
}
|
|
44
|
+
toObject() {
|
|
45
|
+
return Object.fromEntries(this.servers);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.MCPServerBuilder = MCPServerBuilder;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// MCP Server Registry - Builds MCP servers from provider definitions
|
|
3
|
+
// This file NO LONGER contains hardcoded server configurations
|
|
4
|
+
// All provider MCP server configs come from the provider registry (server or local fallback)
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BASE_MCP_SERVERS = void 0;
|
|
7
|
+
exports.buildProviderMCPServer = buildProviderMCPServer;
|
|
8
|
+
exports.getBaseMCPServer = getBaseMCPServer;
|
|
9
|
+
exports.getProviderMCPServerIds = getProviderMCPServerIds;
|
|
10
|
+
exports.getAllMCPServerIds = getAllMCPServerIds;
|
|
11
|
+
exports.isProviderServer = isProviderServer;
|
|
12
|
+
exports.isHTTPServer = isHTTPServer;
|
|
13
|
+
exports.buildAllBaseServers = buildAllBaseServers;
|
|
14
|
+
const provider_registry_1 = require("../providers/provider-registry");
|
|
15
|
+
exports.BASE_MCP_SERVERS = [
|
|
16
|
+
{
|
|
17
|
+
id: 'git',
|
|
18
|
+
name: 'Git',
|
|
19
|
+
description: 'Git repository operations (commit, branch, merge, etc.)',
|
|
20
|
+
buildServer: () => ({
|
|
21
|
+
command: 'npx',
|
|
22
|
+
args: ['-y', '@cyanheads/git-mcp-server']
|
|
23
|
+
})
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'playwright',
|
|
27
|
+
name: 'Playwright',
|
|
28
|
+
description: 'Browser automation and testing',
|
|
29
|
+
buildServer: () => ({
|
|
30
|
+
command: 'npx',
|
|
31
|
+
args: ['-y', '@playwright/mcp']
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'fraim',
|
|
36
|
+
name: 'FRAIM',
|
|
37
|
+
description: 'FRAIM workflow orchestration and mentoring',
|
|
38
|
+
buildServer: (fraimKey) => ({
|
|
39
|
+
command: 'fraim-mcp',
|
|
40
|
+
env: {
|
|
41
|
+
FRAIM_API_KEY: fraimKey,
|
|
42
|
+
FRAIM_REMOTE_URL: 'https://fraim.wellnessatwork.me'
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// PROVIDER MCP SERVER BUILDER (uses provider registry)
|
|
49
|
+
// ============================================================================
|
|
50
|
+
/**
|
|
51
|
+
* Build an MCP server for a provider using its definition from the registry
|
|
52
|
+
*/
|
|
53
|
+
async function buildProviderMCPServer(providerId, token, config) {
|
|
54
|
+
// Get provider definition from registry (server or local fallback)
|
|
55
|
+
const provider = await (0, provider_registry_1.getProvider)(providerId);
|
|
56
|
+
if (!provider) {
|
|
57
|
+
throw new Error(`Unknown provider: ${providerId}`);
|
|
58
|
+
}
|
|
59
|
+
if (!provider.mcpServer) {
|
|
60
|
+
throw new Error(`Provider ${providerId} does not have an MCP server configuration`);
|
|
61
|
+
}
|
|
62
|
+
const mcpConfig = provider.mcpServer;
|
|
63
|
+
// Validate config if provider requires additional config
|
|
64
|
+
if (provider.hasAdditionalConfig) {
|
|
65
|
+
const validation = await (0, provider_registry_1.validateProviderConfig)(providerId, config || {});
|
|
66
|
+
if (!validation.valid) {
|
|
67
|
+
throw new Error(`${provider.displayName} requires additional configuration: ${validation.missing.join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Build MCP server based on type
|
|
71
|
+
if (mcpConfig.type === 'http') {
|
|
72
|
+
return buildHTTPServer(mcpConfig, token);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return buildStdioServer(mcpConfig, token, config);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build an HTTP MCP server
|
|
80
|
+
*/
|
|
81
|
+
function buildHTTPServer(mcpConfig, token) {
|
|
82
|
+
if (!mcpConfig.url) {
|
|
83
|
+
throw new Error('HTTP MCP server requires url');
|
|
84
|
+
}
|
|
85
|
+
const authHeader = mcpConfig.authHeaderTemplate?.replace('{token}', token) || `Bearer ${token}`;
|
|
86
|
+
return {
|
|
87
|
+
url: mcpConfig.url,
|
|
88
|
+
headers: {
|
|
89
|
+
Authorization: authHeader
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build a stdio MCP server
|
|
95
|
+
*/
|
|
96
|
+
function buildStdioServer(mcpConfig, token, config) {
|
|
97
|
+
if (!mcpConfig.command) {
|
|
98
|
+
throw new Error('Stdio MCP server requires command');
|
|
99
|
+
}
|
|
100
|
+
// Build environment variables from template
|
|
101
|
+
const env = {};
|
|
102
|
+
if (mcpConfig.envTemplate) {
|
|
103
|
+
for (const [key, template] of Object.entries(mcpConfig.envTemplate)) {
|
|
104
|
+
let value = template;
|
|
105
|
+
// Replace {token} placeholder
|
|
106
|
+
value = value.replace('{token}', token);
|
|
107
|
+
// Replace {config.key} placeholders
|
|
108
|
+
if (config) {
|
|
109
|
+
for (const [configKey, configValue] of Object.entries(config)) {
|
|
110
|
+
value = value.replace(`{config.${configKey}}`, String(configValue));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Handle URL normalization for Jira
|
|
114
|
+
if (key === 'JIRA_URL' && value && !value.startsWith('http')) {
|
|
115
|
+
value = `https://${value}`;
|
|
116
|
+
}
|
|
117
|
+
env[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
command: mcpConfig.command,
|
|
122
|
+
args: mcpConfig.args || [],
|
|
123
|
+
env
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// REGISTRY LOOKUP FUNCTIONS
|
|
128
|
+
// ============================================================================
|
|
129
|
+
function getBaseMCPServer(id) {
|
|
130
|
+
return exports.BASE_MCP_SERVERS.find(server => server.id === id);
|
|
131
|
+
}
|
|
132
|
+
async function getProviderMCPServerIds() {
|
|
133
|
+
// This would need to fetch all providers and filter those with MCP servers
|
|
134
|
+
// For now, return empty array - this function is not critical
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
function getAllMCPServerIds() {
|
|
138
|
+
// Return only base server IDs
|
|
139
|
+
// Provider server IDs are dynamic and come from the registry
|
|
140
|
+
return exports.BASE_MCP_SERVERS.map(s => s.id);
|
|
141
|
+
}
|
|
142
|
+
async function isProviderServer(serverId) {
|
|
143
|
+
const provider = await (0, provider_registry_1.getProvider)(serverId);
|
|
144
|
+
return provider !== undefined && provider.mcpServer !== undefined;
|
|
145
|
+
}
|
|
146
|
+
async function isHTTPServer(serverId) {
|
|
147
|
+
const provider = await (0, provider_registry_1.getProvider)(serverId);
|
|
148
|
+
return provider?.mcpServer?.type === 'http';
|
|
149
|
+
}
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// BUILDER HELPERS
|
|
152
|
+
// ============================================================================
|
|
153
|
+
function buildAllBaseServers(fraimKey) {
|
|
154
|
+
const servers = new Map();
|
|
155
|
+
for (const def of exports.BASE_MCP_SERVERS) {
|
|
156
|
+
servers.set(def.id, def.buildServer(fraimKey));
|
|
157
|
+
}
|
|
158
|
+
return servers;
|
|
159
|
+
}
|