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.
- package/README.md +19 -10
- package/lib/setup.js +82 -16
- 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
|
-
| チャネル
|
|
28
|
-
|
|
|
29
|
-
| 安定版
|
|
30
|
-
| Release Candidate | `next`
|
|
31
|
-
| Beta
|
|
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
|
|
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
|
|
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
|
|
297
|
-
|
|
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
|
|
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: '.
|
|
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,
|
|
210
|
-
|
|
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, {
|
|
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
|
+
"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",
|