rulesync 7.13.0 → 7.15.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
@@ -50,8 +50,10 @@ import {
50
50
  findFilesByGlobs,
51
51
  formatError,
52
52
  generate,
53
+ getFileSize,
53
54
  getLocalSkillDirNames,
54
55
  importFromTool,
56
+ isSymlink,
55
57
  listDirectoryFiles,
56
58
  logger,
57
59
  readFileContent,
@@ -60,7 +62,7 @@ import {
60
62
  removeTempDirectory,
61
63
  stringifyFrontmatter,
62
64
  writeFileContent
63
- } from "../chunk-JGRHJWG5.js";
65
+ } from "../chunk-L5AQUWUM.js";
64
66
 
65
67
  // src/cli/index.ts
66
68
  import { Command } from "commander";
@@ -1205,6 +1207,8 @@ var RULESYNC_IGNORE_ENTRIES = [
1205
1207
  // Junie
1206
1208
  "**/.junie/guidelines.md",
1207
1209
  "**/.junie/mcp.json",
1210
+ "**/.junie/skills/",
1211
+ "**/.junie/agents/",
1208
1212
  // Kilo Code
1209
1213
  "**/.kilocode/rules/",
1210
1214
  "**/.kilocode/skills/",
@@ -1609,12 +1613,175 @@ async function initCommand() {
1609
1613
  }
1610
1614
 
1611
1615
  // src/lib/sources.ts
1612
- import { join as join5, resolve, sep } from "path";
1616
+ import { join as join6, resolve, sep } from "path";
1613
1617
  import { Semaphore as Semaphore2 } from "es-toolkit/promise";
1614
1618
 
1619
+ // src/lib/git-client.ts
1620
+ import { execFile } from "child_process";
1621
+ import { join as join4 } from "path";
1622
+ import { promisify } from "util";
1623
+ var execFileAsync = promisify(execFile);
1624
+ var GIT_TIMEOUT_MS = 6e4;
1625
+ var ALLOWED_URL_SCHEMES = /^(https?:\/\/|ssh:\/\/|git:\/\/|file:\/\/\/|[a-zA-Z0-9_.+-]+@[a-zA-Z0-9.-]+:[a-zA-Z0-9_.+/~-]+)/;
1626
+ var INSECURE_URL_SCHEMES = /^(git:\/\/|http:\/\/)/;
1627
+ function findControlCharacter(value) {
1628
+ for (let i = 0; i < value.length; i++) {
1629
+ const code = value.charCodeAt(i);
1630
+ if (code >= 0 && code <= 31 || code === 127) {
1631
+ return { position: i, hex: `0x${code.toString(16).padStart(2, "0")}` };
1632
+ }
1633
+ }
1634
+ return null;
1635
+ }
1636
+ var GitClientError = class extends Error {
1637
+ constructor(message, cause) {
1638
+ super(message, { cause });
1639
+ this.name = "GitClientError";
1640
+ }
1641
+ };
1642
+ function validateGitUrl(url) {
1643
+ const ctrl = findControlCharacter(url);
1644
+ if (ctrl) {
1645
+ throw new GitClientError(
1646
+ `Git URL contains control character ${ctrl.hex} at position ${ctrl.position}`
1647
+ );
1648
+ }
1649
+ if (!ALLOWED_URL_SCHEMES.test(url)) {
1650
+ throw new GitClientError(
1651
+ `Unsupported or unsafe git URL: "${url}". Use https, ssh, git, or file schemes.`
1652
+ );
1653
+ }
1654
+ if (INSECURE_URL_SCHEMES.test(url)) {
1655
+ logger.warn(
1656
+ `URL "${url}" uses an unencrypted protocol. Consider using https:// or ssh:// instead.`
1657
+ );
1658
+ }
1659
+ }
1660
+ function validateRef(ref) {
1661
+ if (ref.startsWith("-")) {
1662
+ throw new GitClientError(`Ref must not start with "-": "${ref}"`);
1663
+ }
1664
+ const ctrl = findControlCharacter(ref);
1665
+ if (ctrl) {
1666
+ throw new GitClientError(
1667
+ `Ref contains control character ${ctrl.hex} at position ${ctrl.position}`
1668
+ );
1669
+ }
1670
+ }
1671
+ var gitChecked = false;
1672
+ async function checkGitAvailable() {
1673
+ if (gitChecked) return;
1674
+ try {
1675
+ await execFileAsync("git", ["--version"], { timeout: GIT_TIMEOUT_MS });
1676
+ gitChecked = true;
1677
+ } catch {
1678
+ throw new GitClientError("git is not installed or not found in PATH");
1679
+ }
1680
+ }
1681
+ async function resolveDefaultRef(url) {
1682
+ validateGitUrl(url);
1683
+ await checkGitAvailable();
1684
+ try {
1685
+ const { stdout } = await execFileAsync("git", ["ls-remote", "--symref", "--", url, "HEAD"], {
1686
+ timeout: GIT_TIMEOUT_MS
1687
+ });
1688
+ const ref = stdout.match(/^ref: refs\/heads\/(.+)\tHEAD$/m)?.[1];
1689
+ const sha = stdout.match(/^([0-9a-f]{40})\tHEAD$/m)?.[1];
1690
+ if (!ref || !sha) throw new GitClientError(`Could not parse default branch from: ${url}`);
1691
+ return { ref, sha };
1692
+ } catch (error) {
1693
+ if (error instanceof GitClientError) throw error;
1694
+ throw new GitClientError(`Failed to resolve default ref for ${url}`, error);
1695
+ }
1696
+ }
1697
+ async function resolveRefToSha(url, ref) {
1698
+ validateGitUrl(url);
1699
+ validateRef(ref);
1700
+ await checkGitAvailable();
1701
+ try {
1702
+ const { stdout } = await execFileAsync("git", ["ls-remote", "--", url, ref], {
1703
+ timeout: GIT_TIMEOUT_MS
1704
+ });
1705
+ const sha = stdout.match(/^([0-9a-f]{40})\t/m)?.[1];
1706
+ if (!sha) throw new GitClientError(`Ref "${ref}" not found in ${url}`);
1707
+ return sha;
1708
+ } catch (error) {
1709
+ if (error instanceof GitClientError) throw error;
1710
+ throw new GitClientError(`Failed to resolve ref "${ref}" for ${url}`, error);
1711
+ }
1712
+ }
1713
+ async function fetchSkillFiles(params) {
1714
+ const { url, ref, skillsPath } = params;
1715
+ validateGitUrl(url);
1716
+ validateRef(ref);
1717
+ await checkGitAvailable();
1718
+ const tmpDir = await createTempDirectory("rulesync-git-");
1719
+ try {
1720
+ await execFileAsync(
1721
+ "git",
1722
+ [
1723
+ "clone",
1724
+ "--depth",
1725
+ "1",
1726
+ "--branch",
1727
+ ref,
1728
+ "--no-checkout",
1729
+ "--filter=blob:none",
1730
+ "--",
1731
+ url,
1732
+ tmpDir
1733
+ ],
1734
+ { timeout: GIT_TIMEOUT_MS }
1735
+ );
1736
+ await execFileAsync("git", ["-C", tmpDir, "sparse-checkout", "set", "--", skillsPath], {
1737
+ timeout: GIT_TIMEOUT_MS
1738
+ });
1739
+ await execFileAsync("git", ["-C", tmpDir, "checkout"], { timeout: GIT_TIMEOUT_MS });
1740
+ const skillsDir = join4(tmpDir, skillsPath);
1741
+ if (!await directoryExists(skillsDir)) return [];
1742
+ return await walkDirectory(skillsDir, skillsDir);
1743
+ } catch (error) {
1744
+ if (error instanceof GitClientError) throw error;
1745
+ throw new GitClientError(`Failed to fetch skill files from ${url}`, error);
1746
+ } finally {
1747
+ await removeTempDirectory(tmpDir);
1748
+ }
1749
+ }
1750
+ var MAX_WALK_DEPTH = 20;
1751
+ async function walkDirectory(dir, baseDir, depth = 0) {
1752
+ if (depth > MAX_WALK_DEPTH) {
1753
+ throw new GitClientError(
1754
+ `Directory tree exceeds max depth of ${MAX_WALK_DEPTH}: "${dir}". Aborting to prevent resource exhaustion.`
1755
+ );
1756
+ }
1757
+ const results = [];
1758
+ for (const name of await listDirectoryFiles(dir)) {
1759
+ if (name === ".git") continue;
1760
+ const fullPath = join4(dir, name);
1761
+ if (await isSymlink(fullPath)) {
1762
+ logger.warn(`Skipping symlink "${fullPath}".`);
1763
+ continue;
1764
+ }
1765
+ if (await directoryExists(fullPath)) {
1766
+ results.push(...await walkDirectory(fullPath, baseDir, depth + 1));
1767
+ } else {
1768
+ const size = await getFileSize(fullPath);
1769
+ if (size > MAX_FILE_SIZE) {
1770
+ logger.warn(
1771
+ `Skipping file "${fullPath}" (${(size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`
1772
+ );
1773
+ continue;
1774
+ }
1775
+ const content = await readFileContent(fullPath);
1776
+ results.push({ relativePath: fullPath.substring(baseDir.length + 1), content, size });
1777
+ }
1778
+ }
1779
+ return results;
1780
+ }
1781
+
1615
1782
  // src/lib/sources-lock.ts
1616
1783
  import { createHash } from "crypto";
1617
- import { join as join4 } from "path";
1784
+ import { join as join5 } from "path";
1618
1785
  import { optional, z as z4 } from "zod/mini";
1619
1786
  var LOCKFILE_VERSION = 1;
1620
1787
  var LockedSkillSchema = z4.object({
@@ -1658,7 +1825,7 @@ function createEmptyLock() {
1658
1825
  return { lockfileVersion: LOCKFILE_VERSION, sources: {} };
1659
1826
  }
1660
1827
  async function readLockFile(params) {
1661
- const lockPath = join4(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
1828
+ const lockPath = join5(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
1662
1829
  if (!await fileExists(lockPath)) {
1663
1830
  logger.debug("No sources lockfile found, starting fresh.");
1664
1831
  return createEmptyLock();
@@ -1686,7 +1853,7 @@ async function readLockFile(params) {
1686
1853
  }
1687
1854
  }
1688
1855
  async function writeLockFile(params) {
1689
- const lockPath = join4(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
1856
+ const lockPath = join5(params.baseDir, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH);
1690
1857
  const content = JSON.stringify(params.lock, null, 2) + "\n";
1691
1858
  await writeFileContent(lockPath, content);
1692
1859
  logger.debug(`Wrote sources lockfile to ${lockPath}`);
@@ -1792,15 +1959,30 @@ async function resolveAndFetchSources(params) {
1792
1959
  const allFetchedSkillNames = /* @__PURE__ */ new Set();
1793
1960
  for (const sourceEntry of sources) {
1794
1961
  try {
1795
- const { skillCount, fetchedSkillNames, updatedLock } = await fetchSource({
1796
- sourceEntry,
1797
- client,
1798
- baseDir,
1799
- lock,
1800
- localSkillNames,
1801
- alreadyFetchedSkillNames: allFetchedSkillNames,
1802
- updateSources: options.updateSources ?? false
1803
- });
1962
+ const transport = sourceEntry.transport ?? "github";
1963
+ let result;
1964
+ if (transport === "git") {
1965
+ result = await fetchSourceViaGit({
1966
+ sourceEntry,
1967
+ baseDir,
1968
+ lock,
1969
+ localSkillNames,
1970
+ alreadyFetchedSkillNames: allFetchedSkillNames,
1971
+ updateSources: options.updateSources ?? false,
1972
+ frozen: options.frozen ?? false
1973
+ });
1974
+ } else {
1975
+ result = await fetchSource({
1976
+ sourceEntry,
1977
+ client,
1978
+ baseDir,
1979
+ lock,
1980
+ localSkillNames,
1981
+ alreadyFetchedSkillNames: allFetchedSkillNames,
1982
+ updateSources: options.updateSources ?? false
1983
+ });
1984
+ }
1985
+ const { skillCount, fetchedSkillNames, updatedLock } = result;
1804
1986
  lock = updatedLock;
1805
1987
  totalSkillCount += skillCount;
1806
1988
  for (const name of fetchedSkillNames) {
@@ -1833,7 +2015,7 @@ async function resolveAndFetchSources(params) {
1833
2015
  async function checkLockedSkillsExist(curatedDir, skillNames) {
1834
2016
  if (skillNames.length === 0) return true;
1835
2017
  for (const name of skillNames) {
1836
- if (!await directoryExists(join5(curatedDir, name))) {
2018
+ if (!await directoryExists(join6(curatedDir, name))) {
1837
2019
  return false;
1838
2020
  }
1839
2021
  }
@@ -1864,7 +2046,7 @@ async function fetchSource(params) {
1864
2046
  ref = resolvedSha;
1865
2047
  logger.debug(`Resolved ${sourceKey} ref "${requestedRef}" to SHA: ${resolvedSha}`);
1866
2048
  }
1867
- const curatedDir = join5(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
2049
+ const curatedDir = join6(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
1868
2050
  if (locked && resolvedSha === locked.resolvedRef && !updateSources) {
1869
2051
  const allExist = await checkLockedSkillsExist(curatedDir, lockedSkillNames);
1870
2052
  if (allExist) {
@@ -1896,7 +2078,7 @@ async function fetchSource(params) {
1896
2078
  if (locked) {
1897
2079
  const resolvedCuratedDir = resolve(curatedDir);
1898
2080
  for (const prevSkill of lockedSkillNames) {
1899
- const prevDir = join5(curatedDir, prevSkill);
2081
+ const prevDir = join6(curatedDir, prevSkill);
1900
2082
  if (!resolve(prevDir).startsWith(resolvedCuratedDir + sep)) {
1901
2083
  logger.warn(
1902
2084
  `Skipping removal of "${prevSkill}": resolved path is outside the curated directory.`
@@ -1947,10 +2129,10 @@ async function fetchSource(params) {
1947
2129
  const skillFiles = [];
1948
2130
  for (const file of files) {
1949
2131
  const relativeToSkill = file.path.substring(skillDir.path.length + 1);
1950
- const localFilePath = join5(curatedDir, skillDir.name, relativeToSkill);
2132
+ const localFilePath = join6(curatedDir, skillDir.name, relativeToSkill);
1951
2133
  checkPathTraversal({
1952
2134
  relativePath: relativeToSkill,
1953
- intendedRootDir: join5(curatedDir, skillDir.name)
2135
+ intendedRootDir: join6(curatedDir, skillDir.name)
1954
2136
  });
1955
2137
  const content = await withSemaphore(
1956
2138
  semaphore,
@@ -1993,6 +2175,127 @@ async function fetchSource(params) {
1993
2175
  updatedLock: lock
1994
2176
  };
1995
2177
  }
2178
+ async function fetchSourceViaGit(params) {
2179
+ const { sourceEntry, baseDir, localSkillNames, alreadyFetchedSkillNames, updateSources, frozen } = params;
2180
+ let { lock } = params;
2181
+ const url = sourceEntry.source;
2182
+ const locked = getLockedSource(lock, url);
2183
+ const lockedSkillNames = locked ? getLockedSkillNames(locked) : [];
2184
+ let resolvedSha;
2185
+ let requestedRef;
2186
+ if (locked && !updateSources) {
2187
+ resolvedSha = locked.resolvedRef;
2188
+ requestedRef = locked.requestedRef;
2189
+ if (requestedRef) {
2190
+ validateRef(requestedRef);
2191
+ }
2192
+ } else if (sourceEntry.ref) {
2193
+ requestedRef = sourceEntry.ref;
2194
+ resolvedSha = await resolveRefToSha(url, requestedRef);
2195
+ } else {
2196
+ const def = await resolveDefaultRef(url);
2197
+ requestedRef = def.ref;
2198
+ resolvedSha = def.sha;
2199
+ }
2200
+ const curatedDir = join6(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
2201
+ if (locked && resolvedSha === locked.resolvedRef && !updateSources) {
2202
+ if (await checkLockedSkillsExist(curatedDir, lockedSkillNames)) {
2203
+ return { skillCount: 0, fetchedSkillNames: lockedSkillNames, updatedLock: lock };
2204
+ }
2205
+ }
2206
+ if (!requestedRef) {
2207
+ if (frozen) {
2208
+ throw new Error(
2209
+ `Frozen install failed: lockfile entry for "${url}" is missing requestedRef. Run 'rulesync install' to update the lockfile.`
2210
+ );
2211
+ }
2212
+ const def = await resolveDefaultRef(url);
2213
+ requestedRef = def.ref;
2214
+ resolvedSha = def.sha;
2215
+ }
2216
+ const skillFilter = sourceEntry.skills ?? ["*"];
2217
+ const isWildcard = skillFilter.length === 1 && skillFilter[0] === "*";
2218
+ const remoteFiles = await fetchSkillFiles({
2219
+ url,
2220
+ ref: requestedRef,
2221
+ skillsPath: sourceEntry.path ?? "skills"
2222
+ });
2223
+ const skillFileMap = /* @__PURE__ */ new Map();
2224
+ for (const file of remoteFiles) {
2225
+ const idx = file.relativePath.indexOf("/");
2226
+ if (idx === -1) continue;
2227
+ const name = file.relativePath.substring(0, idx);
2228
+ const inner = file.relativePath.substring(idx + 1);
2229
+ const arr = skillFileMap.get(name) ?? [];
2230
+ arr.push({ relativePath: inner, content: file.content });
2231
+ skillFileMap.set(name, arr);
2232
+ }
2233
+ const allNames = [...skillFileMap.keys()];
2234
+ const filteredNames = isWildcard ? allNames : allNames.filter((n) => skillFilter.includes(n));
2235
+ if (locked) {
2236
+ const base = resolve(curatedDir);
2237
+ for (const prev of lockedSkillNames) {
2238
+ const dir = join6(curatedDir, prev);
2239
+ if (resolve(dir).startsWith(base + sep) && await directoryExists(dir)) {
2240
+ await removeDirectory(dir);
2241
+ }
2242
+ }
2243
+ }
2244
+ const fetchedSkills = {};
2245
+ for (const skillName of filteredNames) {
2246
+ if (skillName.includes("..") || skillName.includes("/") || skillName.includes("\\")) {
2247
+ logger.warn(
2248
+ `Skipping skill with invalid name "${skillName}" from ${url}: contains path traversal characters.`
2249
+ );
2250
+ continue;
2251
+ }
2252
+ if (localSkillNames.has(skillName)) {
2253
+ logger.debug(
2254
+ `Skipping remote skill "${skillName}" from ${url}: local skill takes precedence.`
2255
+ );
2256
+ continue;
2257
+ }
2258
+ if (alreadyFetchedSkillNames.has(skillName)) {
2259
+ logger.warn(
2260
+ `Skipping duplicate skill "${skillName}" from ${url}: already fetched from another source.`
2261
+ );
2262
+ continue;
2263
+ }
2264
+ const files = skillFileMap.get(skillName) ?? [];
2265
+ const written = [];
2266
+ for (const file of files) {
2267
+ checkPathTraversal({
2268
+ relativePath: file.relativePath,
2269
+ intendedRootDir: join6(curatedDir, skillName)
2270
+ });
2271
+ await writeFileContent(join6(curatedDir, skillName, file.relativePath), file.content);
2272
+ written.push({ path: file.relativePath, content: file.content });
2273
+ }
2274
+ const integrity = computeSkillIntegrity(written);
2275
+ const lockedSkillEntry = locked?.skills[skillName];
2276
+ if (lockedSkillEntry?.integrity && lockedSkillEntry.integrity !== integrity && resolvedSha === locked?.resolvedRef) {
2277
+ logger.warn(`Integrity mismatch for skill "${skillName}" from ${url}.`);
2278
+ }
2279
+ fetchedSkills[skillName] = { integrity };
2280
+ }
2281
+ const fetchedNames = Object.keys(fetchedSkills);
2282
+ const mergedSkills = { ...fetchedSkills };
2283
+ if (locked) {
2284
+ for (const [k, v] of Object.entries(locked.skills)) {
2285
+ if (!(k in mergedSkills)) mergedSkills[k] = v;
2286
+ }
2287
+ }
2288
+ lock = setLockedSource(lock, url, {
2289
+ requestedRef,
2290
+ resolvedRef: resolvedSha,
2291
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
2292
+ skills: mergedSkills
2293
+ });
2294
+ logger.info(
2295
+ `Fetched ${fetchedNames.length} skill(s) from ${url}: ${fetchedNames.join(", ") || "(none)"}`
2296
+ );
2297
+ return { skillCount: fetchedNames.length, fetchedSkillNames: fetchedNames, updatedLock: lock };
2298
+ }
1996
2299
 
1997
2300
  // src/cli/commands/install.ts
1998
2301
  async function installCommand(options) {
@@ -2036,12 +2339,12 @@ import { FastMCP } from "fastmcp";
2036
2339
  import { z as z13 } from "zod/mini";
2037
2340
 
2038
2341
  // src/mcp/commands.ts
2039
- import { basename, join as join6 } from "path";
2342
+ import { basename, join as join7 } from "path";
2040
2343
  import { z as z5 } from "zod/mini";
2041
2344
  var maxCommandSizeBytes = 1024 * 1024;
2042
2345
  var maxCommandsCount = 1e3;
2043
2346
  async function listCommands() {
2044
- const commandsDir = join6(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
2347
+ const commandsDir = join7(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
2045
2348
  try {
2046
2349
  const files = await listDirectoryFiles(commandsDir);
2047
2350
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -2057,7 +2360,7 @@ async function listCommands() {
2057
2360
  });
2058
2361
  const frontmatter = command.getFrontmatter();
2059
2362
  return {
2060
- relativePathFromCwd: join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
2363
+ relativePathFromCwd: join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, file),
2061
2364
  frontmatter
2062
2365
  };
2063
2366
  } catch (error) {
@@ -2085,7 +2388,7 @@ async function getCommand({ relativePathFromCwd }) {
2085
2388
  relativeFilePath: filename
2086
2389
  });
2087
2390
  return {
2088
- relativePathFromCwd: join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
2391
+ relativePathFromCwd: join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
2089
2392
  frontmatter: command.getFrontmatter(),
2090
2393
  body: command.getBody()
2091
2394
  };
@@ -2114,7 +2417,7 @@ async function putCommand({
2114
2417
  try {
2115
2418
  const existingCommands = await listCommands();
2116
2419
  const isUpdate = existingCommands.some(
2117
- (command2) => command2.relativePathFromCwd === join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
2420
+ (command2) => command2.relativePathFromCwd === join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
2118
2421
  );
2119
2422
  if (!isUpdate && existingCommands.length >= maxCommandsCount) {
2120
2423
  throw new Error(
@@ -2131,11 +2434,11 @@ async function putCommand({
2131
2434
  fileContent,
2132
2435
  validate: true
2133
2436
  });
2134
- const commandsDir = join6(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
2437
+ const commandsDir = join7(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH);
2135
2438
  await ensureDir(commandsDir);
2136
2439
  await writeFileContent(command.getFilePath(), command.getFileContent());
2137
2440
  return {
2138
- relativePathFromCwd: join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
2441
+ relativePathFromCwd: join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename),
2139
2442
  frontmatter: command.getFrontmatter(),
2140
2443
  body: command.getBody()
2141
2444
  };
@@ -2151,11 +2454,11 @@ async function deleteCommand({ relativePathFromCwd }) {
2151
2454
  intendedRootDir: process.cwd()
2152
2455
  });
2153
2456
  const filename = basename(relativePathFromCwd);
2154
- const fullPath = join6(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
2457
+ const fullPath = join7(process.cwd(), RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename);
2155
2458
  try {
2156
2459
  await removeFile(fullPath);
2157
2460
  return {
2158
- relativePathFromCwd: join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
2461
+ relativePathFromCwd: join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, filename)
2159
2462
  };
2160
2463
  } catch (error) {
2161
2464
  throw new Error(`Failed to delete command file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -2180,7 +2483,7 @@ var commandToolSchemas = {
2180
2483
  var commandTools = {
2181
2484
  listCommands: {
2182
2485
  name: "listCommands",
2183
- description: `List all commands from ${join6(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
2486
+ description: `List all commands from ${join7(RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
2184
2487
  parameters: commandToolSchemas.listCommands,
2185
2488
  execute: async () => {
2186
2489
  const commands = await listCommands();
@@ -2307,11 +2610,11 @@ var generateTools = {
2307
2610
  };
2308
2611
 
2309
2612
  // src/mcp/ignore.ts
2310
- import { join as join7 } from "path";
2613
+ import { join as join8 } from "path";
2311
2614
  import { z as z7 } from "zod/mini";
2312
2615
  var maxIgnoreFileSizeBytes = 100 * 1024;
2313
2616
  async function getIgnoreFile() {
2314
- const ignoreFilePath = join7(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2617
+ const ignoreFilePath = join8(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2315
2618
  try {
2316
2619
  const content = await readFileContent(ignoreFilePath);
2317
2620
  return {
@@ -2328,7 +2631,7 @@ async function getIgnoreFile() {
2328
2631
  }
2329
2632
  }
2330
2633
  async function putIgnoreFile({ content }) {
2331
- const ignoreFilePath = join7(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2634
+ const ignoreFilePath = join8(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2332
2635
  const contentSizeBytes = Buffer.byteLength(content, "utf8");
2333
2636
  if (contentSizeBytes > maxIgnoreFileSizeBytes) {
2334
2637
  throw new Error(
@@ -2352,8 +2655,8 @@ async function putIgnoreFile({ content }) {
2352
2655
  }
2353
2656
  }
2354
2657
  async function deleteIgnoreFile() {
2355
- const aiignorePath = join7(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2356
- const legacyIgnorePath = join7(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
2658
+ const aiignorePath = join8(process.cwd(), RULESYNC_AIIGNORE_RELATIVE_FILE_PATH);
2659
+ const legacyIgnorePath = join8(process.cwd(), RULESYNC_IGNORE_RELATIVE_FILE_PATH);
2357
2660
  try {
2358
2661
  await Promise.all([removeFile(aiignorePath), removeFile(legacyIgnorePath)]);
2359
2662
  return {
@@ -2481,7 +2784,7 @@ var importTools = {
2481
2784
  };
2482
2785
 
2483
2786
  // src/mcp/mcp.ts
2484
- import { join as join8 } from "path";
2787
+ import { join as join9 } from "path";
2485
2788
  import { z as z9 } from "zod/mini";
2486
2789
  var maxMcpSizeBytes = 1024 * 1024;
2487
2790
  async function getMcpFile() {
@@ -2489,7 +2792,7 @@ async function getMcpFile() {
2489
2792
  const rulesyncMcp = await RulesyncMcp.fromFile({
2490
2793
  validate: true
2491
2794
  });
2492
- const relativePathFromCwd = join8(
2795
+ const relativePathFromCwd = join9(
2493
2796
  rulesyncMcp.getRelativeDirPath(),
2494
2797
  rulesyncMcp.getRelativeFilePath()
2495
2798
  );
@@ -2527,7 +2830,7 @@ async function putMcpFile({ content }) {
2527
2830
  const paths = RulesyncMcp.getSettablePaths();
2528
2831
  const relativeDirPath = paths.recommended.relativeDirPath;
2529
2832
  const relativeFilePath = paths.recommended.relativeFilePath;
2530
- const fullPath = join8(baseDir, relativeDirPath, relativeFilePath);
2833
+ const fullPath = join9(baseDir, relativeDirPath, relativeFilePath);
2531
2834
  const rulesyncMcp = new RulesyncMcp({
2532
2835
  baseDir,
2533
2836
  relativeDirPath,
@@ -2535,9 +2838,9 @@ async function putMcpFile({ content }) {
2535
2838
  fileContent: content,
2536
2839
  validate: true
2537
2840
  });
2538
- await ensureDir(join8(baseDir, relativeDirPath));
2841
+ await ensureDir(join9(baseDir, relativeDirPath));
2539
2842
  await writeFileContent(fullPath, content);
2540
- const relativePathFromCwd = join8(relativeDirPath, relativeFilePath);
2843
+ const relativePathFromCwd = join9(relativeDirPath, relativeFilePath);
2541
2844
  return {
2542
2845
  relativePathFromCwd,
2543
2846
  content: rulesyncMcp.getFileContent()
@@ -2555,15 +2858,15 @@ async function deleteMcpFile() {
2555
2858
  try {
2556
2859
  const baseDir = process.cwd();
2557
2860
  const paths = RulesyncMcp.getSettablePaths();
2558
- const recommendedPath = join8(
2861
+ const recommendedPath = join9(
2559
2862
  baseDir,
2560
2863
  paths.recommended.relativeDirPath,
2561
2864
  paths.recommended.relativeFilePath
2562
2865
  );
2563
- const legacyPath = join8(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
2866
+ const legacyPath = join9(baseDir, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
2564
2867
  await removeFile(recommendedPath);
2565
2868
  await removeFile(legacyPath);
2566
- const relativePathFromCwd = join8(
2869
+ const relativePathFromCwd = join9(
2567
2870
  paths.recommended.relativeDirPath,
2568
2871
  paths.recommended.relativeFilePath
2569
2872
  );
@@ -2617,12 +2920,12 @@ var mcpTools = {
2617
2920
  };
2618
2921
 
2619
2922
  // src/mcp/rules.ts
2620
- import { basename as basename2, join as join9 } from "path";
2923
+ import { basename as basename2, join as join10 } from "path";
2621
2924
  import { z as z10 } from "zod/mini";
2622
2925
  var maxRuleSizeBytes = 1024 * 1024;
2623
2926
  var maxRulesCount = 1e3;
2624
2927
  async function listRules() {
2625
- const rulesDir = join9(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
2928
+ const rulesDir = join10(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
2626
2929
  try {
2627
2930
  const files = await listDirectoryFiles(rulesDir);
2628
2931
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -2635,7 +2938,7 @@ async function listRules() {
2635
2938
  });
2636
2939
  const frontmatter = rule.getFrontmatter();
2637
2940
  return {
2638
- relativePathFromCwd: join9(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
2941
+ relativePathFromCwd: join10(RULESYNC_RULES_RELATIVE_DIR_PATH, file),
2639
2942
  frontmatter
2640
2943
  };
2641
2944
  } catch (error) {
@@ -2664,7 +2967,7 @@ async function getRule({ relativePathFromCwd }) {
2664
2967
  validate: true
2665
2968
  });
2666
2969
  return {
2667
- relativePathFromCwd: join9(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
2970
+ relativePathFromCwd: join10(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
2668
2971
  frontmatter: rule.getFrontmatter(),
2669
2972
  body: rule.getBody()
2670
2973
  };
@@ -2693,7 +2996,7 @@ async function putRule({
2693
2996
  try {
2694
2997
  const existingRules = await listRules();
2695
2998
  const isUpdate = existingRules.some(
2696
- (rule2) => rule2.relativePathFromCwd === join9(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
2999
+ (rule2) => rule2.relativePathFromCwd === join10(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
2697
3000
  );
2698
3001
  if (!isUpdate && existingRules.length >= maxRulesCount) {
2699
3002
  throw new Error(
@@ -2708,11 +3011,11 @@ async function putRule({
2708
3011
  body,
2709
3012
  validate: true
2710
3013
  });
2711
- const rulesDir = join9(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
3014
+ const rulesDir = join10(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH);
2712
3015
  await ensureDir(rulesDir);
2713
3016
  await writeFileContent(rule.getFilePath(), rule.getFileContent());
2714
3017
  return {
2715
- relativePathFromCwd: join9(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
3018
+ relativePathFromCwd: join10(RULESYNC_RULES_RELATIVE_DIR_PATH, filename),
2716
3019
  frontmatter: rule.getFrontmatter(),
2717
3020
  body: rule.getBody()
2718
3021
  };
@@ -2728,11 +3031,11 @@ async function deleteRule({ relativePathFromCwd }) {
2728
3031
  intendedRootDir: process.cwd()
2729
3032
  });
2730
3033
  const filename = basename2(relativePathFromCwd);
2731
- const fullPath = join9(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
3034
+ const fullPath = join10(process.cwd(), RULESYNC_RULES_RELATIVE_DIR_PATH, filename);
2732
3035
  try {
2733
3036
  await removeFile(fullPath);
2734
3037
  return {
2735
- relativePathFromCwd: join9(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
3038
+ relativePathFromCwd: join10(RULESYNC_RULES_RELATIVE_DIR_PATH, filename)
2736
3039
  };
2737
3040
  } catch (error) {
2738
3041
  throw new Error(`Failed to delete rule file ${relativePathFromCwd}: ${formatError(error)}`, {
@@ -2757,7 +3060,7 @@ var ruleToolSchemas = {
2757
3060
  var ruleTools = {
2758
3061
  listRules: {
2759
3062
  name: "listRules",
2760
- description: `List all rules from ${join9(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
3063
+ description: `List all rules from ${join10(RULESYNC_RULES_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
2761
3064
  parameters: ruleToolSchemas.listRules,
2762
3065
  execute: async () => {
2763
3066
  const rules = await listRules();
@@ -2799,7 +3102,7 @@ var ruleTools = {
2799
3102
  };
2800
3103
 
2801
3104
  // src/mcp/skills.ts
2802
- import { basename as basename3, dirname, join as join10 } from "path";
3105
+ import { basename as basename3, dirname, join as join11 } from "path";
2803
3106
  import { z as z11 } from "zod/mini";
2804
3107
  var maxSkillSizeBytes = 1024 * 1024;
2805
3108
  var maxSkillsCount = 1e3;
@@ -2823,9 +3126,9 @@ function extractDirName(relativeDirPathFromCwd) {
2823
3126
  return dirName;
2824
3127
  }
2825
3128
  async function listSkills() {
2826
- const skillsDir = join10(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
3129
+ const skillsDir = join11(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH);
2827
3130
  try {
2828
- const skillDirPaths = await findFilesByGlobs(join10(skillsDir, "*"), { type: "dir" });
3131
+ const skillDirPaths = await findFilesByGlobs(join11(skillsDir, "*"), { type: "dir" });
2829
3132
  const skills = await Promise.all(
2830
3133
  skillDirPaths.map(async (dirPath) => {
2831
3134
  const dirName = basename3(dirPath);
@@ -2836,7 +3139,7 @@ async function listSkills() {
2836
3139
  });
2837
3140
  const frontmatter = skill.getFrontmatter();
2838
3141
  return {
2839
- relativeDirPathFromCwd: join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
3142
+ relativeDirPathFromCwd: join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
2840
3143
  frontmatter
2841
3144
  };
2842
3145
  } catch (error) {
@@ -2864,7 +3167,7 @@ async function getSkill({ relativeDirPathFromCwd }) {
2864
3167
  dirName
2865
3168
  });
2866
3169
  return {
2867
- relativeDirPathFromCwd: join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
3170
+ relativeDirPathFromCwd: join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
2868
3171
  frontmatter: skill.getFrontmatter(),
2869
3172
  body: skill.getBody(),
2870
3173
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -2898,7 +3201,7 @@ async function putSkill({
2898
3201
  try {
2899
3202
  const existingSkills = await listSkills();
2900
3203
  const isUpdate = existingSkills.some(
2901
- (skill2) => skill2.relativeDirPathFromCwd === join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
3204
+ (skill2) => skill2.relativeDirPathFromCwd === join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
2902
3205
  );
2903
3206
  if (!isUpdate && existingSkills.length >= maxSkillsCount) {
2904
3207
  throw new Error(
@@ -2915,9 +3218,9 @@ async function putSkill({
2915
3218
  otherFiles: aiDirFiles,
2916
3219
  validate: true
2917
3220
  });
2918
- const skillDirPath = join10(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
3221
+ const skillDirPath = join11(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
2919
3222
  await ensureDir(skillDirPath);
2920
- const skillFilePath = join10(skillDirPath, SKILL_FILE_NAME);
3223
+ const skillFilePath = join11(skillDirPath, SKILL_FILE_NAME);
2921
3224
  const skillFileContent = stringifyFrontmatter(body, frontmatter);
2922
3225
  await writeFileContent(skillFilePath, skillFileContent);
2923
3226
  for (const file of otherFiles) {
@@ -2925,15 +3228,15 @@ async function putSkill({
2925
3228
  relativePath: file.name,
2926
3229
  intendedRootDir: skillDirPath
2927
3230
  });
2928
- const filePath = join10(skillDirPath, file.name);
2929
- const fileDir = join10(skillDirPath, dirname(file.name));
3231
+ const filePath = join11(skillDirPath, file.name);
3232
+ const fileDir = join11(skillDirPath, dirname(file.name));
2930
3233
  if (fileDir !== skillDirPath) {
2931
3234
  await ensureDir(fileDir);
2932
3235
  }
2933
3236
  await writeFileContent(filePath, file.body);
2934
3237
  }
2935
3238
  return {
2936
- relativeDirPathFromCwd: join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
3239
+ relativeDirPathFromCwd: join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName),
2937
3240
  frontmatter: skill.getFrontmatter(),
2938
3241
  body: skill.getBody(),
2939
3242
  otherFiles: skill.getOtherFiles().map(aiDirFileToMcpSkillFile)
@@ -2955,13 +3258,13 @@ async function deleteSkill({
2955
3258
  intendedRootDir: process.cwd()
2956
3259
  });
2957
3260
  const dirName = extractDirName(relativeDirPathFromCwd);
2958
- const skillDirPath = join10(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
3261
+ const skillDirPath = join11(process.cwd(), RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName);
2959
3262
  try {
2960
3263
  if (await directoryExists(skillDirPath)) {
2961
3264
  await removeDirectory(skillDirPath);
2962
3265
  }
2963
3266
  return {
2964
- relativeDirPathFromCwd: join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
3267
+ relativeDirPathFromCwd: join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName)
2965
3268
  };
2966
3269
  } catch (error) {
2967
3270
  throw new Error(
@@ -2994,7 +3297,7 @@ var skillToolSchemas = {
2994
3297
  var skillTools = {
2995
3298
  listSkills: {
2996
3299
  name: "listSkills",
2997
- description: `List all skills from ${join10(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
3300
+ description: `List all skills from ${join11(RULESYNC_SKILLS_RELATIVE_DIR_PATH, "*", SKILL_FILE_NAME)} with their frontmatter.`,
2998
3301
  parameters: skillToolSchemas.listSkills,
2999
3302
  execute: async () => {
3000
3303
  const skills = await listSkills();
@@ -3037,12 +3340,12 @@ var skillTools = {
3037
3340
  };
3038
3341
 
3039
3342
  // src/mcp/subagents.ts
3040
- import { basename as basename4, join as join11 } from "path";
3343
+ import { basename as basename4, join as join12 } from "path";
3041
3344
  import { z as z12 } from "zod/mini";
3042
3345
  var maxSubagentSizeBytes = 1024 * 1024;
3043
3346
  var maxSubagentsCount = 1e3;
3044
3347
  async function listSubagents() {
3045
- const subagentsDir = join11(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
3348
+ const subagentsDir = join12(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
3046
3349
  try {
3047
3350
  const files = await listDirectoryFiles(subagentsDir);
3048
3351
  const mdFiles = files.filter((file) => file.endsWith(".md"));
@@ -3055,7 +3358,7 @@ async function listSubagents() {
3055
3358
  });
3056
3359
  const frontmatter = subagent.getFrontmatter();
3057
3360
  return {
3058
- relativePathFromCwd: join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
3361
+ relativePathFromCwd: join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, file),
3059
3362
  frontmatter
3060
3363
  };
3061
3364
  } catch (error) {
@@ -3086,7 +3389,7 @@ async function getSubagent({ relativePathFromCwd }) {
3086
3389
  validate: true
3087
3390
  });
3088
3391
  return {
3089
- relativePathFromCwd: join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
3392
+ relativePathFromCwd: join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
3090
3393
  frontmatter: subagent.getFrontmatter(),
3091
3394
  body: subagent.getBody()
3092
3395
  };
@@ -3115,7 +3418,7 @@ async function putSubagent({
3115
3418
  try {
3116
3419
  const existingSubagents = await listSubagents();
3117
3420
  const isUpdate = existingSubagents.some(
3118
- (subagent2) => subagent2.relativePathFromCwd === join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
3421
+ (subagent2) => subagent2.relativePathFromCwd === join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
3119
3422
  );
3120
3423
  if (!isUpdate && existingSubagents.length >= maxSubagentsCount) {
3121
3424
  throw new Error(
@@ -3130,11 +3433,11 @@ async function putSubagent({
3130
3433
  body,
3131
3434
  validate: true
3132
3435
  });
3133
- const subagentsDir = join11(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
3436
+ const subagentsDir = join12(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH);
3134
3437
  await ensureDir(subagentsDir);
3135
3438
  await writeFileContent(subagent.getFilePath(), subagent.getFileContent());
3136
3439
  return {
3137
- relativePathFromCwd: join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
3440
+ relativePathFromCwd: join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename),
3138
3441
  frontmatter: subagent.getFrontmatter(),
3139
3442
  body: subagent.getBody()
3140
3443
  };
@@ -3150,11 +3453,11 @@ async function deleteSubagent({ relativePathFromCwd }) {
3150
3453
  intendedRootDir: process.cwd()
3151
3454
  });
3152
3455
  const filename = basename4(relativePathFromCwd);
3153
- const fullPath = join11(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
3456
+ const fullPath = join12(process.cwd(), RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename);
3154
3457
  try {
3155
3458
  await removeFile(fullPath);
3156
3459
  return {
3157
- relativePathFromCwd: join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
3460
+ relativePathFromCwd: join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, filename)
3158
3461
  };
3159
3462
  } catch (error) {
3160
3463
  throw new Error(
@@ -3182,7 +3485,7 @@ var subagentToolSchemas = {
3182
3485
  var subagentTools = {
3183
3486
  listSubagents: {
3184
3487
  name: "listSubagents",
3185
- description: `List all subagents from ${join11(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
3488
+ description: `List all subagents from ${join12(RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, "*.md")} with their frontmatter.`,
3186
3489
  parameters: subagentToolSchemas.listSubagents,
3187
3490
  execute: async () => {
3188
3491
  const subagents = await listSubagents();
@@ -3807,7 +4110,7 @@ async function updateCommand(currentVersion, options) {
3807
4110
  }
3808
4111
 
3809
4112
  // src/cli/index.ts
3810
- var getVersion = () => "7.13.0";
4113
+ var getVersion = () => "7.15.0";
3811
4114
  var main = async () => {
3812
4115
  const program = new Command();
3813
4116
  const version = getVersion();