rulesync 0.65.0 → 0.68.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "0.65.0",
3
+ "version": "0.68.1",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",
@@ -40,13 +40,16 @@
40
40
  "chokidar": "4.0.3",
41
41
  "commander": "14.0.0",
42
42
  "consola": "3.4.2",
43
+ "es-toolkit": "1.39.10",
43
44
  "fast-xml-parser": "5.2.5",
44
45
  "gray-matter": "4.0.3",
45
46
  "js-yaml": "4.1.0",
46
47
  "micromatch": "4.0.8",
48
+ "smol-toml": "1.4.2",
47
49
  "zod": "4.0.17"
48
50
  },
49
51
  "devDependencies": {
52
+ "@anthropic-ai/claude-code": "1.0.93",
50
53
  "@biomejs/biome": "2.1.4",
51
54
  "@eslint/js": "9.33.0",
52
55
  "@secretlint/secretlint-rule-preset-recommend": "11.0.2",
@@ -58,8 +61,10 @@
58
61
  "@vitest/coverage-v8": "3.2.4",
59
62
  "cspell": "9.2.0",
60
63
  "eslint": "9.33.0",
64
+ "eslint-plugin-import": "2.32.0",
61
65
  "eslint-plugin-no-type-assertion": "1.3.0",
62
66
  "eslint-plugin-oxlint": "1.11.2",
67
+ "eslint-plugin-strict-dependencies": "1.3.22",
63
68
  "eslint-plugin-zod-import": "0.3.0",
64
69
  "knip": "5.62.0",
65
70
  "lint-staged": "16.1.5",
@@ -81,8 +86,8 @@
81
86
  "access": "public"
82
87
  },
