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/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;
|
|
@@ -5803,7 +5860,10 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
|
|
|
5803
5860
|
stripMcpServerFields(fields) {
|
|
5804
5861
|
if (fields.length === 0) return this;
|
|
5805
5862
|
const filteredServers = Object.fromEntries(
|
|
5806
|
-
Object.entries(this.json.mcpServers).map(([name, config]) => [
|
|
5863
|
+
Object.entries(this.json.mcpServers).map(([name, config]) => [
|
|
5864
|
+
name,
|
|
5865
|
+
Object.fromEntries(Object.entries(config).filter(([key]) => !fields.includes(key)))
|
|
5866
|
+
])
|
|
5807
5867
|
);
|
|
5808
5868
|
return new _RulesyncMcp({
|
|
5809
5869
|
baseDir: this.baseDir,
|
|
@@ -6309,12 +6369,26 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6309
6369
|
json;
|
|
6310
6370
|
constructor(params) {
|
|
6311
6371
|
super(params);
|
|
6312
|
-
|
|
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
|
+
}
|
|
6313
6384
|
}
|
|
6314
6385
|
getJson() {
|
|
6315
6386
|
return this.json;
|
|
6316
6387
|
}
|
|
6317
|
-
|
|
6388
|
+
isDeletable() {
|
|
6389
|
+
return !this.global;
|
|
6390
|
+
}
|
|
6391
|
+
static getSettablePaths(_options) {
|
|
6318
6392
|
return {
|
|
6319
6393
|
relativeDirPath: ".cursor",
|
|
6320
6394
|
relativeFilePath: "mcp.json"
|
|
@@ -6322,41 +6396,62 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6322
6396
|
}
|
|
6323
6397
|
static async fromFile({
|
|
6324
6398
|
baseDir = process.cwd(),
|
|
6325
|
-
validate = true
|
|
6399
|
+
validate = true,
|
|
6400
|
+
global = false
|
|
6326
6401
|
}) {
|
|
6327
|
-
const
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
)
|
|
6333
|
-
)
|
|
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 ?? {} };
|
|
6334
6415
|
return new _CursorMcp({
|
|
6335
6416
|
baseDir,
|
|
6336
|
-
relativeDirPath:
|
|
6337
|
-
relativeFilePath:
|
|
6338
|
-
fileContent,
|
|
6339
|
-
validate
|
|
6417
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6418
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6419
|
+
fileContent: JSON.stringify(newJson, null, 2),
|
|
6420
|
+
validate,
|
|
6421
|
+
global
|
|
6340
6422
|
});
|
|
6341
6423
|
}
|
|
6342
|
-
static fromRulesyncMcp({
|
|
6424
|
+
static async fromRulesyncMcp({
|
|
6343
6425
|
baseDir = process.cwd(),
|
|
6344
6426
|
rulesyncMcp,
|
|
6345
|
-
validate = true
|
|
6427
|
+
validate = true,
|
|
6428
|
+
global = false
|
|
6346
6429
|
}) {
|
|
6347
|
-
const
|
|
6348
|
-
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 : {};
|
|
6349
6446
|
const transformedServers = convertEnvToCursorFormat(mcpServers);
|
|
6350
|
-
const cursorConfig = {
|
|
6351
|
-
mcpServers: transformedServers
|
|
6352
|
-
};
|
|
6353
|
-
const fileContent = JSON.stringify(cursorConfig, null, 2);
|
|
6447
|
+
const cursorConfig = { ...json, mcpServers: transformedServers };
|
|
6354
6448
|
return new _CursorMcp({
|
|
6355
6449
|
baseDir,
|
|
6356
|
-
relativeDirPath:
|
|
6357
|
-
relativeFilePath:
|
|
6358
|
-
fileContent,
|
|
6359
|
-
validate
|
|
6450
|
+
relativeDirPath: paths.relativeDirPath,
|
|
6451
|
+
relativeFilePath: paths.relativeFilePath,
|
|
6452
|
+
fileContent: JSON.stringify(cursorConfig, null, 2),
|
|
6453
|
+
validate,
|
|
6454
|
+
global
|
|
6360
6455
|
});
|
|
6361
6456
|
}
|
|
6362
6457
|
toRulesyncMcp() {
|
|
@@ -6380,14 +6475,16 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
6380
6475
|
static forDeletion({
|
|
6381
6476
|
baseDir = process.cwd(),
|
|
6382
6477
|
relativeDirPath,
|
|
6383
|
-
relativeFilePath
|
|
6478
|
+
relativeFilePath,
|
|
6479
|
+
global = false
|
|
6384
6480
|
}) {
|
|
6385
6481
|
return new _CursorMcp({
|
|
6386
6482
|
baseDir,
|
|
6387
6483
|
relativeDirPath,
|
|
6388
6484
|
relativeFilePath,
|
|
6389
6485
|
fileContent: "{}",
|
|
6390
|
-
validate: false
|
|
6486
|
+
validate: false,
|
|
6487
|
+
global
|
|
6391
6488
|
});
|
|
6392
6489
|
}
|
|
6393
6490
|
};
|
|
@@ -7216,7 +7313,7 @@ var toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
7216
7313
|
class: CursorMcp,
|
|
7217
7314
|
meta: {
|
|
7218
7315
|
supportsProject: true,
|
|
7219
|
-
supportsGlobal:
|
|
7316
|
+
supportsGlobal: true,
|
|
7220
7317
|
supportsEnabledTools: false,
|
|
7221
7318
|
supportsDisabledTools: false
|
|
7222
7319
|
}
|
|
@@ -7929,9 +8026,15 @@ import { join as join59 } from "path";
|
|
|
7929
8026
|
var DirFeatureProcessor = class {
|
|
7930
8027
|
baseDir;
|
|
7931
8028
|
dryRun;
|
|
7932
|
-
|
|
8029
|
+
avoidBlockScalars;
|
|
8030
|
+
constructor({
|
|
8031
|
+
baseDir = process.cwd(),
|
|
8032
|
+
dryRun = false,
|
|
8033
|
+
avoidBlockScalars = false
|
|
8034
|
+
}) {
|
|
7933
8035
|
this.baseDir = baseDir;
|
|
7934
8036
|
this.dryRun = dryRun;
|
|
8037
|
+
this.avoidBlockScalars = avoidBlockScalars;
|
|
7935
8038
|
}
|
|
7936
8039
|
/**
|
|
7937
8040
|
* Return tool targets that this feature supports.
|
|
@@ -7957,7 +8060,9 @@ var DirFeatureProcessor = class {
|
|
|
7957
8060
|
let mainFileContent;
|
|
7958
8061
|
if (mainFile) {
|
|
7959
8062
|
const mainFilePath = join59(dirPath, mainFile.name);
|
|
7960
|
-
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter
|
|
8063
|
+
const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter, {
|
|
8064
|
+
avoidBlockScalars: this.avoidBlockScalars
|
|
8065
|
+
});
|
|
7961
8066
|
mainFileContent = addTrailingNewline(content);
|
|
7962
8067
|
const existingContent = await readFileContentOrNull(mainFilePath);
|
|
7963
8068
|
if (existingContent !== mainFileContent) {
|
|
@@ -10696,7 +10801,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
10696
10801
|
getFactory = defaultGetFactory4,
|
|
10697
10802
|
dryRun = false
|
|
10698
10803
|
}) {
|
|
10699
|
-
super({ baseDir, dryRun });
|
|
10804
|
+
super({ baseDir, dryRun, avoidBlockScalars: toolTarget === "cursor" });
|
|
10700
10805
|
const result = SkillsProcessorToolTargetSchema.safeParse(toolTarget);
|
|
10701
10806
|
if (!result.success) {
|
|
10702
10807
|
throw new Error(
|
|
@@ -11777,7 +11882,7 @@ var CursorSubagent = class _CursorSubagent extends ToolSubagent {
|
|
|
11777
11882
|
...cursorSection
|
|
11778
11883
|
};
|
|
11779
11884
|
const body = rulesyncSubagent.getBody();
|
|
11780
|
-
const fileContent = stringifyFrontmatter(body, cursorFrontmatter);
|
|
11885
|
+
const fileContent = stringifyFrontmatter(body, cursorFrontmatter, { avoidBlockScalars: true });
|
|
11781
11886
|
const paths = this.getSettablePaths({ global });
|
|
11782
11887
|
return new _CursorSubagent({
|
|
11783
11888
|
baseDir,
|
|
@@ -16912,6 +17017,7 @@ export {
|
|
|
16912
17017
|
ALL_FEATURES,
|
|
16913
17018
|
ALL_FEATURES_WITH_WILDCARD,
|
|
16914
17019
|
ALL_TOOL_TARGETS,
|
|
17020
|
+
findControlCharacter,
|
|
16915
17021
|
ConfigResolver,
|
|
16916
17022
|
stringifyFrontmatter,
|
|
16917
17023
|
RulesyncCommandFrontmatterSchema,
|