sparkle-design-cli 2.0.7-beta.8 → 2.0.7-beta.9

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.
@@ -277,15 +277,33 @@ export function updateGlobalsWithFonts(
277
277
  // 2. 既存のimportを削除
278
278
  globalsContent = removeExistingImports(globalsContent);
279
279
 
280
- // 3. Tailwind import の位置を見つける
281
- const tailwindInfo = findTailwindImport(globalsContent);
280
+ // 3. Tailwind import の位置を見つける。無ければ先頭に自動で prepend する。
281
+ // ここで silent に失敗すると `create-vite` 等が生成した既存 index.css に
282
+ // `@import "tailwindcss"` が無いプロジェクトで setup が no-op に終わり、
283
+ // AI が後から手書きで import を補うが `@source` を知らず落とす、という
284
+ // 連鎖的な崩れが起きていた(beta.8 試用で確認)。canonical な import を
285
+ // 自動投入することでその連鎖を根絶する。
286
+ // en: If `@import "tailwindcss"` is missing from an existing entry CSS
287
+ // (e.g. untouched `create-vite` default), auto-prepend it instead of
288
+ // silently warning. Without this recovery, the whole patch becomes a no-op
289
+ // and AI ends up hand-writing imports without `@source`, producing drifted
290
+ // output (observed in beta.8 user testing).
291
+ let tailwindInfo = findTailwindImport(globalsContent);
282
292
  if (!tailwindInfo) {
283
- // 表示はプロジェクト相対パスにする。絶対パスだと「どのファイルをいじるのか」
284
- // が一目で分かりにくく、リポジトリ間で絶対パスが変わるので diff も読みにくい。
285
- // en: Show the project-relative path so it's obvious which file to edit.
286
293
  const displayPath = path.relative(process.cwd(), globalsPath) || globalsPath;
287
- console.warn(MESSAGES.TAILWIND_NOT_FOUND(displayPath));
288
- return { status: 'failed', reason: 'tailwind-import-missing' };
294
+ console.warn(
295
+ `⚠️ ${displayPath} に \`@import "tailwindcss";\` が見つからなかったため先頭に追記します(canonical な Tailwind v4 entry point にするため)。`
296
+ );
297
+ globalsContent = `${IMPORTS.TAILWIND}\n${globalsContent.startsWith('\n') ? '' : ''}${globalsContent}`;
298
+ tailwindInfo = findTailwindImport(globalsContent);
299
+ if (!tailwindInfo) {
300
+ // prepend したのに正規表現で拾えないのは `REGEX.TAILWIND_IMPORT` が
301
+ // 想定と違う(= コードの不整合)。fail-fast する。
302
+ // en: We just wrote the canonical import but the regex doesn't see it —
303
+ // this is an internal inconsistency, not a user error. Fail loud.
304
+ console.error(MESSAGES.TAILWIND_NOT_FOUND(displayPath));
305
+ return { status: 'failed', reason: 'tailwind-import-missing-after-prepend' };
306
+ }
289
307
  }
290
308
 
291
309
  // 4. importブロックを生成(フォント @import は SparkleHead に移行したため生成しない)
@@ -451,11 +469,22 @@ function resolveGlobalsPath(sparkleDesignPath, explicitGlobalsPath = null) {
451
469
  const candidates = isViteProject(cwd)
452
470
  ? GLOBALS_CSS_CANDIDATES.slice().sort((a, b) => vitePriority(a) - vitePriority(b))
453
471
  : GLOBALS_CSS_CANDIDATES;
472
+ // 2-a) まず既知候補の中で `@import "tailwindcss"` を持つファイルを探す。
473
+ // 持っているファイルが第一候補(canonical Tailwind entry CSS)。
474
+ // 2-b) 2-a で見つからなかった場合、`@import` 無しで既存の候補ファイルが
475
+ // あればそれを拾う(Vite の `create-vite` 直後のように entry CSS は
476
+ // あるが Tailwind 未設定のプロジェクト)。これで上流の
477
+ // `updateGlobalsWithFonts` が auto-prepend で tailwind import を
478
+ // 補えるため、silent に no-op 終了する回帰を避けられる(beta.8 で再現)。
479
+ // en: First pick candidates that already contain `@import "tailwindcss"`.
480
+ // If none match, fall back to the first existing candidate anyway so the
481
+ // upstream patcher can auto-prepend the canonical tailwind import. Without
482
+ // this fallback, a Vite project created by `create-vite` with an untouched
483
+ // `src/index.css` would cause setup to end as a silent no-op.
484
+ let fallbackExistingPath = null;
454
485
  for (const candidate of candidates) {
455
486
  const absolute = path.resolve(cwd, candidate);
456
487
  if (!fs.existsSync(absolute)) continue;
457
- // 自身(sparkle-design.css)は除外
458
- // en: Skip sparkle-design.css itself just in case a candidate points at it.
459
488
  if (path.resolve(absolute) === path.resolve(sparkleDesignPath)) continue;
460
489
  try {
461
490
  const content = fs.readFileSync(absolute, 'utf8');
@@ -463,6 +492,9 @@ function resolveGlobalsPath(sparkleDesignPath, explicitGlobalsPath = null) {
463
492
  console.log(`📝 Tailwind エントリポイントを検出しました(project root): ${candidate}`);
464
493
  return { path: absolute, source: 'project' };
465
494
  }
495
+ if (!fallbackExistingPath) {
496
+ fallbackExistingPath = { path: absolute, candidate };
497
+ }
466
498
  } catch (err) {
467
499
  // ENOENT 系は existsSync で既に弾いているので、ここに来るのは権限不足や
468
500
  // ディレクトリ衝突などデバッグ価値のあるケース。silent に消さずに理由を出す。
@@ -474,6 +506,13 @@ function resolveGlobalsPath(sparkleDesignPath, explicitGlobalsPath = null) {
474
506
  }
475
507
  }
476
508
 
509
+ if (fallbackExistingPath) {
510
+ console.log(
511
+ `📝 Tailwind import 未設定の既存 entry CSS を検出しました(project root): ${fallbackExistingPath.candidate}。後続処理で \`@import "tailwindcss";\` を自動追記します。`
512
+ );
513
+ return { path: fallbackExistingPath.path, source: 'existing-no-tailwind' };
514
+ }
515
+
477
516
  // 3. デフォルト: sparkle-design.css と同じディレクトリの globals.css
478
517
  // en: Last resort — a globals.css next to sparkle-design.css.
479
518
  const defaultPath = path.join(dir, 'globals.css');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design-cli",
3
- "version": "2.0.7-beta.8",
3
+ "version": "2.0.7-beta.9",
4
4
  "description": "Sparkle Design CLI — プロジェクトセットアップ、CSS・フォント生成、アンチパターン検査、AI エージェント(Claude Code / Cursor / Codex)向けのガードと hook 設定まで一括で行う sparkle-design 公式 CLI。",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",