rulesync 11.0.0 → 13.0.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/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as removeFile, A as CLAUDECODE_SKILLS_DIR_PATH, At as RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH, B as ErrorCodes, C as RulesyncHooks, Ct as RULESYNC_PERMISSIONS_FILE_NAME, D as CLAUDECODE_LOCAL_RULE_FILE_NAME, Dt as RULESYNC_RELATIVE_DIR_PATH, E as CLAUDECODE_DIR, Et as RULESYNC_PERMISSIONS_SCHEMA_URL, F as ConfigResolver, G as fileExists, H as createTempDirectory, I as findControlCharacter, J as getHomeDirectory, K as findFilesByGlobs, L as ConsoleLogger, M as RulesyncCommandFrontmatterSchema, Mt as formatError, N as stringifyFrontmatter, Nt as ALL_FEATURES, O as CLAUDECODE_MEMORIES_DIR_NAME, Ot as RULESYNC_RULES_RELATIVE_DIR_PATH, P as loadYaml, Pt as ALL_FEATURES_WITH_WILDCARD, Q as removeDirectory, R as JsonLogger, S as HooksProcessor, St as RULESYNC_OVERVIEW_FILE_NAME, T as CODEXCLI_DIR, Tt as RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH, U as directoryExists, V as checkPathTraversal, W as ensureDir, X as listDirectoryFiles, Y as isSymlink, Z as readFileContent, _ as RulesyncPermissions, _t as RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH, a as convertFromTool, at as ToolTargetSchema, b as IgnoreProcessor, bt as RULESYNC_MCP_RELATIVE_FILE_PATH, c as RulesyncRuleFrontmatterSchema, ct as RULESYNC_AIIGNORE_RELATIVE_FILE_PATH, d as RulesyncSubagentFrontmatterSchema, dt as RULESYNC_CONFIG_SCHEMA_URL, et as removeTempDirectory, f as SkillsProcessor, ft as RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH, g as SKILL_FILE_NAME$1, gt as RULESYNC_IGNORE_RELATIVE_FILE_PATH, h as RulesyncSkillFrontmatterSchema, ht as RULESYNC_HOOKS_RELATIVE_FILE_PATH, i as getProcessorRegistryEntry, it as ALL_TOOL_TARGETS_WITH_WILDCARD, j as RulesyncCommand, jt as RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, k as CLAUDECODE_SETTINGS_LOCAL_FILE_NAME, kt as RULESYNC_SKILLS_RELATIVE_DIR_PATH, l as SubagentsProcessor, lt as RULESYNC_COMMANDS_RELATIVE_DIR_PATH, m as RulesyncSkill, mt as RULESYNC_HOOKS_JSONC_FILE_NAME, n as checkRulesyncDirExists, nt as writeFileContent, o as RulesProcessor, ot as MAX_FILE_SIZE, p as getLocalSkillDirNames, pt as RULESYNC_HOOKS_FILE_NAME, q as getFileSize, r as generate, rt as ALL_TOOL_TARGETS, s as RulesyncRule, st as RULESYNC_AIIGNORE_FILE_NAME, t as importFromTool, tt as toPosixPath, u as RulesyncSubagent, ut as RULESYNC_CONFIG_RELATIVE_FILE_PATH, v as McpProcessor, vt as RULESYNC_MCP_FILE_NAME, w as CommandsProcessor, wt as RULESYNC_PERMISSIONS_JSONC_FILE_NAME, x as RulesyncIgnore, xt as RULESYNC_MCP_SCHEMA_URL, y as RulesyncMcp, yt as RULESYNC_MCP_JSONC_FILE_NAME, z as CLIError } from "../import-AKytnIKl.js";
2
+ import { $ as isSymlink, A as CLAUDECODE_SETTINGS_LOCAL_FILE_NAME, At as RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH, B as findControlCharacter, C as CommandsProcessor, Ct as RULESYNC_MCP_FILE_NAME, D as CLAUDECODE_DIR, Dt as RULESYNC_OVERVIEW_FILE_NAME, E as CODEXCLI_DIR, Et as RULESYNC_MCP_SCHEMA_URL, F as RulesyncCheck, Ft as RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH, G as checkPathTraversal, H as JsonLogger, I as RulesyncCheckFrontmatterSchema, It as RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, J as ensureDir, K as createTempDirectory, L as stringifyFrontmatter, Lt as formatError, M as RulesyncCommand, Mt as RULESYNC_RELATIVE_DIR_PATH, N as RulesyncCommandFrontmatterSchema, Nt as RULESYNC_RULES_RELATIVE_DIR_PATH, O as CLAUDECODE_LOCAL_RULE_FILE_NAME, Ot as RULESYNC_PERMISSIONS_FILE_NAME, P as ChecksProcessor, Pt as RULESYNC_SKILLS_RELATIVE_DIR_PATH, Q as getHomeDirectory, R as loadYaml, Rt as ALL_FEATURES, S as RulesyncHooks, St as RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH, T as CODEXCLI_BASH_RULES_FILE_NAME, Tt as RULESYNC_MCP_RELATIVE_FILE_PATH, U as CLIError, V as ConsoleLogger, W as ErrorCodes, X as findFilesByGlobs, Y as fileExists, Z as getFileSize, _ as McpProcessor, _t as RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH, a as convertFromTool, at as toPosixPath, b as RulesyncIgnore, bt as RULESYNC_HOOKS_RELATIVE_FILE_PATH, c as RulesyncRuleFrontmatterSchema, ct as ALL_TOOL_TARGETS_WITH_WILDCARD, d as RulesyncSubagentFrontmatterSchema, dt as RULESYNC_AIIGNORE_FILE_NAME, et as listDirectoryFiles, f as SkillsProcessor, ft as RULESYNC_AIIGNORE_RELATIVE_FILE_PATH, g as RulesyncPermissions, gt as RULESYNC_CONFIG_SCHEMA_URL, h as RulesyncSkillFrontmatterSchema, ht as RULESYNC_CONFIG_RELATIVE_FILE_PATH, i as getProcessorRegistryEntry, it as removeTempDirectory, j as CLAUDECODE_SKILLS_DIR_PATH, jt as RULESYNC_PERMISSIONS_SCHEMA_URL, k as CLAUDECODE_MEMORIES_DIR_NAME, kt as RULESYNC_PERMISSIONS_JSONC_FILE_NAME, l as SubagentsProcessor, lt as ToolTargetSchema, m as RulesyncSkill, mt as RULESYNC_COMMANDS_RELATIVE_DIR_PATH, n as checkRulesyncDirExists, nt as removeDirectory, o as RulesProcessor, ot as writeFileContent, p as getLocalSkillDirNames, pt as RULESYNC_CHECKS_RELATIVE_DIR_PATH, q as directoryExists, r as generate, rt as removeFile, s as RulesyncRule, st as ALL_TOOL_TARGETS, t as importFromTool, tt as readFileContent, u as RulesyncSubagent, ut as MAX_FILE_SIZE, v as RulesyncMcp, vt as RULESYNC_HOOKS_FILE_NAME, w as SKILL_FILE_NAME$1, wt as RULESYNC_MCP_JSONC_FILE_NAME, x as HooksProcessor, xt as RULESYNC_IGNORE_RELATIVE_FILE_PATH, y as IgnoreProcessor, yt as RULESYNC_HOOKS_JSONC_FILE_NAME, z as ConfigResolver, zt as ALL_FEATURES_WITH_WILDCARD } from "../import-CMSHVMqU.js";
3
3
  import { Command } from "commander";
