fraim 2.0.176 → 2.0.179
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/ai-hub/server.js +50 -1
- package/dist/src/cli/commands/add-provider.js +74 -61
- package/dist/src/cli/commands/add-surface.js +128 -0
- package/dist/src/cli/commands/first-run.js +3 -5
- package/dist/src/cli/commands/login.js +5 -69
- package/dist/src/cli/commands/setup.js +27 -347
- package/dist/src/cli/distribution/marketplace-bundles.js +576 -0
- package/dist/src/cli/fraim.js +2 -0
- package/dist/src/cli/mcp/ide-formats.js +5 -3
- package/dist/src/cli/mcp/mcp-server-registry.js +10 -3
- package/dist/src/cli/providers/local-provider-registry.js +2 -3
- package/dist/src/cli/setup/auto-mcp-setup.js +9 -32
- package/dist/src/cli/setup/ide-detector.js +65 -12
- package/dist/src/config/persona-capability-bundles.js +17 -13
- package/dist/src/first-run/install-state.js +1 -0
- package/dist/src/first-run/server.js +13 -0
- package/dist/src/first-run/session-service.js +22 -3
- package/dist/src/local-mcp-server/stdio-server.js +28 -4
- package/dist/src/local-mcp-server/usage-collector.js +24 -0
- package/package.json +5 -2
- package/public/ai-hub/index.html +14 -2
- package/public/ai-hub/script.js +340 -66
- package/public/ai-hub/styles.css +83 -0
- package/public/first-run/script.js +64 -0
- package/public/first-run/styles.css +14 -0
|
@@ -44,8 +44,6 @@ const prompts_1 = __importDefault(require("prompts"));
|
|
|
44
44
|
const fs_1 = __importDefault(require("fs"));
|
|
45
45
|
const path_1 = __importDefault(require("path"));
|
|
46
46
|
const auto_mcp_setup_1 = require("../setup/auto-mcp-setup");
|
|
47
|
-
const provider_client_1 = require("../api/provider-client");
|
|
48
|
-
const provider_prompts_1 = require("../setup/provider-prompts");
|
|
49
47
|
const provider_registry_1 = require("../providers/provider-registry");
|
|
50
48
|
const script_sync_utils_1 = require("../utils/script-sync-utils");
|
|
51
49
|
function parseModeOption(mode) {
|
|
@@ -170,67 +168,15 @@ const promptForMode = async () => {
|
|
|
170
168
|
}
|
|
171
169
|
return response.mode;
|
|
172
170
|
};
|
|
173
|
-
|
|
174
|
-
* Sanitize a token by removing control characters that cause JSON serialization issues
|
|
175
|
-
*/
|
|
176
|
-
const sanitizeToken = (token) => {
|
|
177
|
-
if (!token)
|
|
178
|
-
return token;
|
|
179
|
-
// Remove control characters (0x00-0x1F and 0x7F) that cause JSON escaping issues
|
|
180
|
-
// These characters are not valid in API tokens and are likely copy-paste artifacts
|
|
181
|
-
return token.replace(/[\x00-\x1F\x7F]/g, '');
|
|
182
|
-
};
|
|
183
|
-
/**
|
|
184
|
-
* Sanitize all tokens in a ProviderTokens object
|
|
185
|
-
*/
|
|
186
|
-
const sanitizeTokens = (tokens) => {
|
|
187
|
-
const sanitized = {};
|
|
188
|
-
Object.entries(tokens).forEach(([providerId, token]) => {
|
|
189
|
-
if (token) {
|
|
190
|
-
const originalToken = token;
|
|
191
|
-
const sanitizedToken = sanitizeToken(token);
|
|
192
|
-
if (originalToken !== sanitizedToken) {
|
|
193
|
-
console.log(chalk_1.default.yellow(`⚠️ Sanitized ${providerId} token: removed ${originalToken.length - sanitizedToken.length} control character(s)`));
|
|
194
|
-
}
|
|
195
|
-
sanitized[providerId] = sanitizedToken;
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
return sanitized;
|
|
199
|
-
};
|
|
200
|
-
const saveGlobalConfig = (fraimKey, mode, tokens, configs) => {
|
|
171
|
+
const saveGlobalConfig = (fraimKey, mode) => {
|
|
201
172
|
const globalConfigDir = (0, script_sync_utils_1.getUserFraimDir)();
|
|
202
173
|
const globalConfigPath = path_1.default.join(globalConfigDir, 'config.json');
|
|
203
174
|
if (!fs_1.default.existsSync(globalConfigDir)) {
|
|
204
175
|
fs_1.default.mkdirSync(globalConfigDir, { recursive: true });
|
|
205
176
|
}
|
|
206
|
-
// Read existing config to preserve any existing data
|
|
207
|
-
let existingConfig = {};
|
|
208
|
-
if (fs_1.default.existsSync(globalConfigPath)) {
|
|
209
|
-
try {
|
|
210
|
-
existingConfig = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
|
|
211
|
-
}
|
|
212
|
-
catch (e) {
|
|
213
|
-
// Ignore parse errors, will create new config
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
// Sanitize tokens before saving to prevent JSON serialization issues
|
|
217
|
-
const sanitizedTokens = sanitizeTokens(tokens);
|
|
218
|
-
// Merge provider configs (e.g., jiraConfig)
|
|
219
|
-
const providerConfigs = { ...(existingConfig.providerConfigs || {}) };
|
|
220
|
-
Object.entries(configs).forEach(([providerId, config]) => {
|
|
221
|
-
providerConfigs[`${providerId}Config`] = {
|
|
222
|
-
...(providerConfigs[`${providerId}Config`] || {}),
|
|
223
|
-
...config
|
|
224
|
-
};
|
|
225
|
-
});
|
|
226
177
|
const config = {
|
|
227
178
|
apiKey: fraimKey,
|
|
228
179
|
mode: mode,
|
|
229
|
-
tokens: {
|
|
230
|
-
...(existingConfig.tokens || {}),
|
|
231
|
-
...sanitizedTokens
|
|
232
|
-
},
|
|
233
|
-
providerConfigs,
|
|
234
180
|
configuredAt: new Date().toISOString(),
|
|
235
181
|
userPreferences: {
|
|
236
182
|
autoSync: true,
|
|
@@ -241,49 +187,6 @@ const saveGlobalConfig = (fraimKey, mode, tokens, configs) => {
|
|
|
241
187
|
console.log(chalk_1.default.green('✅ Global FRAIM configuration saved'));
|
|
242
188
|
};
|
|
243
189
|
exports.saveGlobalConfig = saveGlobalConfig;
|
|
244
|
-
// Parse CLI options into generic format using provider registry from server
|
|
245
|
-
// Tokens/config are optional - will prompt if not provided
|
|
246
|
-
const parseLegacyOptions = async (options, fraimKey) => {
|
|
247
|
-
const requestedProviders = [];
|
|
248
|
-
const providedTokens = {};
|
|
249
|
-
const providedConfigs = {};
|
|
250
|
-
// Use provider registry (with fallback) instead of direct client call
|
|
251
|
-
const { getAllProviderIds, getProviderConfigRequirements } = await Promise.resolve().then(() => __importStar(require('../providers/provider-registry')));
|
|
252
|
-
const providerIds = await getAllProviderIds();
|
|
253
|
-
// Dynamically check for provider flags from server registry
|
|
254
|
-
for (const providerId of providerIds) {
|
|
255
|
-
// Check for provider flag (e.g., --github)
|
|
256
|
-
if (options[providerId]) {
|
|
257
|
-
requestedProviders.push(providerId);
|
|
258
|
-
}
|
|
259
|
-
// Check for token option (e.g., --github-token)
|
|
260
|
-
const tokenKey = `${providerId}Token`;
|
|
261
|
-
if (options[tokenKey]) {
|
|
262
|
-
providedTokens[providerId] = options[tokenKey];
|
|
263
|
-
}
|
|
264
|
-
// Check for provider-specific config options
|
|
265
|
-
const configReqs = await getProviderConfigRequirements(providerId);
|
|
266
|
-
if (configReqs.length > 0) {
|
|
267
|
-
const config = {};
|
|
268
|
-
let hasAnyConfig = false;
|
|
269
|
-
configReqs.forEach(req => {
|
|
270
|
-
// Use custom CLI option name if provided, otherwise convert key to camelCase
|
|
271
|
-
const optionSuffix = req.cliOptionName
|
|
272
|
-
? req.cliOptionName.charAt(0).toUpperCase() + req.cliOptionName.slice(1)
|
|
273
|
-
: req.key.charAt(0).toUpperCase() + req.key.slice(1);
|
|
274
|
-
const optionKey = `${providerId}${optionSuffix}`;
|
|
275
|
-
if (options[optionKey]) {
|
|
276
|
-
config[req.key] = options[optionKey];
|
|
277
|
-
hasAnyConfig = true;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
if (hasAnyConfig) {
|
|
281
|
-
providedConfigs[providerId] = config;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return { requestedProviders, providedTokens, providedConfigs };
|
|
286
|
-
};
|
|
287
190
|
const runSetup = async (options) => {
|
|
288
191
|
console.log(chalk_1.default.blue('🚀 Welcome to FRAIM! Let\'s get you set up.\n'));
|
|
289
192
|
// Determine if this is an update (adding platforms to existing setup)
|
|
@@ -291,54 +194,27 @@ const runSetup = async (options) => {
|
|
|
291
194
|
const isUpdate = fs_1.default.existsSync(globalConfigPath);
|
|
292
195
|
let fraimKey;
|
|
293
196
|
let mode;
|
|
294
|
-
const tokens = {};
|
|
295
|
-
const configs = {};
|
|
296
|
-
let requestedProviders = [];
|
|
297
|
-
let providedTokens = {};
|
|
298
|
-
let providedConfigs = {};
|
|
299
197
|
if (isUpdate) {
|
|
300
|
-
// Update existing setup - add platforms
|
|
301
198
|
console.log(chalk_1.default.blue('📝 Existing FRAIM configuration detected.\n'));
|
|
302
199
|
try {
|
|
303
200
|
const existingConfig = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
|
|
304
|
-
// Allow updating FRAIM key even without provider changes
|
|
305
201
|
fraimKey = options.key || existingConfig.apiKey;
|
|
306
|
-
|
|
307
|
-
const parsed = await parseLegacyOptions(options, fraimKey);
|
|
308
|
-
requestedProviders = parsed.requestedProviders;
|
|
309
|
-
providedTokens = parsed.providedTokens;
|
|
310
|
-
providedConfigs = parsed.providedConfigs;
|
|
311
|
-
// Check if this is just a key update or a provider update
|
|
202
|
+
mode = existingConfig.mode || 'integrated';
|
|
312
203
|
const isKeyUpdate = options.key && options.key !== existingConfig.apiKey;
|
|
313
|
-
|
|
314
|
-
// If no specific changes requested, offer interactive update
|
|
315
|
-
if (!isKeyUpdate && !isProviderUpdate) {
|
|
204
|
+
if (!isKeyUpdate) {
|
|
316
205
|
console.log(chalk_1.default.gray(' Current configuration:'));
|
|
317
|
-
console.log(chalk_1.default.gray(` • Mode: ${
|
|
318
|
-
|
|
319
|
-
const { getProvider } = await Promise.resolve().then(() => __importStar(require('../providers/provider-registry')));
|
|
320
|
-
if (existingConfig.tokens && Object.keys(existingConfig.tokens).length > 0) {
|
|
321
|
-
const providerNames = await Promise.all(Object.keys(existingConfig.tokens).map(async (id) => {
|
|
322
|
-
const provider = await getProvider(id);
|
|
323
|
-
return provider?.displayName || id;
|
|
324
|
-
}));
|
|
325
|
-
console.log(chalk_1.default.gray(` • Providers: ${providerNames.join(', ')}`));
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
console.log(chalk_1.default.gray(' • Providers: none'));
|
|
329
|
-
}
|
|
206
|
+
console.log(chalk_1.default.gray(` • Mode: ${mode}`));
|
|
207
|
+
console.log(chalk_1.default.gray(' • Platforms: managed per-project via fraim add-provider'));
|
|
330
208
|
console.log();
|
|
331
|
-
|
|
209
|
+
if (process.env.FRAIM_NON_INTERACTIVE || process.env.CI) {
|
|
210
|
+
console.log(chalk_1.default.gray('Setup already configured. Use "fraim add-provider <provider>" to connect platforms.'));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
332
213
|
const response = await (0, prompts_1.default)({
|
|
333
214
|
type: 'select',
|
|
334
215
|
name: 'action',
|
|
335
216
|
message: 'What would you like to do?',
|
|
336
217
|
choices: [
|
|
337
|
-
{
|
|
338
|
-
title: 'Add a provider',
|
|
339
|
-
value: 'add-provider',
|
|
340
|
-
description: 'Add a new platform integration (GitHub, GitLab, etc.)'
|
|
341
|
-
},
|
|
342
218
|
{
|
|
343
219
|
title: 'Update FRAIM key',
|
|
344
220
|
value: 'update-key',
|
|
@@ -361,104 +237,27 @@ const runSetup = async (options) => {
|
|
|
361
237
|
console.log(chalk_1.default.gray('\nSetup cancelled. No changes made.'));
|
|
362
238
|
return;
|
|
363
239
|
}
|
|
364
|
-
if (response.action === '
|
|
365
|
-
console.log(chalk_1.default.blue('\n📦 Adding a provider...\n'));
|
|
366
|
-
const providerClient = new provider_client_1.ProviderClient(fraimKey, process.env.FRAIM_REMOTE_URL || undefined);
|
|
367
|
-
// Prompt for which provider to add
|
|
368
|
-
const providersToAdd = await (0, provider_prompts_1.promptForProviders)(providerClient);
|
|
369
|
-
requestedProviders = providersToAdd;
|
|
370
|
-
}
|
|
371
|
-
else if (response.action === 'update-key') {
|
|
240
|
+
if (response.action === 'update-key') {
|
|
372
241
|
console.log(chalk_1.default.blue('\n🔑 Updating FRAIM key...\n'));
|
|
373
242
|
fraimKey = await promptForFraimKey();
|
|
374
243
|
}
|
|
375
244
|
else if (response.action === 'reconfigure') {
|
|
376
245
|
console.log(chalk_1.default.blue('\n🔄 Starting fresh setup...\n'));
|
|
377
|
-
// Backup existing config
|
|
378
246
|
const backupPath = globalConfigPath + '.backup.' + Date.now();
|
|
379
247
|
fs_1.default.copyFileSync(globalConfigPath, backupPath);
|
|
380
248
|
console.log(chalk_1.default.gray(` Backed up existing config to: ${path_1.default.basename(backupPath)}\n`));
|
|
381
|
-
// Treat as fresh setup
|
|
382
249
|
fraimKey = options.key || await promptForFraimKey();
|
|
383
250
|
console.log(chalk_1.default.green('✅ FRAIM key accepted\n'));
|
|
384
251
|
mode = options.mode ? parseModeOption(options.mode) : await promptForMode();
|
|
385
|
-
const parsed = await parseLegacyOptions(options, fraimKey);
|
|
386
|
-
requestedProviders = parsed.requestedProviders;
|
|
387
|
-
providedTokens = parsed.providedTokens;
|
|
388
|
-
providedConfigs = parsed.providedConfigs;
|
|
389
|
-
// Clear existing tokens/configs for fresh start
|
|
390
|
-
Object.keys(tokens).forEach(key => delete tokens[key]);
|
|
391
|
-
Object.keys(configs).forEach(key => delete configs[key]);
|
|
392
|
-
// Continue with fresh setup flow
|
|
393
|
-
const providerClient = new provider_client_1.ProviderClient(fraimKey, process.env.FRAIM_REMOTE_URL || undefined);
|
|
394
|
-
if (mode === 'integrated') {
|
|
395
|
-
let providersToSetup = requestedProviders;
|
|
396
|
-
if (providersToSetup.length === 0) {
|
|
397
|
-
providersToSetup = await (0, provider_prompts_1.promptForProviders)(providerClient);
|
|
398
|
-
}
|
|
399
|
-
for (const providerId of providersToSetup) {
|
|
400
|
-
try {
|
|
401
|
-
const creds = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, providerId, providedTokens[providerId], providedConfigs[providerId]);
|
|
402
|
-
tokens[providerId] = creds.token;
|
|
403
|
-
if (creds.config) {
|
|
404
|
-
configs[providerId] = creds.config;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
catch (e) {
|
|
408
|
-
const providerName = await (0, provider_registry_1.getProviderDisplayName)(providerId);
|
|
409
|
-
console.log(chalk_1.default.red(`❌ Failed to get ${providerName} credentials`));
|
|
410
|
-
process.exit(1);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
else if (mode === 'split') {
|
|
415
|
-
// Split mode setup
|
|
416
|
-
console.log(chalk_1.default.blue('\n🔀 Split Mode Configuration'));
|
|
417
|
-
console.log(chalk_1.default.gray('Configure separate platforms for code hosting and issue tracking.\n'));
|
|
418
|
-
const codeRepoProvider = await (0, provider_prompts_1.promptForSingleProvider)(providerClient, 'code');
|
|
419
|
-
const creds1 = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, codeRepoProvider, providedTokens[codeRepoProvider], providedConfigs[codeRepoProvider]);
|
|
420
|
-
tokens[codeRepoProvider] = creds1.token;
|
|
421
|
-
if (creds1.config) {
|
|
422
|
-
configs[codeRepoProvider] = creds1.config;
|
|
423
|
-
}
|
|
424
|
-
const issueProvider = await (0, provider_prompts_1.promptForSingleProvider)(providerClient, 'issues');
|
|
425
|
-
if (!tokens[issueProvider]) {
|
|
426
|
-
const creds2 = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, issueProvider, providedTokens[issueProvider], providedConfigs[issueProvider]);
|
|
427
|
-
tokens[issueProvider] = creds2.token;
|
|
428
|
-
if (creds2.config) {
|
|
429
|
-
configs[issueProvider] = creds2.config;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
// Save and configure MCP
|
|
434
252
|
console.log(chalk_1.default.blue('\n💾 Saving global configuration...'));
|
|
435
|
-
(0, exports.saveGlobalConfig)(fraimKey, mode
|
|
253
|
+
(0, exports.saveGlobalConfig)(fraimKey, mode);
|
|
436
254
|
console.log(chalk_1.default.blue('\n🔌 Configuring MCP servers...'));
|
|
437
|
-
|
|
438
|
-
Object.entries(tokens).forEach(([id, token]) => {
|
|
439
|
-
mcpTokens[id] = token;
|
|
440
|
-
});
|
|
441
|
-
const providerConfigsMap = {};
|
|
442
|
-
Object.entries(configs).forEach(([providerId, config]) => {
|
|
443
|
-
providerConfigsMap[providerId] = config;
|
|
444
|
-
});
|
|
445
|
-
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey, mcpTokens, options.ide ? [options.ide] : undefined, providerConfigsMap);
|
|
255
|
+
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey, options.ide ? [options.ide] : undefined);
|
|
446
256
|
console.log(chalk_1.default.green('\n🎯 Reconfiguration complete!'));
|
|
257
|
+
console.log(chalk_1.default.cyan('\n💡 To connect platforms, run: fraim add-provider <github|gitlab|ado|jira>'));
|
|
447
258
|
return;
|
|
448
259
|
}
|
|
449
260
|
}
|
|
450
|
-
mode = existingConfig.mode || 'integrated';
|
|
451
|
-
// Preserve existing tokens
|
|
452
|
-
if (existingConfig.tokens) {
|
|
453
|
-
Object.assign(tokens, existingConfig.tokens);
|
|
454
|
-
}
|
|
455
|
-
// Preserve existing configs
|
|
456
|
-
if (existingConfig.providerConfigs) {
|
|
457
|
-
Object.entries(existingConfig.providerConfigs).forEach(([key, value]) => {
|
|
458
|
-
const providerId = key.replace('Config', '');
|
|
459
|
-
configs[providerId] = value;
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
261
|
}
|
|
463
262
|
catch (e) {
|
|
464
263
|
console.log(chalk_1.default.red('❌ Failed to read existing configuration'));
|
|
@@ -467,129 +266,29 @@ const runSetup = async (options) => {
|
|
|
467
266
|
}
|
|
468
267
|
}
|
|
469
268
|
else {
|
|
470
|
-
// Initial setup
|
|
471
269
|
console.log(chalk_1.default.yellow('📋 This setup will:'));
|
|
472
270
|
console.log(chalk_1.default.gray(' • Validate your FRAIM key'));
|
|
473
271
|
console.log(chalk_1.default.gray(' • Choose your usage mode'));
|
|
474
|
-
console.log(chalk_1.default.gray(' • Configure
|
|
272
|
+
console.log(chalk_1.default.gray(' • Configure FRAIM MCP servers in your IDEs'));
|
|
475
273
|
console.log(chalk_1.default.gray(' • Sync FRAIM scripts to your system\n'));
|
|
476
|
-
|
|
274
|
+
console.log(chalk_1.default.gray(' Platforms (GitHub, GitLab, etc.) are connected per-project'));
|
|
275
|
+
console.log(chalk_1.default.gray(' via "fraim add-provider" — no tokens needed here.\n'));
|
|
477
276
|
fraimKey = options.key || await promptForFraimKey();
|
|
478
277
|
console.log(chalk_1.default.green('✅ FRAIM key accepted\n'));
|
|
479
|
-
// Ask for mode preference (or use explicit option)
|
|
480
278
|
mode = options.mode ? parseModeOption(options.mode) : await promptForMode();
|
|
481
|
-
// Parse provider CLI flags on first-time setup too
|
|
482
|
-
const parsed = await parseLegacyOptions(options, fraimKey);
|
|
483
|
-
requestedProviders = parsed.requestedProviders;
|
|
484
|
-
providedTokens = parsed.providedTokens;
|
|
485
|
-
providedConfigs = parsed.providedConfigs;
|
|
486
|
-
}
|
|
487
|
-
const providerClient = new provider_client_1.ProviderClient(fraimKey, process.env.FRAIM_REMOTE_URL || undefined);
|
|
488
|
-
// Handle platform tokens based on mode
|
|
489
|
-
if (mode === 'integrated') {
|
|
490
|
-
let providersToSetup = requestedProviders;
|
|
491
|
-
// If no specific providers requested and not an update, ask user
|
|
492
|
-
if (!isUpdate && providersToSetup.length === 0) {
|
|
493
|
-
providersToSetup = await (0, provider_prompts_1.promptForProviders)(providerClient);
|
|
494
|
-
}
|
|
495
|
-
// Get credentials for each provider
|
|
496
|
-
for (const providerId of providersToSetup) {
|
|
497
|
-
if (!tokens[providerId]) {
|
|
498
|
-
try {
|
|
499
|
-
// Use provided tokens if available, otherwise prompt
|
|
500
|
-
const creds = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, providerId, providedTokens[providerId], providedConfigs[providerId]);
|
|
501
|
-
tokens[providerId] = creds.token;
|
|
502
|
-
if (creds.config) {
|
|
503
|
-
configs[providerId] = creds.config;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
catch (e) {
|
|
507
|
-
const providerName = await (0, provider_registry_1.getProviderDisplayName)(providerId);
|
|
508
|
-
console.log(chalk_1.default.red(`❌ Failed to get ${providerName} credentials`));
|
|
509
|
-
process.exit(1);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (Object.keys(tokens).length === 0) {
|
|
514
|
-
console.log(chalk_1.default.yellow('⚠️ No platform tokens configured.'));
|
|
515
|
-
console.log(chalk_1.default.gray(' You can add them later with:'));
|
|
516
|
-
const allProviderIds = await (0, provider_registry_1.getAllProviderIds)();
|
|
517
|
-
allProviderIds.forEach(id => {
|
|
518
|
-
console.log(chalk_1.default.cyan(` fraim setup --${id}`));
|
|
519
|
-
});
|
|
520
|
-
console.log();
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
else if (mode === 'split') {
|
|
524
|
-
// Split mode: separate platforms for code repository and issue tracking
|
|
525
|
-
console.log(chalk_1.default.blue('\n🔀 Split Mode Configuration'));
|
|
526
|
-
console.log(chalk_1.default.gray('Configure separate platforms for code hosting and issue tracking.\n'));
|
|
527
|
-
// Get code repository platform
|
|
528
|
-
const codeRepoProvider = await (0, provider_prompts_1.promptForSingleProvider)(providerClient, 'code');
|
|
529
|
-
// Get code repository credentials
|
|
530
|
-
if (!tokens[codeRepoProvider]) {
|
|
531
|
-
try {
|
|
532
|
-
// Use provided tokens if available, otherwise prompt
|
|
533
|
-
const creds = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, codeRepoProvider, providedTokens[codeRepoProvider], providedConfigs[codeRepoProvider]);
|
|
534
|
-
tokens[codeRepoProvider] = creds.token;
|
|
535
|
-
if (creds.config) {
|
|
536
|
-
configs[codeRepoProvider] = creds.config;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
catch (e) {
|
|
540
|
-
const providerName = await (0, provider_registry_1.getProviderDisplayName)(codeRepoProvider);
|
|
541
|
-
console.log(chalk_1.default.red(`❌ Failed to get ${providerName} credentials`));
|
|
542
|
-
process.exit(1);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
// Get issue tracking platform
|
|
546
|
-
const issueProvider = await (0, provider_prompts_1.promptForSingleProvider)(providerClient, 'issues');
|
|
547
|
-
// Get issue tracking credentials (if different from code repo)
|
|
548
|
-
if (!tokens[issueProvider]) {
|
|
549
|
-
try {
|
|
550
|
-
// Use provided tokens if available, otherwise prompt
|
|
551
|
-
const creds = await (0, provider_prompts_1.promptForProviderCredentials)(providerClient, issueProvider, providedTokens[issueProvider], providedConfigs[issueProvider]);
|
|
552
|
-
tokens[issueProvider] = creds.token;
|
|
553
|
-
if (creds.config) {
|
|
554
|
-
configs[issueProvider] = creds.config;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
catch (e) {
|
|
558
|
-
const providerName = await (0, provider_registry_1.getProviderDisplayName)(issueProvider);
|
|
559
|
-
console.log(chalk_1.default.red(`❌ Failed to get ${providerName} credentials`));
|
|
560
|
-
process.exit(1);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
const codeRepoName = await (0, provider_registry_1.getProviderDisplayName)(codeRepoProvider);
|
|
564
|
-
const issueName = await (0, provider_registry_1.getProviderDisplayName)(issueProvider);
|
|
565
|
-
console.log(chalk_1.default.green(`\n✅ Split mode configured: ${codeRepoName} (code) + ${issueName} (issues)\n`));
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
console.log(chalk_1.default.gray('ℹ️ Conversational mode: No platform tokens needed\n'));
|
|
569
279
|
}
|
|
570
|
-
// Save global configuration
|
|
280
|
+
// Save global configuration (key + mode only; provider tokens live in IDE MCP configs)
|
|
571
281
|
console.log(chalk_1.default.blue('💾 Saving global configuration...'));
|
|
572
|
-
(0, exports.saveGlobalConfig)(fraimKey, mode
|
|
282
|
+
(0, exports.saveGlobalConfig)(fraimKey, mode);
|
|
573
283
|
// Configure MCP servers
|
|
574
284
|
if (!isUpdate) {
|
|
575
|
-
// Initial setup - configure all detected IDEs
|
|
576
285
|
console.log(chalk_1.default.blue('\n🔌 Configuring MCP servers...'));
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
mcpTokens[id] = token;
|
|
581
|
-
});
|
|
582
|
-
if (mode === 'conversational' && Object.keys(mcpTokens).length === 0) {
|
|
583
|
-
console.log(chalk_1.default.yellow('ℹ️ Conversational mode: Configuring MCP servers without platform integration'));
|
|
584
|
-
console.log(chalk_1.default.gray(' FRAIM jobs will work, but platform-specific features will be unavailable\n'));
|
|
286
|
+
if (mode === 'conversational') {
|
|
287
|
+
console.log(chalk_1.default.yellow('ℹ️ Conversational mode: Configuring FRAIM MCP server'));
|
|
288
|
+
console.log(chalk_1.default.gray(' FRAIM jobs will work; platform-specific features are added via fraim add-provider\n'));
|
|
585
289
|
}
|
|
586
290
|
try {
|
|
587
|
-
|
|
588
|
-
const providerConfigsMap = {};
|
|
589
|
-
Object.entries(configs).forEach(([providerId, config]) => {
|
|
590
|
-
providerConfigsMap[providerId] = config;
|
|
591
|
-
});
|
|
592
|
-
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey, mcpTokens, options.ide ? [options.ide] : undefined, providerConfigsMap);
|
|
291
|
+
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey, options.ide ? [options.ide] : undefined);
|
|
593
292
|
}
|
|
594
293
|
catch (e) {
|
|
595
294
|
console.log(chalk_1.default.yellow('⚠️ MCP configuration encountered issues'));
|
|
@@ -597,7 +296,6 @@ const runSetup = async (options) => {
|
|
|
597
296
|
}
|
|
598
297
|
}
|
|
599
298
|
else {
|
|
600
|
-
// Update existing setup - refresh all IDE MCP configs with new keys
|
|
601
299
|
console.log(chalk_1.default.blue('\n🔄 Updating IDE MCP configurations...'));
|
|
602
300
|
try {
|
|
603
301
|
const { detectInstalledIDEs } = await Promise.resolve().then(() => __importStar(require('../setup/ide-detector')));
|
|
@@ -606,18 +304,8 @@ const runSetup = async (options) => {
|
|
|
606
304
|
console.log(chalk_1.default.gray(' No IDE configurations found to update'));
|
|
607
305
|
}
|
|
608
306
|
else {
|
|
609
|
-
// Convert to legacy format for MCP config generator
|
|
610
|
-
const mcpTokens = {};
|
|
611
|
-
Object.entries(tokens).forEach(([id, token]) => {
|
|
612
|
-
mcpTokens[id] = token;
|
|
613
|
-
});
|
|
614
|
-
// Build providerConfigs map from configs
|
|
615
|
-
const providerConfigsMap = {};
|
|
616
|
-
Object.entries(configs).forEach(([providerId, config]) => {
|
|
617
|
-
providerConfigsMap[providerId] = config;
|
|
618
|
-
});
|
|
619
307
|
const ideNames = installedIDEs.map(ide => ide.name);
|
|
620
|
-
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey,
|
|
308
|
+
await (0, auto_mcp_setup_1.autoConfigureMCP)(fraimKey, ideNames);
|
|
621
309
|
console.log(chalk_1.default.green(`✅ Updated MCP configs for: ${ideNames.join(', ')}`));
|
|
622
310
|
}
|
|
623
311
|
}
|
|
@@ -709,18 +397,10 @@ const runSetup = async (options) => {
|
|
|
709
397
|
console.log(chalk_1.default.white(' cd your-project && fraim init-project'));
|
|
710
398
|
console.log(chalk_1.default.gray(' This enables project-specific customizations,'));
|
|
711
399
|
console.log(chalk_1.default.gray(' GitHub workflows, and team learning.'));
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
const allProviderIds = await (0, provider_registry_1.getAllProviderIds)();
|
|
717
|
-
const unconfiguredProviders = allProviderIds.filter(id => !tokens[id]);
|
|
718
|
-
if (unconfiguredProviders.length > 0) {
|
|
719
|
-
console.log(chalk_1.default.gray('\n To add more platforms later:'));
|
|
720
|
-
unconfiguredProviders.forEach(id => {
|
|
721
|
-
console.log(chalk_1.default.gray(` fraim setup --${id}`));
|
|
722
|
-
});
|
|
723
|
-
}
|
|
400
|
+
console.log(chalk_1.default.cyan('\n To connect platforms (GitHub, GitLab, ADO, Jira):'));
|
|
401
|
+
console.log(chalk_1.default.white(' fraim add-provider <provider>'));
|
|
402
|
+
console.log(chalk_1.default.gray(' Provider tokens are stored directly in IDE MCP configs.'));
|
|
403
|
+
console.log(chalk_1.default.gray(' GitHub uses IDE-native OAuth — no token needed.'));
|
|
724
404
|
}
|
|
725
405
|
}
|
|
726
406
|
else {
|