rulesync 3.23.6 → 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 +802 -112
- package/dist/index.js +802 -112
- 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:
|
|
@@ -4570,7 +4595,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
|
|
|
4570
4595
|
fromFile
|
|
4571
4596
|
}) {
|
|
4572
4597
|
const paths = await findFilesByGlobs((0, import_node_path46.join)(this.baseDir, relativeDirPath, "*.md"));
|
|
4573
|
-
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);
|
|
4574
4599
|
logger.info(`Successfully loaded ${subagents.length} ${relativeDirPath} subagents`);
|
|
4575
4600
|
return subagents;
|
|
4576
4601
|
}
|
|
@@ -7092,6 +7117,614 @@ For example, if the user instructs \`Call planner subagent to plan the refactori
|
|
|
7092
7117
|
}
|
|
7093
7118
|
};
|
|
7094
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
|
+
|
|
7095
7728
|
// src/cli/commands/generate.ts
|
|
7096
7729
|
async function generateCommand(options) {
|
|
7097
7730
|
const config = await ConfigResolver.resolve(options);
|
|
@@ -7107,7 +7740,8 @@ async function generateCommand(options) {
|
|
|
7107
7740
|
const totalMcpOutputs = await generateMcp(config);
|
|
7108
7741
|
const totalCommandOutputs = await generateCommands(config);
|
|
7109
7742
|
const totalSubagentOutputs = await generateSubagents(config);
|
|
7110
|
-
const
|
|
7743
|
+
const totalSkillOutputs = await generateSkills(config);
|
|
7744
|
+
const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs + totalSkillOutputs;
|
|
7111
7745
|
if (totalGenerated === 0) {
|
|
7112
7746
|
const enabledFeatures = config.getFeatures().join(", ");
|
|
7113
7747
|
logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
|
|
@@ -7120,6 +7754,7 @@ async function generateCommand(options) {
|
|
|
7120
7754
|
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
|
|
7121
7755
|
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
7122
7756
|
if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
|
|
7757
|
+
if (totalSkillOutputs > 0) parts.push(`${totalSkillOutputs} skills`);
|
|
7123
7758
|
logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
|
|
7124
7759
|
}
|
|
7125
7760
|
}
|
|
@@ -7294,11 +7929,39 @@ async function generateSubagents(config) {
|
|
|
7294
7929
|
}
|
|
7295
7930
|
return totalSubagentOutputs;
|
|
7296
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
|
+
}
|
|
7297
7960
|
|
|
7298
7961
|
// src/cli/commands/gitignore.ts
|
|
7299
|
-
var
|
|
7962
|
+
var import_node_path72 = require("path");
|
|
7300
7963
|
var gitignoreCommand = async () => {
|
|
7301
|
-
const gitignorePath = (0,
|
|
7964
|
+
const gitignorePath = (0, import_node_path72.join)(process.cwd(), ".gitignore");
|
|
7302
7965
|
const rulesFilesToIgnore = [
|
|
7303
7966
|
"# Generated by rulesync - AI tool configuration files",
|
|
7304
7967
|
// AGENTS.md
|
|
@@ -7315,6 +7978,7 @@ var gitignoreCommand = async () => {
|
|
|
7315
7978
|
"**/.claude/memories/",
|
|
7316
7979
|
"**/.claude/commands/",
|
|
7317
7980
|
"**/.claude/agents/",
|
|
7981
|
+
"**/.claude/skills/",
|
|
7318
7982
|
"**/.claude/settings.local.json",
|
|
7319
7983
|
"**/.mcp.json",
|
|
7320
7984
|
// Cline
|
|
@@ -7408,6 +8072,7 @@ async function importCommand(options) {
|
|
|
7408
8072
|
await importMcp(config, tool);
|
|
7409
8073
|
await importCommands(config, tool);
|
|
7410
8074
|
await importSubagents(config, tool);
|
|
8075
|
+
await importSkills(config, tool);
|
|
7411
8076
|
}
|
|
7412
8077
|
async function importRules(config, tool) {
|
|
7413
8078
|
if (!config.getFeatures().includes("rules")) {
|
|
@@ -7537,9 +8202,34 @@ async function importSubagents(config, tool) {
|
|
|
7537
8202
|
}
|
|
7538
8203
|
return writtenCount;
|
|
7539
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
|
+
}
|
|
7540
8230
|
|
|
7541
8231
|
// src/cli/commands/init.ts
|
|
7542
|
-
var
|
|
8232
|
+
var import_node_path73 = require("path");
|
|
7543
8233
|
async function initCommand() {
|
|
7544
8234
|
logger.info("Initializing rulesync...");
|
|
7545
8235
|
await ensureDir(RULESYNC_RELATIVE_DIR_PATH);
|
|
@@ -7702,14 +8392,14 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7702
8392
|
await ensureDir(commandPaths.relativeDirPath);
|
|
7703
8393
|
await ensureDir(subagentPaths.relativeDirPath);
|
|
7704
8394
|
await ensureDir(ignorePaths.relativeDirPath);
|
|
7705
|
-
const ruleFilepath = (0,
|
|
8395
|
+
const ruleFilepath = (0, import_node_path73.join)(rulePaths.recommended.relativeDirPath, sampleRuleFile.filename);
|
|
7706
8396
|
if (!await fileExists(ruleFilepath)) {
|
|
7707
8397
|
await writeFileContent(ruleFilepath, sampleRuleFile.content);
|
|
7708
8398
|
logger.success(`Created ${ruleFilepath}`);
|
|
7709
8399
|
} else {
|
|
7710
8400
|
logger.info(`Skipped ${ruleFilepath} (already exists)`);
|
|
7711
8401
|
}
|
|
7712
|
-
const mcpFilepath = (0,
|
|
8402
|
+
const mcpFilepath = (0, import_node_path73.join)(
|
|
7713
8403
|
mcpPaths.recommended.relativeDirPath,
|
|
7714
8404
|
mcpPaths.recommended.relativeFilePath
|
|
7715
8405
|
);
|
|
@@ -7719,21 +8409,21 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7719
8409
|
} else {
|
|
7720
8410
|
logger.info(`Skipped ${mcpFilepath} (already exists)`);
|
|
7721
8411
|
}
|
|
7722
|
-
const commandFilepath = (0,
|
|
8412
|
+
const commandFilepath = (0, import_node_path73.join)(commandPaths.relativeDirPath, sampleCommandFile.filename);
|
|
7723
8413
|
if (!await fileExists(commandFilepath)) {
|
|
7724
8414
|
await writeFileContent(commandFilepath, sampleCommandFile.content);
|
|
7725
8415
|
logger.success(`Created ${commandFilepath}`);
|
|
7726
8416
|
} else {
|
|
7727
8417
|
logger.info(`Skipped ${commandFilepath} (already exists)`);
|
|
7728
8418
|
}
|
|
7729
|
-
const subagentFilepath = (0,
|
|
8419
|
+
const subagentFilepath = (0, import_node_path73.join)(subagentPaths.relativeDirPath, sampleSubagentFile.filename);
|
|
7730
8420
|
if (!await fileExists(subagentFilepath)) {
|
|
7731
8421
|
await writeFileContent(subagentFilepath, sampleSubagentFile.content);
|
|
7732
8422
|
logger.success(`Created ${subagentFilepath}`);
|
|
7733
8423
|
} else {
|
|
7734
8424
|
logger.info(`Skipped ${subagentFilepath} (already exists)`);
|
|
7735
8425
|
}
|
|
7736
|
-
const ignoreFilepath = (0,
|
|
8426
|
+
const ignoreFilepath = (0, import_node_path73.join)(ignorePaths.relativeDirPath, ignorePaths.relativeFilePath);
|
|
7737
8427
|
if (!await fileExists(ignoreFilepath)) {
|
|
7738
8428
|
await writeFileContent(ignoreFilepath, sampleIgnoreFile.content);
|
|
7739
8429
|
logger.success(`Created ${ignoreFilepath}`);
|
|
@@ -7746,12 +8436,12 @@ Attention, again, you are just the planner, so though you can read any files and
|
|
|
7746
8436
|
var import_fastmcp = require("fastmcp");
|
|
7747
8437
|
|
|
7748
8438
|
// src/mcp/commands.ts
|
|
7749
|
-
var
|
|
7750
|
-
var
|
|
8439
|
+
var import_node_path74 = require("path");
|
|
8440
|
+
var import_mini28 = require("zod/mini");
|
|
7751
8441
|
var maxCommandSizeBytes = 1024 * 1024;
|
|
7752
8442
|
var maxCommandsCount = 1e3;
|
|
7753
8443
|
async function listCommands() {
|
|
7754
|
-
const commandsDir = (0,
|
|
8444
|
+
const commandsDir = (0, import_node_path74.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
7755
8445
|
try {
|
|
7756
8446
|
const files = await listDirectoryFiles(commandsDir);
|
|
7757
8447
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -7763,7 +8453,7 @@ async function listCommands() {
|
|
|
7763
8453
|
});
|
|
7764
8454
|
const frontmatter = command.getFrontmatter();
|
|
7765
8455
|
return {
|
|
7766
|
-
relativePathFromCwd: (0,
|
|
8456
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
|
|
7767
8457
|
frontmatter
|
|
7768
8458
|
};
|
|
7769
8459
|
} catch (error) {
|
|
@@ -7783,13 +8473,13 @@ async function getCommand({ relativePathFromCwd }) {
|
|
|
7783
8473
|
relativePath: relativePathFromCwd,
|
|
7784
8474
|
intendedRootDir: process.cwd()
|
|
7785
8475
|
});
|
|
7786
|
-
const filename = (0,
|
|
8476
|
+
const filename = (0, import_node_path74.basename)(relativePathFromCwd);
|
|
7787
8477
|
try {
|
|
7788
8478
|
const command = await RulesyncCommand.fromFile({
|
|
7789
8479
|
relativeFilePath: filename
|
|
7790
8480
|
});
|
|
7791
8481
|
return {
|
|
7792
|
-
relativePathFromCwd: (0,
|
|
8482
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
7793
8483
|
frontmatter: command.getFrontmatter(),
|
|
7794
8484
|
body: command.getBody()
|
|
7795
8485
|
};
|
|
@@ -7808,7 +8498,7 @@ async function putCommand({
|
|
|
7808
8498
|
relativePath: relativePathFromCwd,
|
|
7809
8499
|
intendedRootDir: process.cwd()
|
|
7810
8500
|
});
|
|
7811
|
-
const filename = (0,
|
|
8501
|
+
const filename = (0, import_node_path74.basename)(relativePathFromCwd);
|
|
7812
8502
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
7813
8503
|
if (estimatedSize > maxCommandSizeBytes) {
|
|
7814
8504
|
throw new Error(
|
|
@@ -7818,7 +8508,7 @@ async function putCommand({
|
|
|
7818
8508
|
try {
|
|
7819
8509
|
const existingCommands = await listCommands();
|
|
7820
8510
|
const isUpdate = existingCommands.some(
|
|
7821
|
-
(command2) => command2.relativePathFromCwd === (0,
|
|
8511
|
+
(command2) => command2.relativePathFromCwd === (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
7822
8512
|
);
|
|
7823
8513
|
if (!isUpdate && existingCommands.length >= maxCommandsCount) {
|
|
7824
8514
|
throw new Error(`Maximum number of commands (${maxCommandsCount}) reached`);
|
|
@@ -7833,11 +8523,11 @@ async function putCommand({
|
|
|
7833
8523
|
fileContent,
|
|
7834
8524
|
validate: true
|
|
7835
8525
|
});
|
|
7836
|
-
const commandsDir = (0,
|
|
8526
|
+
const commandsDir = (0, import_node_path74.join)(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
|
|
7837
8527
|
await ensureDir(commandsDir);
|
|
7838
8528
|
await writeFileContent(command.getFilePath(), command.getFileContent());
|
|
7839
8529
|
return {
|
|
7840
|
-
relativePathFromCwd: (0,
|
|
8530
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
|
|
7841
8531
|
frontmatter: command.getFrontmatter(),
|
|
7842
8532
|
body: command.getBody()
|
|
7843
8533
|
};
|
|
@@ -7852,12 +8542,12 @@ async function deleteCommand({ relativePathFromCwd }) {
|
|
|
7852
8542
|
relativePath: relativePathFromCwd,
|
|
7853
8543
|
intendedRootDir: process.cwd()
|
|
7854
8544
|
});
|
|
7855
|
-
const filename = (0,
|
|
7856
|
-
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);
|
|
7857
8547
|
try {
|
|
7858
8548
|
await removeFile(fullPath);
|
|
7859
8549
|
return {
|
|
7860
|
-
relativePathFromCwd: (0,
|
|
8550
|
+
relativePathFromCwd: (0, import_node_path74.join)(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
|
|
7861
8551
|
};
|
|
7862
8552
|
} catch (error) {
|
|
7863
8553
|
throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -7866,23 +8556,23 @@ async function deleteCommand({ relativePathFromCwd }) {
|
|
|
7866
8556
|
}
|
|
7867
8557
|
}
|
|
7868
8558
|
var commandToolSchemas = {
|
|
7869
|
-
listCommands:
|
|
7870
|
-
getCommand:
|
|
7871
|
-
relativePathFromCwd:
|
|
8559
|
+
listCommands: import_mini28.z.object({}),
|
|
8560
|
+
getCommand: import_mini28.z.object({
|
|
8561
|
+
relativePathFromCwd: import_mini28.z.string()
|
|
7872
8562
|
}),
|
|
7873
|
-
putCommand:
|
|
7874
|
-
relativePathFromCwd:
|
|
8563
|
+
putCommand: import_mini28.z.object({
|
|
8564
|
+
relativePathFromCwd: import_mini28.z.string(),
|
|
7875
8565
|
frontmatter: RulesyncCommandFrontmatterSchema,
|
|
7876
|
-
body:
|
|
8566
|
+
body: import_mini28.z.string()
|
|
7877
8567
|
}),
|
|
7878
|
-
deleteCommand:
|
|
7879
|
-
relativePathFromCwd:
|
|
8568
|
+
deleteCommand: import_mini28.z.object({
|
|
8569
|
+
relativePathFromCwd: import_mini28.z.string()
|
|
7880
8570
|
})
|
|
7881
8571
|
};
|
|
7882
8572
|
var commandTools = {
|
|
7883
8573
|
listCommands: {
|
|
7884
8574
|
name: "listCommands",
|
|
7885
|
-
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.`,
|
|
7886
8576
|
parameters: commandToolSchemas.listCommands,
|
|
7887
8577
|
execute: async () => {
|
|
7888
8578
|
const commands = await listCommands();
|
|
@@ -7924,11 +8614,11 @@ var commandTools = {
|
|
|
7924
8614
|
};
|
|
7925
8615
|
|
|
7926
8616
|
// src/mcp/ignore.ts
|
|
7927
|
-
var
|
|
7928
|
-
var
|
|
8617
|
+
var import_node_path75 = require("path");
|
|
8618
|
+
var import_mini29 = require("zod/mini");
|
|
7929
8619
|
var maxIgnoreFileSizeBytes = 100 * 1024;
|
|
7930
8620
|
async function getIgnoreFile() {
|
|
7931
|
-
const ignoreFilePath = (0,
|
|
8621
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7932
8622
|
try {
|
|
7933
8623
|
const content = await readFileContent(ignoreFilePath);
|
|
7934
8624
|
return {
|
|
@@ -7942,7 +8632,7 @@ async function getIgnoreFile() {
|
|
|
7942
8632
|
}
|
|
7943
8633
|
}
|
|
7944
8634
|
async function putIgnoreFile({ content }) {
|
|
7945
|
-
const ignoreFilePath = (0,
|
|
8635
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7946
8636
|
const contentSizeBytes = Buffer.byteLength(content, "utf8");
|
|
7947
8637
|
if (contentSizeBytes > maxIgnoreFileSizeBytes) {
|
|
7948
8638
|
throw new Error(
|
|
@@ -7963,7 +8653,7 @@ async function putIgnoreFile({ content }) {
|
|
|
7963
8653
|
}
|
|
7964
8654
|
}
|
|
7965
8655
|
async function deleteIgnoreFile() {
|
|
7966
|
-
const ignoreFilePath = (0,
|
|
8656
|
+
const ignoreFilePath = (0, import_node_path75.join)(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
|
|
7967
8657
|
try {
|
|
7968
8658
|
await removeFile(ignoreFilePath);
|
|
7969
8659
|
return {
|
|
@@ -7976,11 +8666,11 @@ async function deleteIgnoreFile() {
|
|
|
7976
8666
|
}
|
|
7977
8667
|
}
|
|
7978
8668
|
var ignoreToolSchemas = {
|
|
7979
|
-
getIgnoreFile:
|
|
7980
|
-
putIgnoreFile:
|
|
7981
|
-
content:
|
|
8669
|
+
getIgnoreFile: import_mini29.z.object({}),
|
|
8670
|
+
putIgnoreFile: import_mini29.z.object({
|
|
8671
|
+
content: import_mini29.z.string()
|
|
7982
8672
|
}),
|
|
7983
|
-
deleteIgnoreFile:
|
|
8673
|
+
deleteIgnoreFile: import_mini29.z.object({})
|
|
7984
8674
|
};
|
|
7985
8675
|
var ignoreTools = {
|
|
7986
8676
|
getIgnoreFile: {
|
|
@@ -8013,8 +8703,8 @@ var ignoreTools = {
|
|
|
8013
8703
|
};
|
|
8014
8704
|
|
|
8015
8705
|
// src/mcp/mcp.ts
|
|
8016
|
-
var
|
|
8017
|
-
var
|
|
8706
|
+
var import_node_path76 = require("path");
|
|
8707
|
+
var import_mini30 = require("zod/mini");
|
|
8018
8708
|
var maxMcpSizeBytes = 1024 * 1024;
|
|
8019
8709
|
async function getMcpFile() {
|
|
8020
8710
|
const config = await ConfigResolver.resolve({});
|
|
@@ -8023,7 +8713,7 @@ async function getMcpFile() {
|
|
|
8023
8713
|
validate: true,
|
|
8024
8714
|
modularMcp: config.getModularMcp()
|
|
8025
8715
|
});
|
|
8026
|
-
const relativePathFromCwd = (0,
|
|
8716
|
+
const relativePathFromCwd = (0, import_node_path76.join)(
|
|
8027
8717
|
rulesyncMcp.getRelativeDirPath(),
|
|
8028
8718
|
rulesyncMcp.getRelativeFilePath()
|
|
8029
8719
|
);
|
|
@@ -8056,7 +8746,7 @@ async function putMcpFile({ content }) {
|
|
|
8056
8746
|
const paths = RulesyncMcp.getSettablePaths();
|
|
8057
8747
|
const relativeDirPath = paths.recommended.relativeDirPath;
|
|
8058
8748
|
const relativeFilePath = paths.recommended.relativeFilePath;
|
|
8059
|
-
const fullPath = (0,
|
|
8749
|
+
const fullPath = (0, import_node_path76.join)(baseDir, relativeDirPath, relativeFilePath);
|
|
8060
8750
|
const rulesyncMcp = new RulesyncMcp({
|
|
8061
8751
|
baseDir,
|
|
8062
8752
|
relativeDirPath,
|
|
@@ -8065,9 +8755,9 @@ async function putMcpFile({ content }) {
|
|
|
8065
8755
|
validate: true,
|
|
8066
8756
|
modularMcp: config.getModularMcp()
|
|
8067
8757
|
});
|
|
8068
|
-
await ensureDir((0,
|
|
8758
|
+
await ensureDir((0, import_node_path76.join)(baseDir, relativeDirPath));
|
|
8069
8759
|
await writeFileContent(fullPath, content);
|
|
8070
|
-
const relativePathFromCwd = (0,
|
|
8760
|
+
const relativePathFromCwd = (0, import_node_path76.join)(relativeDirPath, relativeFilePath);
|
|
8071
8761
|
return {
|
|
8072
8762
|
relativePathFromCwd,
|
|
8073
8763
|
content: rulesyncMcp.getFileContent()
|
|
@@ -8082,15 +8772,15 @@ async function deleteMcpFile() {
|
|
|
8082
8772
|
try {
|
|
8083
8773
|
const baseDir = process.cwd();
|
|
8084
8774
|
const paths = RulesyncMcp.getSettablePaths();
|
|
8085
|
-
const recommendedPath = (0,
|
|
8775
|
+
const recommendedPath = (0, import_node_path76.join)(
|
|
8086
8776
|
baseDir,
|
|
8087
8777
|
paths.recommended.relativeDirPath,
|
|
8088
8778
|
paths.recommended.relativeFilePath
|
|
8089
8779
|
);
|
|
8090
|
-
const legacyPath = (0,
|
|
8780
|
+
const legacyPath = (0, import_node_path76.join)(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
|
|
8091
8781
|
await removeFile(recommendedPath);
|
|
8092
8782
|
await removeFile(legacyPath);
|
|
8093
|
-
const relativePathFromCwd = (0,
|
|
8783
|
+
const relativePathFromCwd = (0, import_node_path76.join)(
|
|
8094
8784
|
paths.recommended.relativeDirPath,
|
|
8095
8785
|
paths.recommended.relativeFilePath
|
|
8096
8786
|
);
|
|
@@ -8104,11 +8794,11 @@ async function deleteMcpFile() {
|
|
|
8104
8794
|
}
|
|
8105
8795
|
}
|
|
8106
8796
|
var mcpToolSchemas = {
|
|
8107
|
-
getMcpFile:
|
|
8108
|
-
putMcpFile:
|
|
8109
|
-
content:
|
|
8797
|
+
getMcpFile: import_mini30.z.object({}),
|
|
8798
|
+
putMcpFile: import_mini30.z.object({
|
|
8799
|
+
content: import_mini30.z.string()
|
|
8110
8800
|
}),
|
|
8111
|
-
deleteMcpFile:
|
|
8801
|
+
deleteMcpFile: import_mini30.z.object({})
|
|
8112
8802
|
};
|
|
8113
8803
|
var mcpTools = {
|
|
8114
8804
|
getMcpFile: {
|
|
@@ -8141,12 +8831,12 @@ var mcpTools = {
|
|
|
8141
8831
|
};
|
|
8142
8832
|
|
|
8143
8833
|
// src/mcp/rules.ts
|
|
8144
|
-
var
|
|
8145
|
-
var
|
|
8834
|
+
var import_node_path77 = require("path");
|
|
8835
|
+
var import_mini31 = require("zod/mini");
|
|
8146
8836
|
var maxRuleSizeBytes = 1024 * 1024;
|
|
8147
8837
|
var maxRulesCount = 1e3;
|
|
8148
8838
|
async function listRules() {
|
|
8149
|
-
const rulesDir = (0,
|
|
8839
|
+
const rulesDir = (0, import_node_path77.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
8150
8840
|
try {
|
|
8151
8841
|
const files = await listDirectoryFiles(rulesDir);
|
|
8152
8842
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -8159,7 +8849,7 @@ async function listRules() {
|
|
|
8159
8849
|
});
|
|
8160
8850
|
const frontmatter = rule.getFrontmatter();
|
|
8161
8851
|
return {
|
|
8162
|
-
relativePathFromCwd: (0,
|
|
8852
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
|
|
8163
8853
|
frontmatter
|
|
8164
8854
|
};
|
|
8165
8855
|
} catch (error) {
|
|
@@ -8179,14 +8869,14 @@ async function getRule({ relativePathFromCwd }) {
|
|
|
8179
8869
|
relativePath: relativePathFromCwd,
|
|
8180
8870
|
intendedRootDir: process.cwd()
|
|
8181
8871
|
});
|
|
8182
|
-
const filename = (0,
|
|
8872
|
+
const filename = (0, import_node_path77.basename)(relativePathFromCwd);
|
|
8183
8873
|
try {
|
|
8184
8874
|
const rule = await RulesyncRule.fromFile({
|
|
8185
8875
|
relativeFilePath: filename,
|
|
8186
8876
|
validate: true
|
|
8187
8877
|
});
|
|
8188
8878
|
return {
|
|
8189
|
-
relativePathFromCwd: (0,
|
|
8879
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
8190
8880
|
frontmatter: rule.getFrontmatter(),
|
|
8191
8881
|
body: rule.getBody()
|
|
8192
8882
|
};
|
|
@@ -8205,7 +8895,7 @@ async function putRule({
|
|
|
8205
8895
|
relativePath: relativePathFromCwd,
|
|
8206
8896
|
intendedRootDir: process.cwd()
|
|
8207
8897
|
});
|
|
8208
|
-
const filename = (0,
|
|
8898
|
+
const filename = (0, import_node_path77.basename)(relativePathFromCwd);
|
|
8209
8899
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
8210
8900
|
if (estimatedSize > maxRuleSizeBytes) {
|
|
8211
8901
|
throw new Error(
|
|
@@ -8215,7 +8905,7 @@ async function putRule({
|
|
|
8215
8905
|
try {
|
|
8216
8906
|
const existingRules = await listRules();
|
|
8217
8907
|
const isUpdate = existingRules.some(
|
|
8218
|
-
(rule2) => rule2.relativePathFromCwd === (0,
|
|
8908
|
+
(rule2) => rule2.relativePathFromCwd === (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
8219
8909
|
);
|
|
8220
8910
|
if (!isUpdate && existingRules.length >= maxRulesCount) {
|
|
8221
8911
|
throw new Error(`Maximum number of rules (${maxRulesCount}) reached`);
|
|
@@ -8228,11 +8918,11 @@ async function putRule({
|
|
|
8228
8918
|
body,
|
|
8229
8919
|
validate: true
|
|
8230
8920
|
});
|
|
8231
|
-
const rulesDir = (0,
|
|
8921
|
+
const rulesDir = (0, import_node_path77.join)(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
|
|
8232
8922
|
await ensureDir(rulesDir);
|
|
8233
8923
|
await writeFileContent(rule.getFilePath(), rule.getFileContent());
|
|
8234
8924
|
return {
|
|
8235
|
-
relativePathFromCwd: (0,
|
|
8925
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
|
|
8236
8926
|
frontmatter: rule.getFrontmatter(),
|
|
8237
8927
|
body: rule.getBody()
|
|
8238
8928
|
};
|
|
@@ -8247,12 +8937,12 @@ async function deleteRule({ relativePathFromCwd }) {
|
|
|
8247
8937
|
relativePath: relativePathFromCwd,
|
|
8248
8938
|
intendedRootDir: process.cwd()
|
|
8249
8939
|
});
|
|
8250
|
-
const filename = (0,
|
|
8251
|
-
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);
|
|
8252
8942
|
try {
|
|
8253
8943
|
await removeFile(fullPath);
|
|
8254
8944
|
return {
|
|
8255
|
-
relativePathFromCwd: (0,
|
|
8945
|
+
relativePathFromCwd: (0, import_node_path77.join)(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
|
|
8256
8946
|
};
|
|
8257
8947
|
} catch (error) {
|
|
8258
8948
|
throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
|
|
@@ -8261,23 +8951,23 @@ async function deleteRule({ relativePathFromCwd }) {
|
|
|
8261
8951
|
}
|
|
8262
8952
|
}
|
|
8263
8953
|
var ruleToolSchemas = {
|
|
8264
|
-
listRules:
|
|
8265
|
-
getRule:
|
|
8266
|
-
relativePathFromCwd:
|
|
8954
|
+
listRules: import_mini31.z.object({}),
|
|
8955
|
+
getRule: import_mini31.z.object({
|
|
8956
|
+
relativePathFromCwd: import_mini31.z.string()
|
|
8267
8957
|
}),
|
|
8268
|
-
putRule:
|
|
8269
|
-
relativePathFromCwd:
|
|
8958
|
+
putRule: import_mini31.z.object({
|
|
8959
|
+
relativePathFromCwd: import_mini31.z.string(),
|
|
8270
8960
|
frontmatter: RulesyncRuleFrontmatterSchema,
|
|
8271
|
-
body:
|
|
8961
|
+
body: import_mini31.z.string()
|
|
8272
8962
|
}),
|
|
8273
|
-
deleteRule:
|
|
8274
|
-
relativePathFromCwd:
|
|
8963
|
+
deleteRule: import_mini31.z.object({
|
|
8964
|
+
relativePathFromCwd: import_mini31.z.string()
|
|
8275
8965
|
})
|
|
8276
8966
|
};
|
|
8277
8967
|
var ruleTools = {
|
|
8278
8968
|
listRules: {
|
|
8279
8969
|
name: "listRules",
|
|
8280
|
-
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.`,
|
|
8281
8971
|
parameters: ruleToolSchemas.listRules,
|
|
8282
8972
|
execute: async () => {
|
|
8283
8973
|
const rules = await listRules();
|
|
@@ -8319,12 +9009,12 @@ var ruleTools = {
|
|
|
8319
9009
|
};
|
|
8320
9010
|
|
|
8321
9011
|
// src/mcp/subagents.ts
|
|
8322
|
-
var
|
|
8323
|
-
var
|
|
9012
|
+
var import_node_path78 = require("path");
|
|
9013
|
+
var import_mini32 = require("zod/mini");
|
|
8324
9014
|
var maxSubagentSizeBytes = 1024 * 1024;
|
|
8325
9015
|
var maxSubagentsCount = 1e3;
|
|
8326
9016
|
async function listSubagents() {
|
|
8327
|
-
const subagentsDir = (0,
|
|
9017
|
+
const subagentsDir = (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
8328
9018
|
try {
|
|
8329
9019
|
const files = await listDirectoryFiles(subagentsDir);
|
|
8330
9020
|
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
@@ -8337,7 +9027,7 @@ async function listSubagents() {
|
|
|
8337
9027
|
});
|
|
8338
9028
|
const frontmatter = subagent.getFrontmatter();
|
|
8339
9029
|
return {
|
|
8340
|
-
relativePathFromCwd: (0,
|
|
9030
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
|
|
8341
9031
|
frontmatter
|
|
8342
9032
|
};
|
|
8343
9033
|
} catch (error) {
|
|
@@ -8359,14 +9049,14 @@ async function getSubagent({ relativePathFromCwd }) {
|
|
|
8359
9049
|
relativePath: relativePathFromCwd,
|
|
8360
9050
|
intendedRootDir: process.cwd()
|
|
8361
9051
|
});
|
|
8362
|
-
const filename = (0,
|
|
9052
|
+
const filename = (0, import_node_path78.basename)(relativePathFromCwd);
|
|
8363
9053
|
try {
|
|
8364
9054
|
const subagent = await RulesyncSubagent.fromFile({
|
|
8365
9055
|
relativeFilePath: filename,
|
|
8366
9056
|
validate: true
|
|
8367
9057
|
});
|
|
8368
9058
|
return {
|
|
8369
|
-
relativePathFromCwd: (0,
|
|
9059
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
8370
9060
|
frontmatter: subagent.getFrontmatter(),
|
|
8371
9061
|
body: subagent.getBody()
|
|
8372
9062
|
};
|
|
@@ -8385,7 +9075,7 @@ async function putSubagent({
|
|
|
8385
9075
|
relativePath: relativePathFromCwd,
|
|
8386
9076
|
intendedRootDir: process.cwd()
|
|
8387
9077
|
});
|
|
8388
|
-
const filename = (0,
|
|
9078
|
+
const filename = (0, import_node_path78.basename)(relativePathFromCwd);
|
|
8389
9079
|
const estimatedSize = JSON.stringify(frontmatter).length + body.length;
|
|
8390
9080
|
if (estimatedSize > maxSubagentSizeBytes) {
|
|
8391
9081
|
throw new Error(
|
|
@@ -8395,7 +9085,7 @@ async function putSubagent({
|
|
|
8395
9085
|
try {
|
|
8396
9086
|
const existingSubagents = await listSubagents();
|
|
8397
9087
|
const isUpdate = existingSubagents.some(
|
|
8398
|
-
(subagent2) => subagent2.relativePathFromCwd === (0,
|
|
9088
|
+
(subagent2) => subagent2.relativePathFromCwd === (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
8399
9089
|
);
|
|
8400
9090
|
if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
|
|
8401
9091
|
throw new Error(`Maximum number of subagents (${maxSubagentsCount}) reached`);
|
|
@@ -8408,11 +9098,11 @@ async function putSubagent({
|
|
|
8408
9098
|
body,
|
|
8409
9099
|
validate: true
|
|
8410
9100
|
});
|
|
8411
|
-
const subagentsDir = (0,
|
|
9101
|
+
const subagentsDir = (0, import_node_path78.join)(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
|
|
8412
9102
|
await ensureDir(subagentsDir);
|
|
8413
9103
|
await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
|
|
8414
9104
|
return {
|
|
8415
|
-
relativePathFromCwd: (0,
|
|
9105
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
|
|
8416
9106
|
frontmatter: subagent.getFrontmatter(),
|
|
8417
9107
|
body: subagent.getBody()
|
|
8418
9108
|
};
|
|
@@ -8427,12 +9117,12 @@ async function deleteSubagent({ relativePathFromCwd }) {
|
|
|
8427
9117
|
relativePath: relativePathFromCwd,
|
|
8428
9118
|
intendedRootDir: process.cwd()
|
|
8429
9119
|
});
|
|
8430
|
-
const filename = (0,
|
|
8431
|
-
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);
|
|
8432
9122
|
try {
|
|
8433
9123
|
await removeFile(fullPath);
|
|
8434
9124
|
return {
|
|
8435
|
-
relativePathFromCwd: (0,
|
|
9125
|
+
relativePathFromCwd: (0, import_node_path78.join)(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
|
|
8436
9126
|
};
|
|
8437
9127
|
} catch (error) {
|
|
8438
9128
|
throw new Error(
|
|
@@ -8444,23 +9134,23 @@ async function deleteSubagent({ relativePathFromCwd }) {
|
|
|
8444
9134
|
}
|
|
8445
9135
|
}
|
|
8446
9136
|
var subagentToolSchemas = {
|
|
8447
|
-
listSubagents:
|
|
8448
|
-
getSubagent:
|
|
8449
|
-
relativePathFromCwd:
|
|
9137
|
+
listSubagents: import_mini32.z.object({}),
|
|
9138
|
+
getSubagent: import_mini32.z.object({
|
|
9139
|
+
relativePathFromCwd: import_mini32.z.string()
|
|
8450
9140
|
}),
|
|
8451
|
-
putSubagent:
|
|
8452
|
-
relativePathFromCwd:
|
|
9141
|
+
putSubagent: import_mini32.z.object({
|
|
9142
|
+
relativePathFromCwd: import_mini32.z.string(),
|
|
8453
9143
|
frontmatter: RulesyncSubagentFrontmatterSchema,
|
|
8454
|
-
body:
|
|
9144
|
+
body: import_mini32.z.string()
|
|
8455
9145
|
}),
|
|
8456
|
-
deleteSubagent:
|
|
8457
|
-
relativePathFromCwd:
|
|
9146
|
+
deleteSubagent: import_mini32.z.object({
|
|
9147
|
+
relativePathFromCwd: import_mini32.z.string()
|
|
8458
9148
|
})
|
|
8459
9149
|
};
|
|
8460
9150
|
var subagentTools = {
|
|
8461
9151
|
listSubagents: {
|
|
8462
9152
|
name: "listSubagents",
|
|
8463
|
-
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.`,
|
|
8464
9154
|
parameters: subagentToolSchemas.listSubagents,
|
|
8465
9155
|
execute: async () => {
|
|
8466
9156
|
const subagents = await listSubagents();
|
|
@@ -8534,7 +9224,7 @@ async function mcpCommand({ version }) {
|
|
|
8534
9224
|
}
|
|
8535
9225
|
|
|
8536
9226
|
// src/cli/index.ts
|
|
8537
|
-
var getVersion = () => "3.
|
|
9227
|
+
var getVersion = () => "3.24.0";
|
|
8538
9228
|
var main = async () => {
|
|
8539
9229
|
const program = new import_commander.Command();
|
|
8540
9230
|
const version = getVersion();
|