4
4
  import { nonnegative, optional, refine, z } from "zod/mini";
5
5
  import * as path$1 from "node:path";
@@ -7,11 +7,11 @@ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } fr
7
7
  import * as os$1 from "node:os";
8
8
  import { promisify } from "node:util";
9
9
  import { dump } from "js-yaml";
10
+ import * as crypto from "node:crypto";
11
+ import { createHash } from "node:crypto";
10
12
  import { Semaphore } from "es-toolkit/promise";
11
13
  import { RequestError } from "@octokit/request-error";
12
14
  import { Octokit } from "@octokit/rest";
13
- import * as crypto from "node:crypto";
14
- import { createHash } from "node:crypto";
15
15
  import { execFile } from "node:child_process";
16
16
  import { FastMCP } from "fastmcp";
17
17
  import * as fs from "node:fs";
@@ -34,7 +34,7 @@ const parseCommaSeparatedList = (value) => value.split(",").map((s) => s.trim())
34
34
  * Calculate the total count from a result object
35
35
  */
36
36
  function calculateTotalCount(result) {
37
- return result.rulesCount + result.ignoreCount + result.mcpCount + result.commandsCount + result.subagentsCount + result.skillsCount + result.hooksCount + result.permissionsCount;
37
+ return result.rulesCount + result.ignoreCount + result.mcpCount + result.commandsCount + result.subagentsCount + result.skillsCount + result.hooksCount + result.permissionsCount + result.checksCount;
38
38
  }
