rulesync 0.40.0 → 0.42.0
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.ja.md +57 -19
- package/README.md +44 -4
- package/dist/{chunk-QR656A7R.js → chunk-2SPL7QTK.js} +1 -1
- package/dist/{chunk-XSHEX7Q4.js → chunk-3NRSCDLQ.js} +5 -1
- package/dist/{chunk-4SFPBBIB.js → chunk-D3YGI36J.js} +1 -1
- package/dist/{chunk-CUKKFQFO.js → chunk-HMMPZV7X.js} +1 -1
- package/dist/{chunk-XN7RGMJW.js → chunk-X3FEMISQ.js} +1 -1
- package/dist/{claude-JS6ARGB3.js → claude-3YGZIO5F.js} +1 -1
- package/dist/{cline-MM3R4QQE.js → cline-ERYW7TOO.js} +1 -1
- package/dist/{cursor-AU3PRMGD.js → cursor-CX55HMO4.js} +1 -1
- package/dist/{geminicli-LINS3RMZ.js → geminicli-XHQR4RCQ.js} +1 -1
- package/dist/index.cjs +142 -60
- package/dist/index.js +142 -60
- package/dist/{roo-EHU65CDY.js → roo-OKE7XF3B.js} +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -164,14 +164,14 @@ rulesyncは2レベルのルールシステムを使用します:
|
|
|
164
164
|
|
|
165
165
|
各AIツールはルールレベルを異なって処理します:
|
|
166
166
|
|
|
167
|
-
| ツール
|
|
168
|
-
|
|
169
|
-
| **Claude Code**
|
|
170
|
-
| **Cursor**
|
|
171
|
-
| **GitHub Copilot** | 標準フォーマット
|
|
172
|
-
| **Cline**
|
|
173
|
-
| **Roo Code**
|
|
174
|
-
| **Gemini CLI**
|
|
167
|
+
| ツール | ルートルール | 非ルートルール | 特別な動作 |
|
|
168
|
+
| ------------------ | ------------------ | ------------------------ | -------------------------------------------------------------------- |
|
|
169
|
+
| **Claude Code** | `./CLAUDE.md` | `.claude/memories/*.md` | CLAUDE.mdが詳細ファイルへの`@filename`参照を含む |
|
|
170
|
+
| **Cursor** | `cursorRuleType: always` | `cursorRuleType: specificFiles` (globs指定時)<br>`cursorRuleType: intelligently` (description指定時)<br>`cursorRuleType: manual` (デフォルト) | コンテンツ解析に基づく高度なルールタイプシステム |
|
|
171
|
+
| **GitHub Copilot** | 標準フォーマット | 標準フォーマット | すべてのルールがフロントマター付きの同じフォーマットを使用 |
|
|
172
|
+
| **Cline** | 標準フォーマット | 標準フォーマット | すべてのルールがプレーンMarkdownフォーマットを使用 |
|
|
173
|
+
| **Roo Code** | 標準フォーマット | 標準フォーマット | すべてのルールが説明ヘッダー付きのプレーンMarkdownフォーマットを使用 |
|
|
174
|
+
| **Gemini CLI** | `GEMINI.md` | `.gemini/memories/*.md` | GEMINI.mdがメモリファイルへの`@filename`参照を含む |
|
|
175
175
|
|
|
176
176
|
### 3. 設定ファイルの生成
|
|
177
177
|
|
|
@@ -241,6 +241,34 @@ importコマンドの動作:
|
|
|
241
241
|
- YAMLフロントマター付きのCursorのMDCファイルなど複雑なフォーマットをサポート
|
|
242
242
|
- 複数ファイルのインポート(例:`.claude/memories/`ディレクトリのすべてのファイル)に対応
|
|
243
243
|
|
|
244
|
+
### Cursorインポートの詳細
|
|
245
|
+
|
|
246
|
+
Cursorからのインポートでは、以下の4つのルールタイプが自動的に識別されます:
|
|
247
|
+
|
|
248
|
+
1. **always** (`cursorRuleType: always`)
|
|
249
|
+
- 条件: `alwaysApply: true` が設定されている場合
|
|
250
|
+
- 変換: ルートルール(`root: false`)としてインポート、`globs: ["**/*"]`を設定
|
|
251
|
+
|
|
252
|
+
2. **manual** (`cursorRuleType: manual`)
|
|
253
|
+
- 条件: description空 + globs空 + `alwaysApply: false`
|
|
254
|
+
- 変換: 空のglobsパターンでインポート(手動適用ルール)
|
|
255
|
+
|
|
256
|
+
3. **specificFiles** (`cursorRuleType: specificFiles`)
|
|
257
|
+
- 条件: globs指定あり(description有無問わず)
|
|
258
|
+
- 変換: 指定されたglobsパターンを配列として保持、descriptionは空文字に設定
|
|
259
|
+
|
|
260
|
+
4. **intelligently** (`cursorRuleType: intelligently`)
|
|
261
|
+
- 条件: description指定あり + globs空
|
|
262
|
+
- 変換: descriptionを保持、空のglobsパターンを設定
|
|
263
|
+
|
|
264
|
+
#### エッジケース処理
|
|
265
|
+
- **description非空 + globs非空の場合**: `specificFiles`として処理(globsパターンを優先)
|
|
266
|
+
- **判定条件に該当しない場合**: `manual`として処理(デフォルト)
|
|
267
|
+
|
|
268
|
+
#### Cursorのサポートファイル
|
|
269
|
+
- `.cursor/rules/*.mdc` (モダンな推奨形式)
|
|
270
|
+
- `.cursorrules` (レガシーな形式)
|
|
271
|
+
|
|
244
272
|
### 5. その他のコマンド
|
|
245
273
|
|
|
246
274
|
```bash
|
|
@@ -314,9 +342,19 @@ root: true | false # 必須: ルールレベル (概要の場合tr
|
|
|
314
342
|
targets: ["*"] # 必須: ターゲットツール (* = すべて、または特定のツール)
|
|
315
343
|
description: "簡潔な説明" # 必須: ルールの説明
|
|
316
344
|
globs: "**/*.ts,**/*.js" # 必須: ファイルパターン (カンマ区切りまたは空文字列)
|
|
345
|
+
cursorRuleType: "always" # オプション: Cursor固有のルールタイプ (always, manual, specificFiles, intelligently)
|
|
317
346
|
---
|
|
318
347
|
```
|
|
319
348
|
|
|
349
|
+
#### cursorRuleTypeフィールド (オプション)
|
|
350
|
+
|
|
351
|
+
Cursorツール用の追加メタデータフィールド:
|
|
352
|
+
|
|
353
|
+
- **`always`**: プロジェクト全体に常に適用されるルール
|
|
354
|
+
- **`manual`**: 手動で適用するルール(デフォルト)
|
|
355
|
+
- **`specificFiles`**: 特定のファイルパターンに自動適用されるルール
|
|
356
|
+
- **`intelligently`**: AIが判断して適用するルール
|
|
357
|
+
|
|
320
358
|
### ファイル例
|
|
321
359
|
|
|
322
360
|
**ルートファイル** (`.rulesync/overview.md`):
|
|
@@ -351,14 +389,14 @@ globs: "**/*.ts,**/*.tsx"
|
|
|
351
389
|
|
|
352
390
|
## 生成される設定ファイル
|
|
353
391
|
|
|
354
|
-
| ツール
|
|
355
|
-
|
|
356
|
-
| **GitHub Copilot** | `.github/instructions/*.instructions.md`
|
|
357
|
-
| **Cursor**
|
|
358
|
-
| **Cline**
|
|
359
|
-
| **Claude Code**
|
|
360
|
-
| **Roo Code**
|
|
361
|
-
| **Gemini CLI**
|
|
392
|
+
| ツール | 出力パス | フォーマット | ルールレベル処理 |
|
|
393
|
+
| ------------------ | ------------------------------------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
394
|
+
| **GitHub Copilot** | `.github/instructions/*.instructions.md` | フロントマター + Markdown | 両レベルとも同じフォーマットを使用 |
|
|
395
|
+
| **Cursor** | `.cursor/rules/*.mdc` | MDC (YAMLヘッダー + Markdown) | ルート: `cursorRuleType: always`<br>非ルート: `cursorRuleType: specificFiles` (globs指定時)<br>非ルート: `cursorRuleType: intelligently` (description指定時)<br>非ルート: `cursorRuleType: manual` (デフォルト) |
|
|
396
|
+
| **Cline** | `.clinerules/*.md` | プレーンMarkdown | 両レベルとも同じフォーマットを使用 |
|
|
397
|
+
| **Claude Code** | `./CLAUDE.md` (ルート)<br>`.claude/memories/*.md` (非ルート) | プレーンMarkdown | ルートはCLAUDE.mdに移動<br>非ルートは別メモリファイルに移動<br>CLAUDE.mdは`@filename`参照を含む |
|
|
398
|
+
| **Roo Code** | `.roo/rules/*.md` | プレーンMarkdown | 両レベルとも説明ヘッダー付きの同じフォーマットを使用 |
|
|
399
|
+
| **Gemini CLI** | `GEMINI.md` (ルート)<br>`.gemini/memories/*.md` (非ルート) | プレーンMarkdown | ルートはGEMINI.mdに移動<br>非ルートは別メモリファイルに移動<br>GEMINI.mdは`@filename`参照を含む |
|
|
362
400
|
|
|
363
401
|
## バリデーション
|
|
364
402
|
|
|
@@ -402,7 +440,7 @@ rulesyncは、対応するAIツール用のMCPサーバー設定も管理でき
|
|
|
402
440
|
"ghcr.io/github/github-mcp-server"
|
|
403
441
|
],
|
|
404
442
|
"env": {},
|
|
405
|
-
"
|
|
443
|
+
"targets": ["*"]
|
|
406
444
|
}
|
|
407
445
|
}
|
|
408
446
|
}
|
|
@@ -415,7 +453,7 @@ rulesyncは、対応するAIツール用のMCPサーバー設定も管理でき
|
|
|
415
453
|
- **`args`**: コマンド引数
|
|
416
454
|
- **`url`**: HTTP/SSEベースのサーバー用URL
|
|
417
455
|
- **`env`**: サーバーに渡す環境変数
|
|
418
|
-
- **`
|
|
456
|
+
- **`targets`**: このサーバーをデプロイするツール名の配列
|
|
419
457
|
- 特定のツール名を使用: `["claude", "cursor", "copilot"]`
|
|
420
458
|
- すべてのサポートツールにデプロイするには`["*"]`を使用
|
|
421
459
|
- 省略した場合、デフォルトですべてのツールにデプロイ
|
|
@@ -445,4 +483,4 @@ MIT License
|
|
|
445
483
|
|
|
446
484
|
Issues と Pull Requests を歓迎します!
|
|
447
485
|
|
|
448
|
-
開発環境の設定と貢献ガイドラインについては、[CONTRIBUTING.ja.md](./CONTRIBUTING.ja.md)を参照してください。
|
|
486
|
+
開発環境の設定と貢献ガイドラインについては、[CONTRIBUTING.ja.md](./CONTRIBUTING.ja.md)を参照してください。
|
package/README.md
CHANGED
|
@@ -167,7 +167,7 @@ Each AI tool handles rule levels differently:
|
|
|
167
167
|
| Tool | Root Rules | Non-Root Rules | Special Behavior |
|
|
168
168
|
|------|------------|----------------|------------------|
|
|
169
169
|
| **Claude Code** | `./CLAUDE.md` | `.claude/memories/*.md` | CLAUDE.md includes `@filename` references to detail files |
|
|
170
|
-
| **Cursor** | `
|
|
170
|
+
| **Cursor** | `cursorRuleType: always` | `cursorRuleType: specificFiles` (with globs)<br>`cursorRuleType: intelligently` (with description)<br>`cursorRuleType: manual` (default) | Advanced rule type system based on content analysis |
|
|
171
171
|
| **GitHub Copilot** | Standard format | Standard format | All rules use same format with frontmatter |
|
|
172
172
|
| **Cline** | Standard format | Standard format | All rules use plain Markdown format |
|
|
173
173
|
| **Roo Code** | Standard format | Standard format | All rules use plain Markdown format with description header |
|
|
@@ -241,6 +241,36 @@ The import command will:
|
|
|
241
241
|
- Support complex formats like Cursor's MDC files with YAML frontmatter
|
|
242
242
|
- Handle multiple file imports (e.g., all files from `.claude/memories/` directory)
|
|
243
243
|
|
|
244
|
+
### Cursor Import Details
|
|
245
|
+
|
|
246
|
+
When importing from Cursor, the following four rule types are automatically identified:
|
|
247
|
+
|
|
248
|
+
1. **always** (`cursorRuleType: always`)
|
|
249
|
+
- Condition: `alwaysApply: true` is set
|
|
250
|
+
- Conversion: Imported as root rule (`root: false`), with `globs: ["**/*"]` set
|
|
251
|
+
|
|
252
|
+
2. **manual** (`cursorRuleType: manual`)
|
|
253
|
+
- Condition: empty description + empty globs + `alwaysApply: false`
|
|
254
|
+
- Conversion: Imported with empty globs patterns (manual application rule)
|
|
255
|
+
|
|
256
|
+
3. **specificFiles** (`cursorRuleType: specificFiles`)
|
|
257
|
+
- Condition: globs specified (regardless of description)
|
|
258
|
+
- Conversion: Specified globs patterns preserved as array, description set to empty string
|
|
259
|
+
|
|
260
|
+
4. **intelligently** (`cursorRuleType: intelligently`)
|
|
261
|
+
- Condition: description specified + empty globs
|
|
262
|
+
- Conversion: Description preserved, empty globs patterns set
|
|
263
|
+
|
|
264
|
+
#### Edge Case Handling
|
|
265
|
+
- **Non-empty description + non-empty globs**: Processed as `specificFiles` (globs patterns take priority)
|
|
266
|
+
- **No matching conditions**: Processed as `manual` (default)
|
|
267
|
+
|
|
268
|
+
#### Supported Files
|
|
269
|
+
- `.cursorrules` (legacy format)
|
|
270
|
+
- `.cursor/rules/*.mdc` (modern MDC format)
|
|
271
|
+
- `.cursorignore` (ignore patterns)
|
|
272
|
+
- `.cursor/mcp.json` (MCP server configuration)
|
|
273
|
+
|
|
244
274
|
### 5. Other Commands
|
|
245
275
|
|
|
246
276
|
```bash
|
|
@@ -314,9 +344,19 @@ root: true | false # Required: Rule level (true for overview, fals
|
|
|
314
344
|
targets: ["*"] # Required: Target tools (* = all, or specific tools)
|
|
315
345
|
description: "Brief description" # Required: Rule description
|
|
316
346
|
globs: "**/*.ts,**/*.js" # Required: File patterns (comma-separated or empty string)
|
|
347
|
+
cursorRuleType: "always" # Optional: Cursor-specific rule type (always, manual, specificFiles, intelligently)
|
|
317
348
|
---
|
|
318
349
|
```
|
|
319
350
|
|
|
351
|
+
#### cursorRuleType Field (Optional)
|
|
352
|
+
|
|
353
|
+
Additional metadata field for Cursor tool:
|
|
354
|
+
|
|
355
|
+
- **`always`**: Rules applied to the entire project constantly
|
|
356
|
+
- **`manual`**: Rules applied manually (default)
|
|
357
|
+
- **`specificFiles`**: Rules automatically applied to specific file patterns
|
|
358
|
+
- **`intelligently`**: Rules applied by AI judgment
|
|
359
|
+
|
|
320
360
|
### Example Files
|
|
321
361
|
|
|
322
362
|
**Root file** (`.rulesync/overview.md`):
|
|
@@ -354,7 +394,7 @@ globs: "**/*.ts,**/*.tsx"
|
|
|
354
394
|
| Tool | Output Path | Format | Rule Level Handling |
|
|
355
395
|
|------|------------|--------|-------------------|
|
|
356
396
|
| **GitHub Copilot** | `.github/instructions/*.instructions.md` | Front Matter + Markdown | Both levels use same format |
|
|
357
|
-
| **Cursor** | `.cursor/rules/*.mdc` | MDC (YAML header + Markdown) | Root: `
|
|
397
|
+
| **Cursor** | `.cursor/rules/*.mdc` | MDC (YAML header + Markdown) | Root: `cursorRuleType: always`<br>Non-root: `cursorRuleType: specificFiles` (with globs)<br>Non-root: `cursorRuleType: intelligently` (with description)<br>Non-root: `cursorRuleType: manual` (default) |
|
|
358
398
|
| **Cline** | `.clinerules/*.md` | Plain Markdown | Both levels use same format |
|
|
359
399
|
| **Claude Code** | `./CLAUDE.md` (root)<br>`.claude/memories/*.md` (non-root) | Plain Markdown | Root goes to CLAUDE.md<br>Non-root go to separate memory files<br>CLAUDE.md includes `@filename` references |
|
|
360
400
|
| **Roo Code** | `.roo/rules/*.md` | Plain Markdown | Both levels use same format with description header |
|
|
@@ -402,7 +442,7 @@ Create a `.rulesync/.mcp.json` file in your project:
|
|
|
402
442
|
"ghcr.io/github/github-mcp-server"
|
|
403
443
|
],
|
|
404
444
|
"env": {},
|
|
405
|
-
"
|
|
445
|
+
"targets": ["*"]
|
|
406
446
|
}
|
|
407
447
|
}
|
|
408
448
|
}
|
|
@@ -415,7 +455,7 @@ Create a `.rulesync/.mcp.json` file in your project:
|
|
|
415
455
|
- **`args`**: Command arguments
|
|
416
456
|
- **`url`**: URL for HTTP/SSE-based servers
|
|
417
457
|
- **`env`**: Environment variables to pass to the server
|
|
418
|
-
- **`
|
|
458
|
+
- **`targets`**: Array of tool names to deploy this server to
|
|
419
459
|
- Use specific tool names: `["claude", "cursor", "copilot"]`
|
|
420
460
|
- Use `["*"]` to deploy to all supported tools
|
|
421
461
|
- If omitted, server is deployed to all tools by default
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-6YNGMPAL.js";
|
|
4
4
|
|
|
5
5
|
// src/generators/mcp/roo.ts
|
|
6
|
-
function generateRooMcp(config
|
|
6
|
+
function generateRooMcp(config) {
|
|
7
7
|
const rooConfig = {
|
|
8
8
|
mcpServers: {}
|
|
9
9
|
};
|
|
@@ -61,6 +61,10 @@ function generateRooMcpConfiguration(mcpServers, baseDir = "") {
|
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
const { targets: _targets, ...serverConfig } = serverObj;
|
|
64
|
+
if (serverConfig.httpUrl && serverConfig.url) {
|
|
65
|
+
serverConfig.url = serverConfig.httpUrl;
|
|
66
|
+
delete serverConfig.httpUrl;
|
|
67
|
+
}
|
|
64
68
|
config.mcpServers[serverName] = serverConfig;
|
|
65
69
|
}
|
|
66
70
|
return [
|
package/dist/index.cjs
CHANGED
|
@@ -92,7 +92,7 @@ var init_mcp_helpers = __esm({
|
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
// src/generators/mcp/claude.ts
|
|
95
|
-
function generateClaudeMcp(config
|
|
95
|
+
function generateClaudeMcp(config) {
|
|
96
96
|
const claudeSettings = {
|
|
97
97
|
mcpServers: {}
|
|
98
98
|
};
|
|
@@ -131,7 +131,7 @@ var init_claude = __esm({
|
|
|
131
131
|
});
|
|
132
132
|
|
|
133
133
|
// src/generators/mcp/cline.ts
|
|
134
|
-
function generateClineMcp(config
|
|
134
|
+
function generateClineMcp(config) {
|
|
135
135
|
const clineConfig = {
|
|
136
136
|
mcpServers: {}
|
|
137
137
|
};
|
|
@@ -230,7 +230,7 @@ var init_copilot = __esm({
|
|
|
230
230
|
});
|
|
231
231
|
|
|
232
232
|
// src/generators/mcp/cursor.ts
|
|
233
|
-
function generateCursorMcp(config
|
|
233
|
+
function generateCursorMcp(config) {
|
|
234
234
|
const cursorConfig = {
|
|
235
235
|
mcpServers: {}
|
|
236
236
|
};
|
|
@@ -269,7 +269,7 @@ var init_cursor = __esm({
|
|
|
269
269
|
});
|
|
270
270
|
|
|
271
271
|
// src/generators/mcp/geminicli.ts
|
|
272
|
-
function generateGeminiCliMcp(config
|
|
272
|
+
function generateGeminiCliMcp(config) {
|
|
273
273
|
const geminiSettings = {
|
|
274
274
|
mcpServers: {}
|
|
275
275
|
};
|
|
@@ -314,7 +314,7 @@ var init_geminicli = __esm({
|
|
|
314
314
|
});
|
|
315
315
|
|
|
316
316
|
// src/generators/mcp/roo.ts
|
|
317
|
-
function generateRooMcp(config
|
|
317
|
+
function generateRooMcp(config) {
|
|
318
318
|
const rooConfig = {
|
|
319
319
|
mcpServers: {}
|
|
320
320
|
};
|
|
@@ -773,24 +773,56 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
773
773
|
}
|
|
774
774
|
function generateCursorMarkdown(rule) {
|
|
775
775
|
const lines = [];
|
|
776
|
+
const ruleType = determineCursorRuleType(rule.frontmatter);
|
|
776
777
|
lines.push("---");
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
778
|
+
switch (ruleType) {
|
|
779
|
+
case "always":
|
|
780
|
+
lines.push("description:");
|
|
781
|
+
lines.push("globs:");
|
|
782
|
+
lines.push("alwaysApply: true");
|
|
783
|
+
break;
|
|
784
|
+
case "manual":
|
|
785
|
+
lines.push("description:");
|
|
786
|
+
lines.push("globs:");
|
|
787
|
+
lines.push("alwaysApply: false");
|
|
788
|
+
break;
|
|
789
|
+
case "specificFiles":
|
|
790
|
+
lines.push("description:");
|
|
791
|
+
lines.push(`globs: ${rule.frontmatter.globs.join(",")}`);
|
|
792
|
+
lines.push("alwaysApply: false");
|
|
793
|
+
break;
|
|
794
|
+
case "intelligently":
|
|
795
|
+
lines.push(`description: ${rule.frontmatter.description}`);
|
|
796
|
+
lines.push("globs:");
|
|
797
|
+
lines.push("alwaysApply: false");
|
|
798
|
+
break;
|
|
788
799
|
}
|
|
789
|
-
lines.push(`ruletype: ${ruletype}`);
|
|
790
800
|
lines.push("---");
|
|
801
|
+
lines.push("");
|
|
791
802
|
lines.push(rule.content);
|
|
792
803
|
return lines.join("\n");
|
|
793
804
|
}
|
|
805
|
+
function determineCursorRuleType(frontmatter) {
|
|
806
|
+
if (frontmatter.cursorRuleType) {
|
|
807
|
+
return frontmatter.cursorRuleType;
|
|
808
|
+
}
|
|
809
|
+
const isDescriptionEmpty = !frontmatter.description || frontmatter.description.trim() === "";
|
|
810
|
+
const isGlobsEmpty = frontmatter.globs.length === 0;
|
|
811
|
+
const isGlobsExactlyAllFiles = frontmatter.globs.length === 1 && frontmatter.globs[0] === "**/*";
|
|
812
|
+
if (isGlobsExactlyAllFiles) {
|
|
813
|
+
return "always";
|
|
814
|
+
}
|
|
815
|
+
if (isDescriptionEmpty && isGlobsEmpty) {
|
|
816
|
+
return "manual";
|
|
817
|
+
}
|
|
818
|
+
if (isDescriptionEmpty && !isGlobsEmpty) {
|
|
819
|
+
return "specificFiles";
|
|
820
|
+
}
|
|
821
|
+
if (!isDescriptionEmpty && isGlobsEmpty) {
|
|
822
|
+
return "intelligently";
|
|
823
|
+
}
|
|
824
|
+
return "intelligently";
|
|
825
|
+
}
|
|
794
826
|
function generateCursorIgnore(patterns) {
|
|
795
827
|
const lines = [
|
|
796
828
|
"# Generated by rulesync from .rulesyncignore",
|
|
@@ -1053,9 +1085,9 @@ function validateFrontmatter(data, filepath) {
|
|
|
1053
1085
|
`Missing required field "description" in ${filepath}: must be a descriptive string`
|
|
1054
1086
|
);
|
|
1055
1087
|
}
|
|
1056
|
-
if (
|
|
1088
|
+
if (typeof obj.description !== "string") {
|
|
1057
1089
|
throw new Error(
|
|
1058
|
-
`Invalid "description" field in ${filepath}: must be a
|
|
1090
|
+
`Invalid "description" field in ${filepath}: must be a string, got ${typeof obj.description}`
|
|
1059
1091
|
);
|
|
1060
1092
|
}
|
|
1061
1093
|
if (obj.globs === void 0) {
|
|
@@ -1128,7 +1160,6 @@ async function validateRule(rule) {
|
|
|
1128
1160
|
}
|
|
1129
1161
|
|
|
1130
1162
|
// src/core/mcp-generator.ts
|
|
1131
|
-
var import_node_os = __toESM(require("os"), 1);
|
|
1132
1163
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
1133
1164
|
|
|
1134
1165
|
// src/generators/mcp/index.ts
|
|
@@ -1180,7 +1211,7 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1180
1211
|
{
|
|
1181
1212
|
tool: "claude-project",
|
|
1182
1213
|
path: import_node_path13.default.join(targetRoot, ".mcp.json"),
|
|
1183
|
-
generate: () => generateClaudeMcp(config
|
|
1214
|
+
generate: () => generateClaudeMcp(config)
|
|
1184
1215
|
},
|
|
1185
1216
|
{
|
|
1186
1217
|
tool: "copilot-editor",
|
|
@@ -1190,43 +1221,24 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
1190
1221
|
{
|
|
1191
1222
|
tool: "cursor-project",
|
|
1192
1223
|
path: import_node_path13.default.join(targetRoot, ".cursor", "mcp.json"),
|
|
1193
|
-
generate: () => generateCursorMcp(config
|
|
1224
|
+
generate: () => generateCursorMcp(config)
|
|
1194
1225
|
},
|
|
1195
1226
|
{
|
|
1196
1227
|
tool: "cline-project",
|
|
1197
1228
|
path: import_node_path13.default.join(targetRoot, ".cline", "mcp.json"),
|
|
1198
|
-
generate: () => generateClineMcp(config
|
|
1229
|
+
generate: () => generateClineMcp(config)
|
|
1199
1230
|
},
|
|
1200
1231
|
{
|
|
1201
1232
|
tool: "gemini-project",
|
|
1202
1233
|
path: import_node_path13.default.join(targetRoot, ".gemini", "settings.json"),
|
|
1203
|
-
generate: () => generateGeminiCliMcp(config
|
|
1234
|
+
generate: () => generateGeminiCliMcp(config)
|
|
1204
1235
|
},
|
|
1205
1236
|
{
|
|
1206
1237
|
tool: "roo-project",
|
|
1207
1238
|
path: import_node_path13.default.join(targetRoot, ".roo", "mcp.json"),
|
|
1208
|
-
generate: () => generateRooMcp(config
|
|
1239
|
+
generate: () => generateRooMcp(config)
|
|
1209
1240
|
}
|
|
1210
1241
|
];
|
|
1211
|
-
if (!baseDir) {
|
|
1212
|
-
generators.push(
|
|
1213
|
-
{
|
|
1214
|
-
tool: "claude-global",
|
|
1215
|
-
path: import_node_path13.default.join(import_node_os.default.homedir(), ".claude", "settings.json"),
|
|
1216
|
-
generate: () => generateClaudeMcp(config, "global")
|
|
1217
|
-
},
|
|
1218
|
-
{
|
|
1219
|
-
tool: "cursor-global",
|
|
1220
|
-
path: import_node_path13.default.join(import_node_os.default.homedir(), ".cursor", "mcp.json"),
|
|
1221
|
-
generate: () => generateCursorMcp(config, "global")
|
|
1222
|
-
},
|
|
1223
|
-
{
|
|
1224
|
-
tool: "gemini-global",
|
|
1225
|
-
path: import_node_path13.default.join(import_node_os.default.homedir(), ".gemini", "settings.json"),
|
|
1226
|
-
generate: () => generateGeminiCliMcp(config, "global")
|
|
1227
|
-
}
|
|
1228
|
-
);
|
|
1229
|
-
}
|
|
1230
1242
|
for (const generator of generators) {
|
|
1231
1243
|
try {
|
|
1232
1244
|
const content = generator.generate();
|
|
@@ -1419,7 +1431,7 @@ var gitignoreCommand = async () => {
|
|
|
1419
1431
|
}
|
|
1420
1432
|
}
|
|
1421
1433
|
if (linesToAdd.length === 0) {
|
|
1422
|
-
console.log("\u2705 .gitignore
|
|
1434
|
+
console.log("\u2705 .gitignore is already up to date");
|
|
1423
1435
|
return;
|
|
1424
1436
|
}
|
|
1425
1437
|
const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
|
|
@@ -1428,7 +1440,7 @@ ${linesToAdd.join("\n")}
|
|
|
1428
1440
|
` : `${linesToAdd.join("\n")}
|
|
1429
1441
|
`;
|
|
1430
1442
|
(0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
|
|
1431
|
-
console.log(`\u2705
|
|
1443
|
+
console.log(`\u2705 Added ${linesToAdd.length} rules to .gitignore:`);
|
|
1432
1444
|
for (const line of linesToAdd) {
|
|
1433
1445
|
if (!line.startsWith("#")) {
|
|
1434
1446
|
console.log(` ${line}`);
|
|
@@ -1732,7 +1744,7 @@ var customMatterOptions = {
|
|
|
1732
1744
|
yaml: {
|
|
1733
1745
|
parse: (str) => {
|
|
1734
1746
|
try {
|
|
1735
|
-
|
|
1747
|
+
let preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"').replace(/^(\s*globs:\s*)([^\s"'[\n][^"'[\n]*?)(\s*)$/gm, '$1"$2"$3');
|
|
1736
1748
|
return (0, import_js_yaml.load)(preprocessed, { schema: import_js_yaml.DEFAULT_SCHEMA });
|
|
1737
1749
|
} catch (error) {
|
|
1738
1750
|
try {
|
|
@@ -1745,6 +1757,85 @@ var customMatterOptions = {
|
|
|
1745
1757
|
}
|
|
1746
1758
|
}
|
|
1747
1759
|
};
|
|
1760
|
+
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1761
|
+
const frontmatter = cursorFrontmatter;
|
|
1762
|
+
const description = normalizeValue(frontmatter?.description);
|
|
1763
|
+
const globs = normalizeGlobsValue(frontmatter?.globs);
|
|
1764
|
+
const alwaysApply = frontmatter?.alwaysApply === true || frontmatter?.alwaysApply === "true";
|
|
1765
|
+
if (alwaysApply) {
|
|
1766
|
+
return {
|
|
1767
|
+
root: false,
|
|
1768
|
+
targets: ["*"],
|
|
1769
|
+
description: description || "",
|
|
1770
|
+
globs: ["**/*"],
|
|
1771
|
+
cursorRuleType: "always"
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
if (isEmpty(description) && isEmpty(globs)) {
|
|
1775
|
+
return {
|
|
1776
|
+
root: false,
|
|
1777
|
+
targets: ["*"],
|
|
1778
|
+
description: "",
|
|
1779
|
+
globs: [],
|
|
1780
|
+
cursorRuleType: "manual"
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
if (!isEmpty(globs)) {
|
|
1784
|
+
return {
|
|
1785
|
+
root: false,
|
|
1786
|
+
targets: ["*"],
|
|
1787
|
+
description: "",
|
|
1788
|
+
globs: convertGlobsToArray(globs),
|
|
1789
|
+
cursorRuleType: "specificFiles"
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
if (!isEmpty(description)) {
|
|
1793
|
+
return {
|
|
1794
|
+
root: false,
|
|
1795
|
+
targets: ["*"],
|
|
1796
|
+
description,
|
|
1797
|
+
globs: [],
|
|
1798
|
+
cursorRuleType: "intelligently"
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
return {
|
|
1802
|
+
root: false,
|
|
1803
|
+
targets: ["*"],
|
|
1804
|
+
description: "",
|
|
1805
|
+
globs: [],
|
|
1806
|
+
cursorRuleType: "manual"
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
function normalizeValue(value) {
|
|
1810
|
+
if (value === void 0 || value === null || value === "") {
|
|
1811
|
+
return void 0;
|
|
1812
|
+
}
|
|
1813
|
+
return String(value);
|
|
1814
|
+
}
|
|
1815
|
+
function normalizeGlobsValue(value) {
|
|
1816
|
+
if (value === void 0 || value === null || value === "") {
|
|
1817
|
+
return void 0;
|
|
1818
|
+
}
|
|
1819
|
+
if (Array.isArray(value)) {
|
|
1820
|
+
return value.length === 0 ? void 0 : value;
|
|
1821
|
+
}
|
|
1822
|
+
return String(value);
|
|
1823
|
+
}
|
|
1824
|
+
function isEmpty(value) {
|
|
1825
|
+
return value === void 0 || value === null || value === "";
|
|
1826
|
+
}
|
|
1827
|
+
function convertGlobsToArray(globs) {
|
|
1828
|
+
if (!globs) {
|
|
1829
|
+
return [];
|
|
1830
|
+
}
|
|
1831
|
+
if (Array.isArray(globs)) {
|
|
1832
|
+
return globs;
|
|
1833
|
+
}
|
|
1834
|
+
if (typeof globs === "string") {
|
|
1835
|
+
return globs.split(",").map((g) => g.trim()).filter((g) => g.length > 0);
|
|
1836
|
+
}
|
|
1837
|
+
return [];
|
|
1838
|
+
}
|
|
1748
1839
|
async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
1749
1840
|
const errors = [];
|
|
1750
1841
|
const rules = [];
|
|
@@ -1757,12 +1848,8 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1757
1848
|
const parsed = (0, import_gray_matter3.default)(rawContent, customMatterOptions);
|
|
1758
1849
|
const content = parsed.content.trim();
|
|
1759
1850
|
if (content) {
|
|
1760
|
-
const frontmatter =
|
|
1761
|
-
|
|
1762
|
-
targets: ["cursor"],
|
|
1763
|
-
description: "Cursor IDE configuration rules",
|
|
1764
|
-
globs: ["**/*"]
|
|
1765
|
-
};
|
|
1851
|
+
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
1852
|
+
frontmatter.targets = ["cursor"];
|
|
1766
1853
|
rules.push({
|
|
1767
1854
|
frontmatter,
|
|
1768
1855
|
content,
|
|
@@ -1789,12 +1876,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1789
1876
|
const content = parsed.content.trim();
|
|
1790
1877
|
if (content) {
|
|
1791
1878
|
const filename = (0, import_node_path18.basename)(file, ".mdc");
|
|
1792
|
-
const frontmatter =
|
|
1793
|
-
root: false,
|
|
1794
|
-
targets: ["cursor"],
|
|
1795
|
-
description: `Cursor rule: ${filename}`,
|
|
1796
|
-
globs: ["**/*"]
|
|
1797
|
-
};
|
|
1879
|
+
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
1798
1880
|
rules.push({
|
|
1799
1881
|
frontmatter,
|
|
1800
1882
|
content,
|
|
@@ -2535,7 +2617,7 @@ async function watchCommand() {
|
|
|
2535
2617
|
|
|
2536
2618
|
// src/cli/index.ts
|
|
2537
2619
|
var program = new import_commander.Command();
|
|
2538
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2620
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.42.0");
|
|
2539
2621
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2540
2622
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2541
2623
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
generateClaudeMcp
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HMMPZV7X.js";
|
|
5
5
|
import {
|
|
6
6
|
generateClineMcp
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-X3FEMISQ.js";
|
|
8
8
|
import {
|
|
9
9
|
generateCopilotMcp
|
|
10
10
|
} from "./chunk-SXEFNT27.js";
|
|
11
11
|
import {
|
|
12
12
|
generateCursorMcp
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-D3YGI36J.js";
|
|
14
14
|
import {
|
|
15
15
|
generateGeminiCliMcp
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2SPL7QTK.js";
|
|
17
17
|
import {
|
|
18
18
|
generateRooMcp
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-3NRSCDLQ.js";
|
|
20
20
|
import "./chunk-6YNGMPAL.js";
|
|
21
21
|
|
|
22
22
|
// src/cli/index.ts
|
|
@@ -427,24 +427,56 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
427
427
|
}
|
|
428
428
|
function generateCursorMarkdown(rule) {
|
|
429
429
|
const lines = [];
|
|
430
|
+
const ruleType = determineCursorRuleType(rule.frontmatter);
|
|
430
431
|
lines.push("---");
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
432
|
+
switch (ruleType) {
|
|
433
|
+
case "always":
|
|
434
|
+
lines.push("description:");
|
|
435
|
+
lines.push("globs:");
|
|
436
|
+
lines.push("alwaysApply: true");
|
|
437
|
+
break;
|
|
438
|
+
case "manual":
|
|
439
|
+
lines.push("description:");
|
|
440
|
+
lines.push("globs:");
|
|
441
|
+
lines.push("alwaysApply: false");
|
|
442
|
+
break;
|
|
443
|
+
case "specificFiles":
|
|
444
|
+
lines.push("description:");
|
|
445
|
+
lines.push(`globs: ${rule.frontmatter.globs.join(",")}`);
|
|
446
|
+
lines.push("alwaysApply: false");
|
|
447
|
+
break;
|
|
448
|
+
case "intelligently":
|
|
449
|
+
lines.push(`description: ${rule.frontmatter.description}`);
|
|
450
|
+
lines.push("globs:");
|
|
451
|
+
lines.push("alwaysApply: false");
|
|
452
|
+
break;
|
|
442
453
|
}
|
|
443
|
-
lines.push(`ruletype: ${ruletype}`);
|
|
444
454
|
lines.push("---");
|
|
455
|
+
lines.push("");
|
|
445
456
|
lines.push(rule.content);
|
|
446
457
|
return lines.join("\n");
|
|
447
458
|
}
|
|
459
|
+
function determineCursorRuleType(frontmatter) {
|
|
460
|
+
if (frontmatter.cursorRuleType) {
|
|
461
|
+
return frontmatter.cursorRuleType;
|
|
462
|
+
}
|
|
463
|
+
const isDescriptionEmpty = !frontmatter.description || frontmatter.description.trim() === "";
|
|
464
|
+
const isGlobsEmpty = frontmatter.globs.length === 0;
|
|
465
|
+
const isGlobsExactlyAllFiles = frontmatter.globs.length === 1 && frontmatter.globs[0] === "**/*";
|
|
466
|
+
if (isGlobsExactlyAllFiles) {
|
|
467
|
+
return "always";
|
|
468
|
+
}
|
|
469
|
+
if (isDescriptionEmpty && isGlobsEmpty) {
|
|
470
|
+
return "manual";
|
|
471
|
+
}
|
|
472
|
+
if (isDescriptionEmpty && !isGlobsEmpty) {
|
|
473
|
+
return "specificFiles";
|
|
474
|
+
}
|
|
475
|
+
if (!isDescriptionEmpty && isGlobsEmpty) {
|
|
476
|
+
return "intelligently";
|
|
477
|
+
}
|
|
478
|
+
return "intelligently";
|
|
479
|
+
}
|
|
448
480
|
function generateCursorIgnore(patterns) {
|
|
449
481
|
const lines = [
|
|
450
482
|
"# Generated by rulesync from .rulesyncignore",
|
|
@@ -707,9 +739,9 @@ function validateFrontmatter(data, filepath) {
|
|
|
707
739
|
`Missing required field "description" in ${filepath}: must be a descriptive string`
|
|
708
740
|
);
|
|
709
741
|
}
|
|
710
|
-
if (
|
|
742
|
+
if (typeof obj.description !== "string") {
|
|
711
743
|
throw new Error(
|
|
712
|
-
`Invalid "description" field in ${filepath}: must be a
|
|
744
|
+
`Invalid "description" field in ${filepath}: must be a string, got ${typeof obj.description}`
|
|
713
745
|
);
|
|
714
746
|
}
|
|
715
747
|
if (obj.globs === void 0) {
|
|
@@ -782,7 +814,6 @@ async function validateRule(rule) {
|
|
|
782
814
|
}
|
|
783
815
|
|
|
784
816
|
// src/core/mcp-generator.ts
|
|
785
|
-
import os from "os";
|
|
786
817
|
import path3 from "path";
|
|
787
818
|
|
|
788
819
|
// src/core/mcp-parser.ts
|
|
@@ -826,7 +857,7 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
826
857
|
{
|
|
827
858
|
tool: "claude-project",
|
|
828
859
|
path: path3.join(targetRoot, ".mcp.json"),
|
|
829
|
-
generate: () => generateClaudeMcp(config
|
|
860
|
+
generate: () => generateClaudeMcp(config)
|
|
830
861
|
},
|
|
831
862
|
{
|
|
832
863
|
tool: "copilot-editor",
|
|
@@ -836,43 +867,24 @@ async function generateMcpConfigs(projectRoot, baseDir) {
|
|
|
836
867
|
{
|
|
837
868
|
tool: "cursor-project",
|
|
838
869
|
path: path3.join(targetRoot, ".cursor", "mcp.json"),
|
|
839
|
-
generate: () => generateCursorMcp(config
|
|
870
|
+
generate: () => generateCursorMcp(config)
|
|
840
871
|
},
|
|
841
872
|
{
|
|
842
873
|
tool: "cline-project",
|
|
843
874
|
path: path3.join(targetRoot, ".cline", "mcp.json"),
|
|
844
|
-
generate: () => generateClineMcp(config
|
|
875
|
+
generate: () => generateClineMcp(config)
|
|
845
876
|
},
|
|
846
877
|
{
|
|
847
878
|
tool: "gemini-project",
|
|
848
879
|
path: path3.join(targetRoot, ".gemini", "settings.json"),
|
|
849
|
-
generate: () => generateGeminiCliMcp(config
|
|
880
|
+
generate: () => generateGeminiCliMcp(config)
|
|
850
881
|
},
|
|
851
882
|
{
|
|
852
883
|
tool: "roo-project",
|
|
853
884
|
path: path3.join(targetRoot, ".roo", "mcp.json"),
|
|
854
|
-
generate: () => generateRooMcp(config
|
|
885
|
+
generate: () => generateRooMcp(config)
|
|
855
886
|
}
|
|
856
887
|
];
|
|
857
|
-
if (!baseDir) {
|
|
858
|
-
generators.push(
|
|
859
|
-
{
|
|
860
|
-
tool: "claude-global",
|
|
861
|
-
path: path3.join(os.homedir(), ".claude", "settings.json"),
|
|
862
|
-
generate: () => generateClaudeMcp(config, "global")
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
tool: "cursor-global",
|
|
866
|
-
path: path3.join(os.homedir(), ".cursor", "mcp.json"),
|
|
867
|
-
generate: () => generateCursorMcp(config, "global")
|
|
868
|
-
},
|
|
869
|
-
{
|
|
870
|
-
tool: "gemini-global",
|
|
871
|
-
path: path3.join(os.homedir(), ".gemini", "settings.json"),
|
|
872
|
-
generate: () => generateGeminiCliMcp(config, "global")
|
|
873
|
-
}
|
|
874
|
-
);
|
|
875
|
-
}
|
|
876
888
|
for (const generator of generators) {
|
|
877
889
|
try {
|
|
878
890
|
const content = generator.generate();
|
|
@@ -1065,7 +1077,7 @@ var gitignoreCommand = async () => {
|
|
|
1065
1077
|
}
|
|
1066
1078
|
}
|
|
1067
1079
|
if (linesToAdd.length === 0) {
|
|
1068
|
-
console.log("\u2705 .gitignore
|
|
1080
|
+
console.log("\u2705 .gitignore is already up to date");
|
|
1069
1081
|
return;
|
|
1070
1082
|
}
|
|
1071
1083
|
const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
|
|
@@ -1074,7 +1086,7 @@ ${linesToAdd.join("\n")}
|
|
|
1074
1086
|
` : `${linesToAdd.join("\n")}
|
|
1075
1087
|
`;
|
|
1076
1088
|
writeFileSync(gitignorePath, newContent);
|
|
1077
|
-
console.log(`\u2705
|
|
1089
|
+
console.log(`\u2705 Added ${linesToAdd.length} rules to .gitignore:`);
|
|
1078
1090
|
for (const line of linesToAdd) {
|
|
1079
1091
|
if (!line.startsWith("#")) {
|
|
1080
1092
|
console.log(` ${line}`);
|
|
@@ -1378,7 +1390,7 @@ var customMatterOptions = {
|
|
|
1378
1390
|
yaml: {
|
|
1379
1391
|
parse: (str) => {
|
|
1380
1392
|
try {
|
|
1381
|
-
|
|
1393
|
+
let preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"').replace(/^(\s*globs:\s*)([^\s"'[\n][^"'[\n]*?)(\s*)$/gm, '$1"$2"$3');
|
|
1382
1394
|
return load(preprocessed, { schema: DEFAULT_SCHEMA });
|
|
1383
1395
|
} catch (error) {
|
|
1384
1396
|
try {
|
|
@@ -1391,6 +1403,85 @@ var customMatterOptions = {
|
|
|
1391
1403
|
}
|
|
1392
1404
|
}
|
|
1393
1405
|
};
|
|
1406
|
+
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
1407
|
+
const frontmatter = cursorFrontmatter;
|
|
1408
|
+
const description = normalizeValue(frontmatter?.description);
|
|
1409
|
+
const globs = normalizeGlobsValue(frontmatter?.globs);
|
|
1410
|
+
const alwaysApply = frontmatter?.alwaysApply === true || frontmatter?.alwaysApply === "true";
|
|
1411
|
+
if (alwaysApply) {
|
|
1412
|
+
return {
|
|
1413
|
+
root: false,
|
|
1414
|
+
targets: ["*"],
|
|
1415
|
+
description: description || "",
|
|
1416
|
+
globs: ["**/*"],
|
|
1417
|
+
cursorRuleType: "always"
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
if (isEmpty(description) && isEmpty(globs)) {
|
|
1421
|
+
return {
|
|
1422
|
+
root: false,
|
|
1423
|
+
targets: ["*"],
|
|
1424
|
+
description: "",
|
|
1425
|
+
globs: [],
|
|
1426
|
+
cursorRuleType: "manual"
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
if (!isEmpty(globs)) {
|
|
1430
|
+
return {
|
|
1431
|
+
root: false,
|
|
1432
|
+
targets: ["*"],
|
|
1433
|
+
description: "",
|
|
1434
|
+
globs: convertGlobsToArray(globs),
|
|
1435
|
+
cursorRuleType: "specificFiles"
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
if (!isEmpty(description)) {
|
|
1439
|
+
return {
|
|
1440
|
+
root: false,
|
|
1441
|
+
targets: ["*"],
|
|
1442
|
+
description,
|
|
1443
|
+
globs: [],
|
|
1444
|
+
cursorRuleType: "intelligently"
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
return {
|
|
1448
|
+
root: false,
|
|
1449
|
+
targets: ["*"],
|
|
1450
|
+
description: "",
|
|
1451
|
+
globs: [],
|
|
1452
|
+
cursorRuleType: "manual"
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
function normalizeValue(value) {
|
|
1456
|
+
if (value === void 0 || value === null || value === "") {
|
|
1457
|
+
return void 0;
|
|
1458
|
+
}
|
|
1459
|
+
return String(value);
|
|
1460
|
+
}
|
|
1461
|
+
function normalizeGlobsValue(value) {
|
|
1462
|
+
if (value === void 0 || value === null || value === "") {
|
|
1463
|
+
return void 0;
|
|
1464
|
+
}
|
|
1465
|
+
if (Array.isArray(value)) {
|
|
1466
|
+
return value.length === 0 ? void 0 : value;
|
|
1467
|
+
}
|
|
1468
|
+
return String(value);
|
|
1469
|
+
}
|
|
1470
|
+
function isEmpty(value) {
|
|
1471
|
+
return value === void 0 || value === null || value === "";
|
|
1472
|
+
}
|
|
1473
|
+
function convertGlobsToArray(globs) {
|
|
1474
|
+
if (!globs) {
|
|
1475
|
+
return [];
|
|
1476
|
+
}
|
|
1477
|
+
if (Array.isArray(globs)) {
|
|
1478
|
+
return globs;
|
|
1479
|
+
}
|
|
1480
|
+
if (typeof globs === "string") {
|
|
1481
|
+
return globs.split(",").map((g) => g.trim()).filter((g) => g.length > 0);
|
|
1482
|
+
}
|
|
1483
|
+
return [];
|
|
1484
|
+
}
|
|
1394
1485
|
async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
1395
1486
|
const errors = [];
|
|
1396
1487
|
const rules = [];
|
|
@@ -1403,12 +1494,8 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1403
1494
|
const parsed = matter3(rawContent, customMatterOptions);
|
|
1404
1495
|
const content = parsed.content.trim();
|
|
1405
1496
|
if (content) {
|
|
1406
|
-
const frontmatter =
|
|
1407
|
-
|
|
1408
|
-
targets: ["cursor"],
|
|
1409
|
-
description: "Cursor IDE configuration rules",
|
|
1410
|
-
globs: ["**/*"]
|
|
1411
|
-
};
|
|
1497
|
+
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
1498
|
+
frontmatter.targets = ["cursor"];
|
|
1412
1499
|
rules.push({
|
|
1413
1500
|
frontmatter,
|
|
1414
1501
|
content,
|
|
@@ -1435,12 +1522,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
1435
1522
|
const content = parsed.content.trim();
|
|
1436
1523
|
if (content) {
|
|
1437
1524
|
const filename = basename4(file, ".mdc");
|
|
1438
|
-
const frontmatter =
|
|
1439
|
-
root: false,
|
|
1440
|
-
targets: ["cursor"],
|
|
1441
|
-
description: `Cursor rule: ${filename}`,
|
|
1442
|
-
globs: ["**/*"]
|
|
1443
|
-
};
|
|
1525
|
+
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
1444
1526
|
rules.push({
|
|
1445
1527
|
frontmatter,
|
|
1446
1528
|
content,
|
|
@@ -2181,7 +2263,7 @@ async function watchCommand() {
|
|
|
2181
2263
|
|
|
2182
2264
|
// src/cli/index.ts
|
|
2183
2265
|
var program = new Command();
|
|
2184
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
2266
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.42.0");
|
|
2185
2267
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
2186
2268
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
2187
2269
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|