rulesync 5.8.0 → 5.9.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 -0
- package/dist/index.cjs +306 -171
- package/dist/index.js +295 -160
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -93,9 +93,6 @@ var Logger = class {
|
|
|
93
93
|
};
|
|
94
94
|
var logger = new Logger();
|
|
95
95
|
|
|
96
|
-
// src/cli/commands/generate.ts
|
|
97
|
-
import { intersection } from "es-toolkit";
|
|
98
|
-
|
|
99
96
|
// src/config/config-resolver.ts
|
|
100
97
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
101
98
|
import { resolve as resolve2 } from "path";
|
|
@@ -467,6 +464,10 @@ function getBaseDirsInLightOfGlobal({
|
|
|
467
464
|
return resolvedBaseDirs;
|
|
468
465
|
}
|
|
469
466
|
|
|
467
|
+
// src/lib/generate.ts
|
|
468
|
+
import { intersection } from "es-toolkit";
|
|
469
|
+
import { join as join96 } from "path";
|
|
470
|
+
|
|
470
471
|
// src/constants/rulesync-paths.ts
|
|
471
472
|
import { join as join2 } from "path";
|
|
472
473
|
var RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
@@ -8916,7 +8917,8 @@ import { join as join74 } from "path";
|
|
|
8916
8917
|
import { basename as basename22, join as join73 } from "path";
|
|
8917
8918
|
import { z as z38 } from "zod/mini";
|
|
8918
8919
|
var RulesyncRuleFrontmatterSchema = z38.object({
|
|
8919
|
-
root: z38.optional(z38.
|
|
8920
|
+
root: z38.optional(z38.boolean()),
|
|
8921
|
+
localRoot: z38.optional(z38.boolean()),
|
|
8920
8922
|
targets: z38.optional(RulesyncTargetsSchema),
|
|
8921
8923
|
description: z38.optional(z38.string()),
|
|
8922
8924
|
globs: z38.optional(z38.array(z38.string())),
|
|
@@ -9024,6 +9026,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
|
|
|
9024
9026
|
}
|
|
9025
9027
|
const validatedFrontmatter = {
|
|
9026
9028
|
root: result.data.root ?? false,
|
|
9029
|
+
localRoot: result.data.localRoot ?? false,
|
|
9027
9030
|
targets: result.data.targets ?? ["*"],
|
|
9028
9031
|
description: result.data.description ?? "",
|
|
9029
9032
|
globs: result.data.globs ?? [],
|
|
@@ -9057,6 +9060,7 @@ var RulesyncRule = class _RulesyncRule extends RulesyncFile {
|
|
|
9057
9060
|
}
|
|
9058
9061
|
const validatedFrontmatter = {
|
|
9059
9062
|
root: result.data.root ?? false,
|
|
9063
|
+
localRoot: result.data.localRoot ?? false,
|
|
9060
9064
|
targets: result.data.targets ?? ["*"],
|
|
9061
9065
|
description: result.data.description ?? "",
|
|
9062
9066
|
globs: result.data.globs ?? [],
|
|
@@ -11699,9 +11703,11 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11699
11703
|
const rulesyncRules = rulesyncFiles.filter(
|
|
11700
11704
|
(file) => file instanceof RulesyncRule
|
|
11701
11705
|
);
|
|
11706
|
+
const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
|
|
11707
|
+
const nonLocalRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().localRoot);
|
|
11702
11708
|
const factory = this.getFactory(this.toolTarget);
|
|
11703
11709
|
const { meta } = factory;
|
|
11704
|
-
const toolRules =
|
|
11710
|
+
const toolRules = nonLocalRootRules.map((rulesyncRule) => {
|
|
11705
11711
|
if (!factory.class.isTargetedByRulesyncRule(rulesyncRule)) {
|
|
11706
11712
|
return null;
|
|
11707
11713
|
}
|
|
@@ -11712,6 +11718,12 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11712
11718
|
global: this.global
|
|
11713
11719
|
});
|
|
11714
11720
|
}).filter((rule) => rule !== null);
|
|
11721
|
+
if (localRootRules.length > 0 && !this.global) {
|
|
11722
|
+
const localRootRule = localRootRules[0];
|
|
11723
|
+
if (localRootRule && factory.class.isTargetedByRulesyncRule(localRootRule)) {
|
|
11724
|
+
this.handleLocalRootRule(toolRules, localRootRule, factory);
|
|
11725
|
+
}
|
|
11726
|
+
}
|
|
11715
11727
|
const isSimulated = this.simulateCommands || this.simulateSubagents || this.simulateSkills;
|
|
11716
11728
|
if (isSimulated && meta.createsSeparateConventionsRule && meta.additionalConventions) {
|
|
11717
11729
|
const conventionsContent = this.generateAdditionalConventionsSectionFromMeta(meta);
|
|
@@ -11766,6 +11778,50 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11766
11778
|
};
|
|
11767
11779
|
});
|
|
11768
11780
|
}
|
|
11781
|
+
/**
|
|
11782
|
+
* Handle localRoot rule generation based on tool target.
|
|
11783
|
+
* - Claude Code: generates `.claude/CLAUDE.local.md`
|
|
11784
|
+
* - Claude Code Legacy: generates `./CLAUDE.local.md`
|
|
11785
|
+
* - Other tools: appends content to the root file with one blank line separator
|
|
11786
|
+
*/
|
|
11787
|
+
handleLocalRootRule(toolRules, localRootRule, _factory) {
|
|
11788
|
+
const localRootBody = localRootRule.getBody();
|
|
11789
|
+
if (this.toolTarget === "claudecode") {
|
|
11790
|
+
const paths = ClaudecodeRule.getSettablePaths({ global: this.global });
|
|
11791
|
+
toolRules.push(
|
|
11792
|
+
new ClaudecodeRule({
|
|
11793
|
+
baseDir: this.baseDir,
|
|
11794
|
+
relativeDirPath: paths.root.relativeDirPath,
|
|
11795
|
+
relativeFilePath: "CLAUDE.local.md",
|
|
11796
|
+
frontmatter: {},
|
|
11797
|
+
body: localRootBody,
|
|
11798
|
+
validate: true,
|
|
11799
|
+
root: true
|
|
11800
|
+
// Treat as root so it doesn't have frontmatter
|
|
11801
|
+
})
|
|
11802
|
+
);
|
|
11803
|
+
} else if (this.toolTarget === "claudecode-legacy") {
|
|
11804
|
+
const paths = ClaudecodeLegacyRule.getSettablePaths({ global: this.global });
|
|
11805
|
+
toolRules.push(
|
|
11806
|
+
new ClaudecodeLegacyRule({
|
|
11807
|
+
baseDir: this.baseDir,
|
|
11808
|
+
relativeDirPath: paths.root.relativeDirPath,
|
|
11809
|
+
relativeFilePath: "CLAUDE.local.md",
|
|
11810
|
+
fileContent: localRootBody,
|
|
11811
|
+
validate: true,
|
|
11812
|
+
root: true
|
|
11813
|
+
// Treat as root so it doesn't have frontmatter
|
|
11814
|
+
})
|
|
11815
|
+
);
|
|
11816
|
+
} else {
|
|
11817
|
+
const rootRule = toolRules.find((rule) => rule.isRoot());
|
|
11818
|
+
if (rootRule) {
|
|
11819
|
+
const currentContent = rootRule.getFileContent();
|
|
11820
|
+
const newContent = currentContent + "\n\n" + localRootBody;
|
|
11821
|
+
rootRule.setFileContent(newContent);
|
|
11822
|
+
}
|
|
11823
|
+
}
|
|
11824
|
+
}
|
|
11769
11825
|
/**
|
|
11770
11826
|
* Generate reference section based on meta configuration.
|
|
11771
11827
|
*/
|
|
@@ -11834,6 +11890,18 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11834
11890
|
if (rootRules.length > 1) {
|
|
11835
11891
|
throw new Error("Multiple root rulesync rules found");
|
|
11836
11892
|
}
|
|
11893
|
+
if (rootRules.length === 0 && rulesyncRules.length > 0) {
|
|
11894
|
+
logger.warn(
|
|
11895
|
+
`No root rulesync rule file found. Consider adding 'root: true' to one of your rule files in ${RULESYNC_RULES_RELATIVE_DIR_PATH}.`
|
|
11896
|
+
);
|
|
11897
|
+
}
|
|
11898
|
+
const localRootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().localRoot);
|
|
11899
|
+
if (localRootRules.length > 1) {
|
|
11900
|
+
throw new Error("Multiple localRoot rules found. Only one rule can have localRoot: true");
|
|
11901
|
+
}
|
|
11902
|
+
if (localRootRules.length > 0 && rootRules.length === 0) {
|
|
11903
|
+
throw new Error("localRoot: true requires a root: true rule to exist");
|
|
11904
|
+
}
|
|
11837
11905
|
if (this.global) {
|
|
11838
11906
|
const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root);
|
|
11839
11907
|
if (nonRootRules.length > 0) {
|
|
@@ -11841,6 +11909,11 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11841
11909
|
`${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them`
|
|
11842
11910
|
);
|
|
11843
11911
|
}
|
|
11912
|
+
if (localRootRules.length > 0) {
|
|
11913
|
+
logger.warn(
|
|
11914
|
+
`${localRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them`
|
|
11915
|
+
);
|
|
11916
|
+
}
|
|
11844
11917
|
return rootRules;
|
|
11845
11918
|
}
|
|
11846
11919
|
return rulesyncRules;
|
|
@@ -11894,6 +11967,29 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11894
11967
|
);
|
|
11895
11968
|
})();
|
|
11896
11969
|
logger.debug(`Found ${rootToolRules.length} root tool rule files`);
|
|
11970
|
+
const localRootToolRules = await (async () => {
|
|
11971
|
+
if (!forDeletion) {
|
|
11972
|
+
return [];
|
|
11973
|
+
}
|
|
11974
|
+
if (this.toolTarget !== "claudecode" && this.toolTarget !== "claudecode-legacy") {
|
|
11975
|
+
return [];
|
|
11976
|
+
}
|
|
11977
|
+
if (!settablePaths.root) {
|
|
11978
|
+
return [];
|
|
11979
|
+
}
|
|
11980
|
+
const localRootFilePaths = await findFilesByGlobs(
|
|
11981
|
+
join95(this.baseDir, settablePaths.root.relativeDirPath ?? ".", "CLAUDE.local.md")
|
|
11982
|
+
);
|
|
11983
|
+
return localRootFilePaths.map(
|
|
11984
|
+
(filePath) => factory.class.forDeletion({
|
|
11985
|
+
baseDir: this.baseDir,
|
|
11986
|
+
relativeDirPath: settablePaths.root?.relativeDirPath ?? ".",
|
|
11987
|
+
relativeFilePath: basename24(filePath),
|
|
11988
|
+
global: this.global
|
|
11989
|
+
})
|
|
11990
|
+
).filter((rule) => rule.isDeletable());
|
|
11991
|
+
})();
|
|
11992
|
+
logger.debug(`Found ${localRootToolRules.length} local root tool rule files for deletion`);
|
|
11897
11993
|
const nonRootToolRules = await (async () => {
|
|
11898
11994
|
if (!settablePaths.nonRoot) {
|
|
11899
11995
|
return [];
|
|
@@ -11922,7 +12018,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
11922
12018
|
);
|
|
11923
12019
|
})();
|
|
11924
12020
|
logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
|
|
11925
|
-
return [...rootToolRules, ...nonRootToolRules];
|
|
12021
|
+
return [...rootToolRules, ...localRootToolRules, ...nonRootToolRules];
|
|
11926
12022
|
} catch (error) {
|
|
11927
12023
|
logger.error(`Failed to load tool files: ${formatError(error)}`);
|
|
11928
12024
|
return [];
|
|
@@ -12042,51 +12138,34 @@ ${toonContent}`;
|
|
|
12042
12138
|
}
|
|
12043
12139
|
};
|
|
12044
12140
|
|
|
12045
|
-
// src/
|
|
12046
|
-
async function
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
});
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
}
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12141
|
+
// src/lib/generate.ts
|
|
12142
|
+
async function checkRulesyncDirExists(params) {
|
|
12143
|
+
return fileExists(join96(params.baseDir, RULESYNC_RELATIVE_DIR_PATH));
|
|
12144
|
+
}
|
|
12145
|
+
async function generate(params) {
|
|
12146
|
+
const { config } = params;
|
|
12147
|
+
const ignoreCount = await generateIgnoreCore({ config });
|
|
12148
|
+
const mcpCount = await generateMcpCore({ config });
|
|
12149
|
+
const commandsCount = await generateCommandsCore({ config });
|
|
12150
|
+
const subagentsCount = await generateSubagentsCore({ config });
|
|
12151
|
+
const skillsResult = await generateSkillsCore({ config });
|
|
12152
|
+
const rulesCount = await generateRulesCore({ config, skills: skillsResult.skills });
|
|
12153
|
+
return {
|
|
12154
|
+
rulesCount,
|
|
12155
|
+
ignoreCount,
|
|
12156
|
+
mcpCount,
|
|
12157
|
+
commandsCount,
|
|
12158
|
+
subagentsCount,
|
|
12159
|
+
skillsCount: skillsResult.count,
|
|
12064
12160
|
skills: skillsResult.skills
|
|
12065
|
-
}
|
|
12066
|
-
const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs + skillsResult.totalOutputs;
|
|
12067
|
-
if (totalGenerated === 0) {
|
|
12068
|
-
const enabledFeatures = config.getFeatures().join(", ");
|
|
12069
|
-
logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
|
|
12070
|
-
return;
|
|
12071
|
-
}
|
|
12072
|
-
if (totalGenerated > 0) {
|
|
12073
|
-
const parts = [];
|
|
12074
|
-
if (totalRulesOutputs > 0) parts.push(`${totalRulesOutputs} rules`);
|
|
12075
|
-
if (totalIgnoreOutputs > 0) parts.push(`${totalIgnoreOutputs} ignore files`);
|
|
12076
|
-
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
|
|
12077
|
-
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
12078
|
-
if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
|
|
12079
|
-
if (skillsResult.totalOutputs > 0) parts.push(`${skillsResult.totalOutputs} skills`);
|
|
12080
|
-
logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
|
|
12081
|
-
}
|
|
12161
|
+
};
|
|
12082
12162
|
}
|
|
12083
|
-
async function
|
|
12163
|
+
async function generateRulesCore(params) {
|
|
12164
|
+
const { config, skills } = params;
|
|
12084
12165
|
if (!config.getFeatures().includes("rules")) {
|
|
12085
|
-
logger.debug("Skipping rule generation (not in --features)");
|
|
12086
12166
|
return 0;
|
|
12087
12167
|
}
|
|
12088
|
-
let
|
|
12089
|
-
logger.info("Generating rule files...");
|
|
12168
|
+
let totalCount = 0;
|
|
12090
12169
|
const toolTargets = intersection(
|
|
12091
12170
|
config.getTargets(),
|
|
12092
12171
|
RulesProcessor.getToolTargets({ global: config.getGlobal() })
|
|
@@ -12100,7 +12179,7 @@ async function generateRules(config, options) {
|
|
|
12100
12179
|
simulateCommands: config.getSimulateCommands(),
|
|
12101
12180
|
simulateSubagents: config.getSimulateSubagents(),
|
|
12102
12181
|
simulateSkills: config.getSimulateSkills(),
|
|
12103
|
-
skills
|
|
12182
|
+
skills
|
|
12104
12183
|
});
|
|
12105
12184
|
if (config.getDelete()) {
|
|
12106
12185
|
const oldToolFiles = await processor.loadToolFiles({ forDeletion: true });
|
|
@@ -12109,23 +12188,20 @@ async function generateRules(config, options) {
|
|
|
12109
12188
|
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
12110
12189
|
const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
|
|
12111
12190
|
const writtenCount = await processor.writeAiFiles(toolFiles);
|
|
12112
|
-
|
|
12113
|
-
logger.success(`Generated ${writtenCount} ${toolTarget} rule(s) in ${baseDir}`);
|
|
12191
|
+
totalCount += writtenCount;
|
|
12114
12192
|
}
|
|
12115
12193
|
}
|
|
12116
|
-
return
|
|
12194
|
+
return totalCount;
|
|
12117
12195
|
}
|
|
12118
|
-
async function
|
|
12196
|
+
async function generateIgnoreCore(params) {
|
|
12197
|
+
const { config } = params;
|
|
12119
12198
|
if (!config.getFeatures().includes("ignore")) {
|
|
12120
|
-
logger.debug("Skipping ignore file generation (not in --features)");
|
|
12121
12199
|
return 0;
|
|
12122
12200
|
}
|
|
12123
12201
|
if (config.getGlobal()) {
|
|
12124
|
-
logger.debug("Skipping ignore file generation (not supported in global mode)");
|
|
12125
12202
|
return 0;
|
|
12126
12203
|
}
|
|
12127
|
-
let
|
|
12128
|
-
logger.info("Generating ignore files...");
|
|
12204
|
+
let totalCount = 0;
|
|
12129
12205
|
for (const toolTarget of intersection(config.getTargets(), IgnoreProcessor.getToolTargets())) {
|
|
12130
12206
|
for (const baseDir of config.getBaseDirs()) {
|
|
12131
12207
|
try {
|
|
@@ -12141,30 +12217,24 @@ async function generateIgnore(config) {
|
|
|
12141
12217
|
if (rulesyncFiles.length > 0) {
|
|
12142
12218
|
const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
|
|
12143
12219
|
const writtenCount = await processor.writeAiFiles(toolFiles);
|
|
12144
|
-
|
|
12145
|
-
logger.success(`Generated ${writtenCount} ${toolTarget} ignore file(s) in ${baseDir}`);
|
|
12220
|
+
totalCount += writtenCount;
|
|
12146
12221
|
}
|
|
12147
12222
|
} catch (error) {
|
|
12148
12223
|
logger.warn(
|
|
12149
|
-
`Failed to generate ${toolTarget} ignore files for ${baseDir}
|
|
12150
|
-
error instanceof Error ? error.message : String(error)
|
|
12224
|
+
`Failed to generate ${toolTarget} ignore files for ${baseDir}: ${formatError(error)}`
|
|
12151
12225
|
);
|
|
12152
12226
|
continue;
|
|
12153
12227
|
}
|
|
12154
12228
|
}
|
|
12155
12229
|
}
|
|
12156
|
-
return
|
|
12230
|
+
return totalCount;
|
|
12157
12231
|
}
|
|
12158
|
-
async function
|
|
12232
|
+
async function generateMcpCore(params) {
|
|
12233
|
+
const { config } = params;
|
|
12159
12234
|
if (!config.getFeatures().includes("mcp")) {
|
|
12160
|
-
logger.debug("Skipping MCP configuration generation (not in --features)");
|
|
12161
12235
|
return 0;
|
|
12162
12236
|
}
|
|
12163
|
-
let
|
|
12164
|
-
logger.info("Generating MCP files...");
|
|
12165
|
-
if (config.getModularMcp()) {
|
|
12166
|
-
logger.info("\u2139\uFE0F Modular MCP support is experimental.");
|
|
12167
|
-
}
|
|
12237
|
+
let totalCount = 0;
|
|
12168
12238
|
const toolTargets = intersection(
|
|
12169
12239
|
config.getTargets(),
|
|
12170
12240
|
McpProcessor.getToolTargets({ global: config.getGlobal() })
|
|
@@ -12184,19 +12254,17 @@ async function generateMcp(config) {
|
|
|
12184
12254
|
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
12185
12255
|
const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
|
|
12186
12256
|
const writtenCount = await processor.writeAiFiles(toolFiles);
|
|
12187
|
-
|
|
12188
|
-
logger.success(`Generated ${writtenCount} ${toolTarget} MCP configuration(s) in ${baseDir}`);
|
|
12257
|
+
totalCount += writtenCount;
|
|
12189
12258
|
}
|
|
12190
12259
|
}
|
|
12191
|
-
return
|
|
12260
|
+
return totalCount;
|
|
12192
12261
|
}
|
|
12193
|
-
async function
|
|
12262
|
+
async function generateCommandsCore(params) {
|
|
12263
|
+
const { config } = params;
|
|
12194
12264
|
if (!config.getFeatures().includes("commands")) {
|
|
12195
|
-
logger.debug("Skipping command file generation (not in --features)");
|
|
12196
12265
|
return 0;
|
|
12197
12266
|
}
|
|
12198
|
-
let
|
|
12199
|
-
logger.info("Generating command files...");
|
|
12267
|
+
let totalCount = 0;
|
|
12200
12268
|
const toolTargets = intersection(
|
|
12201
12269
|
config.getTargets(),
|
|
12202
12270
|
CommandsProcessor.getToolTargets({
|
|
@@ -12218,19 +12286,17 @@ async function generateCommands(config) {
|
|
|
12218
12286
|
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
12219
12287
|
const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
|
|
12220
12288
|
const writtenCount = await processor.writeAiFiles(toolFiles);
|
|
12221
|
-
|
|
12222
|
-
logger.success(`Generated ${writtenCount} ${toolTarget} command(s) in ${baseDir}`);
|
|
12289
|
+
totalCount += writtenCount;
|
|
12223
12290
|
}
|
|
12224
12291
|
}
|
|
12225
|
-
return
|
|
12292
|
+
return totalCount;
|
|
12226
12293
|
}
|
|
12227
|
-
async function
|
|
12294
|
+
async function generateSubagentsCore(params) {
|
|
12295
|
+
const { config } = params;
|
|
12228
12296
|
if (!config.getFeatures().includes("subagents")) {
|
|
12229
|
-
logger.debug("Skipping subagent file generation (not in --features)");
|
|
12230
12297
|
return 0;
|
|
12231
12298
|
}
|
|
12232
|
-
let
|
|
12233
|
-
logger.info("Generating subagent files...");
|
|
12299
|
+
let totalCount = 0;
|
|
12234
12300
|
const toolTargets = intersection(
|
|
12235
12301
|
config.getTargets(),
|
|
12236
12302
|
SubagentsProcessor.getToolTargets({
|
|
@@ -12252,20 +12318,18 @@ async function generateSubagents(config) {
|
|
|
12252
12318
|
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
12253
12319
|
const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
|
|
12254
12320
|
const writtenCount = await processor.writeAiFiles(toolFiles);
|
|
12255
|
-
|
|
12256
|
-
logger.success(`Generated ${writtenCount} ${toolTarget} subagent(s) in ${baseDir}`);
|
|
12321
|
+
totalCount += writtenCount;
|
|
12257
12322
|
}
|
|
12258
12323
|
}
|
|
12259
|
-
return
|
|
12324
|
+
return totalCount;
|
|
12260
12325
|
}
|
|
12261
|
-
async function
|
|
12326
|
+
async function generateSkillsCore(params) {
|
|
12327
|
+
const { config } = params;
|
|
12262
12328
|
if (!config.getFeatures().includes("skills")) {
|
|
12263
|
-
|
|
12264
|
-
return { totalOutputs: 0, skills: [] };
|
|
12329
|
+
return { count: 0, skills: [] };
|
|
12265
12330
|
}
|
|
12266
|
-
let
|
|
12331
|
+
let totalCount = 0;
|
|
12267
12332
|
const allSkills = [];
|
|
12268
|
-
logger.info("Generating skill files...");
|
|
12269
12333
|
const toolTargets = intersection(
|
|
12270
12334
|
config.getTargets(),
|
|
12271
12335
|
SkillsProcessor.getToolTargets({
|
|
@@ -12292,15 +12356,84 @@ async function generateSkills(config) {
|
|
|
12292
12356
|
}
|
|
12293
12357
|
const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
|
|
12294
12358
|
const writtenCount = await processor.writeAiDirs(toolDirs);
|
|
12295
|
-
|
|
12296
|
-
|
|
12359
|
+
totalCount += writtenCount;
|
|
12360
|
+
}
|
|
12361
|
+
}
|
|
12362
|
+
return { count: totalCount, skills: allSkills };
|
|
12363
|
+
}
|
|
12364
|
+
|
|
12365
|
+
// src/cli/commands/generate.ts
|
|
12366
|
+
async function generateCommand(options) {
|
|
12367
|
+
const config = await ConfigResolver.resolve(options);
|
|
12368
|
+
logger.configure({
|
|
12369
|
+
verbose: config.getVerbose(),
|
|
12370
|
+
silent: config.getSilent()
|
|
12371
|
+
});
|
|
12372
|
+
logger.info("Generating files...");
|
|
12373
|
+
if (!await checkRulesyncDirExists({ baseDir: config.getBaseDirs()[0] ?? process.cwd() })) {
|
|
12374
|
+
logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
12375
|
+
process.exit(1);
|
|
12376
|
+
}
|
|
12377
|
+
logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
|
|
12378
|
+
const features = config.getFeatures();
|
|
12379
|
+
if (features.includes("ignore")) {
|
|
12380
|
+
logger.info("Generating ignore files...");
|
|
12381
|
+
}
|
|
12382
|
+
if (features.includes("mcp")) {
|
|
12383
|
+
logger.info("Generating MCP files...");
|
|
12384
|
+
if (config.getModularMcp()) {
|
|
12385
|
+
logger.info("\u2139\uFE0F Modular MCP support is experimental.");
|
|
12297
12386
|
}
|
|
12298
12387
|
}
|
|
12299
|
-
|
|
12388
|
+
if (features.includes("commands")) {
|
|
12389
|
+
logger.info("Generating command files...");
|
|
12390
|
+
}
|
|
12391
|
+
if (features.includes("subagents")) {
|
|
12392
|
+
logger.info("Generating subagent files...");
|
|
12393
|
+
}
|
|
12394
|
+
if (features.includes("skills")) {
|
|
12395
|
+
logger.info("Generating skill files...");
|
|
12396
|
+
}
|
|
12397
|
+
if (features.includes("rules")) {
|
|
12398
|
+
logger.info("Generating rule files...");
|
|
12399
|
+
}
|
|
12400
|
+
const result = await generate({ config });
|
|
12401
|
+
if (result.ignoreCount > 0) {
|
|
12402
|
+
logger.success(`Generated ${result.ignoreCount} ignore file(s)`);
|
|
12403
|
+
}
|
|
12404
|
+
if (result.mcpCount > 0) {
|
|
12405
|
+
logger.success(`Generated ${result.mcpCount} MCP configuration(s)`);
|
|
12406
|
+
}
|
|
12407
|
+
if (result.commandsCount > 0) {
|
|
12408
|
+
logger.success(`Generated ${result.commandsCount} command(s)`);
|
|
12409
|
+
}
|
|
12410
|
+
if (result.subagentsCount > 0) {
|
|
12411
|
+
logger.success(`Generated ${result.subagentsCount} subagent(s)`);
|
|
12412
|
+
}
|
|
12413
|
+
if (result.skillsCount > 0) {
|
|
12414
|
+
logger.success(`Generated ${result.skillsCount} skill(s)`);
|
|
12415
|
+
}
|
|
12416
|
+
if (result.rulesCount > 0) {
|
|
12417
|
+
logger.success(`Generated ${result.rulesCount} rule(s)`);
|
|
12418
|
+
}
|
|
12419
|
+
const totalGenerated = result.rulesCount + result.ignoreCount + result.mcpCount + result.commandsCount + result.subagentsCount + result.skillsCount;
|
|
12420
|
+
if (totalGenerated === 0) {
|
|
12421
|
+
const enabledFeatures = features.join(", ");
|
|
12422
|
+
logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
|
|
12423
|
+
return;
|
|
12424
|
+
}
|
|
12425
|
+
const parts = [];
|
|
12426
|
+
if (result.rulesCount > 0) parts.push(`${result.rulesCount} rules`);
|
|
12427
|
+
if (result.ignoreCount > 0) parts.push(`${result.ignoreCount} ignore files`);
|
|
12428
|
+
if (result.mcpCount > 0) parts.push(`${result.mcpCount} MCP files`);
|
|
12429
|
+
if (result.commandsCount > 0) parts.push(`${result.commandsCount} commands`);
|
|
12430
|
+
if (result.subagentsCount > 0) parts.push(`${result.subagentsCount} subagents`);
|
|
12431
|
+
if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
|
|
12432
|
+
logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
|
|
12300
12433
|
}
|
|
12301
12434
|
|
|
12302
12435
|
// src/cli/commands/gitignore.ts
|
|
12303
|
-
import { join as
|
|
12436
|
+
import { join as join97 } from "path";
|
|
12304
12437
|
var RULESYNC_HEADER = "# Generated by Rulesync";
|
|
12305
12438
|
var LEGACY_RULESYNC_HEADER = "# Generated by rulesync - AI tool configuration files";
|
|
12306
12439
|
var RULESYNC_IGNORE_ENTRIES = [
|
|
@@ -12317,7 +12450,9 @@ var RULESYNC_IGNORE_ENTRIES = [
|
|
|
12317
12450
|
"**/.augment-guidelines",
|
|
12318
12451
|
// Claude Code
|
|
12319
12452
|
"**/CLAUDE.md",
|
|
12453
|
+
"**/CLAUDE.local.md",
|
|
12320
12454
|
"**/.claude/CLAUDE.md",
|
|
12455
|
+
"**/.claude/CLAUDE.local.md",
|
|
12321
12456
|
"**/.claude/memories/",
|
|
12322
12457
|
"**/.claude/rules/",
|
|
12323
12458
|
"**/.claude/commands/",
|
|
@@ -12441,7 +12576,7 @@ var removeExistingRulesyncEntries = (content) => {
|
|
|
12441
12576
|
return result;
|
|
12442
12577
|
};
|
|
12443
12578
|
var gitignoreCommand = async () => {
|
|
12444
|
-
const gitignorePath =
|
|
12579
|
+
const gitignorePath = join97(process.cwd(), ".gitignore");
|
|
12445
12580
|
let gitignoreContent = "";
|
|
12446
12581
|
if (await fileExists(gitignorePath)) {
|
|
12447
12582
|
gitignoreContent = await readFileContent(gitignorePath);
|
|
@@ -12643,7 +12778,7 @@ async function importSkills(config, tool) {
|
|
|
12643
12778
|
}
|
|
12644
12779
|
|
|
12645
12780
|
// src/cli/commands/init.ts
|
|
12646
|
-
import { join as
|
|
12781
|
+
import { join as join98 } from "path";
|
|
12647
12782
|
async function initCommand() {
|
|
12648
12783
|
logger.info("Initializing rulesync...");
|
|
12649
12784
|
await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
|
|
@@ -12821,14 +12956,14 @@ Keep the summary concise and ready to reuse in future tasks.`
|
|
|
12821
12956
|
await ensureDir(subagentPaths.relativeDirPath);
|
|
12822
12957
|
await ensureDir(skillPaths.relativeDirPath);
|
|
12823
12958
|
await ensureDir(ignorePaths.recommended.relativeDirPath);
|
|
12824
|
-
const ruleFilepath =
|
|
12959
|
+
const ruleFilepath = join98(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
|
|
12825
12960
|
if (!await fileExists(ruleFilepath)) {
|
|
12826
12961
|
await writeFileContent(ruleFilepath, sampleRuleFile.content);
|
|
12827
12962
|
logger.success(`Created ${ruleFilepath}`);
|
|
12828
12963
|
} else {
|
|
12829
12964
|
logger.info(`Skipped ${ruleFilepath} (already exists)`);
|
|
12830
12965
|
}
|
|
12831
|
-
const mcpFilepath =
|
|
12966
|
+
const mcpFilepath = join98(
|
|
12832
12967
|
mcpPaths.recommended.relativeDirPath,
|
|
12833
12968
|
mcpPaths.recommended.relativeFilePath
|
|
12834
12969
|
);
|
|
@@ -12838,30 +12973,30 @@ Keep the summary concise and ready to reuse in future tasks.`
|
|
|
12838
12973
|
} else {
|
|
12839
12974
|
logger.info(`Skipped ${mcpFilepath} (already exists)`);
|
|
12840
12975
|
}
|
|
12841
|
-
const commandFilepath =
|
|
12976
|
+
const commandFilepath = join98(commandPaths.relativeDirPath, sampleCommandFile.filename);
|
|
12842
12977
|
if (!await fileExists(commandFilepath)) {
|
|
12843
12978
|
await writeFileContent(commandFilepath, sampleCommandFile.content);
|
|
12844
12979
|
logger.success(`Created ${commandFilepath}`);
|
|
12845
12980
|
} else {
|
|
12846
12981
|
logger.info(`Skipped ${commandFilepath} (already exists)`);
|
|
12847
12982
|
}
|
|
12848
|
-
const subagentFilepath =
|
|
12983
|
+
const subagentFilepath = join98(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
|
|
12849
12984
|
if (!await fileExists(subagentFilepath)) {
|
|
12850
12985
|
await writeFileContent(subagentFilepath, sampleSubagentFile.content);
|
|
12851
12986
|
logger.success(`Created ${subagentFilepath}`);
|
|
12852
12987
|
} else {
|
|
12853
12988
|
logger.info(`Skipped ${subagentFilepath} (already exists)`);
|
|
12854
12989
|
}
|
|
12855
|
-
const skillDirPath =
|
|
12990
|
+
const skillDirPath = join98(skillPaths.relativeDirPath, sampleSkillFile.dirName);
|
|
12856
12991
|
await ensureDir(skillDirPath);
|
|
12857
|
-
const skillFilepath =
|
|
12992
|
+
const skillFilepath = join98(skillDirPath, SKILL_FILE_NAME);
|
|
12858
12993
|
if (!await fileExists(skillFilepath)) {
|
|
12859
12994
|
await writeFileContent(skillFilepath, sampleSkillFile.content);
|
|
12860
12995
|
logger.success(`Created ${skillFilepath}`);
|
|
12861
12996
|
} else {
|
|
12862
12997
|
logger.info(`Skipped ${skillFilepath} (already exists)`);
|
|
12863
12998
|
}
|
|
12864
|
-
const ignoreFilepath =
|
|
12999
|
+
const ignoreFilepath = join98(
|
|
12865
13000
|
ignorePaths.recommended.relativeDirPath,
|
|
12866
13001
|
ignorePaths.recommended.relativeFilePath
|
|
12867
13002
|
);
|
|
@@ -12880,12 +13015,12 @@ import { FastMCP } from "fastmcp";
|
|
|
12880
13015
|
import { z as z51 } from "zod/mini";
|
|
12881
13016
|
|
|
12882
13017
|
// src/mcp/commands.ts
|
|
12883
|
-
import { basename as basename25, join as
|
|
13018
|
+
import { basename as basename25, join as join99 } from "path";
|
|
12884
13019
|
import { z as z45 } from "zod/mini";
|
|
12885
13020
|
var maxCommandSizeBytes = 1024 * 1024;
|
|
12886
13021
|
var maxCommandsCount = 1e3;
|
|
12887
13022
|
async function listCommands() {
|
|
12888
|
-
const commandsDir =
|
|
13023
|
+
const commandsDir = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
12889
13024
|
try {
|
|
12890
13025
|
const files = await listDirectoryFiles(commandsDir);
|
|
12891
13026
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -12897,7 +13032,7 @@ async function listCommands() {
|
|
|
12897
13032
|
});
|
|
12898
13033
|
const frontmatter = command.getFrontmatter();
|
|
12899
13034
|
return {
|
|
12900
|
-
relativePathFromCwd:
|
|
13035
|
+
relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
|
|
12901
13036
|
frontmatter
|
|
12902
13037
|
};
|
|
12903
13038
|
} catch (error) {
|
|
@@ -12923,7 +13058,7 @@ async function getCommand({ relativePathFromCwd }) {
|
|
|
12923
13058
|
relativeFilePath: filename
|
|
12924
13059
|
});
|
|
12925
13060
|
return {
|
|
12926
|
-
relativePathFromCwd:
|
|
13061
|
+
relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
12927
13062
|
frontmatter: command.getFrontmatter(),
|
|
12928
13063
|
body: command.getBody()
|
|
12929
13064
|
};
|
|
@@ -12952,7 +13087,7 @@ async function putCommand({
|
|
|
12952
13087
|
try {
|
|
12953
13088
|
const existingCommands = await listCommands();
|
|
12954
13089
|
const isUpdate = existingCommands.some(
|
|
12955
|
-
(command2) => command2.relativePathFromCwd ===
|
|
13090
|
+
(command2) => command2.relativePathFromCwd === join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
12956
13091
|
);
|
|
12957
13092
|
if (!isUpdate && existingCommands.length >= maxCommandsCount) {
|
|
12958
13093
|
throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
|
|
@@ -12967,11 +13102,11 @@ async function putCommand({
|
|
|
12967
13102
|
fileContent,
|
|
12968
13103
|
validate: true
|
|
12969
13104
|
});
|
|
12970
|
-
const commandsDir =
|
|
13105
|
+
const commandsDir = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
12971
13106
|
await ensureDir(commandsDir);
|
|
12972
13107
|
await writeFileContent(command.getFilePath(), command.getFileContent());
|
|
12973
13108
|
return {
|
|
12974
|
-
relativePathFromCwd:
|
|
13109
|
+
relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
12975
13110
|
frontmatter: command.getFrontmatter(),
|
|
12976
13111
|
body: command.getBody()
|
|
12977
13112
|
};
|
|
@@ -12987,11 +13122,11 @@ async function deleteCommand({ relativePathFromCwd }) {
|
|
|
12987
13122
|
intendedRootDir: process.cwd()
|
|
12988
13123
|
});
|
|
12989
13124
|
const filename = basename25(relativePathFromCwd);
|
|
12990
|
-
const fullPath =
|
|
13125
|
+
const fullPath = join99(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
|
|
12991
13126
|
try {
|
|
12992
13127
|
await removeFile(fullPath);
|
|
12993
13128
|
return {
|
|
12994
|
-
relativePathFromCwd:
|
|
13129
|
+
relativePathFromCwd: join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
12995
13130
|
};
|
|
12996
13131
|
} catch (error) {
|
|
12997
13132
|
throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -13016,7 +13151,7 @@ var commandToolSchemas = {
|
|
|
13016
13151
|
var commandTools = {
|
|
13017
13152
|
listCommands: {
|
|
13018
13153
|
name: "listCommands",
|
|
13019
|
-
description: `List all commands from ${
|
|
13154
|
+
description: `List all commands from ${join99(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
13020
13155
|
parameters: commandToolSchemas.listCommands,
|
|
13021
13156
|
execute: async () => {
|
|
13022
13157
|
const commands = await listCommands();
|
|
@@ -13058,11 +13193,11 @@ var commandTools = {
|
|
|
13058
13193
|
};
|
|
13059
13194
|
|
|
13060
13195
|
// src/mcp/ignore.ts
|
|
13061
|
-
import { join as
|
|
13196
|
+
import { join as join100 } from "path";
|
|
13062
13197
|
import { z as z46 } from "zod/mini";
|
|
13063
13198
|
var maxIgnoreFileSizeBytes = 100 * 1024;
|
|
13064
13199
|
async function getIgnoreFile() {
|
|
13065
|
-
const ignoreFilePath =
|
|
13200
|
+
const ignoreFilePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
|
|
13066
13201
|
try {
|
|
13067
13202
|
const content = await readFileContent(ignoreFilePath);
|
|
13068
13203
|
return {
|
|
@@ -13076,7 +13211,7 @@ async function getIgnoreFile() {
|
|
|
13076
13211
|
}
|
|
13077
13212
|
}
|
|
13078
13213
|
async function putIgnoreFile({ content }) {
|
|
13079
|
-
const ignoreFilePath =
|
|
13214
|
+
const ignoreFilePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
|
|
13080
13215
|
const contentSizeBytes = Buffer.byteLength(content, "utf8");
|
|
13081
13216
|
if (contentSizeBytes > maxIgnoreFileSizeBytes) {
|
|
13082
13217
|
throw new Error(
|
|
@@ -13097,8 +13232,8 @@ async function putIgnoreFile({ content }) {
|
|
|
13097
13232
|
}
|
|
13098
13233
|
}
|
|
13099
13234
|
async function deleteIgnoreFile() {
|
|
13100
|
-
const aiignorePath =
|
|
13101
|
-
const legacyIgnorePath =
|
|
13235
|
+
const aiignorePath = join100(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
|
|
13236
|
+
const legacyIgnorePath = join100(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
13102
13237
|
try {
|
|
13103
13238
|
await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
|
|
13104
13239
|
return {
|
|
@@ -13153,7 +13288,7 @@ var ignoreTools = {
|
|
|
13153
13288
|
};
|
|
13154
13289
|
|
|
13155
13290
|
// src/mcp/mcp.ts
|
|
13156
|
-
import { join as
|
|
13291
|
+
import { join as join101 } from "path";
|
|
13157
13292
|
import { z as z47 } from "zod/mini";
|
|
13158
13293
|
var maxMcpSizeBytes = 1024 * 1024;
|
|
13159
13294
|
async function getMcpFile() {
|
|
@@ -13163,7 +13298,7 @@ async function getMcpFile() {
|
|
|
13163
13298
|
validate: true,
|
|
13164
13299
|
modularMcp: config.getModularMcp()
|
|
13165
13300
|
});
|
|
13166
|
-
const relativePathFromCwd =
|
|
13301
|
+
const relativePathFromCwd = join101(
|
|
13167
13302
|
rulesyncMcp.getRelativeDirPath(),
|
|
13168
13303
|
rulesyncMcp.getRelativeFilePath()
|
|
13169
13304
|
);
|
|
@@ -13196,7 +13331,7 @@ async function putMcpFile({ content }) {
|
|
|
13196
13331
|
const paths = RulesyncMcp.getSettablePaths();
|
|
13197
13332
|
const relativeDirPath = paths.recommended.relativeDirPath;
|
|
13198
13333
|
const relativeFilePath = paths.recommended.relativeFilePath;
|
|
13199
|
-
const fullPath =
|
|
13334
|
+
const fullPath = join101(baseDir, relativeDirPath, relativeFilePath);
|
|
13200
13335
|
const rulesyncMcp = new RulesyncMcp({
|
|
13201
13336
|
baseDir,
|
|
13202
13337
|
relativeDirPath,
|
|
@@ -13205,9 +13340,9 @@ async function putMcpFile({ content }) {
|
|
|
13205
13340
|
validate: true,
|
|
13206
13341
|
modularMcp: config.getModularMcp()
|
|
13207
13342
|
});
|
|
13208
|
-
await ensureDir(
|
|
13343
|
+
await ensureDir(join101(baseDir, relativeDirPath));
|
|
13209
13344
|
await writeFileContent(fullPath, content);
|
|
13210
|
-
const relativePathFromCwd =
|
|
13345
|
+
const relativePathFromCwd = join101(relativeDirPath, relativeFilePath);
|
|
13211
13346
|
return {
|
|
13212
13347
|
relativePathFromCwd,
|
|
13213
13348
|
content: rulesyncMcp.getFileContent()
|
|
@@ -13222,15 +13357,15 @@ async function deleteMcpFile() {
|
|
|
13222
13357
|
try {
|
|
13223
13358
|
const baseDir = process.cwd();
|
|
13224
13359
|
const paths = RulesyncMcp.getSettablePaths();
|
|
13225
|
-
const recommendedPath =
|
|
13360
|
+
const recommendedPath = join101(
|
|
13226
13361
|
baseDir,
|
|
13227
13362
|
paths.recommended.relativeDirPath,
|
|
13228
13363
|
paths.recommended.relativeFilePath
|
|
13229
13364
|
);
|
|
13230
|
-
const legacyPath =
|
|
13365
|
+
const legacyPath = join101(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
|
|
13231
13366
|
await removeFile(recommendedPath);
|
|
13232
13367
|
await removeFile(legacyPath);
|
|
13233
|
-
const relativePathFromCwd =
|
|
13368
|
+
const relativePathFromCwd = join101(
|
|
13234
13369
|
paths.recommended.relativeDirPath,
|
|
13235
13370
|
paths.recommended.relativeFilePath
|
|
13236
13371
|
);
|
|
@@ -13281,12 +13416,12 @@ var mcpTools = {
|
|
|
13281
13416
|
};
|
|
13282
13417
|
|
|
13283
13418
|
// src/mcp/rules.ts
|
|
13284
|
-
import { basename as basename26, join as
|
|
13419
|
+
import { basename as basename26, join as join102 } from "path";
|
|
13285
13420
|
import { z as z48 } from "zod/mini";
|
|
13286
13421
|
var maxRuleSizeBytes = 1024 * 1024;
|
|
13287
13422
|
var maxRulesCount = 1e3;
|
|
13288
13423
|
async function listRules() {
|
|
13289
|
-
const rulesDir =
|
|
13424
|
+
const rulesDir = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
13290
13425
|
try {
|
|
13291
13426
|
const files = await listDirectoryFiles(rulesDir);
|
|
13292
13427
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -13299,7 +13434,7 @@ async function listRules() {
|
|
|
13299
13434
|
});
|
|
13300
13435
|
const frontmatter = rule.getFrontmatter();
|
|
13301
13436
|
return {
|
|
13302
|
-
relativePathFromCwd:
|
|
13437
|
+
relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
|
|
13303
13438
|
frontmatter
|
|
13304
13439
|
};
|
|
13305
13440
|
} catch (error) {
|
|
@@ -13326,7 +13461,7 @@ async function getRule({ relativePathFromCwd }) {
|
|
|
13326
13461
|
validate: true
|
|
13327
13462
|
});
|
|
13328
13463
|
return {
|
|
13329
|
-
relativePathFromCwd:
|
|
13464
|
+
relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
13330
13465
|
frontmatter: rule.getFrontmatter(),
|
|
13331
13466
|
body: rule.getBody()
|
|
13332
13467
|
};
|
|
@@ -13355,7 +13490,7 @@ async function putRule({
|
|
|
13355
13490
|
try {
|
|
13356
13491
|
const existingRules = await listRules();
|
|
13357
13492
|
const isUpdate = existingRules.some(
|
|
13358
|
-
(rule2) => rule2.relativePathFromCwd ===
|
|
13493
|
+
(rule2) => rule2.relativePathFromCwd === join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
13359
13494
|
);
|
|
13360
13495
|
if (!isUpdate && existingRules.length >= maxRulesCount) {
|
|
13361
13496
|
throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
|
|
@@ -13368,11 +13503,11 @@ async function putRule({
|
|
|
13368
13503
|
body,
|
|
13369
13504
|
validate: true
|
|
13370
13505
|
});
|
|
13371
|
-
const rulesDir =
|
|
13506
|
+
const rulesDir = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
13372
13507
|
await ensureDir(rulesDir);
|
|
13373
13508
|
await writeFileContent(rule.getFilePath(), rule.getFileContent());
|
|
13374
13509
|
return {
|
|
13375
|
-
relativePathFromCwd:
|
|
13510
|
+
relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
13376
13511
|
frontmatter: rule.getFrontmatter(),
|
|
13377
13512
|
body: rule.getBody()
|
|
13378
13513
|
};
|
|
@@ -13388,11 +13523,11 @@ async function deleteRule({ relativePathFromCwd }) {
|
|
|
13388
13523
|
intendedRootDir: process.cwd()
|
|
13389
13524
|
});
|
|
13390
13525
|
const filename = basename26(relativePathFromCwd);
|
|
13391
|
-
const fullPath =
|
|
13526
|
+
const fullPath = join102(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
|
|
13392
13527
|
try {
|
|
13393
13528
|
await removeFile(fullPath);
|
|
13394
13529
|
return {
|
|
13395
|
-
relativePathFromCwd:
|
|
13530
|
+
relativePathFromCwd: join102(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
13396
13531
|
};
|
|
13397
13532
|
} catch (error) {
|
|
13398
13533
|
throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -13417,7 +13552,7 @@ var ruleToolSchemas = {
|
|
|
13417
13552
|
var ruleTools = {
|
|
13418
13553
|
listRules: {
|
|
13419
13554
|
name: "listRules",
|
|
13420
|
-
description: `List all rules from ${
|
|
13555
|
+
description: `List all rules from ${join102(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
13421
13556
|
parameters: ruleToolSchemas.listRules,
|
|
13422
13557
|
execute: async () => {
|
|
13423
13558
|
const rules = await listRules();
|
|
@@ -13459,7 +13594,7 @@ var ruleTools = {
|
|
|
13459
13594
|
};
|
|
13460
13595
|
|
|
13461
13596
|
// src/mcp/skills.ts
|
|
13462
|
-
import { basename as basename27, dirname as dirname2, join as
|
|
13597
|
+
import { basename as basename27, dirname as dirname2, join as join103 } from "path";
|
|
13463
13598
|
import { z as z49 } from "zod/mini";
|
|
13464
13599
|
var maxSkillSizeBytes = 1024 * 1024;
|
|
13465
13600
|
var maxSkillsCount = 1e3;
|
|
@@ -13483,9 +13618,9 @@ function extractDirName(relativeDirPathFromCwd) {
|
|
|
13483
13618
|
return dirName;
|
|
13484
13619
|
}
|
|
13485
13620
|
async function listSkills() {
|
|
13486
|
-
const skillsDir =
|
|
13621
|
+
const skillsDir = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
|
|
13487
13622
|
try {
|
|
13488
|
-
const skillDirPaths = await findFilesByGlobs(
|
|
13623
|
+
const skillDirPaths = await findFilesByGlobs(join103(skillsDir, "*"), { type: "dir" });
|
|
13489
13624
|
const skills = await Promise.all(
|
|
13490
13625
|
skillDirPaths.map(async (dirPath) => {
|
|
13491
13626
|
const dirName = basename27(dirPath);
|
|
@@ -13496,7 +13631,7 @@ async function listSkills() {
|
|
|
13496
13631
|
});
|
|
13497
13632
|
const frontmatter = skill.getFrontmatter();
|
|
13498
13633
|
return {
|
|
13499
|
-
relativeDirPathFromCwd:
|
|
13634
|
+
relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
|
|
13500
13635
|
frontmatter
|
|
13501
13636
|
};
|
|
13502
13637
|
} catch (error) {
|
|
@@ -13522,7 +13657,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
|
|
|
13522
13657
|
dirName
|
|
13523
13658
|
});
|
|
13524
13659
|
return {
|
|
13525
|
-
relativeDirPathFromCwd:
|
|
13660
|
+
relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
|
|
13526
13661
|
frontmatter: skill.getFrontmatter(),
|
|
13527
13662
|
body: skill.getBody(),
|
|
13528
13663
|
otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
|
|
@@ -13556,7 +13691,7 @@ async function putSkill({
|
|
|
13556
13691
|
try {
|
|
13557
13692
|
const existingSkills = await listSkills();
|
|
13558
13693
|
const isUpdate = existingSkills.some(
|
|
13559
|
-
(skill2) => skill2.relativeDirPathFromCwd ===
|
|
13694
|
+
(skill2) => skill2.relativeDirPathFromCwd === join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
|
|
13560
13695
|
);
|
|
13561
13696
|
if (!isUpdate && existingSkills.length >= maxSkillsCount) {
|
|
13562
13697
|
throw new Error(`Maximum number of skills (${maxSkillsCount}) reached`);
|
|
@@ -13571,9 +13706,9 @@ async function putSkill({
|
|
|
13571
13706
|
otherFiles: aiDirFiles,
|
|
13572
13707
|
validate: true
|
|
13573
13708
|
});
|
|
13574
|
-
const skillDirPath =
|
|
13709
|
+
const skillDirPath = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
|
|
13575
13710
|
await ensureDir(skillDirPath);
|
|
13576
|
-
const skillFilePath =
|
|
13711
|
+
const skillFilePath = join103(skillDirPath, SKILL_FILE_NAME);
|
|
13577
13712
|
const skillFileContent = stringifyFrontmatter(body, frontmatter);
|
|
13578
13713
|
await writeFileContent(skillFilePath, skillFileContent);
|
|
13579
13714
|
for (const file of otherFiles) {
|
|
@@ -13581,15 +13716,15 @@ async function putSkill({
|
|
|
13581
13716
|
relativePath: file.name,
|
|
13582
13717
|
intendedRootDir: skillDirPath
|
|
13583
13718
|
});
|
|
13584
|
-
const filePath =
|
|
13585
|
-
const fileDir =
|
|
13719
|
+
const filePath = join103(skillDirPath, file.name);
|
|
13720
|
+
const fileDir = join103(skillDirPath, dirname2(file.name));
|
|
13586
13721
|
if (fileDir !== skillDirPath) {
|
|
13587
13722
|
await ensureDir(fileDir);
|
|
13588
13723
|
}
|
|
13589
13724
|
await writeFileContent(filePath, file.body);
|
|
13590
13725
|
}
|
|
13591
13726
|
return {
|
|
13592
|
-
relativeDirPathFromCwd:
|
|
13727
|
+
relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
|
|
13593
13728
|
frontmatter: skill.getFrontmatter(),
|
|
13594
13729
|
body: skill.getBody(),
|
|
13595
13730
|
otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
|
|
@@ -13611,13 +13746,13 @@ async function deleteSkill({
|
|
|
13611
13746
|
intendedRootDir: process.cwd()
|
|
13612
13747
|
});
|
|
13613
13748
|
const dirName = extractDirName(relativeDirPathFromCwd);
|
|
13614
|
-
const skillDirPath =
|
|
13749
|
+
const skillDirPath = join103(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
|
|
13615
13750
|
try {
|
|
13616
13751
|
if (await directoryExists(skillDirPath)) {
|
|
13617
13752
|
await removeDirectory(skillDirPath);
|
|
13618
13753
|
}
|
|
13619
13754
|
return {
|
|
13620
|
-
relativeDirPathFromCwd:
|
|
13755
|
+
relativeDirPathFromCwd: join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
|
|
13621
13756
|
};
|
|
13622
13757
|
} catch (error) {
|
|
13623
13758
|
throw new Error(
|
|
@@ -13650,7 +13785,7 @@ var skillToolSchemas = {
|
|
|
13650
13785
|
var skillTools = {
|
|
13651
13786
|
listSkills: {
|
|
13652
13787
|
name: "listSkills",
|
|
13653
|
-
description: `List all skills from ${
|
|
13788
|
+
description: `List all skills from ${join103(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
|
|
13654
13789
|
parameters: skillToolSchemas.listSkills,
|
|
13655
13790
|
execute: async () => {
|
|
13656
13791
|
const skills = await listSkills();
|
|
@@ -13693,12 +13828,12 @@ var skillTools = {
|
|
|
13693
13828
|
};
|
|
13694
13829
|
|
|
13695
13830
|
// src/mcp/subagents.ts
|
|
13696
|
-
import { basename as basename28, join as
|
|
13831
|
+
import { basename as basename28, join as join104 } from "path";
|
|
13697
13832
|
import { z as z50 } from "zod/mini";
|
|
13698
13833
|
var maxSubagentSizeBytes = 1024 * 1024;
|
|
13699
13834
|
var maxSubagentsCount = 1e3;
|
|
13700
13835
|
async function listSubagents() {
|
|
13701
|
-
const subagentsDir =
|
|
13836
|
+
const subagentsDir = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
13702
13837
|
try {
|
|
13703
13838
|
const files = await listDirectoryFiles(subagentsDir);
|
|
13704
13839
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -13711,7 +13846,7 @@ async function listSubagents() {
|
|
|
13711
13846
|
});
|
|
13712
13847
|
const frontmatter = subagent.getFrontmatter();
|
|
13713
13848
|
return {
|
|
13714
|
-
relativePathFromCwd:
|
|
13849
|
+
relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
|
|
13715
13850
|
frontmatter
|
|
13716
13851
|
};
|
|
13717
13852
|
} catch (error) {
|
|
@@ -13740,7 +13875,7 @@ async function getSubagent({ relativePathFromCwd }) {
|
|
|
13740
13875
|
validate: true
|
|
13741
13876
|
});
|
|
13742
13877
|
return {
|
|
13743
|
-
relativePathFromCwd:
|
|
13878
|
+
relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
13744
13879
|
frontmatter: subagent.getFrontmatter(),
|
|
13745
13880
|
body: subagent.getBody()
|
|
13746
13881
|
};
|
|
@@ -13769,7 +13904,7 @@ async function putSubagent({
|
|
|
13769
13904
|
try {
|
|
13770
13905
|
const existingSubagents = await listSubagents();
|
|
13771
13906
|
const isUpdate = existingSubagents.some(
|
|
13772
|
-
(subagent2) => subagent2.relativePathFromCwd ===
|
|
13907
|
+
(subagent2) => subagent2.relativePathFromCwd === join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
13773
13908
|
);
|
|
13774
13909
|
if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
|
|
13775
13910
|
throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
|
|
@@ -13782,11 +13917,11 @@ async function putSubagent({
|
|
|
13782
13917
|
body,
|
|
13783
13918
|
validate: true
|
|
13784
13919
|
});
|
|
13785
|
-
const subagentsDir =
|
|
13920
|
+
const subagentsDir = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
13786
13921
|
await ensureDir(subagentsDir);
|
|
13787
13922
|
await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
|
|
13788
13923
|
return {
|
|
13789
|
-
relativePathFromCwd:
|
|
13924
|
+
relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
13790
13925
|
frontmatter: subagent.getFrontmatter(),
|
|
13791
13926
|
body: subagent.getBody()
|
|
13792
13927
|
};
|
|
@@ -13802,11 +13937,11 @@ async function deleteSubagent({ relativePathFromCwd }) {
|
|
|
13802
13937
|
intendedRootDir: process.cwd()
|
|
13803
13938
|
});
|
|
13804
13939
|
const filename = basename28(relativePathFromCwd);
|
|
13805
|
-
const fullPath =
|
|
13940
|
+
const fullPath = join104(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
|
|
13806
13941
|
try {
|
|
13807
13942
|
await removeFile(fullPath);
|
|
13808
13943
|
return {
|
|
13809
|
-
relativePathFromCwd:
|
|
13944
|
+
relativePathFromCwd: join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
13810
13945
|
};
|
|
13811
13946
|
} catch (error) {
|
|
13812
13947
|
throw new Error(
|
|
@@ -13834,7 +13969,7 @@ var subagentToolSchemas = {
|
|
|
13834
13969
|
var subagentTools = {
|
|
13835
13970
|
listSubagents: {
|
|
13836
13971
|
name: "listSubagents",
|
|
13837
|
-
description: `List all subagents from ${
|
|
13972
|
+
description: `List all subagents from ${join104(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
13838
13973
|
parameters: subagentToolSchemas.listSubagents,
|
|
13839
13974
|
execute: async () => {
|
|
13840
13975
|
const subagents = await listSubagents();
|
|
@@ -14085,7 +14220,7 @@ async function mcpCommand({ version }) {
|
|
|
14085
14220
|
}
|
|
14086
14221
|
|
|
14087
14222
|
// src/cli/index.ts
|
|
14088
|
-
var getVersion = () => "5.
|
|
14223
|
+
var getVersion = () => "5.9.0";
|
|
14089
14224
|
var main = async () => {
|
|
14090
14225
|
const program = new Command();
|
|
14091
14226
|
const version = getVersion();
|