rulesync 5.9.1 → 6.1.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 +24 -0
- package/dist/index.cjs +145 -109
- package/dist/index.js +555 -519
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,6 +272,30 @@ Example:
|
|
|
272
272
|
}
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
+
### Local Configuration
|
|
276
|
+
|
|
277
|
+
Rulesync supports a local configuration file (`rulesync.local.jsonc`) for machine-specific or developer-specific settings. This file is automatically added to `.gitignore` by `rulesync gitignore` and should not be committed to the repository.
|
|
278
|
+
|
|
279
|
+
**Configuration Priority** (highest to lowest):
|
|
280
|
+
|
|
281
|
+
1. CLI options
|
|
282
|
+
2. `rulesync.local.jsonc`
|
|
283
|
+
3. `rulesync.jsonc`
|
|
284
|
+
4. Default values
|
|
285
|
+
|
|
286
|
+
Example usage:
|
|
287
|
+
|
|
288
|
+
```jsonc
|
|
289
|
+
// rulesync.local.jsonc (not committed to git)
|
|
290
|
+
{
|
|
291
|
+
"$schema": "https://raw.githubusercontent.com/dyoshikawa/rulesync/refs/heads/main/config-schema.json",
|
|
292
|
+
// Override targets for local development
|
|
293
|
+
"targets": ["claudecode"],
|
|
294
|
+
// Enable verbose output for debugging
|
|
295
|
+
"verbose": true,
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
275
299
|
### Target Order and File Conflicts
|
|
276
300
|
|
|
277
301
|
When multiple targets write to the same output file, **the last target in the array wins**. This is the "last-wins" behavior.
|
package/dist/index.cjs
CHANGED
|
@@ -118,14 +118,29 @@ var logger = new Logger();
|
|
|
118
118
|
|
|
119
119
|
// src/config/config-resolver.ts
|
|
120
120
|
var import_jsonc_parser = require("jsonc-parser");
|
|
121
|
-
var
|
|
121
|
+
var import_node_path3 = require("path");
|
|
122
|
+
|
|
123
|
+
// src/constants/rulesync-paths.ts
|
|
124
|
+
var import_node_path = require("path");
|
|
125
|
+
var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
126
|
+
var RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
|
|
127
|
+
var RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
128
|
+
var RULESYNC_RULES_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "rules");
|
|
129
|
+
var RULESYNC_COMMANDS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "commands");
|
|
130
|
+
var RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "subagents");
|
|
131
|
+
var RULESYNC_MCP_RELATIVE_FILE_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
132
|
+
var RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
133
|
+
var RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
134
|
+
var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
135
|
+
var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
136
|
+
var RULESYNC_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path.join)(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
122
137
|
|
|
123
138
|
// src/utils/file.ts
|
|
124
139
|
var import_es_toolkit = require("es-toolkit");
|
|
125
140
|
var import_globby = require("globby");
|
|
126
141
|
var import_promises = require("fs/promises");
|
|
127
142
|
var import_node_os = __toESM(require("os"), 1);
|
|
128
|
-
var
|
|
143
|
+
var import_node_path2 = require("path");
|
|
129
144
|
async function ensureDir(dirPath) {
|
|
130
145
|
try {
|
|
131
146
|
await (0, import_promises.stat)(dirPath);
|
|
@@ -137,7 +152,7 @@ async function readOrInitializeFileContent(filePath, initialContent = "") {
|
|
|
137
152
|
if (await fileExists(filePath)) {
|
|
138
153
|
return await readFileContent(filePath);
|
|
139
154
|
} else {
|
|
140
|
-
await ensureDir((0,
|
|
155
|
+
await ensureDir((0, import_node_path2.dirname)(filePath));
|
|
141
156
|
await writeFileContent(filePath, initialContent);
|
|
142
157
|
return initialContent;
|
|
143
158
|
}
|
|
@@ -150,16 +165,16 @@ function checkPathTraversal({
|
|
|
150
165
|
if (segments.includes("..")) {
|
|
151
166
|
throw new Error(`Path traversal detected: ${relativePath}`);
|
|
152
167
|
}
|
|
153
|
-
const resolved = (0,
|
|
154
|
-
const rel = (0,
|
|
155
|
-
if (rel.startsWith("..") || (0,
|
|
168
|
+
const resolved = (0, import_node_path2.resolve)(intendedRootDir, relativePath);
|
|
169
|
+
const rel = (0, import_node_path2.relative)(intendedRootDir, resolved);
|
|
170
|
+
if (rel.startsWith("..") || (0, import_node_path2.resolve)(resolved) !== resolved) {
|
|
156
171
|
throw new Error(`Path traversal detected: ${relativePath}`);
|
|
157
172
|
}
|
|
158
173
|
}
|
|
159
174
|
function resolvePath(relativePath, baseDir) {
|
|
160
175
|
if (!baseDir) return relativePath;
|
|
161
176
|
checkPathTraversal({ relativePath, intendedRootDir: baseDir });
|
|
162
|
-
return (0,
|
|
177
|
+
return (0, import_node_path2.resolve)(baseDir, relativePath);
|
|
163
178
|
}
|
|
164
179
|
async function directoryExists(dirPath) {
|
|
165
180
|
try {
|
|
@@ -185,7 +200,7 @@ function addTrailingNewline(content) {
|
|
|
185
200
|
}
|
|
186
201
|
async function writeFileContent(filepath, content) {
|
|
187
202
|
logger.debug(`Writing file: ${filepath}`);
|
|
188
|
-
await ensureDir((0,
|
|
203
|
+
await ensureDir((0, import_node_path2.dirname)(filepath));
|
|
189
204
|
await (0, import_promises.writeFile)(filepath, content, "utf-8");
|
|
190
205
|
}
|
|
191
206
|
async function fileExists(filepath) {
|
|
@@ -413,7 +428,7 @@ var getDefaults = () => ({
|
|
|
413
428
|
verbose: false,
|
|
414
429
|
delete: false,
|
|
415
430
|
baseDirs: [process.cwd()],
|
|
416
|
-
configPath:
|
|
431
|
+
configPath: RULESYNC_CONFIG_RELATIVE_FILE_PATH,
|
|
417
432
|
global: false,
|
|
418
433
|
silent: false,
|
|
419
434
|
simulateCommands: false,
|
|
@@ -421,6 +436,36 @@ var getDefaults = () => ({
|
|
|
421
436
|
simulateSkills: false,
|
|
422
437
|
modularMcp: false
|
|
423
438
|
});
|
|
439
|
+
var loadConfigFromFile = async (filePath) => {
|
|
440
|
+
if (!await fileExists(filePath)) {
|
|
441
|
+
return {};
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const fileContent = await readFileContent(filePath);
|
|
445
|
+
const jsonData = (0, import_jsonc_parser.parse)(fileContent);
|
|
446
|
+
const parsed = ConfigFileSchema.parse(jsonData);
|
|
447
|
+
const { $schema: _schema, ...configParams } = parsed;
|
|
448
|
+
return configParams;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
logger.error(`Failed to load config file "${filePath}": ${formatError(error)}`);
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var mergeConfigs = (baseConfig, localConfig) => {
|
|
455
|
+
return {
|
|
456
|
+
targets: localConfig.targets ?? baseConfig.targets,
|
|
457
|
+
features: localConfig.features ?? baseConfig.features,
|
|
458
|
+
verbose: localConfig.verbose ?? baseConfig.verbose,
|
|
459
|
+
delete: localConfig.delete ?? baseConfig.delete,
|
|
460
|
+
baseDirs: localConfig.baseDirs ?? baseConfig.baseDirs,
|
|
461
|
+
global: localConfig.global ?? baseConfig.global,
|
|
462
|
+
silent: localConfig.silent ?? baseConfig.silent,
|
|
463
|
+
simulateCommands: localConfig.simulateCommands ?? baseConfig.simulateCommands,
|
|
464
|
+
simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
|
|
465
|
+
simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
|
|
466
|
+
modularMcp: localConfig.modularMcp ?? baseConfig.modularMcp
|
|
467
|
+
};
|
|
468
|
+
};
|
|
424
469
|
var ConfigResolver = class {
|
|
425
470
|
static async resolve({
|
|
426
471
|
targets,
|
|
@@ -437,19 +482,11 @@ var ConfigResolver = class {
|
|
|
437
482
|
modularMcp
|
|
438
483
|
}) {
|
|
439
484
|
const validatedConfigPath = resolvePath(configPath, process.cwd());
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const parsed = ConfigFileSchema.parse(jsonData);
|
|
446
|
-
const { $schema: _schema, ...configParams2 } = parsed;
|
|
447
|
-
configByFile = configParams2;
|
|
448
|
-
} catch (error) {
|
|
449
|
-
logger.error(`Failed to load config file: ${formatError(error)}`);
|
|
450
|
-
throw error;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
485
|
+
const baseConfig = await loadConfigFromFile(validatedConfigPath);
|
|
486
|
+
const configDir = (0, import_node_path3.dirname)(validatedConfigPath);
|
|
487
|
+
const localConfigPath = (0, import_node_path3.join)(configDir, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
|
|
488
|
+
const localConfig = await loadConfigFromFile(localConfigPath);
|
|
489
|
+
const configByFile = mergeConfigs(baseConfig, localConfig);
|
|
453
490
|
const resolvedGlobal = global ?? configByFile.global ?? getDefaults().global;
|
|
454
491
|
const resolvedSimulateCommands = simulateCommands ?? configByFile.simulateCommands ?? getDefaults().simulateCommands;
|
|
455
492
|
const resolvedSimulateSubagents = simulateSubagents ?? configByFile.simulateSubagents ?? getDefaults().simulateSubagents;
|
|
@@ -480,7 +517,7 @@ function getBaseDirsInLightOfGlobal({
|
|
|
480
517
|
if (global) {
|
|
481
518
|
return [getHomeDirectory()];
|
|
482
519
|
}
|
|
483
|
-
const resolvedBaseDirs = baseDirs.map((baseDir) => (0,
|
|
520
|
+
const resolvedBaseDirs = baseDirs.map((baseDir) => (0, import_node_path3.resolve)(baseDir));
|
|
484
521
|
resolvedBaseDirs.forEach((baseDir) => {
|
|
485
522
|
validateBaseDir(baseDir);
|
|
486
523
|
});
|
|
@@ -491,20 +528,6 @@ function getBaseDirsInLightOfGlobal({
|
|
|
491
528
|
var import_es_toolkit4 = require("es-toolkit");
|
|
492
529
|
var import_node_path98 = require("path");
|
|
493
530
|
|
|
494
|
-
// src/constants/rulesync-paths.ts
|
|
495
|
-
var import_node_path3 = require("path");
|
|
496
|
-
var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
497
|
-
var RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
498
|
-
var RULESYNC_RULES_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "rules");
|
|
499
|
-
var RULESYNC_COMMANDS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "commands");
|
|
500
|
-
var RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "subagents");
|
|
501
|
-
var RULESYNC_MCP_RELATIVE_FILE_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
502
|
-
var RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
503
|
-
var RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
504
|
-
var RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
505
|
-
var RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
506
|
-
var RULESYNC_SKILLS_RELATIVE_DIR_PATH = (0, import_node_path3.join)(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
507
|
-
|
|
508
531
|
// src/features/commands/commands-processor.ts
|
|
509
532
|
var import_node_path19 = require("path");
|
|
510
533
|
var import_mini12 = require("zod/mini");
|
|
@@ -938,9 +961,6 @@ var RulesyncFile = class extends AiFile {
|
|
|
938
961
|
static async fromFile(_params) {
|
|
939
962
|
throw new Error("Please implement this method in the subclass.");
|
|
940
963
|
}
|
|
941
|
-
static async fromFileLegacy(_params) {
|
|
942
|
-
throw new Error("Please implement this method in the subclass.");
|
|
943
|
-
}
|
|
944
964
|
};
|
|
945
965
|
|
|
946
966
|
// src/features/commands/rulesync-command.ts
|
|
@@ -4321,6 +4341,46 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
|
|
|
4321
4341
|
|
|
4322
4342
|
// src/features/mcp/cursor-mcp.ts
|
|
4323
4343
|
var import_node_path39 = require("path");
|
|
4344
|
+
var CURSOR_ENV_VAR_PATTERN = /\$\{env:([^}]+)\}/g;
|
|
4345
|
+
function isMcpServers(value) {
|
|
4346
|
+
return value !== void 0 && value !== null && typeof value === "object";
|
|
4347
|
+
}
|
|
4348
|
+
function convertEnvFromCursorFormat(mcpServers) {
|
|
4349
|
+
return Object.fromEntries(
|
|
4350
|
+
Object.entries(mcpServers).map(([name, config]) => [
|
|
4351
|
+
name,
|
|
4352
|
+
{
|
|
4353
|
+
...config,
|
|
4354
|
+
...config.env && {
|
|
4355
|
+
env: Object.fromEntries(
|
|
4356
|
+
Object.entries(config.env).map(([k, v]) => [
|
|
4357
|
+
k,
|
|
4358
|
+
v.replace(CURSOR_ENV_VAR_PATTERN, "${$1}")
|
|
4359
|
+
])
|
|
4360
|
+
)
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
])
|
|
4364
|
+
);
|
|
4365
|
+
}
|
|
4366
|
+
function convertEnvToCursorFormat(mcpServers) {
|
|
4367
|
+
return Object.fromEntries(
|
|
4368
|
+
Object.entries(mcpServers).map(([name, config]) => [
|
|
4369
|
+
name,
|
|
4370
|
+
{
|
|
4371
|
+
...config,
|
|
4372
|
+
...config.env && {
|
|
4373
|
+
env: Object.fromEntries(
|
|
4374
|
+
Object.entries(config.env).map(([k, v]) => [
|
|
4375
|
+
k,
|
|
4376
|
+
v.replace(/\$\{(?!env:)([^}:]+)\}/g, "${env:$1}")
|
|
4377
|
+
])
|
|
4378
|
+
)
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
])
|
|
4382
|
+
);
|
|
4383
|
+
}
|
|
4324
4384
|
var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
4325
4385
|
json;
|
|
4326
4386
|
constructor(params) {
|
|
@@ -4361,8 +4421,10 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
4361
4421
|
validate = true
|
|
4362
4422
|
}) {
|
|
4363
4423
|
const json = rulesyncMcp.getJson();
|
|
4424
|
+
const mcpServers = isMcpServers(json.mcpServers) ? json.mcpServers : {};
|
|
4425
|
+
const transformedServers = convertEnvToCursorFormat(mcpServers);
|
|
4364
4426
|
const cursorConfig = {
|
|
4365
|
-
mcpServers:
|
|
4427
|
+
mcpServers: transformedServers
|
|
4366
4428
|
};
|
|
4367
4429
|
const fileContent = JSON.stringify(cursorConfig, null, 2);
|
|
4368
4430
|
return new _CursorMcp({
|
|
@@ -4374,11 +4436,17 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
|
|
|
4374
4436
|
});
|
|
4375
4437
|
}
|
|
4376
4438
|
toRulesyncMcp() {
|
|
4439
|
+
const mcpServers = isMcpServers(this.json.mcpServers) ? this.json.mcpServers : {};
|
|
4440
|
+
const transformedServers = convertEnvFromCursorFormat(mcpServers);
|
|
4441
|
+
const transformedJson = {
|
|
4442
|
+
...this.json,
|
|
4443
|
+
mcpServers: transformedServers
|
|
4444
|
+
};
|
|
4377
4445
|
return new RulesyncMcp({
|
|
4378
4446
|
baseDir: this.baseDir,
|
|
4379
4447
|
relativeDirPath: this.relativeDirPath,
|
|
4380
4448
|
relativeFilePath: "rulesync.mcp.json",
|
|
4381
|
-
fileContent:
|
|
4449
|
+
fileContent: JSON.stringify(transformedJson),
|
|
4382
4450
|
validate: true
|
|
4383
4451
|
});
|
|
4384
4452
|
}
|
|
@@ -9025,47 +9093,6 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
|
|
|
9025
9093
|
};
|
|
9026
9094
|
}
|
|
9027
9095
|
}
|
|
9028
|
-
static async fromFileLegacy({
|
|
9029
|
-
relativeFilePath,
|
|
9030
|
-
validate = true
|
|
9031
|
-
}) {
|
|
9032
|
-
const legacyPath = (0, import_node_path75.join)(
|
|
9033
|
-
process.cwd(),
|
|
9034
|
-
this.getSettablePaths().legacy.relativeDirPath,
|
|
9035
|
-
relativeFilePath
|
|
9036
|
-
);
|
|
9037
|
-
const recommendedPath = (0, import_node_path75.join)(
|
|
9038
|
-
this.getSettablePaths().recommended.relativeDirPath,
|
|
9039
|
-
relativeFilePath
|
|
9040
|
-
);
|
|
9041
|
-
logger.warn(
|
|
9042
|
-
`\u26A0\uFE0F Using deprecated path "${legacyPath}". Please migrate to "${recommendedPath}"`
|
|
9043
|
-
);
|
|
9044
|
-
const fileContent = await readFileContent(legacyPath);
|
|
9045
|
-
const { frontmatter, body: content } = parseFrontmatter(fileContent);
|
|
9046
|
-
const result = RulesyncRuleFrontmatterSchema.safeParse(frontmatter);
|
|
9047
|
-
if (!result.success) {
|
|
9048
|
-
throw new Error(`Invalid frontmatter in ${legacyPath}: ${formatError(result.error)}`);
|
|
9049
|
-
}
|
|
9050
|
-
const validatedFrontmatter = {
|
|
9051
|
-
root: result.data.root ?? false,
|
|
9052
|
-
localRoot: result.data.localRoot ?? false,
|
|
9053
|
-
targets: result.data.targets ?? ["*"],
|
|
9054
|
-
description: result.data.description ?? "",
|
|
9055
|
-
globs: result.data.globs ?? [],
|
|
9056
|
-
agentsmd: result.data.agentsmd,
|
|
9057
|
-
cursor: result.data.cursor
|
|
9058
|
-
};
|
|
9059
|
-
const filename = (0, import_node_path75.basename)(legacyPath);
|
|
9060
|
-
return new _RulesyncRule({
|
|
9061
|
-
baseDir: process.cwd(),
|
|
9062
|
-
relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
|
|
9063
|
-
relativeFilePath: filename,
|
|
9064
|
-
frontmatter: validatedFrontmatter,
|
|
9065
|
-
body: content.trim(),
|
|
9066
|
-
validate
|
|
9067
|
-
});
|
|
9068
|
-
}
|
|
9069
9096
|
static async fromFile({
|
|
9070
9097
|
relativeFilePath,
|
|
9071
9098
|
validate = true
|
|
@@ -9090,11 +9117,10 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
|
|
|
9090
9117
|
agentsmd: result.data.agentsmd,
|
|
9091
9118
|
cursor: result.data.cursor
|
|
9092
9119
|
};
|
|
9093
|
-
const filename = (0, import_node_path75.basename)(filePath);
|
|
9094
9120
|
return new _RulesyncRule({
|
|
9095
9121
|
baseDir: process.cwd(),
|
|
9096
9122
|
relativeDirPath: this.getSettablePaths().recommended.relativeDirPath,
|
|
9097
|
-
relativeFilePath
|
|
9123
|
+
relativeFilePath,
|
|
9098
9124
|
frontmatter: validatedFrontmatter,
|
|
9099
9125
|
body: content.trim(),
|
|
9100
9126
|
validate
|
|
@@ -9927,7 +9953,7 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
|
|
|
9927
9953
|
}
|
|
9928
9954
|
return {
|
|
9929
9955
|
root: {
|
|
9930
|
-
relativeDirPath: ".
|
|
9956
|
+
relativeDirPath: ".",
|
|
9931
9957
|
relativeFilePath: "CLAUDE.md"
|
|
9932
9958
|
},
|
|
9933
9959
|
nonRoot: {
|
|
@@ -10634,7 +10660,7 @@ var CursorRule = class _CursorRule extends ToolRule {
|
|
|
10634
10660
|
return new _CursorRule({
|
|
10635
10661
|
baseDir,
|
|
10636
10662
|
relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
|
|
10637
|
-
relativeFilePath
|
|
10663
|
+
relativeFilePath,
|
|
10638
10664
|
frontmatter: result.data,
|
|
10639
10665
|
body: content.trim(),
|
|
10640
10666
|
validate
|
|
@@ -11803,7 +11829,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11803
11829
|
}
|
|
11804
11830
|
/**
|
|
11805
11831
|
* Handle localRoot rule generation based on tool target.
|
|
11806
|
-
* - Claude Code: generates
|
|
11832
|
+
* - Claude Code: generates `./CLAUDE.local.md`
|
|
11807
11833
|
* - Claude Code Legacy: generates `./CLAUDE.local.md`
|
|
11808
11834
|
* - Other tools: appends content to the root file with one blank line separator
|
|
11809
11835
|
*/
|
|
@@ -11904,10 +11930,17 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11904
11930
|
* Load and parse rulesync rule files from .rulesync/rules/ directory
|
|
11905
11931
|
*/
|
|
11906
11932
|
async loadRulesyncFiles() {
|
|
11907
|
-
const
|
|
11933
|
+
const rulesyncBaseDir = (0, import_node_path97.join)(this.baseDir, RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
11934
|
+
const files = await findFilesByGlobs((0, import_node_path97.join)(rulesyncBaseDir, "**", "*.md"));
|
|
11908
11935
|
logger.debug(`Found ${files.length} rulesync files`);
|
|
11909
11936
|
const rulesyncRules = await Promise.all(
|
|
11910
|
-
files.map((file) =>
|
|
11937
|
+
files.map((file) => {
|
|
11938
|
+
const relativeFilePath = (0, import_node_path97.relative)(rulesyncBaseDir, file);
|
|
11939
|
+
checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: rulesyncBaseDir });
|
|
11940
|
+
return RulesyncRule.fromFile({
|
|
11941
|
+
relativeFilePath
|
|
11942
|
+
});
|
|
11943
|
+
})
|
|
11911
11944
|
);
|
|
11912
11945
|
const rootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().root);
|
|
11913
11946
|
if (rootRules.length > 1) {
|
|
@@ -11941,13 +11974,6 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11941
11974
|
}
|
|
11942
11975
|
return rulesyncRules;
|
|
11943
11976
|
}
|
|
11944
|
-
async loadRulesyncFilesLegacy() {
|
|
11945
|
-
const legacyFiles = await findFilesByGlobs((0, import_node_path97.join)(RULESYNC_RELATIVE_DIR_PATH, "*.md"));
|
|
11946
|
-
logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
|
|
11947
|
-
return Promise.all(
|
|
11948
|
-
legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: (0, import_node_path97.basename)(file) }))
|
|
11949
|
-
);
|
|
11950
|
-
}
|
|
11951
11977
|
/**
|
|
11952
11978
|
* Implementation of abstract method from FeatureProcessor
|
|
11953
11979
|
* Load tool-specific rule configurations and parse them into ToolRule instances
|
|
@@ -12017,27 +12043,35 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
12017
12043
|
if (!settablePaths.nonRoot) {
|
|
12018
12044
|
return [];
|
|
12019
12045
|
}
|
|
12046
|
+
const nonRootBaseDir = (0, import_node_path97.join)(this.baseDir, settablePaths.nonRoot.relativeDirPath);
|
|
12020
12047
|
const nonRootFilePaths = await findFilesByGlobs(
|
|
12021
|
-
(0, import_node_path97.join)(
|
|
12048
|
+
(0, import_node_path97.join)(nonRootBaseDir, "**", `*.${factory.meta.extension}`)
|
|
12022
12049
|
);
|
|
12023
12050
|
if (forDeletion) {
|
|
12024
|
-
return nonRootFilePaths.map(
|
|
12025
|
-
(
|
|
12051
|
+
return nonRootFilePaths.map((filePath) => {
|
|
12052
|
+
const relativeFilePath = (0, import_node_path97.relative)(nonRootBaseDir, filePath);
|
|
12053
|
+
checkPathTraversal({
|
|
12054
|
+
relativePath: relativeFilePath,
|
|
12055
|
+
intendedRootDir: nonRootBaseDir
|
|
12056
|
+
});
|
|
12057
|
+
return factory.class.forDeletion({
|
|
12026
12058
|
baseDir: this.baseDir,
|
|
12027
12059
|
relativeDirPath: settablePaths.nonRoot?.relativeDirPath ?? ".",
|
|
12028
|
-
relativeFilePath
|
|
12060
|
+
relativeFilePath,
|
|
12029
12061
|
global: this.global
|
|
12030
|
-
})
|
|
12031
|
-
).filter((rule) => rule.isDeletable());
|
|
12062
|
+
});
|
|
12063
|
+
}).filter((rule) => rule.isDeletable());
|
|
12032
12064
|
}
|
|
12033
12065
|
return await Promise.all(
|
|
12034
|
-
nonRootFilePaths.map(
|
|
12035
|
-
(
|
|
12066
|
+
nonRootFilePaths.map((filePath) => {
|
|
12067
|
+
const relativeFilePath = (0, import_node_path97.relative)(nonRootBaseDir, filePath);
|
|
12068
|
+
checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: nonRootBaseDir });
|
|
12069
|
+
return factory.class.fromFile({
|
|
12036
12070
|
baseDir: this.baseDir,
|
|
12037
|
-
relativeFilePath
|
|
12071
|
+
relativeFilePath,
|
|
12038
12072
|
global: this.global
|
|
12039
|
-
})
|
|
12040
|
-
)
|
|
12073
|
+
});
|
|
12074
|
+
})
|
|
12041
12075
|
);
|
|
12042
12076
|
})();
|
|
12043
12077
|
logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
|
|
@@ -12548,6 +12582,7 @@ var RULESYNC_IGNORE_ENTRIES = [
|
|
|
12548
12582
|
// Others
|
|
12549
12583
|
"**/modular-mcp.json",
|
|
12550
12584
|
".rulesync/rules/*.local.md",
|
|
12585
|
+
"rulesync.local.jsonc",
|
|
12551
12586
|
"!.rulesync/.aiignore"
|
|
12552
12587
|
];
|
|
12553
12588
|
var isRulesyncHeader = (line) => {
|
|
@@ -12829,6 +12864,7 @@ async function createConfigFile() {
|
|
|
12829
12864
|
baseDirs: ["."],
|
|
12830
12865
|
delete: true,
|
|
12831
12866
|
verbose: false,
|
|
12867
|
+
silent: false,
|
|
12832
12868
|
global: false,
|
|
12833
12869
|
simulateCommands: false,
|
|
12834
12870
|
simulateSubagents: false,
|
|
@@ -14244,7 +14280,7 @@ async function mcpCommand({ version }) {
|
|
|
14244
14280
|
}
|
|
14245
14281
|
|
|
14246
14282
|
// src/cli/index.ts
|
|
14247
|
-
var getVersion = () => "
|
|
14283
|
+
var getVersion = () => "6.1.0";
|
|
14248
14284
|
var main = async () => {
|
|
14249
14285
|
const program = new import_commander.Command();
|
|
14250
14286
|
const version = getVersion();
|