39
39
  //#endregion
40
40
  //#region src/cli/commands/convert.ts
@@ -80,7 +80,8 @@ async function convertCommand(logger, options) {
80
80
  subagents: { count: result.subagentsCount },
81
81
  skills: { count: result.skillsCount },
82
82
  hooks: { count: result.hooksCount },
83
- permissions: { count: result.permissionsCount }
83
+ permissions: { count: result.permissionsCount },
84
+ checks: { count: result.checksCount }
84
85
  });
85
86
  logger.captureData("totalFiles", totalConverted);
86
87
  }
@@ -93,6 +94,7 @@ async function convertCommand(logger, options) {
93
94
  if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
94
95
  if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);
95
96
  if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);
97
+ if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);
96
98
  const summary = `${modePrefix}${isPreview ? "Would convert" : "Converted"} ${totalConverted} file(s) total from ${fromTool} to ${toTools.join(", ")} (${parts.join(" + ")})`;
97
99
  if (isPreview) logger.info(summary);
98
100
  else logger.success(summary);
@@ -539,6 +541,7 @@ const FEATURE_PATHS = {
539
541
  commands: ["commands"],
540
542
  subagents: ["subagents"],
541
543
  skills: ["skills"],
544
+ checks: ["checks"],
542
545
  ignore: [RULESYNC_AIIGNORE_FILE_NAME],
543
546
  mcp: [RULESYNC_MCP_FILE_NAME, RULESYNC_MCP_JSONC_FILE_NAME],
544
547
  hooks: [RULESYNC_HOOKS_FILE_NAME, RULESYNC_HOOKS_JSONC_FILE_NAME],
@@ -624,6 +627,16 @@ async function convertFetchedFilesToRulesync(params) {
624
627
  logger
625
628
  })
626
629
  },
630
+ {
631
+ feature: "checks",
632
+ getTargets: () => ChecksProcessor.getToolTargets({ global: false }),
633
+ createProcessor: () => new ChecksProcessor({
634
+ outputRoot: tempDir,
635
+ toolTarget: target,
636
+ global: false,
637
+ logger
638
+ })
639
+ },
627
640
  {
628
641
  feature: "ignore",
629
642
  getTargets: () => IgnoreProcessor.getToolTargets(),
@@ -947,6 +960,10 @@ function getToolPathMapping(target) {
947
960
  const factory = SkillsProcessor.getFactory(target);
948
961
  if (factory) mapping.skills = factory.class.getSettablePaths({ global: false }).relativeDirPath;
949
962
  }
963
+ if (ChecksProcessor.getToolTargets({ global: false }).includes(target)) {
964
+ const factory = ChecksProcessor.getFactory(target);
965
+ if (factory) mapping.checks = factory.class.getSettablePaths({ global: false }).relativeDirPath;
966
+ }
950
967
  return mapping;
951
968
  }
