create-sdd-project 0.16.6 → 0.16.7

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/lib/doctor.js CHANGED
@@ -70,6 +70,9 @@ function runDoctor(cwd) {
70
70
  // 11. Autonomy/Skills Consistency
71
71
  results.push(checkAutonomySkillConsistency(cwd, aiTools));
72
72
 
73
+ // 12. Gemini Settings Format
74
+ results.push(checkGeminiSettings(cwd, aiTools));
75
+
73
76
  return results;
74
77
  }
75
78
 
@@ -529,6 +532,87 @@ function checkAutonomySkillConsistency(cwd, aiTools) {
529
532
  };
530
533
  }
531
534
 
535
+ function checkGeminiSettings(cwd, aiTools) {
536
+ if (aiTools === 'claude') {
537
+ return {
538
+ status: PASS,
539
+ message: 'Gemini settings: N/A (Claude only)',
540
+ details: [],
541
+ };
542
+ }
543
+
544
+ const settingsPath = path.join(cwd, '.gemini', 'settings.json');
545
+ if (!fs.existsSync(settingsPath)) {
546
+ return {
547
+ status: WARN,
548
+ message: 'Gemini settings: .gemini/settings.json missing',
549
+ details: ['Run: npx create-sdd-project --upgrade to recreate from template'],
550
+ };
551
+ }
552
+
553
+ let settings;
554
+ try {
555
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
556
+ } catch (e) {
557
+ return {
558
+ status: FAIL,
559
+ message: 'Gemini settings: invalid JSON',
560
+ details: [e.message],
561
+ };
562
+ }
563
+
564
+ // Detectably-broken formats only — do NOT enforce stricter rules than upstream Gemini.
565
+ if (typeof settings.model === 'string') {
566
+ return {
567
+ status: FAIL,
568
+ message: 'Gemini settings: obsolete model format (string instead of object)',
569
+ details: [
570
+ `Found: "model": "${settings.model}"`,
571
+ `Expected: "model": { "name": "${settings.model}" }`,
572
+ 'Gemini CLI silently falls back to defaults when model is a string, ignoring this file.',
573
+ 'Verified against Gemini CLI 0.34.0. Run: npx create-sdd-project --upgrade',
574
+ ],
575
+ };
576
+ }
577
+
578
+ if (settings.model !== undefined && (
579
+ settings.model === null ||
580
+ Array.isArray(settings.model) ||
581
+ typeof settings.model !== 'object'
582
+ )) {
583
+ const got = Array.isArray(settings.model)
584
+ ? 'array'
585
+ : settings.model === null
586
+ ? 'null'
587
+ : typeof settings.model;
588
+ return {
589
+ status: FAIL,
590
+ message: 'Gemini settings: model field has invalid type',
591
+ details: [
592
+ 'Expected: object with a "name" property (or absent)',
593
+ `Got: ${got}`,
594
+ 'Run: npx create-sdd-project --upgrade',
595
+ ],
596
+ };
597
+ }
598
+
599
+ if (typeof settings.model === 'object' && !settings.model.name) {
600
+ return {
601
+ status: WARN,
602
+ message: 'Gemini settings: model object is missing "name" property',
603
+ details: [
604
+ 'Gemini accepts this but the model is unset. Add: { "name": "gemini-2.5-pro" }',
605
+ ],
606
+ };
607
+ }
608
+
609
+ return {
610
+ status: PASS,
611
+ message: 'Gemini settings: valid',
612
+ details: [],
613
+ };
614
+ }
615
+
532
616
  module.exports = {
533
617
  runDoctor,
534
618
  printResults,
@@ -255,17 +255,40 @@ function generateUpgrade(config) {
255
255
  }
256
256
  }
257
257
 
258
- // Merge settings.json — update hooks from template, preserve user's permissions/additionalDirectories
258
+ // Merge settings.json — strategy depends on the tool:
259
+ // .claude: template-owned (hooks from template), preserve user permissions/additionalDirectories
260
+ // .gemini: user-owned, only migrate the model field if it's in the obsolete string format
259
261
  const settingsSrc = path.join(templateToolDir, 'settings.json');
260
262
  const settingsDest = path.join(base, 'settings.json');
261
263
  if (fs.existsSync(settingsSrc)) {
262
264
  const templateSettings = JSON.parse(fs.readFileSync(settingsSrc, 'utf8'));
263
265
  if (fs.existsSync(settingsDest)) {
264
266
  const userSettings = JSON.parse(fs.readFileSync(settingsDest, 'utf8'));
265
- // Keep user's permissions and additionalDirectories, take template's hooks
266
- const merged = { ...templateSettings };
267
- if (userSettings.permissions) merged.permissions = userSettings.permissions;
268
- if (userSettings.additionalDirectories) merged.additionalDirectories = userSettings.additionalDirectories;
267
+ let merged;
268
+ if (dir === '.claude') {
269
+ // Claude: take template, restore user's permissions/additionalDirectories
270
+ merged = { ...templateSettings };
271
+ if (userSettings.permissions) merged.permissions = userSettings.permissions;
272
+ if (userSettings.additionalDirectories) merged.additionalDirectories = userSettings.additionalDirectories;
273
+ } else {
274
+ // Gemini: preserve all user keys, only migrate model field
275
+ merged = { ...userSettings };
276
+ if (typeof userSettings.model === 'string') {
277
+ // Obsolete format: convert "model": "name" → "model": { "name": "name" }
278
+ merged.model = { name: userSettings.model };
279
+ } else if (
280
+ userSettings.model !== undefined && (
281
+ userSettings.model === null ||
282
+ Array.isArray(userSettings.model) ||
283
+ typeof userSettings.model !== 'object' ||
284
+ !userSettings.model.name
285
+ )
286
+ ) {
287
+ // Malformed (null, array, primitive, object without name) → reset to template default
288
+ merged.model = { ...templateSettings.model };
289
+ }
290
+ // Otherwise (valid object with name, or absent): leave as-is
291
+ }
269
292
  fs.writeFileSync(settingsDest, JSON.stringify(merged, null, 2) + '\n', 'utf8');
270
293
  } else {
271
294
  fs.copyFileSync(settingsSrc, settingsDest);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sdd-project",
3
- "version": "0.16.6",
3
+ "version": "0.16.7",
4
4
  "description": "Create a new SDD DevFlow project with AI-assisted development workflow",
5
5
  "bin": {
6
6
  "create-sdd-project": "bin/cli.js"
@@ -1,5 +1,5 @@
1
1
  {
2
- "model": "gemini-2.5-pro",
2
+ "model": { "name": "gemini-2.5-pro" },
3
3
  "temperature": 0.2,
4
4
  "instructions": "Follow the development standards in ai-specs/specs/base-standards.mdc. Use the agent instructions in .gemini/agents/ for specialized tasks. Use the workflow skills in .gemini/skills/ for task orchestration. Custom commands are available in .gemini/commands/."
5
5
  }