rulesync 0.36.0 → 0.37.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/dist/index.mjs CHANGED
@@ -1,22 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  generateClaudeMcp
4
- } from "./chunk-UNTCJDMQ.mjs";
4
+ } from "./chunk-2BYTQ4LL.mjs";
5
5
  import {
6
6
  generateClineMcp
7
- } from "./chunk-QHXMJZTJ.mjs";
7
+ } from "./chunk-2CDVII2R.mjs";
8
8
  import {
9
9
  generateCopilotMcp
10
- } from "./chunk-YGXGGUBG.mjs";
10
+ } from "./chunk-TKNVMYAC.mjs";
11
11
  import {
12
12
  generateCursorMcp
13
- } from "./chunk-SBYRCTWS.mjs";
13
+ } from "./chunk-KZATM2CQ.mjs";
14
14
  import {
15
15
  generateGeminiCliMcp
16
- } from "./chunk-6PQ4APY4.mjs";
16
+ } from "./chunk-PBOKMNYU.mjs";
17
17
  import {
18
18
  generateRooMcp
19
- } from "./chunk-QVPQ2X4L.mjs";
19
+ } from "./chunk-3GVVX3G5.mjs";
20
+ import "./chunk-QQN5GTOV.mjs";
20
21
 
21
22
  // src/cli/index.ts
22
23
  import { Command } from "commander";