952
969
  /**
@@ -970,6 +987,10 @@ function mapToToolPath(relativePath, toolPaths) {
970
987
  const restPath = relativePath.substring(7);
971
988
  if (toolPaths.skills) return join(toolPaths.skills, restPath);
972
989
  }
990
+ if (relativePath.startsWith("checks/")) {
991
+ const restPath = relativePath.substring(7);
992
+ if (toolPaths.checks) return join(toolPaths.checks, restPath);
993
+ }
973
994
  return relativePath;
974
995
  }
975
996
  /**
@@ -1045,6 +1066,7 @@ const FEATURE_DEBUG_MESSAGES = {
1045
1066
  subagents: "Generating subagent files...",
1046
1067
  skills: "Generating skill files...",
1047
1068
  hooks: "Generating hooks...",
1069
+ checks: "Generating check files...",
1048
1070
  rules: "Generating rule files..."
1049
1071
  };
1050
1072
  const FEATURE_DEBUG_ORDER = [
@@ -1054,6 +1076,7 @@ const FEATURE_DEBUG_ORDER = [
1054
1076
  "subagents",
1055
1077
  "skills",
1056
1078
  "hooks",
1079
+ "checks",
1057
1080
  "rules"
1058
1081
  ];
1059
1082
  function logFeatureDebugMessages(logger, features) {
@@ -1097,6 +1120,10 @@ function buildSummaryParts(result) {
1097
1120
  {
1098
1121
  count: result.permissionsCount,
1099
1122
  label: "permissions"
1123
+ },
1124
+ {
1125
+ count: result.checksCount,
1126
+ label: "checks"
1100
1127
  }
1101
1128
  ];
1102
1129
  const parts = [];
@@ -1147,6 +1174,10 @@ async function generateCommand(logger, options) {
1147
1174
  count: result.permissionsCount,
1148
1175
  paths: result.permissionsPaths
1149
1176
  },
1177
+ checks: {
1178
+ count: result.checksCount,
1179
+ paths: result.checksPaths
1180
+ },
1150
1181
  rules: {
1151
1182
  count: result.rulesCount,
1152
1183
  paths: result.rulesPaths
@@ -1160,7 +1191,8 @@ async function generateCommand(logger, options) {
1160
1191
  subagents: (count) => `${count === 1 ? "subagent" : "subagents"}`,
1161
1192
  skills: (count) => `${count === 1 ? "skill" : "skills"}`,
1162
1193
  hooks: (count) => `${count === 1 ? "hooks file" : "hooks files"}`,
1163
- permissions: (count) => `${count === 1 ? "permissions file" : "permissions files"}`
1194
+ permissions: (count) => `${count === 1 ? "permissions file" : "permissions files"}`,
1195
+ checks: (count) => `${count === 1 ? "check" : "checks"}`
1164
1196
  };
1165
1197
  for (const [feature, data] of Object.entries(featureResults)) logFeatureResult(logger, {
1166
1198
  count: data.count,
@@ -1261,13 +1293,16 @@ const deriveRulesEntries = () => {
1261
1293
  for (const root of [paths.root, ...paths.alternativeRoots ?? []]) if (root) pushEntry(entries, target, "rules", fileToGlob(root.relativeDirPath, root.relativeFilePath));
1262
1294
  const nonRootDir = paths.nonRoot?.relativeDirPath;
1263
1295
  if (nonRootDir && nonRootDir !== ".") pushEntry(entries, target, "rules", dirToGlob(nonRootDir));
1296
+ const classWithExtraFiles = factory.class;
1297
+ if (classWithExtraFiles.getExtraFixedFiles) for (const file of classWithExtraFiles.getExtraFixedFiles({ global: false })) pushEntry(entries, target, "rules", fileToGlob(file.relativeDirPath, file.relativeFilePath));
1264
1298
  }
1265
1299
  return entries;
1266
1300
  };
1267
1301
  const DIR_FEATURES = /* @__PURE__ */ new Set([
1268
1302
  "commands",
1269
1303
  "skills",
1270
- "subagents"
1304
+ "subagents",
1305
+ "checks"
1271
1306
  ]);
