rulesync 7.15.2 → 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-WY325EI7.js → chunk-E5YWRHGW.js} +142 -39
- package/dist/cli/index.cjs +309 -173
- package/dist/cli/index.js +173 -138
- package/dist/index.cjs +140 -40
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ See [Quick Start guide](https://dyoshikawa.github.io/rulesync/getting-started/qu
|
|
|
71
71
|
| Gemini CLI | geminicli | ✅ 🌏 | ✅ | ✅ 🌏 | ✅ 🌏 | 🎮 | ✅ 🌏 | ✅ 🌏 |
|
|
72
72
|
| Goose | goose | ✅ 🌏 | ✅ | | | | | |
|
|
73
73
|
| GitHub Copilot | copilot | ✅ 🌏 | | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
74
|
-
| Cursor | cursor | ✅ | ✅ |
|
|
74
|
+
| Cursor | cursor | ✅ | ✅ | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 | ✅ |
|
|
75
75
|
| Factory Droid | factorydroid | ✅ 🌏 | | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 |
|
|
76
76
|
| OpenCode | opencode | ✅ 🌏 | | ✅ 🌏 🔧 | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 | ✅ 🌏 |
|
|
77
77
|
| Cline | cline | ✅ | ✅ | ✅ | ✅ 🌏 | | ✅ 🌏 | |
|
|
@@ -342,13 +342,22 @@ async function removeTempDirectory(tempDir) {
|
|
|
342
342
|
// src/config/config.ts
|
|
343
343
|
import { isAbsolute } from "path";
|
|
344
344
|
import { minLength, optional, refine, z as z3 } from "zod/mini";
|
|
345
|
-
|
|
345
|
+
|
|
346
|
+
// src/utils/validation.ts
|
|
347
|
+
function findControlCharacter(value) {
|
|
346
348
|
for (let i = 0; i < value.length; i++) {
|
|
347
349
|
const code = value.charCodeAt(i);
|
|
348
|
-
if (code >= 0 && code <= 31 || code === 127)
|
|
350
|
+
if (code >= 0 && code <= 31 || code === 127) {
|
|
351
|
+
return { position: i, hex: `0x${code.toString(16).padStart(2, "0")}` };
|
|
352
|
+
}
|
|
349
353
|
}
|
|
350
|
-
return
|
|
354
|
+
return null;
|
|
351
355
|
}
|
|
356
|
+
function hasControlCharacters(value) {
|
|
357
|
+
return findControlCharacter(value) !== null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/config/config.ts
|
|
352
361
|
var SourceEntrySchema = z3.object({
|
|
353
362
|
source: z3.string().check(minLength(1, "source must be a non-empty string")),
|
|
354
363
|
skills: optional(z3.array(z3.string())),
|
|
@@ -728,6 +737,7 @@ import { join as join5 } from "path";
|
|
|
728
737
|
|
|
729
738
|
// src/utils/frontmatter.ts
|
|
730
739
|
import matter from "gray-matter";
|
|
740
|
+
import { dump, load } from "js-yaml";
|
|
731
741
|
function isPlainObject(value) {
|
|
732
742
|
if (value === null || typeof value !== "object") return false;
|
|
733
743
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -766,8 +776,55 @@ function deepRemoveNullishObject(obj) {
|
|
|
766
776
|
}
|
|
767
777
|
return result;
|
|
768
778
|
}
|
|
769
|
-
function
|
|
770
|
-
|
|
779
|
+
function deepFlattenStringsValue(value) {
|
|
780
|
+
if (value === null || value === void 0) {
|
|
781
|
+
return void 0;
|
|
782
|
+
}
|
|
783
|
+
if (typeof value === "string") {
|
|
784
|
+
return value.replace(/\n+/g, " ").trim();
|
|
785
|
+
}
|
|
786
|
+
if (Array.isArray(value)) {
|
|
787
|
+
const cleanedArray = value.map((item) => deepFlattenStringsValue(item)).filter((item) => item !== void 0);
|
|
788
|
+
return cleanedArray;
|
|
789
|
+
}
|
|
790
|
+
if (isPlainObject(value)) {
|
|
791
|
+
const result = {};
|
|
792
|
+
for (const [key, val] of Object.entries(value)) {
|
|
793
|
+
const cleaned = deepFlattenStringsValue(val);
|
|
794
|
+
if (cleaned !== void 0) {
|
|
795
|
+
result[key] = cleaned;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
return value;
|
|
801
|
+
}
|
|
802
|
+
function deepFlattenStringsObject(obj) {
|
|
803
|
+
if (!obj || typeof obj !== "object") {
|
|
804
|
+
return {};
|
|
805
|
+
}
|
|
806
|
+
const result = {};
|
|
807
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
808
|
+
const cleaned = deepFlattenStringsValue(val);
|
|
809
|
+
if (cleaned !== void 0) {
|
|
810
|
+
result[key] = cleaned;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return result;
|
|
814
|
+
}
|
|
815
|
+
function stringifyFrontmatter(body, frontmatter, options) {
|
|
816
|
+
const { avoidBlockScalars = false } = options ?? {};
|
|
817
|
+
const cleanFrontmatter = avoidBlockScalars ? deepFlattenStringsObject(frontmatter) : deepRemoveNullishObject(frontmatter);
|
|
818
|
+
if (avoidBlockScalars) {
|
|
819
|
+
return matter.stringify(body, cleanFrontmatter, {
|
|
820
|
+
engines: {
|
|
821
|
+
yaml: {
|
|
822
|
+
parse: (input) => load(input) ?? {},
|
|
823
|
+
stringify: (data) => dump(data, { lineWidth: -1 })
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
}
|
|
771
828
|
return matter.stringify(body, cleanFrontmatter);
|
|
772
829
|
}
|
|
773
830
|
function parseFrontmatter(content, filePath) {
|
|
@@ -1886,7 +1943,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
|
|
|
1886
1943
|
}
|
|
1887
1944
|
super({
|
|
1888
1945
|
...rest,
|
|
1889
|
-
fileContent: stringifyFrontmatter(body, frontmatter)
|
|
1946
|
+
fileContent: stringifyFrontmatter(body, frontmatter, { avoidBlockScalars: true })
|
|
1890
1947
|
});
|
|
1891
1948
|
this.frontmatter = frontmatter;
|
|
1892
1949
|
this.body = body;
|
|
@@ -6312,12 +6369,26 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6312
6369
|
json;
|
|
6313
6370
|
constructor(params) {
|
|
6314
6371
|
super(params);
|
|
6315
|
-
|
|
6372
|
+
if (this.fileContent !== void 0) {
|
|
6373
|
+
try {
|
|
6374
|
+
this.json = JSON.parse(this.fileContent);
|
|
6375
|
+
} catch (error) {
|
|
6376
|
+
throw new Error(
|
|
6377
|
+
`Failed to parse Cursor MCP config at ${join46(this.relativeDirPath, this.relativeFilePath)}: ${formatError(error)}`,
|
|
6378
|
+
{ cause: error }
|
|
6379
|
+
);
|
|
6380
|
+
}
|
|
6381
|
+
} else {
|
|
6382
|
+
this.json = {};
|
|
6383
|
+
}
|
|
6316
6384
|
}
|
|
6317
6385
|
getJson() {
|
|
6318
6386
|
return this.json;
|
|
6319
6387
|
}
|
|
6320
|
-
|
|
6388
|
+
isDeletable() {
|
|
6389
|
+
return !this.global;
|
|
6390
|
+
}
|
|
6391
|
+
static getSettablePaths(_options) {
|
|
6321
6392
|
return {
|
|
6322
6393
|
relativeDirPath: ".cursor",
|
|
6323
6394
|
relativeFilePath: "mcp.json"
|
|
@@ -6325,41 +6396,62 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6325
6396
|
}
|
|
6326
6397
|
static async fromFile({
|
|
6327
6398
|
baseDir = process.cwd(),
|
|
6328
|
-
validate = true
|
|
6399
|
+
validate = true,
|
|
6400
|
+
global = false
|
|
6329
6401
|
}) {
|
|
6330
|
-
const
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
)
|
|
6336
|
-
)
|
|
6402
|
+
const paths = this.getSettablePaths({ global });
|
|
6403
|
+
const filePath = join46(baseDir, paths.relativeDirPath, paths.relativeFilePath);
|
|
6404
|
+
const fileContent = await readFileContentOrNull(filePath) ?? '{"mcpServers":{}}';
|
|
6405
|
+
let json;
|
|
6406
|
+
try {
|
|
6407
|
+
json = JSON.parse(fileContent);
|
|
6408
|
+
} catch (error) {
|
|
6409
|
+
throw new Error(
|
|
6410
|
+
`Failed to parse Cursor MCP config at ${join46(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError(error)}`,
|
|
6411
|
+
{ cause: error }
|
|
6412
|
+
);
|
|
6413
|
+
}
|
|
6414
|
+
const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
|
|
6337
6415
|
return new _CursorMcp({
|
|
6338
6416
|
baseDir,
|
|
6339
|
-
relativeDirPath:
|
|
6340
|
-
relativeFilePath:
|
|
6341
|
-
fileContent,
|
|
6342
|
-
validate
|
|
6417
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6418
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6419
|
+
fileContent: JSON.stringify(newJson, null, 2),
|
|
6420
|
+
validate,
|
|
6421
|
+
global
|
|
6343
6422
|
});
|
|
6344
6423
|
}
|
|
6345
|
-
static fromRulesyncMcp({
|
|
6424
|
+
static async fromRulesyncMcp({
|
|
6346
6425
|
baseDir = process.cwd(),
|
|
6347
6426
|
rulesyncMcp,
|
|
6348
|
-
validate = true
|
|
6427
|
+
validate = true,
|
|
6428
|
+
global = false
|
|
6349
6429
|
}) {
|
|
6350
|
-
const
|
|
6351
|
-
const
|
|
6430
|
+
const paths = this.getSettablePaths({ global });
|
|
6431
|
+
const fileContent = await readOrInitializeFileContent(
|
|
6432
|
+
join46(baseDir, paths.relativeDirPath, paths.relativeFilePath),
|
|
6433
|
+
JSON.stringify({ mcpServers: {} }, null, 2)
|
|
6434
|
+
);
|
|
6435
|
+
let json;
|
|
6436
|
+
try {
|
|
6437
|
+
json = JSON.parse(fileContent);
|
|
6438
|
+
} catch (error) {
|
|
6439
|
+
throw new Error(
|
|
6440
|
+
`Failed to parse Cursor MCP config at ${join46(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError(error)}`,
|
|
6441
|
+
{ cause: error }
|
|
6442
|
+
);
|
|
6443
|
+
}
|
|
6444
|
+
const rulesyncJson = rulesyncMcp.getJson();
|
|
6445
|
+
const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
|
|
6352
6446
|
const transformedServers = convertEnvToCursorFormat(mcpServers);
|
|
6353
|
-
const cursorConfig = {
|
|
6354
|
-
mcpServers: transformedServers
|
|
6355
|
-
};
|
|
6356
|
-
const fileContent = JSON.stringify(cursorConfig, null, 2);
|
|
6447
|
+
const cursorConfig = { ...json, mcpServers: transformedServers };
|
|
6357
6448
|
return new _CursorMcp({
|
|
6358
6449
|
baseDir,
|
|
6359
|
-
relativeDirPath:
|
|
6360
|
-
relativeFilePath:
|
|
6361
|
-
fileContent,
|
|
6362
|
-
validate
|
|
6450
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6451
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6452
|
+
fileContent: JSON.stringify(cursorConfig, null, 2),
|
|
6453
|
+
validate,
|
|
6454
|
+
global
|
|
6363
6455
|
});
|
|
6364
6456
|
}
|
|
6365
6457
|
toRulesyncMcp() {
|
|
@@ -6383,14 +6475,16 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6383
6475
|
static forDeletion({
|
|
6384
6476
|
baseDir = process.cwd(),
|
|
6385
6477
|
relativeDirPath,
|
|
6386
|
-
relativeFilePath
|
|
6478
|
+
relativeFilePath,
|
|
6479
|
+
global = false
|
|
6387
6480
|
}) {
|
|
6388
6481
|
return new _CursorMcp({
|
|
6389
6482
|
baseDir,
|
|
6390
6483
|
relativeDirPath,
|
|
6391
6484
|
relativeFilePath,
|
|
6392
6485
|
fileContent: "{}",
|
|
6393
|
-
validate: false
|
|
6486
|
+
validate: false,
|
|
6487
|
+
global
|
|
6394
6488
|
});
|
|
6395
6489
|
}
|
|
6396
6490
|
};
|
|
@@ -7219,7 +7313,7 @@ var toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
7219
7313
|
class: CursorMcp,
|
|
7220
7314
|
meta: {
|
|
7221
7315
|
supportsProject: true,
|
|
7222
|
-
supportsGlobal:
|
|
7316
|
+
supportsGlobal: true,
|
|
7223
7317
|
supportsEnabledTools: false,
|
|
7224
7318
|
supportsDisabledTools: false
|
|
7225
7319
|
}
|
|
@@ -7932,9 +8026,15 @@ import { join as join59 } from "path";
|
|
|
7932
8026
|
var DirFeatureProcessor = class {
|
|
7933
8027
|
baseDir;
|
|
7934
8028
|
dryRun;
|
|
7935
|
-
|
|
8029
|
+
avoidBlockScalars;
|
|
8030
|
+
constructor({
|
|
8031
|
+
baseDir = process.cwd(),
|
|
8032
|
+
dryRun = false,
|
|
8033
|
+
avoidBlockScalars = false
|
|
8034
|
+
}) {
|
|
7936
8035
|
this.baseDir = baseDir;
|
|
7937
8036
|
this.dryRun = dryRun;
|
|
8037
|
+
this.avoidBlockScalars = avoidBlockScalars;
|
|
7938
8038
|
}
|
|
7939
8039
|
/**
|
|
7940
8040
|
* Return tool targets that this feature supports.
|
|
@@ -7960,7 +8060,9 @@ var DirFeatureProcessor = class {
|
|
|
7960
8060
|
let mainFileContent;
|
|
7961
8061
|
if (mainFile) {
|
|
7962
8062
|
const mainFilePath = join59(dirPath, mainFile.name);
|
|
7963
|
-
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter
|
|
8063
|
+
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter, {
|
|
8064
|
+
avoidBlockScalars: this.avoidBlockScalars
|
|
8065
|
+
});
|
|
7964
8066
|
mainFileContent = addTrailingNewline(content);
|
|
7965
8067
|
const existingContent = await readFileContentOrNull(mainFilePath);
|
|
7966
8068
|
if (existingContent !== mainFileContent) {
|
|
@@ -10699,7 +10801,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
10699
10801
|
getFactory = defaultGetFactory4,
|
|
10700
10802
|
dryRun = false
|
|
10701
10803
|
}) {
|
|
10702
|
-
super({ baseDir, dryRun });
|
|
10804
|
+
super({ baseDir, dryRun, avoidBlockScalars: toolTarget === "cursor" });
|
|
10703
10805
|
const result = SkillsProcessorToolTargetSchema.safeParse(toolTarget);
|
|
10704
10806
|
if (!result.success) {
|
|
10705
10807
|
throw new Error(
|
|
@@ -11780,7 +11882,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
|
|
|
11780
11882
|
...cursorSection
|
|
11781
11883
|
};
|
|
11782
11884
|
const body = rulesyncSubagent.getBody();
|
|
11783
|
-
const fileContent = stringifyFrontmatter(body, cursorFrontmatter);
|
|
11885
|
+
const fileContent = stringifyFrontmatter(body, cursorFrontmatter, { avoidBlockScalars: true });
|
|
11784
11886
|
const paths = this.getSettablePaths({ global });
|
|
11785
11887
|
return new _CursorSubagent({
|
|
11786
11888
|
baseDir,
|
|
@@ -16915,6 +17017,7 @@ export {
|
|
|
16915
17017
|
ALL_FEATURES,
|
|
16916
17018
|
ALL_FEATURES_WITH_WILDCARD,
|
|
16917
17019
|
ALL_TOOL_TARGETS,
|
|
17020
|
+
findControlCharacter,
|
|
16918
17021
|
ConfigResolver,
|
|
16919
17022
|
stringifyFrontmatter,
|
|
16920
17023
|
RulesyncCommandFrontmatterSchema,
|