ccraft 1.0.13 → 1.0.14

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccraft",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Intelligent Claude Code project configurator — role-aware agents, skills, rules, MCPs, and workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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
- const mcpKeys = {};
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
 
@@ -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) {