ccraft 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/install.js +7 -1
- package/src/prompts/gather.js +43 -0
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
gatherProjectPath,
|
|
16
16
|
gatherCreateProfile,
|
|
17
|
+
gatherMcpKeys,
|
|
17
18
|
confirmInstallation,
|
|
18
19
|
} from '../prompts/gather.js';
|
|
19
20
|
import { themedInput } from '../ui/prompts.js';
|
|
@@ -401,7 +402,7 @@ export async function runInstall(options = {}) {
|
|
|
401
402
|
|
|
402
403
|
// All MCPs are auto-installed; no interactive selection
|
|
403
404
|
const selectedMcps = mcpConfigs || [];
|
|
404
|
-
|
|
405
|
+
let mcpKeys = {};
|
|
405
406
|
const securityConfig = { addSecurityGitignore: true };
|
|
406
407
|
|
|
407
408
|
// Confirmation gate (skipped in create mode and non-interactive mode)
|
|
@@ -420,6 +421,11 @@ export async function runInstall(options = {}) {
|
|
|
420
421
|
// ================================================================
|
|
421
422
|
renderPhaseHeader(4, phaseOpts);
|
|
422
423
|
|
|
424
|
+
// Prompt for API keys for MCPs that need them
|
|
425
|
+
if (!options.yes) {
|
|
426
|
+
mcpKeys = await gatherMcpKeys(selectedMcps);
|
|
427
|
+
}
|
|
428
|
+
|
|
423
429
|
let results;
|
|
424
430
|
let filesToWrite;
|
|
425
431
|
|
package/src/prompts/gather.js
CHANGED
|
@@ -227,6 +227,49 @@ export async function gatherMcpConfig(scoredMcps) {
|
|
|
227
227
|
return { selectedMcps, mcpKeys };
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
// ── MCP API key collection (standalone) ──────────────────────────────
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Prompt the user for API keys for MCPs that require them.
|
|
234
|
+
* Returns { [mcpId]: { KEY_NAME: 'value' } }.
|
|
235
|
+
*/
|
|
236
|
+
export async function gatherMcpKeys(selectedMcps) {
|
|
237
|
+
const mcpKeys = {};
|
|
238
|
+
const needKeys = selectedMcps.filter((m) => m.requiresKey);
|
|
239
|
+
|
|
240
|
+
if (needKeys.length === 0) return mcpKeys;
|
|
241
|
+
|
|
242
|
+
console.log(chalk.dim('\n Some MCP servers require API keys.\n'));
|
|
243
|
+
|
|
244
|
+
for (const mcp of needKeys) {
|
|
245
|
+
const keyDefs = mcp.keyNames || [{ name: mcp.keyName, description: mcp.keyDescription }];
|
|
246
|
+
const collected = {};
|
|
247
|
+
|
|
248
|
+
for (const keyDef of keyDefs) {
|
|
249
|
+
const key = await themedPassword({
|
|
250
|
+
message: `${mcp.id} — ${keyDef.description}:`,
|
|
251
|
+
hint: `Press Enter to skip. You can set ${keyDef.name} as an env variable later.`,
|
|
252
|
+
mask: '*',
|
|
253
|
+
});
|
|
254
|
+
if (key && key.trim()) {
|
|
255
|
+
const { warning } = validateApiKeyFormat(mcp.id, keyDef.name, key.trim());
|
|
256
|
+
if (warning) {
|
|
257
|
+
console.log(chalk.yellow(` ⚠ ${warning}`));
|
|
258
|
+
}
|
|
259
|
+
collected[keyDef.name] = key.trim();
|
|
260
|
+
} else {
|
|
261
|
+
console.log(chalk.dim(` Skipped — set ${keyDef.name} env var later`));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (Object.keys(collected).length > 0) {
|
|
266
|
+
mcpKeys[mcp.id] = collected;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return mcpKeys;
|
|
271
|
+
}
|
|
272
|
+
|
|
230
273
|
// ── Security configuration ────────────────────────────────────────────
|
|
231
274
|
|
|
232
275
|
export function gatherSecurityConfig(detected) {
|