1272
1307
  const FILE_FEATURES = /* @__PURE__ */ new Set([
1273
1308
  "mcp",
@@ -1290,7 +1325,8 @@ const DERIVED_FEATURES = [
1290
1325
  "mcp",
1291
1326
  "hooks",
1292
1327
  "permissions",
1293
- "ignore"
1328
+ "ignore",
1329
+ "checks"
1294
1330
  ];
1295
1331
  const deriveAllGitignoreEntriesUnfiltered = () => DERIVED_FEATURES.flatMap((feature) => deriveFeatureGitignoreEntries(feature));
1296
1332
  const deriveAllGitignoreEntries = () => deriveAllGitignoreEntriesUnfiltered().filter((tag) => !DERIVED_PATHS_NOT_GITIGNORED.has(tag.entry));
@@ -1381,6 +1417,16 @@ const GITIGNORE_ENTRY_REGISTRY = [
1381
1417
  feature: "rules",
1382
1418
  entry: "**/.augment-guidelines"
1383
1419
  },
1420
+ {
1421
+ target: "devin",
1422
+ feature: "commands",
1423
+ entry: "**/.devin/workflows/"
1424
+ },
1425
+ {
1426
+ target: "junie",
1427
+ feature: "rules",
1428
+ entry: "**/.junie/memories/"
1429
+ },
1384
1430
  {
1385
1431
  target: "rovodev",
1386
1432
  feature: "skills",
@@ -1429,7 +1475,7 @@ const GITIGNORE_ENTRY_REGISTRY = [
1429
1475
  {
1430
1476
  target: "codexcli",
1431
1477
  feature: "permissions",
1432
- entry: `**/${CODEXCLI_DIR}/rules/`
1478
+ entry: `**/${CODEXCLI_DIR}/rules/${CODEXCLI_BASH_RULES_FILE_NAME}`
1433
1479
  }
1434
1480
  ],
1435
1481
  ...deriveAllGitignoreEntries(),
@@ -1738,7 +1784,8 @@ async function importCommand(logger, options) {
1738
1784
  subagents: { count: result.subagentsCount },
1739
1785
  skills: { count: result.skillsCount },
1740
1786
  hooks: { count: result.hooksCount },
1741
- permissions: { count: result.permissionsCount }
1787
+ permissions: { count: result.permissionsCount },
1788
+ checks: { count: result.checksCount }
1742
1789
  });
1743
1790
  logger.captureData("totalFiles", totalImported);
1744
1791
  }
@@ -1751,6 +1798,7 @@ async function importCommand(logger, options) {
1751
1798
  if (result.skillsCount > 0) parts.push(`${result.skillsCount} skills`);
1752
1799
  if (result.hooksCount > 0) parts.push(`${result.hooksCount} hooks`);
1753
1800
  if (result.permissionsCount > 0) parts.push(`${result.permissionsCount} permissions`);
1801
+ if (result.checksCount > 0) parts.push(`${result.checksCount} checks`);
1754
1802
  logger.success(`Imported ${totalImported} file(s) total (${parts.join(" + ")})`);
1755
1803
  }
1756
1804
  //#endregion
@@ -4422,6 +4470,172 @@ async function runGhInstall(logger, options) {
4422
4470
  else logger.success(`All gh sources up to date (${result.sourcesProcessed} checked).`);
4423
4471
  }
4424
4472
  //#endregion
4473
+ //#region src/mcp/checks.ts
4474
+ const logger$4 = new ConsoleLogger({
4475
+ verbose: false,
4476
+ silent: true
4477
+ });
4478
+ const maxCheckSizeBytes = 1024 * 1024;
4479
+ const maxChecksCount = 1e3;
4480
+ /**
4481
+ * Tool to list all checks from .rulesync/checks/*.md
4482
+ */
4483
+ async function listChecks() {
4484
+ const checksDir = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH);
4485
+ try {
4486
+ const mdFiles = (await listDirectoryFiles(checksDir)).filter((file) => file.endsWith(".md"));
4487
+ return (await Promise.all(mdFiles.map(async (file) => {
4488
+ try {
4489
+ const check = await RulesyncCheck.fromFile({
4490
+ relativeFilePath: file,
4491
+ validate: true
4492
+ });
4493
+ return {
4494
+ relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, file),
4495
+ frontmatter: check.getFrontmatter()
4496
+ };
4497
+ } catch (error) {
4498
+ logger$4.error(`Failed to read check file ${file}: ${formatError(error)}`);
4499
+ return null;
4500
+ }
4501
+ }))).filter((check) => check !== null);
4502
+ } catch (error) {
4503
+ logger$4.error(`Failed to read checks directory (${RULESYNC_CHECKS_RELATIVE_DIR_PATH}): ${formatError(error)}`);
4504
+ return [];
4505
+ }
4506
+ }
4507
+ /**
4508
+ * Tool to get detailed information about a specific check
4509
+ */
4510
+ async function getCheck({ relativePathFromCwd }) {
4511
+ checkPathTraversal({
4512
+ relativePath: relativePathFromCwd,
4513
+ intendedRootDir: process.cwd()
4514
+ });
4515
+ const filename = basename(relativePathFromCwd);
4516
+ try {
4517
+ const check = await RulesyncCheck.fromFile({
4518
+ relativeFilePath: filename,
4519
+ validate: true
4520
+ });
4521
+ return {
4522
+ relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),
4523
+ frontmatter: check.getFrontmatter(),
4524
+ body: check.getBody()
4525
+ };
4526
+ } catch (error) {
4527
+ throw new Error(`Failed to read check file ${relativePathFromCwd}: ${formatError(error)}`, { cause: error });
4528
+ }
4529
+ }
4530
+ /**
4531
+ * Tool to create or update a check (upsert operation)
4532
+ */
4533
+ async function putCheck({ relativePathFromCwd, frontmatter, body }) {
4534
+ checkPathTraversal({
4535
+ relativePath: relativePathFromCwd,
4536
+ intendedRootDir: process.cwd()
4537
+ });
4538
+ const filename = basename(relativePathFromCwd);
4539
+ const estimatedSize = JSON.stringify(frontmatter).length + body.length;
4540
+ if (estimatedSize > maxCheckSizeBytes) throw new Error(`Check size ${estimatedSize} bytes exceeds maximum ${maxCheckSizeBytes} bytes (1MB) for ${relativePathFromCwd}`);
4541
+ try {
4542
+ const existingChecks = await listChecks();
4543
+ if (!existingChecks.some((check) => check.relativePathFromCwd === join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename)) && existingChecks.length >= maxChecksCount) throw new Error(`Maximum number of checks (${maxChecksCount}) reached in ${RULESYNC_CHECKS_RELATIVE_DIR_PATH}`);
4544
+ const check = new RulesyncCheck({
4545
+ outputRoot: process.cwd(),
4546
+ relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,
4547
+ relativeFilePath: filename,
4548
+ frontmatter,
4549
+ body,
4550
+ validate: true
4551
+ });
4552
+ await ensureDir(join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH));
4553
+ await writeFileContent(check.getFilePath(), check.getFileContent());
4554
+ return {
4555
+ relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename),
4556
+ frontmatter: check.getFrontmatter(),
4557
+ body: check.getBody()
4558
+ };
4559
+ } catch (error) {
4560
+ throw new Error(`Failed to write check file ${relativePathFromCwd}: ${formatError(error)}`, { cause: error });
4561
+ }
4562
+ }
4563
+ /**
4564
+ * Tool to delete a check
4565
+ */
4566
+ async function deleteCheck({ relativePathFromCwd }) {
4567
+ checkPathTraversal({
4568
+ relativePath: relativePathFromCwd,
4569
+ intendedRootDir: process.cwd()
4570
+ });
4571
+ const filename = basename(relativePathFromCwd);
4572
+ const fullPath = join(process.cwd(), RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename);
4573
+ try {
4574
+ await removeFile(fullPath);
4575
+ return { relativePathFromCwd: join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, filename) };
4576
+ } catch (error) {
4577
+ throw new Error(`Failed to delete check file ${relativePathFromCwd}: ${formatError(error)}`, { cause: error });
4578
+ }
4579
+ }
4580
+ /**
4581
+ * Schema for check-related tool parameters
4582
+ */
4583
+ const checkToolSchemas = {
4584
+ listChecks: z.object({}),
4585
+ getCheck: z.object({ relativePathFromCwd: z.string() }),
4586
+ putCheck: z.object({
4587
+ relativePathFromCwd: z.string(),
4588
+ frontmatter: RulesyncCheckFrontmatterSchema,
4589
+ body: z.string()
4590
+ }),
4591
+ deleteCheck: z.object({ relativePathFromCwd: z.string() })
4592
+ };
4593
+ /**
4594
+ * Tool definitions for check-related operations
4595
+ */
4596
+ const checkTools = {
4597
+ listChecks: {
4598
+ name: "listChecks",
4599
+ description: `List all checks from ${join(RULESYNC_CHECKS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
4600
+ parameters: checkToolSchemas.listChecks,
4601
+ execute: async () => {
4602
+ const output = { checks: await listChecks() };
4603
+ return JSON.stringify(output, null, 2);
4604
+ }
4605
+ },
4606
+ getCheck: {
4607
+ name: "getCheck",
4608
+ description: "Get detailed information about a specific check. relativePathFromCwd parameter is required.",
4609
+ parameters: checkToolSchemas.getCheck,
4610
+ execute: async (args) => {
4611
+ const result = await getCheck({ relativePathFromCwd: args.relativePathFromCwd });
4612
+ return JSON.stringify(result, null, 2);
4613
+ }
4614
+ },
4615
+ putCheck: {
4616
+ name: "putCheck",
4617
+ description: "Create or update a check (upsert operation). relativePathFromCwd, frontmatter, and body parameters are required.",
4618
+ parameters: checkToolSchemas.putCheck,
4619
+ execute: async (args) => {
4620
+ const result = await putCheck({
4621
+ relativePathFromCwd: args.relativePathFromCwd,
4622
+ frontmatter: args.frontmatter,
4623
+ body: args.body
4624
+ });
4625
+ return JSON.stringify(result, null, 2);
4626
+ }
4627
+ },
4628
+ deleteCheck: {
4629
+ name: "deleteCheck",
4630
+ description: "Delete a check file. relativePathFromCwd parameter is required.",
4631
+ parameters: checkToolSchemas.deleteCheck,
4632
+ execute: async (args) => {
4633
+ const result = await deleteCheck({ relativePathFromCwd: args.relativePathFromCwd });
4634
+ return JSON.stringify(result, null, 2);
4635
+ }
4636
+ }
4637
+ };
4638
+ //#endregion
4425
4639
  //#region src/mcp/commands.ts
4426
4640
  const logger$3 = new ConsoleLogger({
4427
4641
  verbose: false,
@@ -4673,6 +4887,7 @@ function buildSuccessResponse$2(params) {
4673
4887
  skillsCount: convertResult.skillsCount,
4674
4888
  hooksCount: convertResult.hooksCount,
4675
4889
  permissionsCount: convertResult.permissionsCount,
4890
+ checksCount: convertResult.checksCount,
4676
4891
  totalCount
4677
4892
  },
4678
4893
  config: {
@@ -4783,6 +4998,7 @@ function buildSuccessResponse$1(params) {
4783
4998
  skillsCount: generateResult.skillsCount,
4784
4999
  hooksCount: generateResult.hooksCount,
4785
5000
  permissionsCount: generateResult.permissionsCount,
5001
+ checksCount: generateResult.checksCount,
4786
5002
  totalCount
4787
5003
  },
4788
5004
  config: {
@@ -5068,6 +5284,7 @@ function buildSuccessResponse(params) {
5068
5284
  skillsCount: importResult.skillsCount,
5069
5285
  hooksCount: importResult.hooksCount,
5070
5286
  permissionsCount: importResult.permissionsCount,
5287
+ checksCount: importResult.checksCount,
5071
5288
  totalCount
5072
5289
  },
5073
5290
  config: {
@@ -5853,6 +6070,7 @@ const rulesyncFeatureSchema = z.enum([
5853
6070
  "command",
5854
6071
  "subagent",
5855
6072
  "skill",
6073
+ "check",
5856
6074
  "ignore",
5857
6075
  "mcp",
5858
6076
  "permissions",
@@ -5909,6 +6127,12 @@ const supportedOperationsByFeature = {
5909
6127
  "put",
5910
6128
  "delete"
5911
6129
  ],
6130
+ check: [
6131
+ "list",
6132
+ "get",
6133
+ "put",
6134
+ "delete"
6135
+ ],
5912
6136
  ignore: [
5913
6137
  "get",
5914
6138
  "put",
@@ -5947,6 +6171,7 @@ function parseFrontmatter({ feature, frontmatter }) {
5947
6171
  case "command": return RulesyncCommandFrontmatterSchema.parse(frontmatter);
5948
6172
  case "subagent": return RulesyncSubagentFrontmatterSchema.parse(frontmatter);
5949
6173
  case "skill": return RulesyncSkillFrontmatterSchema.parse(frontmatter);
6174
+ case "check": return RulesyncCheckFrontmatterSchema.parse(frontmatter);
5950
6175
  }
5951
6176
  }
5952
6177
  function ensureBody({ body, feature, operation }) {
@@ -6010,6 +6235,19 @@ function executeSkill(parsed) {
6010
6235
  });
6011
6236
  return skillTools.deleteSkill.execute({ relativeDirPathFromCwd: requireTargetPath(parsed) });
6012
6237
  }
6238
+ function executeCheck(parsed) {
6239
+ if (parsed.operation === "list") return checkTools.listChecks.execute();
6240
+ if (parsed.operation === "get") return checkTools.getCheck.execute({ relativePathFromCwd: requireTargetPath(parsed) });
6241
+ if (parsed.operation === "put") return checkTools.putCheck.execute({
6242
+ relativePathFromCwd: requireTargetPath(parsed),
6243
+ frontmatter: parseFrontmatter({
6244
+ feature: "check",
6245
+ frontmatter: parsed.frontmatter ?? {}
6246
+ }),
6247
+ body: ensureBody(parsed)
6248
+ });
6249
+ return checkTools.deleteCheck.execute({ relativePathFromCwd: requireTargetPath(parsed) });
6250
+ }
6013
6251
  function executeIgnore(parsed) {
6014
6252
  if (parsed.operation === "get") return ignoreTools.getIgnoreFile.execute();
6015
6253
  if (parsed.operation === "put") return ignoreTools.putIgnoreFile.execute({ content: requireContent({
@@ -6058,6 +6296,7 @@ const featureExecutors = {
6058
6296
  command: executeCommand,
6059
6297
  subagent: executeSubagent,
6060
6298
  skill: executeSkill,
6299
+ check: executeCheck,
6061
6300
  ignore: executeIgnore,
6062
6301
  mcp: executeMcp,
6063
6302
  permissions: executePermissions,
@@ -6068,7 +6307,7 @@ const featureExecutors = {
6068
6307
  };
6069
6308
  const rulesyncTool = {
6070
6309
  name: "rulesyncTool",
6071
- description: "Manage Rulesync files through a single MCP tool. Features: rule/command/subagent/skill support list/get/put/delete; ignore/mcp/permissions/hooks support get/put/delete only; generate supports run only; import supports run only; convert supports run only. Parameters: list requires no targetPathFromCwd (lists all items); get/delete require targetPathFromCwd; put requires targetPathFromCwd, frontmatter, and body (or content for ignore/mcp/permissions/hooks); generate/run uses generateOptions to configure generation; import/run uses importOptions to configure import; convert/run uses convertOptions to configure conversion.",
6310
+ description: "Manage Rulesync files through a single MCP tool. Features: rule/command/subagent/skill/check support list/get/put/delete; ignore/mcp/permissions/hooks support get/put/delete only; generate supports run only; import supports run only; convert supports run only. Parameters: list requires no targetPathFromCwd (lists all items); get/delete require targetPathFromCwd; put requires targetPathFromCwd, frontmatter, and body (or content for ignore/mcp/permissions/hooks); generate/run uses generateOptions to configure generation; import/run uses importOptions to configure import; convert/run uses convertOptions to configure conversion.",
6072
6311
  parameters: rulesyncToolSchema,
6073
6312
  execute: async (args) => {
6074
6313
  const parsed = rulesyncToolSchema.parse(args);
@@ -6554,7 +6793,7 @@ function wrapCommand$1({ name, errorCode, handler, getVersion, loggerFactory = c
6554
6793
  }
6555
6794
  //#endregion
6556
6795
  //#region src/cli/index.ts
6557
- const getVersion = () => "11.0.0";
6796
+ const getVersion = () => "13.0.0";
6558
6797
  function wrapCommand(name, errorCode, handler) {
6559
6798
  return wrapCommand$1({
6560
6799
  name,