rulesync 7.15.1 → 7.16.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.md +1 -1
- package/dist/{chunk-L5AQUWUM.js → chunk-E5YWRHGW.js} +146 -40
- package/dist/cli/index.cjs +313 -174
- package/dist/cli/index.js +173 -138
- package/dist/index.cjs +144 -41
- package/dist/index.js +1 -1
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -351,14 +351,21 @@ var ToolTargetSchema = import_mini2.z.enum(ALL_TOOL_TARGETS);
|
|
|
351
351
|
var ToolTargetsSchema = import_mini2.z.array(ToolTargetSchema);
|
|
352
352
|
var RulesyncTargetsSchema = import_mini2.z.array(import_mini2.z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
|
|
353
353
|
|
|
354
|
-
// src/
|
|
355
|
-
function
|
|
354
|
+
// src/utils/validation.ts
|
|
355
|
+
function findControlCharacter(value) {
|
|
356
356
|
for (let i = 0; i < value.length; i++) {
|
|
357
357
|
const code = value.charCodeAt(i);
|
|
358
|
-
if (code >= 0 && code <= 31 || code === 127)
|
|
358
|
+
if (code >= 0 && code <= 31 || code === 127) {
|
|
359
|
+
return { position: i, hex: `0x${code.toString(16).padStart(2, "0")}` };
|
|
360
|
+
}
|
|
359
361
|
}
|
|
360
|
-
return
|
|
362
|
+
return null;
|
|
361
363
|
}
|
|
364
|
+
function hasControlCharacters(value) {
|
|
365
|
+
return findControlCharacter(value) !== null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/config/config.ts
|
|
362
369
|
var SourceEntrySchema = import_mini3.z.object({
|
|
363
370
|
source: import_mini3.z.string().check((0, import_mini3.minLength)(1, "source must be a non-empty string")),
|
|
364
371
|
skills: (0, import_mini3.optional)(import_mini3.z.array(import_mini3.z.string())),
|
|
@@ -738,6 +745,7 @@ var import_node_path7 = require("path");
|
|
|
738
745
|
|
|
739
746
|
// src/utils/frontmatter.ts
|
|
740
747
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
748
|
+
var import_js_yaml = require("js-yaml");
|
|
741
749
|
function isPlainObject(value) {
|
|
742
750
|
if (value === null || typeof value !== "object") return false;
|
|
743
751
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -776,8 +784,55 @@ function deepRemoveNullishObject(obj) {
|
|
|
776
784
|
}
|
|
777
785
|
return result;
|
|
778
786
|
}
|
|
779
|
-
function
|
|
780
|
-
|
|
787
|
+
function deepFlattenStringsValue(value) {
|
|
788
|
+
if (value === null || value === void 0) {
|
|
789
|
+
return void 0;
|
|
790
|
+
}
|
|
791
|
+
if (typeof value === "string") {
|
|
792
|
+
return value.replace(/\n+/g, " ").trim();
|
|
793
|
+
}
|
|
794
|
+
if (Array.isArray(value)) {
|
|
795
|
+
const cleanedArray = value.map((item) => deepFlattenStringsValue(item)).filter((item) => item !== void 0);
|
|
796
|
+
return cleanedArray;
|
|
797
|
+
}
|
|
798
|
+
if (isPlainObject(value)) {
|
|
799
|
+
const result = {};
|
|
800
|
+
for (const [key, val] of Object.entries(value)) {
|
|
801
|
+
const cleaned = deepFlattenStringsValue(val);
|
|
802
|
+
if (cleaned !== void 0) {
|
|
803
|
+
result[key] = cleaned;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
return value;
|
|
809
|
+
}
|
|
810
|
+
function deepFlattenStringsObject(obj) {
|
|
811
|
+
if (!obj || typeof obj !== "object") {
|
|
812
|
+
return {};
|
|
813
|
+
}
|
|
814
|
+
const result = {};
|
|
815
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
816
|
+
const cleaned = deepFlattenStringsValue(val);
|
|
817
|
+
if (cleaned !== void 0) {
|
|
818
|
+
result[key] = cleaned;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return result;
|
|
822
|
+
}
|
|
823
|
+
function stringifyFrontmatter(body, frontmatter, options) {
|
|
824
|
+
const { avoidBlockScalars = false } = options ?? {};
|
|
825
|
+
const cleanFrontmatter = avoidBlockScalars ? deepFlattenStringsObject(frontmatter) : deepRemoveNullishObject(frontmatter);
|
|
826
|
+
if (avoidBlockScalars) {
|
|
827
|
+
return import_gray_matter.default.stringify(body, cleanFrontmatter, {
|
|
828
|
+
engines: {
|
|
829
|
+
yaml: {
|
|
830
|
+
parse: (input) => (0, import_js_yaml.load)(input) ?? {},
|
|
831
|
+
stringify: (data) => (0, import_js_yaml.dump)(data, { lineWidth: -1 })
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
}
|
|
781
836
|
return import_gray_matter.default.stringify(body, cleanFrontmatter);
|
|
782
837
|
}
|
|
783
838
|
function parseFrontmatter(content, filePath) {
|
|
@@ -1896,7 +1951,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
|
|
|
1896
1951
|
}
|
|
1897
1952
|
super({
|
|
1898
1953
|
...rest,
|
|
1899
|
-
fileContent: stringifyFrontmatter(body, frontmatter)
|
|
1954
|
+
fileContent: stringifyFrontmatter(body, frontmatter, { avoidBlockScalars: true })
|
|
1900
1955
|
});
|
|
1901
1956
|
this.frontmatter = frontmatter;
|
|
1902
1957
|
this.body = body;
|
|
@@ -5813,7 +5868,10 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
|
|
|
5813
5868
|
stripMcpServerFields(fields) {
|
|
5814
5869
|
if (fields.length === 0) return this;
|
|
5815
5870
|
const filteredServers = Object.fromEntries(
|
|
5816
|
-
Object.entries(this.json.mcpServers).map(([name, config]) => [
|
|
5871
|
+
Object.entries(this.json.mcpServers).map(([name, config]) => [
|
|
5872
|
+
name,
|
|
5873
|
+
Object.fromEntries(Object.entries(config).filter(([key]) => !fields.includes(key)))
|
|
5874
|
+
])
|
|
5817
5875
|
);
|
|
5818
5876
|
return new _RulesyncMcp({
|
|
5819
5877
|
baseDir: this.baseDir,
|
|
@@ -6319,12 +6377,26 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6319
6377
|
json;
|
|
6320
6378
|
constructor(params) {
|
|
6321
6379
|
super(params);
|
|
6322
|
-
|
|
6380
|
+
if (this.fileContent !== void 0) {
|
|
6381
|
+
try {
|
|
6382
|
+
this.json = JSON.parse(this.fileContent);
|
|
6383
|
+
} catch (error) {
|
|
6384
|
+
throw new Error(
|
|
6385
|
+
`Failed to parse Cursor MCP config at ${(0, import_node_path48.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(error)}`,
|
|
6386
|
+
{ cause: error }
|
|
6387
|
+
);
|
|
6388
|
+
}
|
|
6389
|
+
} else {
|
|
6390
|
+
this.json = {};
|
|
6391
|
+
}
|
|
6323
6392
|
}
|
|
6324
6393
|
getJson() {
|
|
6325
6394
|
return this.json;
|
|
6326
6395
|
}
|
|
6327
|
-
|
|
6396
|
+
isDeletable() {
|
|
6397
|
+
return !this.global;
|
|
6398
|
+
}
|
|
6399
|
+
static getSettablePaths(_options) {
|
|
6328
6400
|
return {
|
|
6329
6401
|
relativeDirPath: ".cursor",
|
|
6330
6402
|
relativeFilePath: "mcp.json"
|
|
@@ -6332,41 +6404,62 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6332
6404
|
}
|
|
6333
6405
|
static async fromFile({
|
|
6334
6406
|
baseDir = process.cwd(),
|
|
6335
|
-
validate = true
|
|
6407
|
+
validate = true,
|
|
6408
|
+
global = false
|
|
6336
6409
|
}) {
|
|
6337
|
-
const
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
)
|
|
6343
|
-
)
|
|
6410
|
+
const paths = this.getSettablePaths({ global });
|
|
6411
|
+
const filePath = (0, import_node_path48.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath);
|
|
6412
|
+
const fileContent = await readFileContentOrNull(filePath) ?? '{"mcpServers":{}}';
|
|
6413
|
+
let json;
|
|
6414
|
+
try {
|
|
6415
|
+
json = JSON.parse(fileContent);
|
|
6416
|
+
} catch (error) {
|
|
6417
|
+
throw new Error(
|
|
6418
|
+
`Failed to parse Cursor MCP config at ${(0, import_node_path48.join)(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError(error)}`,
|
|
6419
|
+
{ cause: error }
|
|
6420
|
+
);
|
|
6421
|
+
}
|
|
6422
|
+
const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
|
|
6344
6423
|
return new _CursorMcp({
|
|
6345
6424
|
baseDir,
|
|
6346
|
-
relativeDirPath:
|
|
6347
|
-
relativeFilePath:
|
|
6348
|
-
fileContent,
|
|
6349
|
-
validate
|
|
6425
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6426
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6427
|
+
fileContent: JSON.stringify(newJson, null, 2),
|
|
6428
|
+
validate,
|
|
6429
|
+
global
|
|
6350
6430
|
});
|
|
6351
6431
|
}
|
|
6352
|
-
static fromRulesyncMcp({
|
|
6432
|
+
static async fromRulesyncMcp({
|
|
6353
6433
|
baseDir = process.cwd(),
|
|
6354
6434
|
rulesyncMcp,
|
|
6355
|
-
validate = true
|
|
6435
|
+
validate = true,
|
|
6436
|
+
global = false
|
|
6356
6437
|
}) {
|
|
6357
|
-
const
|
|
6358
|
-
const
|
|
6438
|
+
const paths = this.getSettablePaths({ global });
|
|
6439
|
+
const fileContent = await readOrInitializeFileContent(
|
|
6440
|
+
(0, import_node_path48.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath),
|
|
6441
|
+
JSON.stringify({ mcpServers: {} }, null, 2)
|
|
6442
|
+
);
|
|
6443
|
+
let json;
|
|
6444
|
+
try {
|
|
6445
|
+
json = JSON.parse(fileContent);
|
|
6446
|
+
} catch (error) {
|
|
6447
|
+
throw new Error(
|
|
6448
|
+
`Failed to parse Cursor MCP config at ${(0, import_node_path48.join)(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError(error)}`,
|
|
6449
|
+
{ cause: error }
|
|
6450
|
+
);
|
|
6451
|
+
}
|
|
6452
|
+
const rulesyncJson = rulesyncMcp.getJson();
|
|
6453
|
+
const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
|
|
6359
6454
|
const transformedServers = convertEnvToCursorFormat(mcpServers);
|
|
6360
|
-
const cursorConfig = {
|
|
6361
|
-
mcpServers: transformedServers
|
|
6362
|
-
};
|
|
6363
|
-
const fileContent = JSON.stringify(cursorConfig, null, 2);
|
|
6455
|
+
const cursorConfig = { ...json, mcpServers: transformedServers };
|
|
6364
6456
|
return new _CursorMcp({
|
|
6365
6457
|
baseDir,
|
|
6366
|
-
relativeDirPath:
|
|
6367
|
-
relativeFilePath:
|
|
6368
|
-
fileContent,
|
|
6369
|
-
validate
|
|
6458
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6459
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6460
|
+
fileContent: JSON.stringify(cursorConfig, null, 2),
|
|
6461
|
+
validate,
|
|
6462
|
+
global
|
|
6370
6463
|
});
|
|
6371
6464
|
}
|
|
6372
6465
|
toRulesyncMcp() {
|
|
@@ -6390,14 +6483,16 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6390
6483
|
static forDeletion({
|
|
6391
6484
|
baseDir = process.cwd(),
|
|
6392
6485
|
relativeDirPath,
|
|
6393
|
-
relativeFilePath
|
|
6486
|
+
relativeFilePath,
|
|
6487
|
+
global = false
|
|
6394
6488
|
}) {
|
|
6395
6489
|
return new _CursorMcp({
|
|
6396
6490
|
baseDir,
|
|
6397
6491
|
relativeDirPath,
|
|
6398
6492
|
relativeFilePath,
|
|
6399
6493
|
fileContent: "{}",
|
|
6400
|
-
validate: false
|
|
6494
|
+
validate: false,
|
|
6495
|
+
global
|
|
6401
6496
|
});
|
|
6402
6497
|
}
|
|
6403
6498
|
};
|
|
@@ -7226,7 +7321,7 @@ var toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
7226
7321
|
class: CursorMcp,
|
|
7227
7322
|
meta: {
|
|
7228
7323
|
supportsProject: true,
|
|
7229
|
-
supportsGlobal:
|
|
7324
|
+
supportsGlobal: true,
|
|
7230
7325
|
supportsEnabledTools: false,
|
|
7231
7326
|
supportsDisabledTools: false
|
|
7232
7327
|
}
|
|
@@ -7939,9 +8034,15 @@ var import_node_path61 = require("path");
|
|
|
7939
8034
|
var DirFeatureProcessor = class {
|
|
7940
8035
|
baseDir;
|
|
7941
8036
|
dryRun;
|
|
7942
|
-
|
|
8037
|
+
avoidBlockScalars;
|
|
8038
|
+
constructor({
|
|
8039
|
+
baseDir = process.cwd(),
|
|
8040
|
+
dryRun = false,
|
|
8041
|
+
avoidBlockScalars = false
|
|
8042
|
+
}) {
|
|
7943
8043
|
this.baseDir = baseDir;
|
|
7944
8044
|
this.dryRun = dryRun;
|
|
8045
|
+
this.avoidBlockScalars = avoidBlockScalars;
|
|
7945
8046
|
}
|
|
7946
8047
|
/**
|
|
7947
8048
|
* Return tool targets that this feature supports.
|
|
@@ -7967,7 +8068,9 @@ var DirFeatureProcessor = class {
|
|
|
7967
8068
|
let mainFileContent;
|
|
7968
8069
|
if (mainFile) {
|
|
7969
8070
|
const mainFilePath = (0, import_node_path61.join)(dirPath, mainFile.name);
|
|
7970
|
-
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter
|
|
8071
|
+
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter, {
|
|
8072
|
+
avoidBlockScalars: this.avoidBlockScalars
|
|
8073
|
+
});
|
|
7971
8074
|
mainFileContent = addTrailingNewline(content);
|
|
7972
8075
|
const existingContent = await readFileContentOrNull(mainFilePath);
|
|
7973
8076
|
if (existingContent !== mainFileContent) {
|
|
@@ -10706,7 +10809,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
10706
10809
|
getFactory = defaultGetFactory4,
|
|
10707
10810
|
dryRun = false
|
|
10708
10811
|
}) {
|
|
10709
|
-
super({ baseDir, dryRun });
|
|
10812
|
+
super({ baseDir, dryRun, avoidBlockScalars: toolTarget === "cursor" });
|
|
10710
10813
|
const result = SkillsProcessorToolTargetSchema.safeParse(toolTarget);
|
|
10711
10814
|
if (!result.success) {
|
|
10712
10815
|
throw new Error(
|
|
@@ -11787,7 +11890,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
|
|
|
11787
11890
|
...cursorSection
|
|
11788
11891
|
};
|
|
11789
11892
|
const body = rulesyncSubagent.getBody();
|
|
11790
|
-
const fileContent = stringifyFrontmatter(body, cursorFrontmatter);
|
|
11893
|
+
const fileContent = stringifyFrontmatter(body, cursorFrontmatter, { avoidBlockScalars: true });
|
|
11791
11894
|
const paths = this.getSettablePaths({ global });
|
|
11792
11895
|
return new _CursorSubagent({
|
|
11793
11896
|
baseDir,
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rulesync",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.16.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",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"commander": "14.0.3",
|
|
57
57
|
"consola": "3.4.2",
|
|
58
58
|
"effect": "3.19.19",
|
|
59
|
-
"es-toolkit": "1.
|
|
59
|
+
"es-toolkit": "1.45.1",
|
|
60
60
|
"fastmcp": "3.33.0",
|
|
61
61
|
"globby": "16.1.1",
|
|
62
62
|
"gray-matter": "4.0.3",
|
|
@@ -67,28 +67,28 @@
|
|
|
67
67
|
"zod": "4.3.6"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@anthropic-ai/claude-agent-sdk": "0.2.
|
|
70
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.69",
|
|
71
71
|
"@eslint/js": "9.39.2",
|
|
72
72
|
"@openrouter/sdk": "0.9.11",
|
|
73
73
|
"@secretlint/secretlint-rule-preset-recommend": "11.3.1",
|
|
74
74
|
"@tsconfig/node24": "24.0.4",
|
|
75
75
|
"@types/js-yaml": "4.0.9",
|
|
76
|
-
"@types/node": "25.3.
|
|
77
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
76
|
+
"@types/node": "25.3.3",
|
|
77
|
+
"@typescript/native-preview": "7.0.0-dev.20260304.1",
|
|
78
78
|
"@vitest/coverage-v8": "4.0.18",
|
|
79
79
|
"cspell": "9.7.0",
|
|
80
80
|
"eslint": "9.39.2",
|
|
81
81
|
"eslint-plugin-import": "2.32.0",
|
|
82
82
|
"eslint-plugin-no-type-assertion": "1.3.0",
|
|
83
|
-
"eslint-plugin-oxlint": "1.
|
|
83
|
+
"eslint-plugin-oxlint": "1.51.0",
|
|
84
84
|
"eslint-plugin-strict-dependencies": "1.3.31",
|
|
85
85
|
"eslint-plugin-zod-import": "0.3.0",
|
|
86
86
|
"knip": "5.85.0",
|
|
87
|
-
"lint-staged": "16.2
|
|
88
|
-
"oxfmt": "0.
|
|
89
|
-
"oxlint": "1.
|
|
90
|
-
"repomix": "1.
|
|
91
|
-
"resend": "6.9.
|
|
87
|
+
"lint-staged": "16.3.2",
|
|
88
|
+
"oxfmt": "0.36.0",
|
|
89
|
+
"oxlint": "1.51.0",
|
|
90
|
+
"repomix": "1.12.0",
|
|
91
|
+
"resend": "6.9.3",
|
|
92
92
|
"secretlint": "11.3.1",
|
|
93
93
|
"simple-git-hooks": "2.13.1",
|
|
94
94
|
"sort-package-json": "3.6.1",
|