sparkle-design-cli 2.0.7-rc.3 → 2.0.7-rc.4

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.
Files changed (3) hide show
  1. package/README.md +19 -10
  2. package/lib/setup.js +82 -16
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -24,11 +24,11 @@ npm install -g sparkle-design-cli
24
24
 
25
25
  npm の dist-tag でチャネルを分けています。通常は `latest` を使い、RC や beta は先行試用時のみ指定してください。
26
26
 
27
- | チャネル | dist-tag | バージョン形式 | 用途 |
28
- | --- | --- | --- | --- |
29
- | 安定版 | `latest` | `X.Y.Z` | 本番運用向け(デフォルト) |
30
- | Release Candidate | `next` | `X.Y.Z-rc.N` | GA 直前の検証、チーム展開前 |
31
- | Beta | `beta` | `X.Y.Z-beta.N` | 品質保証中の検証用 |
27
+ | チャネル | dist-tag | バージョン形式 | 用途 |
28
+ | ----------------- | -------- | -------------- | --------------------------- |
29
+ | 安定版 | `latest` | `X.Y.Z` | 本番運用向け(デフォルト) |
30
+ | Release Candidate | `next` | `X.Y.Z-rc.N` | GA 直前の検証、チーム展開前 |
31
+ | Beta | `beta` | `X.Y.Z-beta.N` | 品質保証中の検証用 |
32
32
 
