rulesync 3.23.5 → 3.24.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 +53 -23
- package/dist/index.cjs +815 -119
- package/dist/index.js +815 -119
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,7 +31,7 @@ var ANNOUNCEMENT = "".trim();
|
|
|
31
31
|
|
|
32
32
|
// src/types/features.ts
|
|
33
33
|
var import_mini = require("zod/mini");
|
|
34
|
-
var ALL_FEATURES = ["rules", "ignore", "mcp", "subagents", "commands"];
|
|
34
|
+
var ALL_FEATURES = ["rules", "ignore", "mcp", "subagents", "commands", "skills"];
|
|
35
35
|
var ALL_FEATURES_WITH_WILDCARD = [...ALL_FEATURES, "*"];
|
|
36
36
|
var FeatureSchema = import_mini.z.enum(ALL_FEATURES);
|
|
37
37
|
var FeaturesSchema = import_mini.z.array(FeatureSchema);
|
|
@@ -160,6 +160,10 @@ async function readFileContent(filepath) {
|
|
|
160
160
|
logger.debug(`Reading file: ${filepath}`);
|
|
161
161
|
return (0, import_promises.readFile)(filepath, "utf-8");
|
|
162
162
|
}
|
|
163
|
+
async function readFileBuffer(filepath) {
|
|
164
|
+
logger.debug(`Reading file buffer: ${filepath}`);
|
|
165
|
+
return (0, import_promises.readFile)(filepath);
|
|
166
|
+
}
|
|
163
167
|
function addTrailingNewline(content) {
|
|
164
168
|
if (!content) {
|
|
165
169
|
return "\n";
|
|
@@ -187,11 +191,32 @@ async function listDirectoryFiles(dir) {
|
|
|
187
191
|
}
|
|
188
192
|
}
|
|
189
193
|
async function findFilesByGlobs(globs, options = {}) {
|
|
194
|
+
const { type = "all" } = options;
|
|
190
195
|
const items = (0, import_node_fs.globSync)(globs, { withFileTypes: true });
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
switch (type) {
|
|
197
|
+
case "file":
|
|
198
|
+
return items.filter((item) => item.isFile()).map((item) => (0, import_node_path.join)(item.parentPath, item.name));
|
|
199
|
+
case "dir":
|
|
200
|
+
return items.filter((item) => item.isDirectory()).map((item) => (0, import_node_path.join)(item.parentPath, item.name));
|
|
201
|
+
case "all":
|
|
202
|
+
return items.map((item) => (0, import_node_path.join)(item.parentPath, item.name));
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`Invalid type: ${type}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function removeDirectory(dirPath) {
|
|
208
|
+
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
209
|
+
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
210
|
+
logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
if (await fileExists(dirPath)) {
|
|
215
|
+
await (0, import_promises.rm)(dirPath, { recursive: true, force: true });
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
logger.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
193
219
|
}
|
|
194
|
-
return items.filter((item) => item.isFile()).map((item) => (0, import_node_path.join)(item.parentPath, item.name));
|
|
195
220
|
}
|
|
196
221
|
async function removeFile(filepath) {
|
|
197
222
|
logger.debug(`Removing file: ${filepath}`);
|
|
@@ -1697,7 +1722,7 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
1697
1722
|
);
|
|
1698
1723
|
const rulesyncCommands = (await Promise.allSettled(
|
|
1699
1724
|
rulesyncCommandPaths.map(
|
|
1700
|
-
(
|
|
1725
|
+
(path3) => RulesyncCommand.fromFile({ relativeFilePath: (0, import_node_path14.basename)(path3) })
|
|
1701
1726
|
)
|
|
1702
1727
|
)).filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
1703
1728
|
logger.info(`Successfully loaded ${rulesyncCommands.length} rulesync commands`);
|
|
@@ -1739,45 +1764,45 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
1739
1764
|
(0, import_node_path14.join)(this.baseDir, relativeDirPath, `*.${extension}`)
|
|
1740
1765
|
);
|
|
1741
1766
|
const toolCommands = (await Promise.allSettled(
|
|
1742
|
-
commandFilePaths.map((
|
|
1767
|
+
commandFilePaths.map((path3) => {
|
|
1743
1768
|
switch (toolTarget) {
|
|
1744
1769
|
case "agentsmd":
|
|
1745
1770
|
return AgentsmdCommand.fromFile({
|
|
1746
1771
|
baseDir: this.baseDir,
|
|
1747
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1772
|
+
relativeFilePath: (0, import_node_path14.basename)(path3)
|
|
1748
1773
|
});
|
|
1749
1774
|
case "claudecode":
|
|
1750
1775
|
return ClaudecodeCommand.fromFile({
|
|
1751
1776
|
baseDir: this.baseDir,
|
|
1752
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1777
|
+
relativeFilePath: (0, import_node_path14.basename)(path3),
|
|
1753
1778
|
global: this.global
|
|
1754
1779
|
});
|
|
1755
1780
|
case "geminicli":
|
|
1756
1781
|
return GeminiCliCommand.fromFile({
|
|
1757
1782
|
baseDir: this.baseDir,
|
|
1758
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1783
|
+
relativeFilePath: (0, import_node_path14.basename)(path3),
|
|
1759
1784
|
global: this.global
|
|
1760
1785
|
});
|
|
1761
1786
|
case "roo":
|
|
1762
1787
|
return RooCommand.fromFile({
|
|
1763
1788
|
baseDir: this.baseDir,
|
|
1764
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1789
|
+
relativeFilePath: (0, import_node_path14.basename)(path3)
|
|
1765
1790
|
});
|
|
1766
1791
|
case "copilot":
|
|
1767
1792
|
return CopilotCommand.fromFile({
|
|
1768
1793
|
baseDir: this.baseDir,
|
|
1769
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1794
|
+
relativeFilePath: (0, import_node_path14.basename)(path3)
|
|
1770
1795
|
});
|
|
1771
1796
|
case "cursor":
|
|
1772
1797
|
return CursorCommand.fromFile({
|
|
1773
1798
|
baseDir: this.baseDir,
|
|
1774
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1799
|
+
relativeFilePath: (0, import_node_path14.basename)(path3),
|
|
1775
1800
|
global: this.global
|
|
1776
1801
|
});
|
|
1777
1802
|
case "codexcli":
|
|
1778
1803
|
return CodexcliCommand.fromFile({
|
|
1779
1804
|
baseDir: this.baseDir,
|
|
1780
|
-
relativeFilePath: (0, import_node_path14.basename)(
|
|
1805
|
+
relativeFilePath: (0, import_node_path14.basename)(path3),
|
|
1781
1806
|
global: this.global
|
|
1782
1807
|
});
|
|
1783
1808
|
default:
|
|
@@ -2574,7 +2599,12 @@ var IgnoreProcessor = class extends FeatureProcessor {
|
|
|
2574
2599
|
const toolIgnores = await this.loadToolIgnores();
|
|
2575
2600
|
return toolIgnores;
|
|
2576
2601
|
} catch (error) {
|
|
2577
|
-
|
|
2602
|
+
const errorMessage = `Failed to load tool files: ${formatError(error)}`;
|
|
2603
|
+
if (error instanceof Error && error.message.includes("no such file or directory")) {
|
|
2604
|
+
logger.debug(errorMessage);
|
|
2605
|
+
} else {
|
|
2606
|
+
logger.error(errorMessage);
|
|
2607
|
+
}
|
|
2578
2608
|
return [];
|
|
2579
2609
|
}
|
|
2580
2610
|
}
|
|
@@ -3595,9 +3625,7 @@ var McpProcessor = class extends FeatureProcessor {
|
|
|
3595
3625
|
try {
|
|
3596
3626
|
return [await RulesyncMcp.fromFile({ modularMcp: this.modularMcp })];
|
|
3597
3627
|
} catch (error) {
|
|
3598
|
-
logger.error(
|
|
3599
|
-
`Failed to load MCP files for tool target: ${this.toolTarget}: ${formatError(error)}`
|
|
3600
|
-
);
|
|
3628
|
+
logger.error(`Failed to load a Rulesync MCP file: ${formatError(error)}`);
|
|
3601
3629
|
return [];
|
|
3602
3630
|
}
|
|
3603
3631
|
}
|
|
@@ -3691,9 +3719,12 @@ var McpProcessor = class extends FeatureProcessor {
|
|
|
3691
3719
|
logger.info(`Successfully loaded ${toolMcps.length} ${this.toolTarget} MCP files`);
|
|
3692
3720
|
return toolMcps;
|
|
3693
3721
|
} catch (error) {
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3722
|
+
const errorMessage = `Failed to load MCP files for tool target: ${this.toolTarget}: ${formatError(error)}`;
|
|
3723
|
+
if (error instanceof Error && error.message.includes("no such file or directory")) {
|
|
3724
|
+
logger.debug(errorMessage);
|
|
3725
|
+
} else {
|
|
3726
|
+
logger.error(errorMessage);
|
|
3727
|
+
}
|
|
3697
3728
|
return [];
|
|
3698
3729
|
}
|
|
3699
3730
|
}
|
|
@@ -4564,7 +4595,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
|
|
|
4564
4595
|
fromFile
|
|
4565
4596
|
}) {
|
|
4566
4597
|
const paths = await findFilesByGlobs((0, import_node_path46.join)(this.baseDir, relativeDirPath, "*.md"));
|
|
4567
|
-
const subagents = (await Promise.allSettled(paths.map((
|
|
4598
|
+
const subagents = (await Promise.allSettled(paths.map((path3) => fromFile((0, import_node_path46.basename)(path3))))).filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
4568
4599
|
logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
|
|
4569
4600
|
return subagents;
|
|
4570
4601
|
}
|
|
@@ -7086,6 +7117,614 @@ For example, if the user instructs \`Call planner subagent to plan the refactori
|
|
|
7086
7117
|
}
|
|
7087
7118
|
};
|
|
7088
7119
|
|
|
7120
|
+
// src/features/skills/skills-processor.ts
|
|
7121
|
+
var import_node_path71 = require("path");
|
|
7122
|
+
var import_mini27 = require("zod/mini");
|
|
7123
|
+
|
|
7124
|
+
// src/types/dir-feature-processor.ts
|
|
7125
|
+
var import_node_path67 = require("path");
|
|
7126
|
+
var DirFeatureProcessor = class {
|
|
7127
|
+
baseDir;
|
|
7128
|
+
constructor({ baseDir = process.cwd() }) {
|
|
7129
|
+
this.baseDir = baseDir;
|
|
7130
|
+
}
|
|
7131
|
+
/**
|
|
7132
|
+
* Return tool targets that this feature supports.
|
|
7133
|
+
*/
|
|
7134
|
+
static getToolTargets(_params = {}) {
|
|
7135
|
+
throw new Error("Not implemented");
|
|
7136
|
+
}
|
|
7137
|
+
/**
|
|
7138
|
+
* Once converted to rulesync/tool dirs, write them to the filesystem.
|
|
7139
|
+
* Returns the number of directories written.
|
|
7140
|
+
*/
|
|
7141
|
+
async writeAiDirs(aiDirs) {
|
|
7142
|
+
for (const aiDir of aiDirs) {
|
|
7143
|
+
const dirPath = aiDir.getDirPath();
|
|
7144
|
+
await ensureDir(dirPath);
|
|
7145
|
+
const mainFile = aiDir.getMainFile();
|
|
7146
|
+
if (mainFile) {
|
|
7147
|
+
const mainFilePath = (0, import_node_path67.join)(dirPath, mainFile.name);
|
|
7148
|
+
const contentWithNewline = addTrailingNewline(mainFile.body);
|
|
7149
|
+
await writeFileContent(mainFilePath, contentWithNewline);
|
|
7150
|
+
}
|
|
7151
|
+
const otherFiles = aiDir.getOtherFiles();
|
|
7152
|
+
for (const file of otherFiles) {
|
|
7153
|
+
const filePath = (0, import_node_path67.join)(dirPath, file.relativeFilePathToDirPath);
|
|
7154
|
+
const contentWithNewline = addTrailingNewline(file.fileBuffer.toString("utf-8"));
|
|
7155
|
+
await writeFileContent(filePath, contentWithNewline);
|
|
7156
|
+
}
|
|
7157
|
+
}
|
|
7158
|
+
return aiDirs.length;
|
|
7159
|
+
}
|
|
7160
|
+
async removeAiDirs(aiDirs) {
|
|
7161
|
+
for (const aiDir of aiDirs) {
|
|
7162
|
+
await removeDirectory(aiDir.getDirPath());
|
|
7163
|
+
}
|
|
7164
|
+
}
|
|
7165
|
+
};
|
|
7166
|
+
|
|
7167
|
+
// src/features/skills/claudecode-skill.ts
|
|
7168
|
+
var import_node_path70 = require("path");
|
|
7169
|
+
var import_mini26 = require("zod/mini");
|
|
7170
|
+
|
|
7171
|
+
// src/constants/general.ts
|
|
7172
|
+
var SKILL_FILE_NAME = "SKILL.md";
|
|
7173
|
+
|
|
7174
|
+
// src/features/skills/rulesync-skill.ts
|
|
7175
|
+
var import_node_path69 = require("path");
|
|
7176
|
+
var import_mini25 = require("zod/mini");
|
|
7177
|
+
|
|
7178
|
+
// src/types/ai-dir.ts
|
|
7179
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
7180
|
+
var AiDir = class {
|
|
7181
|
+
/**
|
|
7182
|
+
* @example "."
|
|
7183
|
+
*/
|
|
7184
|
+
baseDir;
|
|
7185
|
+
/**
|
|
7186
|
+
* @example ".rulesync/skills"
|
|
7187
|
+
*/
|
|
7188
|
+
relativeDirPath;
|
|
7189
|
+
/**
|
|
7190
|
+
* @example "my-skill"
|
|
7191
|
+
*/
|
|
7192
|
+
dirName;
|
|
7193
|
+
/**
|
|
7194
|
+
* Optional main file with frontmatter support
|
|
7195
|
+
*/
|
|
7196
|
+
mainFile;
|
|
7197
|
+
/**
|
|
7198
|
+
* Additional files in the directory
|
|
7199
|
+
*/
|
|
7200
|
+
otherFiles;
|
|
7201
|
+
/**
|
|
7202
|
+
* @example false
|
|
7203
|
+
*/
|
|
7204
|
+
global;
|
|
7205
|
+
constructor({
|
|
7206
|
+
baseDir = process.cwd(),
|
|
7207
|
+
relativeDirPath,
|
|
7208
|
+
dirName,
|
|
7209
|
+
mainFile,
|
|
7210
|
+
otherFiles = [],
|
|
7211
|
+
global = false
|
|
7212
|
+
}) {
|
|
7213
|
+
if (dirName.includes(import_node_path68.default.sep) || dirName.includes("/") || dirName.includes("\\")) {
|
|
7214
|
+
throw new Error(`Directory name cannot contain path separators: dirName="${dirName}"`);
|
|
7215
|
+
}
|
|
7216
|
+
this.baseDir = baseDir;
|
|
7217
|
+
this.relativeDirPath = relativeDirPath;
|
|
7218
|
+
this.dirName = dirName;
|
|
7219
|
+
this.mainFile = mainFile;
|
|
7220
|
+
this.otherFiles = otherFiles;
|
|
7221
|
+
this.global = global;
|
|
7222
|
+
}
|
|
7223
|
+
static async fromDir(_params) {
|
|
7224
|
+
throw new Error("Please implement this method in the subclass.");
|
|
7225
|
+
}
|
|
7226
|
+
getBaseDir() {
|
|
7227
|
+
return this.baseDir;
|
|
7228
|
+
}
|
|
7229
|
+
getRelativeDirPath() {
|
|
7230
|
+
return this.relativeDirPath;
|
|
7231
|
+
}
|
|
7232
|
+
getDirName() {
|
|
7233
|
+
return this.dirName;
|
|
7234
|
+
}
|
|
7235
|
+
getDirPath() {
|
|
7236
|
+
const fullPath = import_node_path68.default.join(this.baseDir, this.relativeDirPath, this.dirName);
|
|
7237
|
+
const resolvedFull = (0, import_node_path68.resolve)(fullPath);
|
|
7238
|
+
const resolvedBase = (0, import_node_path68.resolve)(this.baseDir);
|
|
7239
|
+
const rel = (0, import_node_path68.relative)(resolvedBase, resolvedFull);
|
|
7240
|
+
if (rel.startsWith("..") || import_node_path68.default.isAbsolute(rel)) {
|
|
7241
|
+
throw new Error(
|
|
7242
|
+
`Path traversal detected: Final path escapes baseDir. baseDir="${this.baseDir}", relativeDirPath="${this.relativeDirPath}", dirName="${this.dirName}"`
|
|
7243
|
+
);
|
|
7244
|
+
}
|
|
7245
|
+
return fullPath;
|
|
7246
|
+
}
|
|
7247
|
+
getMainFile() {
|
|
7248
|
+
return this.mainFile;
|
|
7249
|
+
}
|
|
7250
|
+
getOtherFiles() {
|
|
7251
|
+
return this.otherFiles;
|
|
7252
|
+
}
|
|
7253
|
+
getRelativePathFromCwd() {
|
|
7254
|
+
return import_node_path68.default.join(this.relativeDirPath, this.dirName);
|
|
7255
|
+
}
|
|
7256
|
+
getGlobal() {
|
|
7257
|
+
return this.global;
|
|
7258
|
+
}
|
|
7259
|
+
setMainFile(name, body, frontmatter) {
|
|
7260
|
+
this.mainFile = { name, body, frontmatter };
|
|
7261
|
+
}
|
|
7262
|
+
/**
|
|
7263
|
+
* Recursively collects all files from a directory, excluding the specified main file.
|
|
7264
|
+
* This is a common utility for loading additional files alongside the main file.
|
|
7265
|
+
*
|
|
7266
|
+
* @param baseDir - The base directory path
|
|
7267
|
+
* @param relativeDirPath - The relative path to the directory containing the skill
|
|
7268
|
+
* @param dirName - The name of the directory
|
|
7269
|
+
* @param excludeFileName - The name of the file to exclude (typically the main file)
|
|
7270
|
+
* @returns Array of files with their relative paths and buffers
|
|
7271
|
+
*/
|
|
7272
|
+
static async collectOtherFiles(baseDir, relativeDirPath, dirName, excludeFileName) {
|
|
7273
|
+
const dirPath = (0, import_node_path68.join)(baseDir, relativeDirPath, dirName);
|
|
7274
|
+
const glob = (0, import_node_path68.join)(dirPath, "**", "*");
|
|
7275
|
+
const filePaths = await findFilesByGlobs(glob, { type: "file" });
|
|
7276
|
+
const filteredPaths = filePaths.filter((filePath) => (0, import_node_path68.basename)(filePath) !== excludeFileName);
|
|
7277
|
+
const files = await Promise.all(
|
|
7278
|
+
filteredPaths.map(async (filePath) => {
|
|
7279
|
+
const fileBuffer = await readFileBuffer(filePath);
|
|
7280
|
+
return {
|
|
7281
|
+
relativeFilePathToDirPath: (0, import_node_path68.relative)(dirPath, filePath),
|
|
7282
|
+
fileBuffer
|
|
7283
|
+
};
|
|
7284
|
+
})
|
|
7285
|
+
);
|
|
7286
|
+
return files;
|
|
7287
|
+
}
|
|
7288
|
+
};
|
|
7289
|
+
|
|
7290
|
+
// src/features/skills/rulesync-skill.ts
|
|
7291
|
+
var RulesyncSkillFrontmatterSchema = import_mini25.z.object({
|
|
7292
|
+
name: import_mini25.z.string(),
|
|
7293
|
+
description: import_mini25.z.string(),
|
|
7294
|
+
claudecode: import_mini25.z.optional(
|
|
7295
|
+
import_mini25.z.object({
|
|
7296
|
+
"allowed-tools": import_mini25.z.optional(import_mini25.z.array(import_mini25.z.string()))
|
|
7297
|
+
})
|
|
7298
|
+
)
|
|
7299
|
+
});
|
|
7300
|
+
var RulesyncSkill = class _RulesyncSkill extends AiDir {
|
|
7301
|
+
constructor({
|
|
7302
|
+
baseDir = process.cwd(),
|
|
7303
|
+
relativeDirPath = RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
7304
|
+
dirName,
|
|
7305
|
+
frontmatter,
|
|
7306
|
+
body,
|
|
7307
|
+
otherFiles = [],
|
|
7308
|
+
validate = true,
|
|
7309
|
+
global = false
|
|
7310
|
+
}) {
|
|
7311
|
+
super({
|
|
7312
|
+
baseDir,
|
|
7313
|
+
relativeDirPath,
|
|
7314
|
+
dirName,
|
|
7315
|
+
mainFile: {
|
|
7316
|
+
name: SKILL_FILE_NAME,
|
|
7317
|
+
body,
|
|
7318
|
+
frontmatter: { ...frontmatter }
|
|
7319
|
+
},
|
|
7320
|
+
otherFiles,
|
|
7321
|
+
global
|
|
7322
|
+
});
|
|
7323
|
+
if (validate) {
|
|
7324
|
+
const result = this.validate();
|
|
7325
|
+
if (!result.success) {
|
|
7326
|
+
throw result.error;
|
|
7327
|
+
}
|
|
7328
|
+
}
|
|
7329
|
+
}
|
|
7330
|
+
static getSettablePaths() {
|
|
7331
|
+
return {
|
|
7332
|
+
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH
|
|
7333
|
+
};
|
|
7334
|
+
}
|
|
7335
|
+
getFrontmatter() {
|
|
7336
|
+
if (!this.mainFile?.frontmatter) {
|
|
7337
|
+
throw new Error("Frontmatter is not defined");
|
|
7338
|
+
}
|
|
7339
|
+
const result = RulesyncSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
|
|
7340
|
+
return result;
|
|
7341
|
+
}
|
|
7342
|
+
getBody() {
|
|
7343
|
+
return this.mainFile?.body ?? "";
|
|
7344
|
+
}
|
|
7345
|
+
validate() {
|
|
7346
|
+
const result = RulesyncSkillFrontmatterSchema.safeParse(this.mainFile?.frontmatter);
|
|
7347
|
+
if (!result.success) {
|
|
7348
|
+
return {
|
|
7349
|
+
success: false,
|
|
7350
|
+
error: new Error(
|
|
7351
|
+
`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`
|
|
7352
|
+
)
|
|
7353
|
+
};
|
|
7354
|
+
}
|
|
7355
|
+
return { success: true, error: null };
|
|
7356
|
+
}
|
|
7357
|
+
static async fromDir({
|
|
7358
|
+
baseDir = process.cwd(),
|
|
7359
|
+
relativeDirPath = RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
7360
|
+
dirName,
|
|
7361
|
+
global = false
|
|
7362
|
+
}) {
|
|
7363
|
+
const skillDirPath = (0, import_node_path69.join)(baseDir, relativeDirPath, dirName);
|
|
7364
|
+
const skillFilePath = (0, import_node_path69.join)(skillDirPath, SKILL_FILE_NAME);
|
|
7365
|
+
if (!await fileExists(skillFilePath)) {
|
|
7366
|
+
throw new Error(`${SKILL_FILE_NAME} not found in ${skillDirPath}`);
|
|
7367
|
+
}
|
|
7368
|
+
const fileContent = await readFileContent(skillFilePath);
|
|
7369
|
+
const { frontmatter, body: content } = parseFrontmatter(fileContent);
|
|
7370
|
+
const result = RulesyncSkillFrontmatterSchema.safeParse(frontmatter);
|
|
7371
|
+
if (!result.success) {
|
|
7372
|
+
throw new Error(`Invalid frontmatter in ${skillFilePath}: ${formatError(result.error)}`);
|
|
7373
|
+
}
|
|
7374
|
+
const otherFiles = await this.collectOtherFiles(
|
|
7375
|
+
baseDir,
|
|
7376
|
+
relativeDirPath,
|
|
7377
|
+
dirName,
|
|
7378
|
+
SKILL_FILE_NAME
|
|
7379
|
+
);
|
|
7380
|
+
return new _RulesyncSkill({
|
|
7381
|
+
baseDir,
|
|
7382
|
+
relativeDirPath,
|
|
7383
|
+
dirName,
|
|
7384
|
+
frontmatter: result.data,
|
|
7385
|
+
body: content.trim(),
|
|
7386
|
+
otherFiles,
|
|
7387
|
+
validate: true,
|
|
7388
|
+
global
|
|
7389
|
+
});
|
|
7390
|
+
}
|
|
7391
|
+
};
|
|
7392
|
+
|
|
7393
|
+
// src/features/skills/tool-skill.ts
|
|
7394
|
+
var ToolSkill = class extends AiDir {
|
|
7395
|
+
/**
|
|
7396
|
+
* Get the settable paths for this tool's skill directories.
|
|
7397
|
+
*
|
|
7398
|
+
* @param options - Optional configuration including global mode
|
|
7399
|
+
* @returns Object containing the relative directory path
|
|
7400
|
+
*/
|
|
7401
|
+
static getSettablePaths(_options) {
|
|
7402
|
+
throw new Error("Please implement this method in the subclass.");
|
|
7403
|
+
}
|
|
7404
|
+
/**
|
|
7405
|
+
* Load a skill from a tool-specific directory.
|
|
7406
|
+
*
|
|
7407
|
+
* This method should:
|
|
7408
|
+
* 1. Read the SKILL.md file content
|
|
7409
|
+
* 2. Parse tool-specific frontmatter format
|
|
7410
|
+
* 3. Validate the parsed data
|
|
7411
|
+
* 4. Collect other skill files in the directory
|
|
7412
|
+
* 5. Return a concrete ToolSkill instance
|
|
7413
|
+
*
|
|
7414
|
+
* @param params - Parameters including the skill directory name
|
|
7415
|
+
* @returns Promise resolving to a concrete ToolSkill instance
|
|
7416
|
+
*/
|
|
7417
|
+
static async fromDir(_params) {
|
|
7418
|
+
throw new Error("Please implement this method in the subclass.");
|
|
7419
|
+
}
|
|
7420
|
+
/**
|
|
7421
|
+
* Convert a RulesyncSkill to the tool-specific skill format.
|
|
7422
|
+
*
|
|
7423
|
+
* This method should:
|
|
7424
|
+
* 1. Extract relevant data from the RulesyncSkill
|
|
7425
|
+
* 2. Transform frontmatter to tool-specific format
|
|
7426
|
+
* 3. Transform body content if needed
|
|
7427
|
+
* 4. Preserve other skill files
|
|
7428
|
+
* 5. Return a concrete ToolSkill instance
|
|
7429
|
+
*
|
|
7430
|
+
* @param params - Parameters including the RulesyncSkill to convert
|
|
7431
|
+
* @returns A concrete ToolSkill instance
|
|
7432
|
+
*/
|
|
7433
|
+
static fromRulesyncSkill(_params) {
|
|
7434
|
+
throw new Error("Please implement this method in the subclass.");
|
|
7435
|
+
}
|
|
7436
|
+
/**
|
|
7437
|
+
* Check if this tool is targeted by a RulesyncSkill.
|
|
7438
|
+
* Since skills don't have targets field like commands/subagents,
|
|
7439
|
+
* the default behavior may vary by tool.
|
|
7440
|
+
*
|
|
7441
|
+
* @param rulesyncSkill - The RulesyncSkill to check
|
|
7442
|
+
* @returns True if this tool should use the skill
|
|
7443
|
+
*/
|
|
7444
|
+
static isTargetedByRulesyncSkill(_rulesyncSkill) {
|
|
7445
|
+
throw new Error("Please implement this method in the subclass.");
|
|
7446
|
+
}
|
|
7447
|
+
};
|
|
7448
|
+
|
|
7449
|
+
// src/features/skills/claudecode-skill.ts
|
|
7450
|
+
var ClaudecodeSkillFrontmatterSchema = import_mini26.z.object({
|
|
7451
|
+
name: import_mini26.z.string(),
|
|
7452
|
+
description: import_mini26.z.string(),
|
|
7453
|
+
"allowed-tools": import_mini26.z.optional(import_mini26.z.array(import_mini26.z.string()))
|
|
7454
|
+
});
|
|
7455
|
+
var ClaudecodeSkill = class _ClaudecodeSkill extends ToolSkill {
|
|
7456
|
+
constructor({
|
|
7457
|
+
baseDir = process.cwd(),
|
|
7458
|
+
relativeDirPath = (0, import_node_path70.join)(".claude", "skills"),
|
|
7459
|
+
dirName,
|
|
7460
|
+
frontmatter,
|
|
7461
|
+
body,
|
|
7462
|
+
otherFiles = [],
|
|
7463
|
+
validate = true,
|
|
7464
|
+
global = false
|
|
7465
|
+
}) {
|
|
7466
|
+
super({
|
|
7467
|
+
baseDir,
|
|
7468
|
+
relativeDirPath,
|
|
7469
|
+
dirName,
|
|
7470
|
+
mainFile: {
|
|
7471
|
+
name: SKILL_FILE_NAME,
|
|
7472
|
+
body,
|
|
7473
|
+
frontmatter: { ...frontmatter }
|
|
7474
|
+
},
|
|
7475
|
+
otherFiles,
|
|
7476
|
+
global
|
|
7477
|
+
});
|
|
7478
|
+
if (validate) {
|
|
7479
|
+
const result = this.validate();
|
|
7480
|
+
if (!result.success) {
|
|
7481
|
+
throw result.error;
|
|
7482
|
+
}
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
static getSettablePaths({
|
|
7486
|
+
global: _global = false
|
|
7487
|
+
} = {}) {
|
|
7488
|
+
return {
|
|
7489
|
+
relativeDirPath: (0, import_node_path70.join)(".claude", "skills")
|
|
7490
|
+
};
|
|
7491
|
+
}
|
|
7492
|
+
getFrontmatter() {
|
|
7493
|
+
if (!this.mainFile?.frontmatter) {
|
|
7494
|
+
throw new Error("Frontmatter is not defined");
|
|
7495
|
+
}
|
|
7496
|
+
const result = ClaudecodeSkillFrontmatterSchema.parse(this.mainFile.frontmatter);
|
|
7497
|
+
return result;
|
|
7498
|
+
}
|
|
7499
|
+
getBody() {
|
|
7500
|
+
return this.mainFile?.body ?? "";
|
|
7501
|
+
}
|
|
7502
|
+
validate() {
|
|
7503
|
+
if (this.mainFile === void 0) {
|
|
7504
|
+
return {
|
|
7505
|
+
success: false,
|
|
7506
|
+
error: new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
7507
|
+
};
|
|
7508
|
+
}
|
|
7509
|
+
const result = ClaudecodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
7510
|
+
if (!result.success) {
|
|
7511
|
+
return {
|
|
7512
|
+
success: false,
|
|
7513
|
+
error: new Error(
|
|
7514
|
+
`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`
|
|
7515
|
+
)
|
|
7516
|
+
};
|
|
7517
|
+
}
|
|
7518
|
+
return { success: true, error: null };
|
|
7519
|
+
}
|
|
7520
|
+
toRulesyncSkill() {
|
|
7521
|
+
const frontmatter = this.getFrontmatter();
|
|
7522
|
+
const rulesyncFrontmatter = {
|
|
7523
|
+
name: frontmatter.name,
|
|
7524
|
+
description: frontmatter.description,
|
|
7525
|
+
...frontmatter["allowed-tools"] && {
|
|
7526
|
+
claudecode: {
|
|
7527
|
+
"allowed-tools": frontmatter["allowed-tools"]
|
|
7528
|
+
}
|
|
7529
|
+
}
|
|
7530
|
+
};
|
|
7531
|
+
return new RulesyncSkill({
|
|
7532
|
+
baseDir: this.baseDir,
|
|
7533
|
+
relativeDirPath: this.relativeDirPath,
|
|
7534
|
+
dirName: this.getDirName(),
|
|
7535
|
+
frontmatter: rulesyncFrontmatter,
|
|
7536
|
+
body: this.getBody(),
|
|
7537
|
+
otherFiles: this.getOtherFiles(),
|
|
7538
|
+
validate: true,
|
|
7539
|
+
global: this.global
|
|
7540
|
+
});
|
|
7541
|
+
}
|
|
7542
|
+
static fromRulesyncSkill({
|
|
7543
|
+
rulesyncSkill,
|
|
7544
|
+
validate = true,
|
|
7545
|
+
global = false
|
|
7546
|
+
}) {
|
|
7547
|
+
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
7548
|
+
const claudecodeFrontmatter = {
|
|
7549
|
+
name: rulesyncFrontmatter.name,
|
|
7550
|
+
description: rulesyncFrontmatter.description,
|
|
7551
|
+
"allowed-tools": rulesyncFrontmatter.claudecode?.["allowed-tools"]
|
|
7552
|
+
};
|
|
7553
|
+
const settablePaths = _ClaudecodeSkill.getSettablePaths({ global });
|
|
7554
|
+
return new _ClaudecodeSkill({
|
|
7555
|
+
baseDir: rulesyncSkill.getBaseDir(),
|
|
7556
|
+
relativeDirPath: settablePaths.relativeDirPath,
|
|
7557
|
+
dirName: rulesyncSkill.getDirName(),
|
|
7558
|
+
frontmatter: claudecodeFrontmatter,
|
|
7559
|
+
body: rulesyncSkill.getBody(),
|
|
7560
|
+
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
7561
|
+
validate,
|
|
7562
|
+
global
|
|
7563
|
+
});
|
|
7564
|
+
}
|
|
7565
|
+
static isTargetedByRulesyncSkill(_rulesyncSkill) {
|
|
7566
|
+
return true;
|
|
7567
|
+
}
|
|
7568
|
+
static async fromDir({
|
|
7569
|
+
baseDir = process.cwd(),
|
|
7570
|
+
relativeDirPath,
|
|
7571
|
+
dirName,
|
|
7572
|
+
global = false
|
|
7573
|
+
}) {
|
|
7574
|
+
const settablePaths = this.getSettablePaths({ global });
|
|
7575
|
+
const actualRelativeDirPath = relativeDirPath ?? settablePaths.relativeDirPath;
|
|
7576
|
+
const skillDirPath = (0, import_node_path70.join)(baseDir, actualRelativeDirPath, dirName);
|
|
7577
|
+
const skillFilePath = (0, import_node_path70.join)(skillDirPath, SKILL_FILE_NAME);
|
|
7578
|
+
if (!await fileExists(skillFilePath)) {
|
|
7579
|
+
throw new Error(`${SKILL_FILE_NAME} not found in ${skillDirPath}`);
|
|
7580
|
+
}
|
|
7581
|
+
const fileContent = await readFileContent(skillFilePath);
|
|
7582
|
+
const { frontmatter, body: content } = parseFrontmatter(fileContent);
|
|
7583
|
+
const result = ClaudecodeSkillFrontmatterSchema.safeParse(frontmatter);
|
|
7584
|
+
if (!result.success) {
|
|
7585
|
+
throw new Error(`Invalid frontmatter in ${skillFilePath}: ${formatError(result.error)}`);
|
|
7586
|
+
}
|
|
7587
|
+
const otherFiles = await this.collectOtherFiles(
|
|
7588
|
+
baseDir,
|
|
7589
|
+
actualRelativeDirPath,
|
|
7590
|
+
dirName,
|
|
7591
|
+
SKILL_FILE_NAME
|
|
7592
|
+
);
|
|
7593
|
+
return new _ClaudecodeSkill({
|
|
7594
|
+
baseDir,
|
|
7595
|
+
relativeDirPath: actualRelativeDirPath,
|
|
7596
|
+
dirName,
|
|
7597
|
+
frontmatter: result.data,
|
|
7598
|
+
body: content.trim(),
|
|
7599
|
+
otherFiles,
|
|
7600
|
+
validate: true,
|
|
7601
|
+
global
|
|
7602
|
+
});
|
|
7603
|
+
}
|
|
7604
|
+
};
|
|
7605
|
+
|
|
7606
|
+
// src/features/skills/skills-processor.ts
|
|
7607
|
+
var skillsProcessorToolTargets = ["claudecode"];
|
|
7608
|
+
var skillsProcessorToolTargetsGlobal = ["claudecode"];
|
|
7609
|
+
var SkillsProcessorToolTargetSchema = import_mini27.z.enum(skillsProcessorToolTargets);
|
|
7610
|
+
var SkillsProcessor = class extends DirFeatureProcessor {
|
|
7611
|
+
toolTarget;
|
|
7612
|
+
global;
|
|
7613
|
+
constructor({
|
|
7614
|
+
baseDir = process.cwd(),
|
|
7615
|
+
toolTarget,
|
|
7616
|
+
global = false
|
|
7617
|
+
}) {
|
|
7618
|
+
super({ baseDir });
|
|
7619
|
+
const result = SkillsProcessorToolTargetSchema.safeParse(toolTarget);
|
|
7620
|
+
if (!result.success) {
|
|
7621
|
+
throw new Error(
|
|
7622
|
+
`Invalid tool target for SkillsProcessor: ${toolTarget}. ${formatError(result.error)}`
|
|
7623
|
+
);
|
|
7624
|
+
}
|
|
7625
|
+
this.toolTarget = result.data;
|
|
7626
|
+
this.global = global;
|
|
7627
|
+
}
|
|
7628
|
+
async convertRulesyncDirsToToolDirs(rulesyncDirs) {
|
|
7629
|
+
const rulesyncSkills = rulesyncDirs.filter(
|
|
7630
|
+
(dir) => dir instanceof RulesyncSkill
|
|
7631
|
+
);
|
|
7632
|
+
const toolSkills = rulesyncSkills.map((rulesyncSkill) => {
|
|
7633
|
+
switch (this.toolTarget) {
|
|
7634
|
+
case "claudecode":
|
|
7635
|
+
if (!ClaudecodeSkill.isTargetedByRulesyncSkill(rulesyncSkill)) {
|
|
7636
|
+
return null;
|
|
7637
|
+
}
|
|
7638
|
+
return ClaudecodeSkill.fromRulesyncSkill({
|
|
7639
|
+
rulesyncSkill,
|
|
7640
|
+
global: this.global
|
|
7641
|
+
});
|
|
7642
|
+
default:
|
|
7643
|
+
throw new Error(`Unsupported tool target: ${this.toolTarget}`);
|
|
7644
|
+
}
|
|
7645
|
+
}).filter((skill) => skill !== null);
|
|
7646
|
+
return toolSkills;
|
|
7647
|
+
}
|
|
7648
|
+
async convertToolDirsToRulesyncDirs(toolDirs) {
|
|
7649
|
+
const toolSkills = toolDirs.filter((dir) => dir instanceof ToolSkill);
|
|
7650
|
+
const rulesyncSkills = toolSkills.map((toolSkill) => {
|
|
7651
|
+
return toolSkill.toRulesyncSkill();
|
|
7652
|
+
});
|
|
7653
|
+
return rulesyncSkills;
|
|
7654
|
+
}
|
|
7655
|
+
/**
|
|
7656
|
+
* Implementation of abstract method from DirFeatureProcessor
|
|
7657
|
+
* Load and parse rulesync skill directories from .rulesync/skills/ directory
|
|
7658
|
+
*/
|
|
7659
|
+
async loadRulesyncDirs() {
|
|
7660
|
+
const paths = RulesyncSkill.getSettablePaths();
|
|
7661
|
+
const rulesyncSkillsDirPath = (0, import_node_path71.join)(this.baseDir, paths.relativeDirPath);
|
|
7662
|
+
const dirPaths = await findFilesByGlobs((0, import_node_path71.join)(rulesyncSkillsDirPath, "*"), { type: "dir" });
|
|
7663
|
+
const dirNames = dirPaths.map((path3) => (0, import_node_path71.basename)(path3));
|
|
7664
|
+
const results = await Promise.allSettled(
|
|
7665
|
+
dirNames.map(
|
|
7666
|
+
(dirName) => RulesyncSkill.fromDir({ baseDir: this.baseDir, dirName, global: this.global })
|
|
7667
|
+
)
|
|
7668
|
+
);
|
|
7669
|
+
const rulesyncSkills = [];
|
|
7670
|
+
for (const result of results) {
|
|
7671
|
+
if (result.status === "fulfilled") {
|
|
7672
|
+
rulesyncSkills.push(result.value);
|
|
7673
|
+
}
|
|
7674
|
+
}
|
|
7675
|
+
logger.info(`Successfully loaded ${rulesyncSkills.length} rulesync skills`);
|
|
7676
|
+
return rulesyncSkills;
|
|
7677
|
+
}
|
|
7678
|
+
/**
|
|
7679
|
+
* Implementation of abstract method from DirFeatureProcessor
|
|
7680
|
+
* Load tool-specific skill configurations and parse them into ToolSkill instances
|
|
7681
|
+
*/
|
|
7682
|
+
async loadToolDirs() {
|
|
7683
|
+
switch (this.toolTarget) {
|
|
7684
|
+
case "claudecode":
|
|
7685
|
+
return await this.loadClaudecodeSkills();
|
|
7686
|
+
default:
|
|
7687
|
+
throw new Error(`Unsupported tool target: ${this.toolTarget}`);
|
|
7688
|
+
}
|
|
7689
|
+
}
|
|
7690
|
+
async loadToolDirsToDelete() {
|
|
7691
|
+
return this.loadToolDirs();
|
|
7692
|
+
}
|
|
7693
|
+
/**
|
|
7694
|
+
* Load Claude Code skill configurations from .claude/skills/ directory
|
|
7695
|
+
*/
|
|
7696
|
+
async loadClaudecodeSkills() {
|
|
7697
|
+
const paths = ClaudecodeSkill.getSettablePaths({ global: this.global });
|
|
7698
|
+
const skillsDirPath = (0, import_node_path71.join)(this.baseDir, paths.relativeDirPath);
|
|
7699
|
+
const dirPaths = await findFilesByGlobs((0, import_node_path71.join)(skillsDirPath, "*"), { type: "dir" });
|
|
7700
|
+
const dirNames = dirPaths.map((path3) => (0, import_node_path71.basename)(path3));
|
|
7701
|
+
const toolSkills = (await Promise.allSettled(
|
|
7702
|
+
dirNames.map(
|
|
7703
|
+
(dirName) => ClaudecodeSkill.fromDir({
|
|
7704
|
+
baseDir: this.baseDir,
|
|
7705
|
+
dirName,
|
|
7706
|
+
global: this.global
|
|
7707
|
+
})
|
|
7708
|
+
)
|
|
7709
|
+
)).filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
7710
|
+
logger.info(`Successfully loaded ${toolSkills.length} ${paths.relativeDirPath} skills`);
|
|
7711
|
+
return toolSkills;
|
|
7712
|
+
}
|
|
7713
|
+
/**
|
|
7714
|
+
* Implementation of abstract method from DirFeatureProcessor
|
|
7715
|
+
* Return the tool targets that this processor supports
|
|
7716
|
+
*/
|
|
7717
|
+
static getToolTargets(_params = {}) {
|
|
7718
|
+
return skillsProcessorToolTargets;
|
|
7719
|
+
}
|
|
7720
|
+
/**
|
|
7721
|
+
* Return the tool targets that this processor supports in global mode
|
|
7722
|
+
*/
|
|
7723
|
+
static getToolTargetsGlobal() {
|
|
7724
|
+
return skillsProcessorToolTargetsGlobal;
|
|
7725
|
+
}
|
|
7726
|
+
};
|
|
7727
|
+
|
|
7089
7728
|
// src/cli/commands/generate.ts
|
|
7090
7729
|
async function generateCommand(options) {
|
|
7091
7730
|
const config = await ConfigResolver.resolve(options);
|
|
@@ -7101,7 +7740,8 @@ async function generateCommand(options) {
|
|
|
7101
7740
|
const totalMcpOutputs = await generateMcp(config);
|
|
7102
7741
|
const totalCommandOutputs = await generateCommands(config);
|
|
7103
7742
|
const totalSubagentOutputs = await generateSubagents(config);
|
|
7104
|
-
const
|
|
7743
|
+
const totalSkillOutputs = await generateSkills(config);
|
|
7744
|
+
const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs + totalSkillOutputs;
|
|
7105
7745
|
if (totalGenerated === 0) {
|
|
7106
7746
|
const enabledFeatures = config.getFeatures().join(", ");
|
|
7107
7747
|
logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
|
|
@@ -7114,6 +7754,7 @@ async function generateCommand(options) {
|
|
|
7114
7754
|
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
|
|
7115
7755
|
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
7116
7756
|
if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
|
|
7757
|
+
if (totalSkillOutputs > 0) parts.push(`${totalSkillOutputs} skills`);
|
|
7117
7758
|
logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
|
|
7118
7759
|
}
|
|
7119
7760
|
}
|
|
@@ -7288,11 +7929,39 @@ async function generateSubagents(config) {
|
|
|
7288
7929
|
}
|
|
7289
7930
|
return totalSubagentOutputs;
|
|
7290
7931
|
}
|
|
7932
|
+
async function generateSkills(config) {
|
|
7933
|
+
if (!config.getFeatures().includes("skills")) {
|
|
7934
|
+
logger.debug("Skipping skill generation (not in --features)");
|
|
7935
|
+
return 0;
|
|
7936
|
+
}
|
|
7937
|
+
let totalSkillOutputs = 0;
|
|
7938
|
+
logger.info("Generating skill files...");
|
|
7939
|
+
const toolTargets = config.getGlobal() ? (0, import_es_toolkit2.intersection)(config.getTargets(), SkillsProcessor.getToolTargetsGlobal()) : (0, import_es_toolkit2.intersection)(config.getTargets(), SkillsProcessor.getToolTargets());
|
|
7940
|
+
for (const baseDir of config.getBaseDirs()) {
|
|
7941
|
+
for (const toolTarget of toolTargets) {
|
|
7942
|
+
const processor = new SkillsProcessor({
|
|
7943
|
+
baseDir,
|
|
7944
|
+
toolTarget,
|
|
7945
|
+
global: config.getGlobal()
|
|
7946
|
+
});
|
|
7947
|
+
if (config.getDelete()) {
|
|
7948
|
+
const oldToolDirs = await processor.loadToolDirsToDelete();
|
|
7949
|
+
await processor.removeAiDirs(oldToolDirs);
|
|
7950
|
+
}
|
|
7951
|
+
const rulesyncDirs = await processor.loadRulesyncDirs();
|
|
7952
|
+
const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
|
|
7953
|
+
const writtenCount = await processor.writeAiDirs(toolDirs);
|
|
7954
|
+
totalSkillOutputs += writtenCount;
|
|
7955
|
+
logger.success(`Generated ${writtenCount} ${toolTarget} skill(s) in ${baseDir}`);
|
|
7956
|
+
}
|
|
7957
|
+
}
|
|
7958
|
+
return totalSkillOutputs;
|
|
7959
|
+
}
|
|
7291
7960
|
|
|
7292
7961
|
// src/cli/commands/gitignore.ts
|
|
7293
|
-
var
|
|
7962
|
+
var import_node_path72 = require("path");
|
|
7294
7963
|
var gitignoreCommand = async () => {
|
|
7295
|
-
const gitignorePath = (0,
|
|
7964
|
+
const gitignorePath = (0, import_node_path72.join)(process.cwd(), ".gitignore");
|
|
7296
7965
|
const rulesFilesToIgnore = [
|
|
7297
7966
|
"# Generated by rulesync - AI tool configuration files",
|
|
7298
7967
|
// AGENTS.md
|
|
@@ -7309,6 +7978,7 @@ var gitignoreCommand = async () => {
|
|
|
7309
7978
|
"**/.claude/memories/",
|
|
7310
7979
|
"**/.claude/commands/",
|
|
7311
7980
|
"**/.claude/agents/",
|
|
7981
|
+
"**/.claude/skills/",
|
|
7312
7982
|
"**/.claude/settings.local.json",
|
|
7313
7983
|
"**/.mcp.json",
|
|
7314
7984
|
// Cline
|
|
@@ -7402,6 +8072,7 @@ async function importCommand(options) {
|
|
|
7402
8072
|
await importMcp(config, tool);
|
|
7403
8073
|
await importCommands(config, tool);
|
|
7404
8074
|
await importSubagents(config, tool);
|
|
8075
|
+
await importSkills(config, tool);
|
|
7405
8076
|
}
|
|
7406
8077
|
async function importRules(config, tool) {
|
|
7407
8078
|
if (!config.getFeatures().includes("rules")) {
|
|
@@ -7531,9 +8202,34 @@ async function importSubagents(config, tool) {
|
|
|
7531
8202
|
}
|
|
7532
8203
|
return writtenCount;
|
|
7533
8204
|
}
|
|
8205
|
+
async function importSkills(config, tool) {
|
|
8206
|
+
if (!config.getFeatures().includes("skills")) {
|
|
8207
|
+
return 0;
|
|
8208
|
+
}
|
|
8209
|
+
const global = config.getGlobal();
|
|
8210
|
+
const supportedTargets = SkillsProcessor.getToolTargets();
|
|
8211
|
+
if (!supportedTargets.includes(tool)) {
|
|
8212
|
+
return 0;
|
|
8213
|
+
}
|
|
8214
|
+
const skillsProcessor = new SkillsProcessor({
|
|
8215
|
+
baseDir: config.getBaseDirs()[0] ?? ".",
|
|
8216
|
+
toolTarget: tool,
|
|
8217
|
+
global
|
|
8218
|
+
});
|
|
8219
|
+
const toolDirs = await skillsProcessor.loadToolDirs();
|
|
8220
|
+
if (toolDirs.length === 0) {
|
|
8221
|
+
return 0;
|
|
8222
|
+
}
|
|
8223
|
+
const rulesyncDirs = await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs);
|
|
8224
|
+
const writtenCount = await skillsProcessor.writeAiDirs(rulesyncDirs);
|
|
8225
|
+
if (config.getVerbose() && writtenCount > 0) {
|
|
8226
|
+
logger.success(`Created ${writtenCount} skill directories`);
|
|
8227
|
+
}
|
|
8228
|
+
return writtenCount;
|
|
8229
|
+
}
|
|
7534
8230
|
|
|
7535
8231
|
// src/cli/commands/init.ts
|
|
7536
|
-
var
|
|
8232
|
+
var import_node_path73 = require("path");
|
|
7537
8233
|
async function initCommand() {
|
|
7538
8234
|
logger.info("Initializing rulesync...");
|
|
7539
8235
|
await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
|
|
@@ -7696,14 +8392,14 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7696
8392
|
await ensureDir(commandPaths.relativeDirPath);
|
|
7697
8393
|
await ensureDir(subagentPaths.relativeDirPath);
|
|
7698
8394
|
await ensureDir(ignorePaths.relativeDirPath);
|
|
7699
|
-
const ruleFilepath = (0,
|
|
8395
|
+
const ruleFilepath = (0, import_node_path73.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
|
|
7700
8396
|
if (!await fileExists(ruleFilepath)) {
|
|
7701
8397
|
await writeFileContent(ruleFilepath, sampleRuleFile.content);
|
|
7702
8398
|
logger.success(`Created ${ruleFilepath}`);
|
|
7703
8399
|
} else {
|
|
7704
8400
|
logger.info(`Skipped ${ruleFilepath} (already exists)`);
|
|
7705
8401
|
}
|
|
7706
|
-
const mcpFilepath = (0,
|
|
8402
|
+
const mcpFilepath = (0, import_node_path73.join)(
|
|
7707
8403
|
mcpPaths.recommended.relativeDirPath,
|
|
7708
8404
|
mcpPaths.recommended.relativeFilePath
|
|
7709
8405
|
);
|
|
@@ -7713,21 +8409,21 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7713
8409
|
} else {
|
|
7714
8410
|
logger.info(`Skipped ${mcpFilepath} (already exists)`);
|
|
7715
8411
|
}
|
|
7716
|
-
const commandFilepath = (0,
|
|
8412
|
+
const commandFilepath = (0, import_node_path73.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
|
|
7717
8413
|
if (!await fileExists(commandFilepath)) {
|
|
7718
8414
|
await writeFileContent(commandFilepath, sampleCommandFile.content);
|
|
7719
8415
|
logger.success(`Created ${commandFilepath}`);
|
|
7720
8416
|
} else {
|
|
7721
8417
|
logger.info(`Skipped ${commandFilepath} (already exists)`);
|
|
7722
8418
|
}
|
|
7723
|
-
const subagentFilepath = (0,
|
|
8419
|
+
const subagentFilepath = (0, import_node_path73.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
|
|
7724
8420
|
if (!await fileExists(subagentFilepath)) {
|
|
7725
8421
|
await writeFileContent(subagentFilepath, sampleSubagentFile.content);
|
|
7726
8422
|
logger.success(`Created ${subagentFilepath}`);
|
|
7727
8423
|
} else {
|
|
7728
8424
|
logger.info(`Skipped ${subagentFilepath} (already exists)`);
|
|
7729
8425
|
}
|
|
7730
|
-
const ignoreFilepath = (0,
|
|
8426
|
+
const ignoreFilepath = (0, import_node_path73.join)(ignorePaths.relativeDirPath, ignorePaths.relativeFilePath);
|
|
7731
8427
|
if (!await fileExists(ignoreFilepath)) {
|
|
7732
8428
|
await writeFileContent(ignoreFilepath, sampleIgnoreFile.content);
|
|
7733
8429
|
logger.success(`Created ${ignoreFilepath}`);
|
|
@@ -7740,12 +8436,12 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7740
8436
|
var import_fastmcp = require("fastmcp");
|
|
7741
8437
|
|
|
7742
8438
|
// src/mcp/commands.ts
|
|
7743
|
-
var
|
|
7744
|
-
var
|
|
8439
|
+
var import_node_path74 = require("path");
|
|
8440
|
+
var import_mini28 = require("zod/mini");
|
|
7745
8441
|
var maxCommandSizeBytes = 1024 * 1024;
|
|
7746
8442
|
var maxCommandsCount = 1e3;
|
|
7747
8443
|
async function listCommands() {
|
|
7748
|
-
const commandsDir = (0,
|
|
8444
|
+
const commandsDir = (0, import_node_path74.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
7749
8445
|
try {
|
|
7750
8446
|
const files = await listDirectoryFiles(commandsDir);
|
|
7751
8447
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -7757,7 +8453,7 @@ async function listCommands() {
|
|
|
7757
8453
|
});
|
|
7758
8454
|
const frontmatter = command.getFrontmatter();
|
|
7759
8455
|
return {
|
|
7760
|
-
relativePathFromCwd: (0,
|
|
8456
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
|
|
7761
8457
|
frontmatter
|
|
7762
8458
|
};
|
|
7763
8459
|
} catch (error) {
|
|
@@ -7777,13 +8473,13 @@ async function getCommand({ relativePathFromCwd }) {
|
|
|
7777
8473
|
relativePath: relativePathFromCwd,
|
|
7778
8474
|
intendedRootDir: process.cwd()
|
|
7779
8475
|
});
|
|
7780
|
-
const filename = (0,
|
|
8476
|
+
const filename = (0, import_node_path74.basename)(relativePathFromCwd);
|
|
7781
8477
|
try {
|
|
7782
8478
|
const command = await RulesyncCommand.fromFile({
|
|
7783
8479
|
relativeFilePath: filename
|
|
7784
8480
|
});
|
|
7785
8481
|
return {
|
|
7786
|
-
relativePathFromCwd: (0,
|
|
8482
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
7787
8483
|
frontmatter: command.getFrontmatter(),
|
|
7788
8484
|
body: command.getBody()
|
|
7789
8485
|
};
|
|
@@ -7802,7 +8498,7 @@ async function putCommand({
|
|
|
7802
8498
|
relativePath: relativePathFromCwd,
|
|
7803
8499
|
intendedRootDir: process.cwd()
|
|
7804
8500
|
});
|
|
7805
|
-
const filename = (0,
|
|
8501
|
+
const filename = (0, import_node_path74.basename)(relativePathFromCwd);
|
|
7806
8502
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
7807
8503
|
if (estimatedSize > maxCommandSizeBytes) {
|
|
7808
8504
|
throw new Error(
|
|
@@ -7812,7 +8508,7 @@ async function putCommand({
|
|
|
7812
8508
|
try {
|
|
7813
8509
|
const existingCommands = await listCommands();
|
|
7814
8510
|
const isUpdate = existingCommands.some(
|
|
7815
|
-
(command2) => command2.relativePathFromCwd === (0,
|
|
8511
|
+
(command2) => command2.relativePathFromCwd === (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
7816
8512
|
);
|
|
7817
8513
|
if (!isUpdate && existingCommands.length >= maxCommandsCount) {
|
|
7818
8514
|
throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
|
|
@@ -7827,11 +8523,11 @@ async function putCommand({
|
|
|
7827
8523
|
fileContent,
|
|
7828
8524
|
validate: true
|
|
7829
8525
|
});
|
|
7830
|
-
const commandsDir = (0,
|
|
8526
|
+
const commandsDir = (0, import_node_path74.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
7831
8527
|
await ensureDir(commandsDir);
|
|
7832
8528
|
await writeFileContent(command.getFilePath(), command.getFileContent());
|
|
7833
8529
|
return {
|
|
7834
|
-
relativePathFromCwd: (0,
|
|
8530
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
7835
8531
|
frontmatter: command.getFrontmatter(),
|
|
7836
8532
|
body: command.getBody()
|
|
7837
8533
|
};
|
|
@@ -7846,12 +8542,12 @@ async function deleteCommand({ relativePathFromCwd }) {
|
|
|
7846
8542
|
relativePath: relativePathFromCwd,
|
|
7847
8543
|
intendedRootDir: process.cwd()
|
|
7848
8544
|
});
|
|
7849
|
-
const filename = (0,
|
|
7850
|
-
const fullPath = (0,
|
|
8545
|
+
const filename = (0, import_node_path74.basename)(relativePathFromCwd);
|
|
8546
|
+
const fullPath = (0, import_node_path74.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
|
|
7851
8547
|
try {
|
|
7852
8548
|
await removeFile(fullPath);
|
|
7853
8549
|
return {
|
|
7854
|
-
relativePathFromCwd: (0,
|
|
8550
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
7855
8551
|
};
|
|
7856
8552
|
} catch (error) {
|
|
7857
8553
|
throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -7860,23 +8556,23 @@ async function deleteCommand({ relativePathFromCwd }) {
|
|
|
7860
8556
|
}
|
|
7861
8557
|
}
|
|
7862
8558
|
var commandToolSchemas = {
|
|
7863
|
-
listCommands:
|
|
7864
|
-
getCommand:
|
|
7865
|
-
relativePathFromCwd:
|
|
8559
|
+
listCommands: import_mini28.z.object({}),
|
|
8560
|
+
getCommand: import_mini28.z.object({
|
|
8561
|
+
relativePathFromCwd: import_mini28.z.string()
|
|
7866
8562
|
}),
|
|
7867
|
-
putCommand:
|
|
7868
|
-
relativePathFromCwd:
|
|
8563
|
+
putCommand: import_mini28.z.object({
|
|
8564
|
+
relativePathFromCwd: import_mini28.z.string(),
|
|
7869
8565
|
frontmatter: RulesyncCommandFrontmatterSchema,
|
|
7870
|
-
body:
|
|
8566
|
+
body: import_mini28.z.string()
|
|
7871
8567
|
}),
|
|
7872
|
-
deleteCommand:
|
|
7873
|
-
relativePathFromCwd:
|
|
8568
|
+
deleteCommand: import_mini28.z.object({
|
|
8569
|
+
relativePathFromCwd: import_mini28.z.string()
|
|
7874
8570
|
})
|
|
7875
8571
|
};
|
|
7876
8572
|
var commandTools = {
|
|
7877
8573
|
listCommands: {
|
|
7878
8574
|
name: "listCommands",
|
|
7879
|
-
description: `List all commands from ${(0,
|
|
8575
|
+
description: `List all commands from ${(0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
7880
8576
|
parameters: commandToolSchemas.listCommands,
|
|
7881
8577
|
execute: async () => {
|
|
7882
8578
|
const commands = await listCommands();
|
|
@@ -7918,11 +8614,11 @@ var commandTools = {
|
|
|
7918
8614
|
};
|
|
7919
8615
|
|
|
7920
8616
|
// src/mcp/ignore.ts
|
|
7921
|
-
var
|
|
7922
|
-
var
|
|
8617
|
+
var import_node_path75 = require("path");
|
|
8618
|
+
var import_mini29 = require("zod/mini");
|
|
7923
8619
|
var maxIgnoreFileSizeBytes = 100 * 1024;
|
|
7924
8620
|
async function getIgnoreFile() {
|
|
7925
|
-
const ignoreFilePath = (0,
|
|
8621
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7926
8622
|
try {
|
|
7927
8623
|
const content = await readFileContent(ignoreFilePath);
|
|
7928
8624
|
return {
|
|
@@ -7936,7 +8632,7 @@ async function getIgnoreFile() {
|
|
|
7936
8632
|
}
|
|
7937
8633
|
}
|
|
7938
8634
|
async function putIgnoreFile({ content }) {
|
|
7939
|
-
const ignoreFilePath = (0,
|
|
8635
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7940
8636
|
const contentSizeBytes = Buffer.byteLength(content, "utf8");
|
|
7941
8637
|
if (contentSizeBytes > maxIgnoreFileSizeBytes) {
|
|
7942
8638
|
throw new Error(
|
|
@@ -7957,7 +8653,7 @@ async function putIgnoreFile({ content }) {
|
|
|
7957
8653
|
}
|
|
7958
8654
|
}
|
|
7959
8655
|
async function deleteIgnoreFile() {
|
|
7960
|
-
const ignoreFilePath = (0,
|
|
8656
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7961
8657
|
try {
|
|
7962
8658
|
await removeFile(ignoreFilePath);
|
|
7963
8659
|
return {
|
|
@@ -7970,11 +8666,11 @@ async function deleteIgnoreFile() {
|
|
|
7970
8666
|
}
|
|
7971
8667
|
}
|
|
7972
8668
|
var ignoreToolSchemas = {
|
|
7973
|
-
getIgnoreFile:
|
|
7974
|
-
putIgnoreFile:
|
|
7975
|
-
content:
|
|
8669
|
+
getIgnoreFile: import_mini29.z.object({}),
|
|
8670
|
+
putIgnoreFile: import_mini29.z.object({
|
|
8671
|
+
content: import_mini29.z.string()
|
|
7976
8672
|
}),
|
|
7977
|
-
deleteIgnoreFile:
|
|
8673
|
+
deleteIgnoreFile: import_mini29.z.object({})
|
|
7978
8674
|
};
|
|
7979
8675
|
var ignoreTools = {
|
|
7980
8676
|
getIgnoreFile: {
|
|
@@ -8007,8 +8703,8 @@ var ignoreTools = {
|
|
|
8007
8703
|
};
|
|
8008
8704
|
|
|
8009
8705
|
// src/mcp/mcp.ts
|
|
8010
|
-
var
|
|
8011
|
-
var
|
|
8706
|
+
var import_node_path76 = require("path");
|
|
8707
|
+
var import_mini30 = require("zod/mini");
|
|
8012
8708
|
var maxMcpSizeBytes = 1024 * 1024;
|
|
8013
8709
|
async function getMcpFile() {
|
|
8014
8710
|
const config = await ConfigResolver.resolve({});
|
|
@@ -8017,7 +8713,7 @@ async function getMcpFile() {
|
|
|
8017
8713
|
validate: true,
|
|
8018
8714
|
modularMcp: config.getModularMcp()
|
|
8019
8715
|
});
|
|
8020
|
-
const relativePathFromCwd = (0,
|
|
8716
|
+
const relativePathFromCwd = (0, import_node_path76.join)(
|
|
8021
8717
|
rulesyncMcp.getRelativeDirPath(),
|
|
8022
8718
|
rulesyncMcp.getRelativeFilePath()
|
|
8023
8719
|
);
|
|
@@ -8050,7 +8746,7 @@ async function putMcpFile({ content }) {
|
|
|
8050
8746
|
const paths = RulesyncMcp.getSettablePaths();
|
|
8051
8747
|
const relativeDirPath = paths.recommended.relativeDirPath;
|
|
8052
8748
|
const relativeFilePath = paths.recommended.relativeFilePath;
|
|
8053
|
-
const fullPath = (0,
|
|
8749
|
+
const fullPath = (0, import_node_path76.join)(baseDir, relativeDirPath, relativeFilePath);
|
|
8054
8750
|
const rulesyncMcp = new RulesyncMcp({
|
|
8055
8751
|
baseDir,
|
|
8056
8752
|
relativeDirPath,
|
|
@@ -8059,9 +8755,9 @@ async function putMcpFile({ content }) {
|
|
|
8059
8755
|
validate: true,
|
|
8060
8756
|
modularMcp: config.getModularMcp()
|
|
8061
8757
|
});
|
|
8062
|
-
await ensureDir((0,
|
|
8758
|
+
await ensureDir((0, import_node_path76.join)(baseDir, relativeDirPath));
|
|
8063
8759
|
await writeFileContent(fullPath, content);
|
|
8064
|
-
const relativePathFromCwd = (0,
|
|
8760
|
+
const relativePathFromCwd = (0, import_node_path76.join)(relativeDirPath, relativeFilePath);
|
|
8065
8761
|
return {
|
|
8066
8762
|
relativePathFromCwd,
|
|
8067
8763
|
content: rulesyncMcp.getFileContent()
|
|
@@ -8076,15 +8772,15 @@ async function deleteMcpFile() {
|
|
|
8076
8772
|
try {
|
|
8077
8773
|
const baseDir = process.cwd();
|
|
8078
8774
|
const paths = RulesyncMcp.getSettablePaths();
|
|
8079
|
-
const recommendedPath = (0,
|
|
8775
|
+
const recommendedPath = (0, import_node_path76.join)(
|
|
8080
8776
|
baseDir,
|
|
8081
8777
|
paths.recommended.relativeDirPath,
|
|
8082
8778
|
paths.recommended.relativeFilePath
|
|
8083
8779
|
);
|
|
8084
|
-
const legacyPath = (0,
|
|
8780
|
+
const legacyPath = (0, import_node_path76.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
|
|
8085
8781
|
await removeFile(recommendedPath);
|
|
8086
8782
|
await removeFile(legacyPath);
|
|
8087
|
-
const relativePathFromCwd = (0,
|
|
8783
|
+
const relativePathFromCwd = (0, import_node_path76.join)(
|
|
8088
8784
|
paths.recommended.relativeDirPath,
|
|
8089
8785
|
paths.recommended.relativeFilePath
|
|
8090
8786
|
);
|
|
@@ -8098,11 +8794,11 @@ async function deleteMcpFile() {
|
|
|
8098
8794
|
}
|
|
8099
8795
|
}
|
|
8100
8796
|
var mcpToolSchemas = {
|
|
8101
|
-
getMcpFile:
|
|
8102
|
-
putMcpFile:
|
|
8103
|
-
content:
|
|
8797
|
+
getMcpFile: import_mini30.z.object({}),
|
|
8798
|
+
putMcpFile: import_mini30.z.object({
|
|
8799
|
+
content: import_mini30.z.string()
|
|
8104
8800
|
}),
|
|
8105
|
-
deleteMcpFile:
|
|
8801
|
+
deleteMcpFile: import_mini30.z.object({})
|
|
8106
8802
|
};
|
|
8107
8803
|
var mcpTools = {
|
|
8108
8804
|
getMcpFile: {
|
|
@@ -8135,12 +8831,12 @@ var mcpTools = {
|
|
|
8135
8831
|
};
|
|
8136
8832
|
|
|
8137
8833
|
// src/mcp/rules.ts
|
|
8138
|
-
var
|
|
8139
|
-
var
|
|
8834
|
+
var import_node_path77 = require("path");
|
|
8835
|
+
var import_mini31 = require("zod/mini");
|
|
8140
8836
|
var maxRuleSizeBytes = 1024 * 1024;
|
|
8141
8837
|
var maxRulesCount = 1e3;
|
|
8142
8838
|
async function listRules() {
|
|
8143
|
-
const rulesDir = (0,
|
|
8839
|
+
const rulesDir = (0, import_node_path77.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
8144
8840
|
try {
|
|
8145
8841
|
const files = await listDirectoryFiles(rulesDir);
|
|
8146
8842
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -8153,7 +8849,7 @@ async function listRules() {
|
|
|
8153
8849
|
});
|
|
8154
8850
|
const frontmatter = rule.getFrontmatter();
|
|
8155
8851
|
return {
|
|
8156
|
-
relativePathFromCwd: (0,
|
|
8852
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
|
|
8157
8853
|
frontmatter
|
|
8158
8854
|
};
|
|
8159
8855
|
} catch (error) {
|
|
@@ -8173,14 +8869,14 @@ async function getRule({ relativePathFromCwd }) {
|
|
|
8173
8869
|
relativePath: relativePathFromCwd,
|
|
8174
8870
|
intendedRootDir: process.cwd()
|
|
8175
8871
|
});
|
|
8176
|
-
const filename = (0,
|
|
8872
|
+
const filename = (0, import_node_path77.basename)(relativePathFromCwd);
|
|
8177
8873
|
try {
|
|
8178
8874
|
const rule = await RulesyncRule.fromFile({
|
|
8179
8875
|
relativeFilePath: filename,
|
|
8180
8876
|
validate: true
|
|
8181
8877
|
});
|
|
8182
8878
|
return {
|
|
8183
|
-
relativePathFromCwd: (0,
|
|
8879
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
8184
8880
|
frontmatter: rule.getFrontmatter(),
|
|
8185
8881
|
body: rule.getBody()
|
|
8186
8882
|
};
|
|
@@ -8199,7 +8895,7 @@ async function putRule({
|
|
|
8199
8895
|
relativePath: relativePathFromCwd,
|
|
8200
8896
|
intendedRootDir: process.cwd()
|
|
8201
8897
|
});
|
|
8202
|
-
const filename = (0,
|
|
8898
|
+
const filename = (0, import_node_path77.basename)(relativePathFromCwd);
|
|
8203
8899
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
8204
8900
|
if (estimatedSize > maxRuleSizeBytes) {
|
|
8205
8901
|
throw new Error(
|
|
@@ -8209,7 +8905,7 @@ async function putRule({
|
|
|
8209
8905
|
try {
|
|
8210
8906
|
const existingRules = await listRules();
|
|
8211
8907
|
const isUpdate = existingRules.some(
|
|
8212
|
-
(rule2) => rule2.relativePathFromCwd === (0,
|
|
8908
|
+
(rule2) => rule2.relativePathFromCwd === (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
8213
8909
|
);
|
|
8214
8910
|
if (!isUpdate && existingRules.length >= maxRulesCount) {
|
|
8215
8911
|
throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
|
|
@@ -8222,11 +8918,11 @@ async function putRule({
|
|
|
8222
8918
|
body,
|
|
8223
8919
|
validate: true
|
|
8224
8920
|
});
|
|
8225
|
-
const rulesDir = (0,
|
|
8921
|
+
const rulesDir = (0, import_node_path77.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
8226
8922
|
await ensureDir(rulesDir);
|
|
8227
8923
|
await writeFileContent(rule.getFilePath(), rule.getFileContent());
|
|
8228
8924
|
return {
|
|
8229
|
-
relativePathFromCwd: (0,
|
|
8925
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
8230
8926
|
frontmatter: rule.getFrontmatter(),
|
|
8231
8927
|
body: rule.getBody()
|
|
8232
8928
|
};
|
|
@@ -8241,12 +8937,12 @@ async function deleteRule({ relativePathFromCwd }) {
|
|
|
8241
8937
|
relativePath: relativePathFromCwd,
|
|
8242
8938
|
intendedRootDir: process.cwd()
|
|
8243
8939
|
});
|
|
8244
|
-
const filename = (0,
|
|
8245
|
-
const fullPath = (0,
|
|
8940
|
+
const filename = (0, import_node_path77.basename)(relativePathFromCwd);
|
|
8941
|
+
const fullPath = (0, import_node_path77.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
|
|
8246
8942
|
try {
|
|
8247
8943
|
await removeFile(fullPath);
|
|
8248
8944
|
return {
|
|
8249
|
-
relativePathFromCwd: (0,
|
|
8945
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
8250
8946
|
};
|
|
8251
8947
|
} catch (error) {
|
|
8252
8948
|
throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -8255,23 +8951,23 @@ async function deleteRule({ relativePathFromCwd }) {
|
|
|
8255
8951
|
}
|
|
8256
8952
|
}
|
|
8257
8953
|
var ruleToolSchemas = {
|
|
8258
|
-
listRules:
|
|
8259
|
-
getRule:
|
|
8260
|
-
relativePathFromCwd:
|
|
8954
|
+
listRules: import_mini31.z.object({}),
|
|
8955
|
+
getRule: import_mini31.z.object({
|
|
8956
|
+
relativePathFromCwd: import_mini31.z.string()
|
|
8261
8957
|
}),
|
|
8262
|
-
putRule:
|
|
8263
|
-
relativePathFromCwd:
|
|
8958
|
+
putRule: import_mini31.z.object({
|
|
8959
|
+
relativePathFromCwd: import_mini31.z.string(),
|
|
8264
8960
|
frontmatter: RulesyncRuleFrontmatterSchema,
|
|
8265
|
-
body:
|
|
8961
|
+
body: import_mini31.z.string()
|
|
8266
8962
|
}),
|
|
8267
|
-
deleteRule:
|
|
8268
|
-
relativePathFromCwd:
|
|
8963
|
+
deleteRule: import_mini31.z.object({
|
|
8964
|
+
relativePathFromCwd: import_mini31.z.string()
|
|
8269
8965
|
})
|
|
8270
8966
|
};
|
|
8271
8967
|
var ruleTools = {
|
|
8272
8968
|
listRules: {
|
|
8273
8969
|
name: "listRules",
|
|
8274
|
-
description: `List all rules from ${(0,
|
|
8970
|
+
description: `List all rules from ${(0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
8275
8971
|
parameters: ruleToolSchemas.listRules,
|
|
8276
8972
|
execute: async () => {
|
|
8277
8973
|
const rules = await listRules();
|
|
@@ -8313,12 +9009,12 @@ var ruleTools = {
|
|
|
8313
9009
|
};
|
|
8314
9010
|
|
|
8315
9011
|
// src/mcp/subagents.ts
|
|
8316
|
-
var
|
|
8317
|
-
var
|
|
9012
|
+
var import_node_path78 = require("path");
|
|
9013
|
+
var import_mini32 = require("zod/mini");
|
|
8318
9014
|
var maxSubagentSizeBytes = 1024 * 1024;
|
|
8319
9015
|
var maxSubagentsCount = 1e3;
|
|
8320
9016
|
async function listSubagents() {
|
|
8321
|
-
const subagentsDir = (0,
|
|
9017
|
+
const subagentsDir = (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
8322
9018
|
try {
|
|
8323
9019
|
const files = await listDirectoryFiles(subagentsDir);
|
|
8324
9020
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -8331,7 +9027,7 @@ async function listSubagents() {
|
|
|
8331
9027
|
});
|
|
8332
9028
|
const frontmatter = subagent.getFrontmatter();
|
|
8333
9029
|
return {
|
|
8334
|
-
relativePathFromCwd: (0,
|
|
9030
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
|
|
8335
9031
|
frontmatter
|
|
8336
9032
|
};
|
|
8337
9033
|
} catch (error) {
|
|
@@ -8353,14 +9049,14 @@ async function getSubagent({ relativePathFromCwd }) {
|
|
|
8353
9049
|
relativePath: relativePathFromCwd,
|
|
8354
9050
|
intendedRootDir: process.cwd()
|
|
8355
9051
|
});
|
|
8356
|
-
const filename = (0,
|
|
9052
|
+
const filename = (0, import_node_path78.basename)(relativePathFromCwd);
|
|
8357
9053
|
try {
|
|
8358
9054
|
const subagent = await RulesyncSubagent.fromFile({
|
|
8359
9055
|
relativeFilePath: filename,
|
|
8360
9056
|
validate: true
|
|
8361
9057
|
});
|
|
8362
9058
|
return {
|
|
8363
|
-
relativePathFromCwd: (0,
|
|
9059
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
8364
9060
|
frontmatter: subagent.getFrontmatter(),
|
|
8365
9061
|
body: subagent.getBody()
|
|
8366
9062
|
};
|
|
@@ -8379,7 +9075,7 @@ async function putSubagent({
|
|
|
8379
9075
|
relativePath: relativePathFromCwd,
|
|
8380
9076
|
intendedRootDir: process.cwd()
|
|
8381
9077
|
});
|
|
8382
|
-
const filename = (0,
|
|
9078
|
+
const filename = (0, import_node_path78.basename)(relativePathFromCwd);
|
|
8383
9079
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
8384
9080
|
if (estimatedSize > maxSubagentSizeBytes) {
|
|
8385
9081
|
throw new Error(
|
|
@@ -8389,7 +9085,7 @@ async function putSubagent({
|
|
|
8389
9085
|
try {
|
|
8390
9086
|
const existingSubagents = await listSubagents();
|
|
8391
9087
|
const isUpdate = existingSubagents.some(
|
|
8392
|
-
(subagent2) => subagent2.relativePathFromCwd === (0,
|
|
9088
|
+
(subagent2) => subagent2.relativePathFromCwd === (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
8393
9089
|
);
|
|
8394
9090
|
if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
|
|
8395
9091
|
throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
|
|
@@ -8402,11 +9098,11 @@ async function putSubagent({
|
|
|
8402
9098
|
body,
|
|
8403
9099
|
validate: true
|
|
8404
9100
|
});
|
|
8405
|
-
const subagentsDir = (0,
|
|
9101
|
+
const subagentsDir = (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
8406
9102
|
await ensureDir(subagentsDir);
|
|
8407
9103
|
await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
|
|
8408
9104
|
return {
|
|
8409
|
-
relativePathFromCwd: (0,
|
|
9105
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
8410
9106
|
frontmatter: subagent.getFrontmatter(),
|
|
8411
9107
|
body: subagent.getBody()
|
|
8412
9108
|
};
|
|
@@ -8421,12 +9117,12 @@ async function deleteSubagent({ relativePathFromCwd }) {
|
|
|
8421
9117
|
relativePath: relativePathFromCwd,
|
|
8422
9118
|
intendedRootDir: process.cwd()
|
|
8423
9119
|
});
|
|
8424
|
-
const filename = (0,
|
|
8425
|
-
const fullPath = (0,
|
|
9120
|
+
const filename = (0, import_node_path78.basename)(relativePathFromCwd);
|
|
9121
|
+
const fullPath = (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
|
|
8426
9122
|
try {
|
|
8427
9123
|
await removeFile(fullPath);
|
|
8428
9124
|
return {
|
|
8429
|
-
relativePathFromCwd: (0,
|
|
9125
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
8430
9126
|
};
|
|
8431
9127
|
} catch (error) {
|
|
8432
9128
|
throw new Error(
|
|
@@ -8438,23 +9134,23 @@ async function deleteSubagent({ relativePathFromCwd }) {
|
|
|
8438
9134
|
}
|
|
8439
9135
|
}
|
|
8440
9136
|
var subagentToolSchemas = {
|
|
8441
|
-
listSubagents:
|
|
8442
|
-
getSubagent:
|
|
8443
|
-
relativePathFromCwd:
|
|
9137
|
+
listSubagents: import_mini32.z.object({}),
|
|
9138
|
+
getSubagent: import_mini32.z.object({
|
|
9139
|
+
relativePathFromCwd: import_mini32.z.string()
|
|
8444
9140
|
}),
|
|
8445
|
-
putSubagent:
|
|
8446
|
-
relativePathFromCwd:
|
|
9141
|
+
putSubagent: import_mini32.z.object({
|
|
9142
|
+
relativePathFromCwd: import_mini32.z.string(),
|
|
8447
9143
|
frontmatter: RulesyncSubagentFrontmatterSchema,
|
|
8448
|
-
body:
|
|
9144
|
+
body: import_mini32.z.string()
|
|
8449
9145
|
}),
|
|
8450
|
-
deleteSubagent:
|
|
8451
|
-
relativePathFromCwd:
|
|
9146
|
+
deleteSubagent: import_mini32.z.object({
|
|
9147
|
+
relativePathFromCwd: import_mini32.z.string()
|
|
8452
9148
|
})
|
|
8453
9149
|
};
|
|
8454
9150
|
var subagentTools = {
|
|
8455
9151
|
listSubagents: {
|
|
8456
9152
|
name: "listSubagents",
|
|
8457
|
-
description: `List all subagents from ${(0,
|
|
9153
|
+
description: `List all subagents from ${(0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
|
|
8458
9154
|
parameters: subagentToolSchemas.listSubagents,
|
|
8459
9155
|
execute: async () => {
|
|
8460
9156
|
const subagents = await listSubagents();
|
|
@@ -8528,7 +9224,7 @@ async function mcpCommand({ version }) {
|
|
|
8528
9224
|
}
|
|
8529
9225
|
|
|
8530
9226
|
// src/cli/index.ts
|
|
8531
|
-
var getVersion = () => "3.
|
|
9227
|
+
var getVersion = () => "3.24.0";
|
|
8532
9228
|
var main = async () => {
|
|
8533
9229
|
const program = new import_commander.Command();
|
|
8534
9230
|
const version = getVersion();
|