83
88
  "scripts": {
84
- "bcheck": "biome check src/",
85
- "bcheck:fix": "biome check --write src/",
89
+ "bcheck": "biome check .",
90
+ "bcheck:fix": "biome check --write .",
86
91
  "build": "tsup src/cli/index.ts --format cjs,esm --dts --clean",
87
92
  "check": "pnpm run bcheck && pnpm run oxlint && pnpm run eslint && pnpm run typecheck",
88
93
  "cspell": "cspell \"**/*\"",
@@ -1,9 +0,0 @@
1
- import {
2
- generateAmazonqcliMcp,
3
- generateAmazonqcliMcpString
4
- } from "./chunk-DM2B7XUB.js";
5
- import "./chunk-M2AUM37M.js";
6
- export {
7
- generateAmazonqcliMcp,
8
- generateAmazonqcliMcpString
9
- };
@@ -1,9 +0,0 @@
1
- import {
2
- generateAugmentcodeMcp,
3
- generateAugmentcodeMcpConfiguration
4
- } from "./chunk-I4NVS7GE.js";
5
- import "./chunk-M2AUM37M.js";
6
- export {
7
- generateAugmentcodeMcp,
8
- generateAugmentcodeMcpConfiguration
9
- };
@@ -1,81 +0,0 @@
1
- import {
2
- shouldIncludeServer
3
- } from "./chunk-M2AUM37M.js";
4
-
5
- // src/generators/mcp/copilot.ts
6
- function generateCopilotMcp(config, target) {
7
- const servers = {};
8
- const inputs = [];
9
- const inputMap = /* @__PURE__ */ new Map();
10
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
11
- if (!shouldIncludeServer(server, "copilot")) continue;
12
- const copilotServer = {};
13
- if (server.command) {
14
- const command = Array.isArray(server.command) ? server.command[0] : server.command;
15
- if (command) {
16
- copilotServer.command = command;
17
- }
18
- if (server.args) copilotServer.args = server.args;
19
- } else if (server.url || server.httpUrl) {
20
- const url = server.httpUrl || server.url;
21
- if (url) {
22
- copilotServer.url = url;
23
- }
24
- }
25
- if (server.env) {
26
- copilotServer.env = {};
27
- for (const [key, value] of Object.entries(server.env)) {
28
- if (target === "editor" && value.includes("SECRET")) {
29
- const inputId = `${serverName}_${key}`;
30
- inputMap.set(inputId, value);
31
- copilotServer.env[key] = `\${input:${inputId}}`;
32
- inputs.push({
33
- id: inputId,
34
- type: "password",
35
- description: `${key} for ${serverName}`
36
- });
37
- } else {
38
- copilotServer.env[key] = value;
39
- }
40
- }
41
- }
42
- if (server.tools) {
43
- copilotServer.tools = server.tools;
44
- } else if (server.alwaysAllow) {
45
- copilotServer.tools = server.alwaysAllow;
46
- }
47
- servers[serverName] = copilotServer;
48
- }
49
- if (target === "codingAgent") {
50
- const config2 = { mcpServers: servers };
51
- return JSON.stringify(config2, null, 2);
52
- } else {
53
- const config2 = { servers };
54
- if (inputs.length > 0) {
55
- config2.inputs = inputs;
56
- }
57
- return JSON.stringify(config2, null, 2);
58
- }
59
- }
60
- function generateCopilotMcpConfiguration(mcpServers, baseDir = "") {
61
- const configs = [];
62
- const rulesyncConfig = { mcpServers };
63
- const editorContent = generateCopilotMcp(rulesyncConfig, "editor");
64
- configs.push({
65
- filepath: baseDir ? `${baseDir}/.vscode/mcp.json` : ".vscode/mcp.json",
66
- content: `${editorContent}
67
- `
68
- });
69
- const codingAgentContent = generateCopilotMcp(rulesyncConfig, "codingAgent");
70
- configs.push({
71
- filepath: baseDir ? `${baseDir}/.copilot/mcp.json` : ".copilot/mcp.json",
72
- content: `${codingAgentContent}
73
- `
74
- });
75
- return configs;
76
- }
77
-
78
- export {
79
- generateCopilotMcp,
80
- generateCopilotMcpConfiguration
81
- };
@@ -1,17 +0,0 @@
1
- import {
2
- generateMcpConfigurationFilesFromRegistry,
3
- generateMcpFromRegistry
4
- } from "./chunk-JXOLLTNV.js";
5
-
6
- // src/generators/mcp/geminicli.ts
7
- function generateGeminiCliMcp(config) {
8
- return generateMcpFromRegistry("geminicli", config);
9
- }
10
- function generateGeminiCliMcpConfiguration(mcpServers, baseDir = "") {
11
- return generateMcpConfigurationFilesFromRegistry("geminicli", mcpServers, baseDir);
12
- }
13
-
14
- export {
15
- generateGeminiCliMcp,
16
- generateGeminiCliMcpConfiguration
17
- };
@@ -1,86 +0,0 @@
1
- import {
2
- shouldIncludeServer
3
- } from "./chunk-M2AUM37M.js";
4
-
5
- // src/generators/mcp/kiro.ts
6
- function generateKiroMcp(config) {
7
- const kiroConfig = {
8
- mcpServers: {}
9
- };
10
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
11
- if (!shouldIncludeServer(server, "kiro")) continue;
12
- const kiroServer = {};
13
- if (server.command) {
14
- kiroServer.command = server.command;
15
- if (server.args) kiroServer.args = server.args;
16
- } else if (server.url || server.httpUrl) {
17
- const url = server.httpUrl || server.url;
18
- if (url) {
19
- kiroServer.url = url;
20
- }
21
- if (server.httpUrl || server.transport === "http") {
22
- kiroServer.transport = "streamable-http";
23
- } else if (server.transport === "sse" || server.type === "sse") {
24
- kiroServer.transport = "sse";
25
- }
26
- }
27
- if (server.env) {
28
- kiroServer.env = server.env;
29
- }
30
- if (server.timeout) {
31
- kiroServer.timeout = server.timeout;
32
- }
33
- if (server.disabled !== void 0) {
34
- kiroServer.disabled = server.disabled;
35
- }
36
- if (server.transport) {
37
- kiroServer.transport = server.transport;
38
- }
39
- if (server.kiroAutoApprove) {
40
- kiroServer.autoApprove = server.kiroAutoApprove;
41
- }
42
- if (server.kiroAutoBlock) {
43
- kiroServer.autoBlock = server.kiroAutoBlock;
44
- }
45
- kiroConfig.mcpServers[serverName] = kiroServer;
46
- }
47
- return JSON.stringify(kiroConfig, null, 2);
48
- }
49
- function generateKiroMcpConfiguration(mcpServers, baseDir = "") {
50
- const filepath = baseDir ? `${baseDir}/.kiro/mcp.json` : ".kiro/mcp.json";
51
- const config = {
52
- mcpServers: {}
53
- };
54
- for (const [serverName, server] of Object.entries(mcpServers)) {
55
- if (!shouldIncludeServer(server, "kiro")) {
56
- continue;
57
- }
58
- const { targets: _targets, ...serverConfig } = server;
59
- const kiroServer = { ...serverConfig };
60
- if (serverConfig.httpUrl !== void 0) {
61
- kiroServer.url = serverConfig.httpUrl;
62
- delete kiroServer.httpUrl;
63
- }
64
- if (serverConfig.kiroAutoApprove !== void 0) {
65
- kiroServer.autoApprove = serverConfig.kiroAutoApprove;
66
- delete kiroServer.kiroAutoApprove;
67
- }
68
- if (serverConfig.kiroAutoBlock !== void 0) {
69
- kiroServer.autoBlock = serverConfig.kiroAutoBlock;
70
- delete kiroServer.kiroAutoBlock;
71
- }
72
- config.mcpServers[serverName] = kiroServer;
73
- }
74
- return [
75
- {
76
- filepath,
77
- content: `${JSON.stringify(config, null, 2)}
78
- `
79
- }
80
- ];
81
- }
82
-
83
- export {
84
- generateKiroMcp,
85
- generateKiroMcpConfiguration
86
- };
@@ -1,210 +0,0 @@
1
- import {
2
- shouldIncludeServer
3
- } from "./chunk-M2AUM37M.js";
4
-
5
- // src/utils/file.ts
6
- import { mkdir, readdir, readFile, rm, stat, writeFile } from "fs/promises";
7
- import { dirname, join, relative, resolve } from "path";
8
-
9
- // src/utils/logger.ts
10
- import { consola } from "consola";
11
- var Logger = class {
12
- _verbose = false;
13
- console = consola.withDefaults({
14
- tag: "rulesync"
15
- });
16
- setVerbose(verbose) {
17
- this._verbose = verbose;
18
- }
19
- get verbose() {
20
- return this._verbose;
21
- }
22
- // Regular log (always shown, regardless of verbose)
23
- log(message, ...args) {
24
- this.console.log(message, ...args);
25
- }
26
- // Info level (shown only in verbose mode)
27
- info(message, ...args) {
28
- if (this._verbose) {
29
- this.console.info(message, ...args);
30
- }
31
- }
32
- // Success (always shown)
33
- success(message, ...args) {
34
- this.console.success(message, ...args);
35
- }
36
- // Warning (always shown)
37
- warn(message, ...args) {
38
- this.console.warn(message, ...args);
39
- }
40
- // Error (always shown)
41
- error(message, ...args) {
42
- this.console.error(message, ...args);
43
- }
44
- // Debug level (shown only in verbose mode)
45
- debug(message, ...args) {
46
- if (this._verbose) {
47
- this.console.debug(message, ...args);
48
- }
49
- }
50
- };
51
- var logger = new Logger();
52
-
53
- // src/utils/file.ts
54
- async function ensureDir(dirPath) {
55
- try {
56
- await stat(dirPath);
57
- } catch {
58
- await mkdir(dirPath, { recursive: true });
59
- }
60
- }
61
- function resolvePath(relativePath, baseDir) {
62
- if (!baseDir) return relativePath;
63
- const resolved = resolve(baseDir, relativePath);
64
- const rel = relative(baseDir, resolved);
65
- if (rel.startsWith("..") || resolve(resolved) !== resolved) {
66
- throw new Error(`Path traversal detected: ${relativePath}`);
67
- }
68
- return resolved;
69
- }
70
- async function readFileContent(filepath) {
71
- return readFile(filepath, "utf-8");
72
- }
73
- async function writeFileContent(filepath, content) {
74
- await ensureDir(dirname(filepath));
75
- await writeFile(filepath, content, "utf-8");
76
- }
77
- async function fileExists(filepath) {
78
- try {
79
- await stat(filepath);
80
- return true;
81
- } catch {
82
- return false;
83
- }
84
- }
85
- async function findFiles(dir, extension = ".md") {
86
- try {
87
- const files = await readdir(dir);
88
- return files.filter((file) => file.endsWith(extension)).map((file) => join(dir, file));
89
- } catch {
90
- return [];
91
- }
92
- }
93
- async function findRuleFiles(aiRulesDir) {
94
- const rulesDir = join(aiRulesDir, "rules");
95
- const newLocationFiles = await findFiles(rulesDir, ".md");
96
- const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
97
- const newLocationBasenames = new Set(
98
- newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
99
- );
100
- const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
101
- const basename = file.split("/").pop()?.replace(/\.md$/, "");
102
- return !newLocationBasenames.has(basename);
103
- });
104
- return [...newLocationFiles, ...filteredLegacyFiles];
105
- }
106
- async function removeDirectory(dirPath) {
107
- const dangerousPaths = [".", "/", "~", "src", "node_modules"];
108
- if (dangerousPaths.includes(dirPath) || dirPath === "") {
109
- logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
110
- return;
111
- }
112
- try {
113
- if (await fileExists(dirPath)) {
114
- await rm(dirPath, { recursive: true, force: true });
115
- }
116
- } catch (error) {
117
- logger.warn(`Failed to remove directory ${dirPath}:`, error);
118
- }
119
- }
120
- async function removeFile(filepath) {
121
- try {
122
- if (await fileExists(filepath)) {
123
- await rm(filepath);
124
- }
125
- } catch (error) {
126
- logger.warn(`Failed to remove file ${filepath}:`, error);
127
- }
128
- }
129
- async function removeClaudeGeneratedFiles() {
130
- const filesToRemove = ["CLAUDE.md", ".claude/memories"];
131
- for (const fileOrDir of filesToRemove) {
132
- if (fileOrDir.endsWith("/memories")) {
133
- await removeDirectory(fileOrDir);
134
- } else {
135
- await removeFile(fileOrDir);
136
- }
137
- }
138
- }
139
-
140
- // src/generators/mcp/amazonqcli.ts
141
- async function generateAmazonqcliMcp(mcpServers, config, baseDir) {
142
- const outputs = [];
143
- const configPaths = [
144
- ".amazonq/mcp.json"
145
- // Workspace configuration
146
- // Note: Global configuration is ~/.aws/amazonq/mcp.json but is user-specific
147
- // According to precautions.md, we should not create user-level files
148
- ];
149
- for (const configPath of configPaths) {
150
- const filepath = resolvePath(configPath, baseDir);
151
- const content = generateAmazonqcliMcpConfig({ mcpServers });
152
- outputs.push({
153
- tool: "amazonqcli",
154
- filepath,
155
- content
156
- });
157
- }
158
- return outputs;
159
- }
160
- function generateAmazonqcliMcpString(config) {
161
- return generateAmazonqcliMcpConfig(config);
162
- }
163
- function generateAmazonqcliMcpConfig(config) {
164
- const servers = {};
165
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
166
- if (!shouldIncludeServer(server, "amazonqcli")) {
167
- continue;
168
- }
169
- const amazonqServer = {};
170
- if (server.command) {
171
- amazonqServer.command = server.command;
172
- if (server.args) {
173
- amazonqServer.args = server.args;
174
- }
175
- }
176
- if (server.env) {
177
- amazonqServer.env = server.env;
178
- }
179
- if (server.timeout !== void 0) {
180
- amazonqServer.timeout = server.timeout;
181
- }
182
- if (server.disabled !== void 0) {
183
- amazonqServer.disabled = server.disabled;
184
- }
185
- if (server.alwaysAllow) {
186
- amazonqServer.autoApprove = server.alwaysAllow;
187
- }
188
- servers[serverName] = amazonqServer;
189
- }
190
- const finalConfig = {
191
- mcpServers: servers
192
- };
193
- return `${JSON.stringify(finalConfig, null, 2)}
194
- `;
195
- }
196
-
197
- export {
198
- logger,
199
- ensureDir,
200
- resolvePath,
201
- readFileContent,
202
- writeFileContent,
203
- fileExists,
204
- findFiles,
205
- findRuleFiles,
206
- removeDirectory,
207
- removeClaudeGeneratedFiles,
208
- generateAmazonqcliMcp,
209
- generateAmazonqcliMcpString
210
- };
@@ -1,12 +0,0 @@
1
- import {
2
- clineMcpGenerator
3
- } from "./chunk-JXOLLTNV.js";
4
-
5
- // src/generators/mcp/cline.ts
6
- var generateClineMcp = clineMcpGenerator.generateMcp;
7
- var generateClineMcpConfiguration = clineMcpGenerator.generateMcpConfiguration;
8
-
9
- export {
10
- generateClineMcp,
11
- generateClineMcpConfiguration
12
- };
@@ -1,12 +0,0 @@
1
- import {
2
- cursorMcpGenerator
3
- } from "./chunk-JXOLLTNV.js";
4
-
5
- // src/generators/mcp/cursor.ts
6
- var generateCursorMcp = cursorMcpGenerator.generateMcp;
7
- var generateCursorMcpConfiguration = cursorMcpGenerator.generateMcpConfiguration;
8
-
9
- export {
10
- generateCursorMcp,
11
- generateCursorMcpConfiguration
12
- };
@@ -1,117 +0,0 @@
1
- import {
2
- shouldIncludeServer
3
- } from "./chunk-M2AUM37M.js";
4
-
5
- // src/generators/mcp/augmentcode.ts
6
- function generateAugmentcodeMcp(config) {
7
- const augmentSettings = {
8
- mcpServers: []
9
- };
10
- const shouldInclude = (server) => {
11
- return shouldIncludeServer(server, "augmentcode");
12
- };
13
- for (const [serverName, server] of Object.entries(config.mcpServers)) {
14
- if (!shouldInclude(server)) continue;
15
- const augmentServer = {
16
- name: serverName
17
- };
18
- if (server.command) {
19
- const command = Array.isArray(server.command) ? server.command[0] : server.command;
20
- if (command) {
21
- augmentServer.command = command;
22
- }
23
- if (server.args) {
24
- augmentServer.args = server.args;
25
- }
26
- } else if (server.url || server.httpUrl) {
27
- const url = server.httpUrl || server.url;
28
- if (url) {
29
- augmentServer.url = url;
30
- }
31
- if (server.httpUrl || server.transport === "http") {
32
- augmentServer.transport = "http";
33
- } else if (server.transport === "sse") {
34
- augmentServer.transport = "sse";
35
- }
36
- if (server.env) {
37
- augmentServer.headers = server.env;
38
- }
39
- }
40
- if (server.env && server.command) {
41
- augmentServer.env = server.env;
42
- }
43
- if (server.timeout) {
44
- augmentServer.timeout = server.timeout;
45
- }
46
- if (server.disabled !== void 0) {
47
- augmentServer.enabled = !server.disabled;
48
- }
49
- if (server.networkTimeout && server.networkTimeout > 0) {
50
- augmentServer.retries = Math.max(1, Math.floor(server.networkTimeout / 3e4));
51
- }
52
- if (augmentSettings.mcpServers) {
53
- augmentSettings.mcpServers.push(augmentServer);
54
- }
55
- }
56
- return JSON.stringify(augmentSettings, null, 2);
57
- }
58
- function generateAugmentcodeMcpConfiguration(mcpServers, baseDir = "") {
59
- const filepath = baseDir ? `${baseDir}/.mcp.json` : ".mcp.json";
60
- const settings = {
61
- mcpServers: {}
62
- };
63
- for (const [serverName, server] of Object.entries(mcpServers)) {
64
- if (!shouldIncludeServer(server, "augmentcode")) {
65
- continue;
66
- }
67
- const { targets: _, ...serverConfig } = server;
68
- const augmentServer = {};
69
- if (serverConfig.command) {
70
- const command = Array.isArray(serverConfig.command) ? serverConfig.command[0] : serverConfig.command;
71
- if (command) {
72
- augmentServer.command = command;
73
- }
74
- if (serverConfig.args) {
75
- augmentServer.args = serverConfig.args;
76
- }
77
- if (serverConfig.env) {
78
- augmentServer.env = serverConfig.env;
79
- }
80
- } else if (serverConfig.url || serverConfig.httpUrl) {
81
- const url = serverConfig.httpUrl || serverConfig.url;
82
- if (url) {
83
- augmentServer.url = url;
84
- }
85
- if (serverConfig.httpUrl || serverConfig.transport === "http") {
86
- augmentServer.transport = "http";
87
- } else if (serverConfig.transport === "sse") {
88
- augmentServer.transport = "sse";
89
- }
90
- if (serverConfig.env) {
91
- augmentServer.headers = serverConfig.env;
92
- }
93
- }
94
- if (serverConfig.timeout) {
95
- augmentServer.timeout = serverConfig.timeout;
96
- }
97
- if (serverConfig.disabled !== void 0) {
98
- augmentServer.enabled = !serverConfig.disabled;
99
- }
100
- if (serverConfig.networkTimeout && serverConfig.networkTimeout > 0) {
101
- augmentServer.retries = Math.max(1, Math.floor(serverConfig.networkTimeout / 3e4));
102
- }
103
- settings.mcpServers[serverName] = augmentServer;
104
- }
105
- return [
106
- {
107
- filepath,
108
- content: `${JSON.stringify(settings, null, 2)}
109
- `
110
- }
111
- ];
112
- }
113
-
114
- export {
115
- generateAugmentcodeMcp,
116
- generateAugmentcodeMcpConfiguration
117
- };