33
33
  ```bash
34
34
  # latest を使う(デフォルト)
@@ -203,7 +203,7 @@ npx --yes sparkle-design-cli setup --assistant claude --skip-install --skip-scaf
203
203
 
204
204
  - `claude`: `CLAUDE.md`
205
205
  - `codex`: `AGENTS.md`
206
- - `cursor`: `.cursor/rules/sparkle-design-guard.mdc`
206
+ - `cursor`: `AGENTS.md`(rc.4 から `.cursor/rules/*.mdc` を廃止。Cursor は AGENTS.md を always-load するため、条件付き読み込みで Guard が silent に skip される問題を解消)
207
207
  - `generic`: `SPARKLE-DESIGN-AI.md`
208
208
 
209
209
  #### setup オプション一覧
@@ -291,10 +291,19 @@ Next.js / Vite 以外ではアプリケーションフレームワークごと
291
291
  ```html
292
292
  <link rel="preconnect" href="https://fonts.googleapis.com" />
293
293
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
294
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:FILL,wght@0..1,500&display=block" />
294
+ <link
295
+ rel="stylesheet"
296
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:FILL,wght@0..1,500&display=block"
297
+ />
295
298
  <!-- sparkle.config.json の font-pro / font-mono に合わせた Google Fonts URL -->
296
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" />
297
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" />
299
+ <link
300
+ rel="stylesheet"
301
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
302
+ />
303
+ <link
304
+ rel="stylesheet"
305
+ href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap"
306
+ />
298
307
  ```
299
308
 
300
309
  **7. アンチパターン検査を package.json に追加(任意)**
@@ -310,7 +319,7 @@ Next.js / Vite 以外ではアプリケーションフレームワークごと
310
319
 
311
320
  **8. AI エージェントを使うなら Guard ブロックと hook を手動で配置**
312
321
 
313
- AI ガード(`CLAUDE.md` / `AGENTS.md` / `.cursor/rules/*.mdc`)と hook 設定(`.claude/settings.json` / `.cursor/hooks.json` / `.codex/hooks.json`)は `setup` に任せるのが最も楽です。
322
+ AI ガード(`CLAUDE.md` / `AGENTS.md`)と hook 設定(`.claude/settings.json` / `.cursor/hooks.json` / `.codex/hooks.json`)は `setup` に任せるのが最も楽です。Cursor 用 Guard は rc.4 から AGENTS.md に統一しました(`.cursor/rules/*.mdc` は条件付き読み込みのため)。
314
323
 
315
324
  ```bash
316
325
  # ガード追加・hook 設定のみ(パッケージインストールや scaffold はスキップ)
package/lib/setup.js CHANGED
@@ -56,6 +56,15 @@ const config = {
56
56
  export default config;
57
57
  `;
58
58
 
59
+ // Guard ブロックは「常に読まれる」ファイルだけに置く。Cursor は 2025 年後半
60
+ // 以降 AGENTS.md を公式サポートしている(https://agents.md)ので、
61
+ // `.cursor/rules/*.mdc`(frontmatter で `alwaysApply: true` を付けない限り
62
+ // 条件付き読み込み)は使わない。条件付き読み込みは Guard が読まれない
63
+ // セッションで silent に lint:sparkle 実行漏れを起こす。
64
+ // en: Keep Guard on always-loaded files. `.cursor/rules/*.mdc` is loaded
65
+ // conditionally unless `alwaysApply: true` is set in frontmatter, which
66
+ // silently skips the Guard in some sessions. Cursor (Codex / Aider / Zed
67
+ // / Gemini CLI etc.) all read AGENTS.md, so route Cursor through it.
59
68
  const ASSISTANT_CONFIG = {
60
69
  claude: {
61
70
  path: 'CLAUDE.md',
@@ -64,13 +73,20 @@ const ASSISTANT_CONFIG = {
64
73
  path: 'AGENTS.md',
65
74
  },
66
75
  cursor: {
67
- path: '.cursor/rules/sparkle-design-guard.mdc',
76
+ path: 'AGENTS.md',
68
77
  },
69
78
  generic: {
70
79
  path: 'SPARKLE-DESIGN-AI.md',
71
80
  },
72
81
  };
73
82
 
83
+ // 旧版(rc.3 以前)が cursor 用に書いていた `.mdc` パス。残骸を検出して
84
+ // AGENTS.md への移行を促す warn に使う。silent 削除はしない(ユーザーが
85
+ // frontmatter を付けて意図的に保持しているケースもあるため)。
86
+ // en: Path used by rc.3 and earlier for cursor assistant. We keep it as a
87
+ // constant so the migration warn can detect leftovers without re-typing.
88
+ const LEGACY_CURSOR_GUARD_PATH = '.cursor/rules/sparkle-design-guard.mdc';
89
+
74
90
  const BLOCK_START = '<!-- sparkle-design-cli:setup:start -->';
75
91
  const BLOCK_END = '<!-- sparkle-design-cli:setup:end -->';
76
92
  const TARGET_CANDIDATES = ['src', 'src/components', 'src/features', 'app', 'components'];
@@ -206,8 +222,14 @@ function isManagedSparkleScript(value, mode) {
206
222
  return false;
207
223
  }
208
224
 
209
- function buildInstructionBlock(target, assistant) {
210
- const heading = assistant === 'cursor' ? '# Sparkle Design Guard' : '## Sparkle Design Guard';
225
+ function buildInstructionBlock(target, _assistant) {
226
+ // Guard ブロックは常に h2 で出す。rc.3 以前は cursor 用に独立 .mdc ファイル
227
+ // へ書いていたため h1 にしていたが、rc.4 で AGENTS.md に統一したため、
228
+ // 親ファイルの heading 階層に揃えて h2 が常に正しい。
229
+ // en: Always emit Guard as h2. rc.3 used h1 for the standalone cursor
230
+ // .mdc file, but rc.4 routes cursor through AGENTS.md so h2 fits the
231
+ // surrounding section hierarchy.
232
+ const heading = '## Sparkle Design Guard';
211
233
 
212
234
  return [
213
235
  BLOCK_START,
@@ -243,10 +265,7 @@ function updateInstructionFile(filePath, block) {
243
265
  `⚠️ ${filePath} に Sparkle Design Guard ブロックが ${markerCount} 個見つかりました。すべて最新版で置き換えます(手動でコピーした古い block が残っている可能性があります)。`
244
266
  );
245
267
  }
246
- const next = current.replace(
247
- new RegExp(`${BLOCK_START}[\\s\\S]*?${BLOCK_END}`, 'g'),
248
- block
249
- );
268
+ const next = current.replace(new RegExp(`${BLOCK_START}[\\s\\S]*?${BLOCK_END}`, 'g'), block);
250
269
  return { changed: next !== current, content: next, existed: exists };
251
270
  }
252
271
 
@@ -510,6 +529,42 @@ function runAssistantGuard(cwd, packageJsonPath, options, assistantConfig) {
510
529
  }
511
530
  }
512
531
 
532
+ // rc.4 で Cursor の Guard 出力先を `.cursor/rules/sparkle-design-guard.mdc`
533
+ // から AGENTS.md に移したため、再 setup 時に旧 .mdc が残っているとガードが
534
+ // 二重定義になる(しかも .mdc は frontmatter 次第で読まれない場合がある)。
535
+ // silent 削除はせず、警告だけ出して移行判断はユーザーに委ねる。Cursor 以外
536
+ // のアシスタントでも、過去に cursor → 別 assistant に切り替えたユーザーが
537
+ // いるので assistant 値に関係なくチェックする。
538
+ // en: rc.4 moved Cursor Guard from `.cursor/rules/*.mdc` to AGENTS.md.
539
+ // Detect leftovers and warn the user instead of deleting silently — the
540
+ // .mdc may still be intentionally retained with `alwaysApply: true`.
541
+ let legacyCursorGuard = null;
542
+ if (!options.instructionsPath) {
543
+ const legacyPath = path.resolve(cwd, LEGACY_CURSOR_GUARD_PATH);
544
+ if (fs.existsSync(legacyPath)) {
545
+ try {
546
+ const content = fs.readFileSync(legacyPath, 'utf8');
547
+ // BLOCK_START だけでなく BLOCK_END も含み、かつ START が END より
548
+ // 前にある完全な block の場合のみ legacy 判定する。途中で削れた断片や
549
+ // ユーザーが手動でコピーした start マーカーだけ残っているケースを
550
+ // legacy 警告対象から外す(false positive 防止)。
551
+ // en: Require both markers in the correct order so partial fragments
552
+ // don't trigger the migration warn.
553
+ const startIndex = content.indexOf(BLOCK_START);
554
+ const endIndex = content.indexOf(BLOCK_END);
555
+ if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
556
+ legacyCursorGuard = { path: legacyPath };
557
+ }
558
+ } catch (error) {
559
+ // 読み込み失敗(権限等)は legacy 検知だけスキップ。setup 本体は続行。
560
+ // en: Skip legacy detection on read failure; do not block setup.
561
+ console.warn(
562
+ `⚠️ ${LEGACY_CURSOR_GUARD_PATH} の読み込みに失敗したため legacy ガード検出をスキップします (${error.code ?? error.message})`
563
+ );
564
+ }
565
+ }
566
+ }
567
+
513
568
  if (!options.dryRun) {
514
569
  if (packageResult.changed) writeJson(packageJsonPath, packageResult.packageJson);
515
570
  if (instructionResult.changed) {
@@ -530,6 +585,7 @@ function runAssistantGuard(cwd, packageJsonPath, options, assistantConfig) {
530
585
  instructionResult,
531
586
  agentsInstructionPath,
532
587
  agentsInstructionResult,
588
+ legacyCursorGuard,
533
589
  };
534
590
  }
535
591
 
@@ -624,12 +680,9 @@ function runClaudeHook(cwd, target, dryRun) {
624
680
  const managedCommand = buildManagedHookCommand(target);
625
681
  const { existed, config } = loadHookJson(settingsPath, '.claude/settings.json');
626
682
 
627
- const nextSettings =
628
- typeof config === 'object' && config ? { ...config } : {};
683
+ const nextSettings = typeof config === 'object' && config ? { ...config } : {};
629
684
  const hooks =
630
- typeof nextSettings.hooks === 'object' && nextSettings.hooks
631
- ? { ...nextSettings.hooks }
632
- : {};
685
+ typeof nextSettings.hooks === 'object' && nextSettings.hooks ? { ...nextSettings.hooks } : {};
633
686
  const stopGroups = Array.isArray(hooks.Stop) ? [...hooks.Stop] : [];
634
687
 
635
688
  const alreadyPresent = stopGroups.some(
@@ -908,6 +961,11 @@ export function setupAssistant(options = {}) {
908
961
  existed: guard.agentsInstructionResult?.existed ?? false,
909
962
  }
910
963
  : null,
964
+ legacyCursorGuard: guard.legacyCursorGuard
965
+ ? {
966
+ path: path.relative(cwd, guard.legacyCursorGuard.path),
967
+ }
968
+ : null,
911
969
  hook: hook
912
970
  ? {
913
971
  assistant: hook.assistant,
@@ -924,8 +982,7 @@ export function setupAssistant(options = {}) {
924
982
  sessionRootMismatch: hook.sessionRootMismatch
925
983
  ? {
926
984
  detected: true,
927
- sessionDir: path.relative(cwd, hook.sessionRootMismatch.sessionDir) ||
928
- '.',
985
+ sessionDir: path.relative(cwd, hook.sessionRootMismatch.sessionDir) || '.',
929
986
  }
930
987
  : null,
931
988
  }
@@ -937,7 +994,10 @@ export function setupAssistant(options = {}) {
937
994
  // セットアップ後のリマインダー。AI の会話履歴にも残るよう stderr に出す。
938
995
  // en: Post-setup reminder. Written to stderr so it stays in the AI transcript
939
996
  // without polluting the JSON stdout payload that tooling parses.
940
- printPostSetupReminder(guard.target, packageManager, { hook });
997
+ printPostSetupReminder(guard.target, packageManager, {
998
+ hook,
999
+ legacyCursorGuard: guard.legacyCursorGuard,
1000
+ });
941
1001
 
942
1002
  return summary;
943
1003
  }
@@ -965,7 +1025,7 @@ const HOOK_LABELS = {
965
1025
  codex: { name: 'Codex', file: '.codex/hooks.json', event: 'Stop' },
966
1026
  };
967
1027
 
968
- function printPostSetupReminder(target, packageManager, { hook } = {}) {
1028
+ function printPostSetupReminder(target, packageManager, { hook, legacyCursorGuard } = {}) {
969
1029
  const lintTarget = target || 'src';
970
1030
  const lintCmd = buildLintCommand(packageManager);
971
1031
  const lines = [
@@ -1001,6 +1061,12 @@ function printPostSetupReminder(target, packageManager, { hook } = {}) {
1001
1061
  );
1002
1062
  }
1003
1063
  }
1064
+ if (legacyCursorGuard) {
1065
+ lines.push(
1066
+ ` ⚠️ ${legacyCursorGuard.path} に旧バージョンの Sparkle Design Guard ブロックが残っています。rc.4 で Cursor のガードは AGENTS.md に統一されました(Cursor の \`.cursor/rules/*.mdc\` は frontmatter で \`alwaysApply: true\` を付けないと条件付き読み込みになり、ガードが silent に skip される問題があるため)。重複防止のため旧 .mdc を削除するか、\`alwaysApply: true\` の frontmatter を付けて意図的に残す運用に切り替えてください。`,
1067
+ ` ⚠️ Found leftover Sparkle Design Guard in ${legacyCursorGuard.path}. rc.4 routes Cursor Guard through AGENTS.md (\`.cursor/rules/*.mdc\` is conditionally loaded unless \`alwaysApply: true\` is set). Either delete the legacy .mdc or add \`alwaysApply: true\` frontmatter to keep it deliberately.`
1068
+ );
1069
+ }
1004
1070
  lines.push('');
1005
1071
  for (const line of lines) {
1006
1072
  console.error(line);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design-cli",
3
- "version": "2.0.7-rc.3",
3
+ "version": "2.0.7-rc.4",
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",