@@ -89,8 +90,34 @@ async function addCommand(filename) {
89
90
  import { join as join3 } from "path";
90
91
 
91
92
  // src/utils/file.ts
92
- import { mkdir as mkdir2, readdir, readFile, rm, stat, writeFile as writeFile2 } from "fs/promises";
93
- import { dirname, join as join2 } from "path";
93
+ import { readdir, rm } from "fs/promises";
94
+ import { join as join2 } from "path";
95
+
96
+ // src/utils/file-ops.ts
97
+ import { mkdir as mkdir2, readFile, stat, writeFile as writeFile2 } from "fs/promises";
98
+ import { dirname } from "path";
99
+ async function ensureDir(dirPath) {
100
+ try {
101
+ await stat(dirPath);
102
+ } catch {
103
+ await mkdir2(dirPath, { recursive: true });
104
+ }
105
+ }
106
+ async function readFileContent(filepath) {
107
+ return readFile(filepath, "utf-8");
108
+ }
109
+ async function writeFileContent(filepath, content) {
110
+ await ensureDir(dirname(filepath));
111
+ await writeFile2(filepath, content, "utf-8");
112
+ }
113
+ async function fileExists(filepath) {
114
+ try {
115
+ await stat(filepath);
116
+ return true;
117
+ } catch {
118
+ return false;
119
+ }
120
+ }
94
121
 
95
122
  // src/utils/ignore.ts
96
123
  import { join } from "path";
@@ -144,20 +171,6 @@ function filterIgnoredFiles(files, ignorePatterns) {
144
171
  }
145
172
 
146
173
  // src/utils/file.ts
147
- async function ensureDir(dirPath) {
148
- try {
149
- await stat(dirPath);
150
- } catch {
151
- await mkdir2(dirPath, { recursive: true });
152
- }
153
- }
154
- async function readFileContent(filepath) {
155
- return readFile(filepath, "utf-8");
156
- }
157
- async function writeFileContent(filepath, content) {
158
- await ensureDir(dirname(filepath));
159
- await writeFile2(filepath, content, "utf-8");
160
- }
161
174
  async function findFiles(dir, extension = ".md", ignorePatterns) {
162
175
  try {
163
176
  const files = await readdir(dir);
@@ -170,14 +183,6 @@ async function findFiles(dir, extension = ".md", ignorePatterns) {
170
183
  return [];
171
184
  }
172
185
  }
173
- async function fileExists(filepath) {
174
- try {
175
- await stat(filepath);
176
- return true;
177
- } catch {
178
- return false;
179
- }
180
- }
181
186
  async function removeDirectory(dirPath) {
182
187
  const dangerousPaths = [".", "/", "~", "src", "node_modules"];
183
188
  if (dangerousPaths.includes(dirPath) || dirPath === "") {
@@ -271,27 +276,34 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
271
276
  try {
272
277
  const content = await readFileContent(settingsPath);
273
278
  settings = JSON.parse(content);
274
- } catch (_error) {
279
+ } catch {
275
280
  console.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
276
281
  settings = {};
277
282
  }
278
283
  }
279
- if (!settings.permissions) {
280
- settings.permissions = {};
284
+ if (typeof settings !== "object" || settings === null) {
285
+ settings = {};
286
+ }
287
+ const settingsObj = settings;
288
+ if (!settingsObj.permissions || typeof settingsObj.permissions !== "object" || settingsObj.permissions === null) {
289
+ settingsObj.permissions = {};
281
290
  }
282
- if (!Array.isArray(settings.permissions.deny)) {
283
- settings.permissions.deny = [];
291
+ const permissions = settingsObj.permissions;
292
+ if (!Array.isArray(permissions.deny)) {
293
+ permissions.deny = [];
284
294
  }
285
295
  const readDenyRules = ignorePatterns.map((pattern) => `Read(${pattern})`);
286
- settings.permissions.deny = settings.permissions.deny.filter((rule) => {
296
+ const denyArray = permissions.deny;
297
+ const filteredDeny = denyArray.filter((rule) => {
298
+ if (typeof rule !== "string") return false;
287
299
  if (!rule.startsWith("Read(")) return true;
288
300
  const match = rule.match(/^Read\((.*)\)$/);
289
301
  if (!match) return true;
290
302
  return !ignorePatterns.includes(match[1] ?? "");
291
303
  });
292
- settings.permissions.deny.push(...readDenyRules);
293
- settings.permissions.deny = [...new Set(settings.permissions.deny)];
294
- const jsonContent = JSON.stringify(settings, null, 2);
304
+ filteredDeny.push(...readDenyRules);
305
+ permissions.deny = [...new Set(filteredDeny)];
306
+ const jsonContent = JSON.stringify(settingsObj, null, 2);
295
307
  await writeFileContent(settingsPath, jsonContent);
296
308
  console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
297
309
  }
@@ -1172,7 +1184,7 @@ async function parseClaudeMemoryFiles(memoryDir) {
1172
1184
  }
1173
1185
  }
1174
1186
  }
1175
- } catch (_error) {
1187
+ } catch {
1176
1188
  }
1177
1189
  return rules;
1178
1190
  }
@@ -1183,17 +1195,25 @@ async function parseClaudeSettings(settingsPath) {
1183
1195
  try {
1184
1196
  const content = await readFileContent(settingsPath);
1185
1197
  const settings = JSON.parse(content);
1186
- if (settings.permissions?.deny) {
1187
- const readPatterns = settings.permissions.deny.filter((rule) => rule.startsWith("Read(") && rule.endsWith(")")).map((rule) => {
1188
- const match = rule.match(/^Read\((.+)\)$/);
1189
- return match ? match[1] : null;
1190
- }).filter((pattern) => pattern !== null);
1191
- if (readPatterns.length > 0) {
1192
- ignorePatterns = readPatterns;
1198
+ if (typeof settings === "object" && settings !== null && "permissions" in settings) {
1199
+ const permissions = settings.permissions;
1200
+ if (permissions && "deny" in permissions && Array.isArray(permissions.deny)) {
1201
+ const readPatterns = permissions.deny.filter(
1202
+ (rule) => typeof rule === "string" && rule.startsWith("Read(") && rule.endsWith(")")
1203
+ ).map((rule) => {
1204
+ const match = rule.match(/^Read\((.+)\)$/);
1205
+ return match ? match[1] : null;
1206
+ }).filter((pattern) => pattern !== null);
1207
+ if (readPatterns.length > 0) {
1208
+ ignorePatterns = readPatterns;
1209
+ }
1193
1210
  }
1194
1211
  }
1195
- if (settings.mcpServers && Object.keys(settings.mcpServers).length > 0) {
1196
- mcpServers = settings.mcpServers;
1212
+ if (typeof settings === "object" && settings !== null && "mcpServers" in settings) {
1213
+ const servers = settings.mcpServers;
1214
+ if (servers && typeof servers === "object" && Object.keys(servers).length > 0) {
1215
+ mcpServers = servers;
1216
+ }
1197
1217
  }
1198
1218
  } catch (error) {
1199
1219
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1351,17 +1371,17 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
1351
1371
  // src/parsers/cursor.ts
1352
1372
  import { basename as basename4, join as join13 } from "path";
1353
1373
  import matter3 from "gray-matter";
1354
- import yaml from "js-yaml";
1374
+ import { DEFAULT_SCHEMA, FAILSAFE_SCHEMA, load } from "js-yaml";
1355
1375
  var customMatterOptions = {
1356
1376
  engines: {
1357
1377
  yaml: {
1358
1378
  parse: (str) => {
1359
1379
  try {
1360
1380
  const preprocessed = str.replace(/^(\s*globs:\s*)\*\s*$/gm, '$1"*"');
1361
- return yaml.load(preprocessed, { schema: yaml.DEFAULT_SCHEMA });
1381
+ return load(preprocessed, { schema: DEFAULT_SCHEMA });
1362
1382
  } catch (error) {
1363
1383
  try {
1364
- return yaml.load(str, { schema: yaml.FAILSAFE_SCHEMA });
1384
+ return load(str, { schema: FAILSAFE_SCHEMA });
1365
1385
  } catch {
1366
1386
  throw error;
1367
1387
  }
@@ -1581,7 +1601,7 @@ async function parseGeminiMemoryFiles(memoryDir) {
1581
1601
  }
1582
1602
  }
1583
1603
  }
1584
- } catch (_error) {
1604
+ } catch {
1585
1605
  }
1586
1606
  return rules;
1587
1607
  }
@@ -1608,7 +1628,7 @@ async function parseAiexclude(aiexcludePath) {
1608
1628
  const content = await readFileContent(aiexcludePath);
1609
1629
  const patterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1610
1630
  return patterns;
1611
- } catch (_error) {
1631
+ } catch {
1612
1632
  return [];
1613
1633
  }
1614
1634
  }
@@ -2119,13 +2139,13 @@ async function validateCommand() {
2119
2139
  }
2120
2140
 
2121
2141
  // src/cli/commands/watch.ts
2122
- import chokidar from "chokidar";
2142
+ import { watch } from "chokidar";
2123
2143
  async function watchCommand() {
2124
2144
  const config = getDefaultConfig();
2125
2145
  console.log("\u{1F440} Watching for changes in .rulesync directory...");
2126
2146
  console.log("Press Ctrl+C to stop watching");
2127
2147
  await generateCommand({ verbose: false });
2128
- const watcher = chokidar.watch(`${config.aiRulesDir}/**/*.md`, {
2148
+ const watcher = watch(`${config.aiRulesDir}/**/*.md`, {
2129
2149
  ignoreInitial: true,
2130
2150
  persistent: true
2131
2151
  });
@@ -2160,7 +2180,7 @@ async function watchCommand() {
2160
2180
 
2161
2181
  // src/cli/index.ts
2162
2182
  var program = new Command();
2163
- program.name("rulesync").description("Unified AI rules management CLI tool").version("0.36.0");
2183
+ program.name("rulesync").description("Unified AI rules management CLI tool").version("0.37.0");
2164
2184
  program.command("init").description("Initialize rulesync in current directory").action(initCommand);
2165
2185
  program.command("add <filename>").description("Add a new rule file").action(addCommand);
2166
2186
  program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  generateRooMcp,
3
3
  generateRooMcpConfiguration
4
- } from "./chunk-QVPQ2X4L.mjs";
4
+ } from "./chunk-3GVVX3G5.mjs";
5
+ import "./chunk-QQN5GTOV.mjs";
5
6
  export {
6
7
  generateRooMcp,
7
8
  generateRooMcpConfiguration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",
@@ -37,7 +37,8 @@
37
37
  "gray-matter": "4.0.3",
38
38
  "js-yaml": "4.1.0",
39
39
  "marked": "15.0.12",
40
- "micromatch": "4.0.8"
40
+ "micromatch": "4.0.8",
41
+ "zod": "3.25.67"
41
42
  },
42
43
  "devDependencies": {
43
44
  "@biomejs/biome": "2.0.0",
@@ -48,7 +49,9 @@
48
49
  "@types/node": "24.0.3",
49
50
  "@typescript/native-preview": "7.0.0-dev.20250623.1",
50
51
  "@vitest/coverage-v8": "3.2.4",
52
+ "lint-staged": "16.1.2",
51
53
  "o3-search-mcp": "0.0.3",
54
+ "oxlint": "1.4.0",
52
55
  "secretlint": "10.1.0",
53
56
  "simple-git-hooks": "2.13.0",
54
57
  "sort-package-json": "3.2.1",
@@ -64,19 +67,29 @@
64
67
  "access": "public"
65
68
  },
66
69
  "simple-git-hooks": {
67
- "pre-commit": "pnpm check && pnpm test && pnpm secretlint"
70
+ "pre-commit": "pnpm exec lint-staged"
71
+ },
72
+ "lint-staged": {
73
+ "*.{ts,js}": [
74
+ "biome check --write",
75
+ "oxlint --fix"
76
+ ],
77
+ "*.ts": [
78
+ "tsgo --noEmit"
79
+ ],
80
+ "**/*": [
81
+ "secretlint"
82
+ ]
68
83
  },
69
84
  "scripts": {
70
85
  "bcheck": "biome check src/",
71
86
  "bcheck:fix": "biome check --write src/",
72
87
  "build": "tsup src/cli/index.ts --format cjs,esm --dts --clean",
73
- "check": "pnpm run lint && pnpm run format && pnpm run bcheck && pnpm run typecheck",
88
+ "check": "pnpm run bcheck && pnpm run lint && pnpm run typecheck",
74
89
  "dev": "tsx src/cli/index.ts",
75
- "fix": "pnpm run lint:fix && pnpm run format:fix && pnpm run bcheck:fix",
76
- "format": "biome format src/",
77
- "format:fix": "biome format --write src/",
78
- "lint": "biome lint src/",
79
- "lint:fix": "biome lint --write src/",
90
+ "fix": "pnpm run bcheck:fix && pnpm run lint:fix",
91
+ "lint": "oxlint . --max-warnings 0",
92
+ "lint:fix": "oxlint . --fix --max-warnings 0",
80
93
  "secretlint": "secretlint \"**/*\"",
81
94
  "sort": "sort-package-json",
82
95
  "test": "vitest run --silent",