rulesync 1.2.5 → 2.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/index.cjs CHANGED
@@ -39,7 +39,18 @@ var RulesyncFeaturesSchema = import_mini.z.array(import_mini.z.enum(ALL_FEATURES
39
39
 
40
40
  // src/utils/logger.ts
41
41
  var import_consola = require("consola");
42
+
43
+ // src/utils/vitest.ts
42
44
  var isEnvTest = process.env.NODE_ENV === "test";
45
+ function getVitestWorkerId() {
46
+ const vitestWorkerId = process.env.VITEST_WORKER_ID;
47
+ if (!vitestWorkerId) {
48
+ throw new Error("VITEST_WORKER_ID is not set");
49
+ }
50
+ return vitestWorkerId;
51
+ }
52
+
53
+ // src/utils/logger.ts
43
54
  var Logger = class {
44
55
  _verbose = false;
45
56
  console = import_consola.consola.withDefaults({
@@ -80,9 +91,17 @@ var Logger = class {
80
91
  };
81
92
  var logger = new Logger();
82
93
 
94
+ // src/cli/commands/generate.ts
95
+ var import_es_toolkit2 = require("es-toolkit");
96
+
97
+ // src/commands/commands-processor.ts
98
+ var import_node_path11 = require("path");
99
+ var import_mini8 = require("zod/mini");
100
+
83
101
  // src/utils/file.ts
84
102
  var import_node_fs = require("fs");
85
103
  var import_promises = require("fs/promises");
104
+ var import_node_os = __toESM(require("os"), 1);
86
105
  var import_node_path = require("path");
87
106
  async function ensureDir(dirPath) {
88
107
  try {
@@ -135,47 +154,32 @@ async function removeFile(filepath) {
135
154
  logger.warn(`Failed to remove file ${filepath}:`, error);
136
155
  }
137
156
  }
138
-
139
- // src/cli/commands/config.ts
140
- async function configCommand(options) {
141
- if (options.init) {
142
- await initConfig();
143
- return;
157
+ function getHomeDirectory() {
158
+ if (isEnvTest) {
159
+ return (0, import_node_path.join)("./tmp", "tests", "home", getVitestWorkerId());
144
160
  }
145
- logger.info(`Please run \`rulesync config --init\` to create a new configuration file`);
161
+ return import_node_os.default.homedir();
146
162
  }
147
- async function initConfig() {
148
- logger.info("Initializing configuration...");
149
- if (await fileExists("rulesync.jsonc")) {
150
- logger.error("rulesync.jsonc already exists");
151
- process.exit(1);
163
+ function validateBaseDir(baseDir) {
164
+ if (baseDir.trim() === "") {
165
+ throw new Error("baseDir cannot be an empty string");
166
+ }
167
+ if (baseDir.includes("..")) {
168
+ throw new Error(`baseDir cannot contain directory traversal (..): ${baseDir}`);
169
+ }
170
+ if (baseDir.startsWith("/")) {
171
+ throw new Error(`baseDir must be a relative path. Absolute path not allowed: ${baseDir}`);
172
+ }
173
+ if (/^[a-zA-Z]:[/\\]/.test(baseDir)) {
174
+ throw new Error(`baseDir must be a relative path. Absolute path not allowed: ${baseDir}`);
175
+ }
176
+ const normalized = (0, import_node_path.resolve)(".", baseDir);
177
+ const rel = (0, import_node_path.relative)(".", normalized);
178
+ if (rel.startsWith("..")) {
179
+ throw new Error(`baseDir cannot contain directory traversal (..): ${baseDir}`);
152
180
  }
153
- await writeFileContent(
154
- "rulesync.jsonc",
155
- JSON.stringify(
156
- {
157
- targets: ["copilot", "cursor", "claudecode", "codexcli"],
158
- features: ["rules", "ignore", "mcp", "commands", "subagents"],
159
- baseDirs: ["."],
160
- delete: true,
161
- verbose: false,
162
- experimentalSimulateCommands: false,
163
- experimentalSimulateSubagents: false
164
- },
165
- null,
166
- 2
167
- )
168
- );
169
- logger.success("Configuration file created successfully!");
170
181
  }
171
182
 
172
- // src/cli/commands/generate.ts
173
- var import_es_toolkit2 = require("es-toolkit");
174
-
175
- // src/commands/commands-processor.ts
176
- var import_node_path11 = require("path");
177
- var import_mini8 = require("zod/mini");
178
-
179
183
  // src/types/feature-processor.ts
180
184
  var FeatureProcessor = class {
181
185
  baseDir;
@@ -281,17 +285,23 @@ var AiFile = class {
281
285
  * Whole raw file content
282
286
  */
283
287
  fileContent;
288
+ /**
289
+ * @example true
290
+ */
291
+ global;
284
292
  constructor({
285
293
  baseDir = ".",
286
294
  relativeDirPath,
287
295
  relativeFilePath,
288
296
  fileContent,
289
- validate = true
297
+ validate = true,
298
+ global = false
290
299
  }) {
291
300
  this.baseDir = baseDir;
292
301
  this.relativeDirPath = relativeDirPath;
293
302
  this.relativeFilePath = relativeFilePath;
294
303
  this.fileContent = fileContent;
304
+ this.global = global;
295
305
  if (validate) {
296
306
  const result = this.validate();
297
307
  if (!result.success) {
@@ -312,7 +322,16 @@ var AiFile = class {
312
322
  return this.relativeFilePath;
313
323
  }
314
324
  getFilePath() {
315
- return import_node_path2.default.join(this.baseDir, this.relativeDirPath, this.relativeFilePath);
325
+ const fullPath = import_node_path2.default.join(this.baseDir, this.relativeDirPath, this.relativeFilePath);
326
+ const resolvedFull = (0, import_node_path2.resolve)(fullPath);
327
+ const resolvedBase = (0, import_node_path2.resolve)(this.baseDir);
328
+ const rel = (0, import_node_path2.relative)(resolvedBase, resolvedFull);
329
+ if (rel.startsWith("..") || import_node_path2.default.isAbsolute(rel)) {
330
+ throw new Error(
331
+ `Path traversal detected: Final path escapes baseDir. baseDir="${this.baseDir}", relativeDirPath="${this.relativeDirPath}", relativeFilePath="${this.relativeFilePath}"`
332
+ );
333
+ }
334
+ return fullPath;
316
335
  }
317
336
  getFileContent() {
318
337
  return this.fileContent;
@@ -1342,6 +1361,7 @@ var CommandsProcessor = class extends FeatureProcessor {
1342
1361
  };
1343
1362
 
1344
1363
  // src/config/config-resolver.ts
1364
+ var import_node_path12 = require("path");
1345
1365
  var import_c12 = require("c12");
1346
1366
 
1347
1367
  // src/config/config.ts
@@ -1351,6 +1371,7 @@ var Config = class {
1351
1371
  features;
1352
1372
  verbose;
1353
1373
  delete;
1374
+ experimentalGlobal;
1354
1375
  experimentalSimulateCommands;
1355
1376
  experimentalSimulateSubagents;
1356
1377
  constructor({
@@ -1359,6 +1380,7 @@ var Config = class {
1359
1380
  features,
1360
1381
  verbose,
1361
1382
  delete: isDelete,
1383
+ experimentalGlobal,
1362
1384
  experimentalSimulateCommands,
1363
1385
  experimentalSimulateSubagents
1364
1386
  }) {
@@ -1367,6 +1389,7 @@ var Config = class {
1367
1389
  this.features = features;
1368
1390
  this.verbose = verbose;
1369
1391
  this.delete = isDelete;
1392
+ this.experimentalGlobal = experimentalGlobal;
1370
1393
  this.experimentalSimulateCommands = experimentalSimulateCommands;
1371
1394
  this.experimentalSimulateSubagents = experimentalSimulateSubagents;
1372
1395
  }
@@ -1391,6 +1414,9 @@ var Config = class {
1391
1414
  getDelete() {
1392
1415
  return this.delete;
1393
1416
  }
1417
+ getExperimentalGlobal() {
1418
+ return this.experimentalGlobal;
1419
+ }
1394
1420
  getExperimentalSimulateCommands() {
1395
1421
  return this.experimentalSimulateCommands;
1396
1422
  }
@@ -1407,6 +1433,7 @@ var defaults = {
1407
1433
  delete: false,
1408
1434
  baseDirs: ["."],
1409
1435
  configPath: "rulesync.jsonc",
1436
+ experimentalGlobal: false,
1410
1437
  experimentalSimulateCommands: false,
1411
1438
  experimentalSimulateSubagents: false
1412
1439
  };
@@ -1418,16 +1445,21 @@ var ConfigResolver = class {
1418
1445
  delete: isDelete,
1419
1446
  baseDirs,
1420
1447
  configPath = defaults.configPath,
1448
+ experimentalGlobal,
1421
1449
  experimentalSimulateCommands,
1422
1450
  experimentalSimulateSubagents
1423
1451
  }) {
1424
- if (!fileExists(configPath)) {
1452
+ if (!await fileExists(configPath)) {
1425
1453
  return new Config({
1426
1454
  targets: targets ?? defaults.targets,
1427
1455
  features: features ?? defaults.features,
1428
1456
  verbose: verbose ?? defaults.verbose,
1429
1457
  delete: isDelete ?? defaults.delete,
1430
- baseDirs: baseDirs ?? defaults.baseDirs,
1458
+ baseDirs: getBaseDirsInLightOfGlobal({
1459
+ baseDirs: baseDirs ?? defaults.baseDirs,
1460
+ global: experimentalGlobal ?? false
1461
+ }),
1462
+ experimentalGlobal: experimentalGlobal ?? defaults.experimentalGlobal,
1431
1463
  experimentalSimulateCommands: experimentalSimulateCommands ?? defaults.experimentalSimulateCommands,
1432
1464
  experimentalSimulateSubagents: experimentalSimulateSubagents ?? defaults.experimentalSimulateSubagents
1433
1465
  });
@@ -1449,19 +1481,38 @@ var ConfigResolver = class {
1449
1481
  features: features ?? configByFile.features ?? defaults.features,
1450
1482
  verbose: verbose ?? configByFile.verbose ?? defaults.verbose,
1451
1483
  delete: isDelete ?? configByFile.delete ?? defaults.delete,
1452
- baseDirs: baseDirs ?? configByFile.baseDirs ?? defaults.baseDirs,
1484
+ baseDirs: getBaseDirsInLightOfGlobal({
1485
+ baseDirs: baseDirs ?? configByFile.baseDirs ?? defaults.baseDirs,
1486
+ global: experimentalGlobal ?? false
1487
+ }),
1488
+ experimentalGlobal: experimentalGlobal ?? configByFile.experimentalGlobal ?? defaults.experimentalGlobal,
1453
1489
  experimentalSimulateCommands: experimentalSimulateCommands ?? configByFile.experimentalSimulateCommands ?? defaults.experimentalSimulateCommands,
1454
1490
  experimentalSimulateSubagents: experimentalSimulateSubagents ?? configByFile.experimentalSimulateSubagents ?? defaults.experimentalSimulateSubagents
1455
1491
  };
1456
1492
  return new Config(configParams);
1457
1493
  }
1458
1494
  };
1495
+ function getBaseDirsInLightOfGlobal({
1496
+ baseDirs,
1497
+ global
1498
+ }) {
1499
+ if (isEnvTest) {
1500
+ return baseDirs.map((baseDir) => (0, import_node_path12.join)(".", baseDir));
1501
+ }
1502
+ if (global) {
1503
+ return [getHomeDirectory()];
1504
+ }
1505
+ baseDirs.forEach((baseDir) => {
1506
+ validateBaseDir(baseDir);
1507
+ });
1508
+ return baseDirs;
1509
+ }
1459
1510
 
1460
1511
  // src/ignore/ignore-processor.ts
1461
1512
  var import_mini9 = require("zod/mini");
1462
1513
 
1463
1514
  // src/ignore/amazonqcli-ignore.ts
1464
- var import_node_path12 = require("path");
1515
+ var import_node_path13 = require("path");
1465
1516
 
1466
1517
  // src/types/tool-file.ts
1467
1518
  var ToolFile = class extends AiFile {
@@ -1569,7 +1620,7 @@ var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1569
1620
  validate = true
1570
1621
  }) {
1571
1622
  const fileContent = await readFileContent(
1572
- (0, import_node_path12.join)(
1623
+ (0, import_node_path13.join)(
1573
1624
  baseDir,
1574
1625
  this.getSettablePaths().relativeDirPath,
1575
1626
  this.getSettablePaths().relativeFilePath
@@ -1586,7 +1637,7 @@ var AmazonqcliIgnore = class _AmazonqcliIgnore extends ToolIgnore {
1586
1637
  };
1587
1638
 
1588
1639
  // src/ignore/augmentcode-ignore.ts
1589
- var import_node_path13 = require("path");
1640
+ var import_node_path14 = require("path");
1590
1641
  var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
1591
1642
  static getSettablePaths() {
1592
1643
  return {
@@ -1624,7 +1675,7 @@ var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
1624
1675
  validate = true
1625
1676
  }) {
1626
1677
  const fileContent = await readFileContent(
1627
- (0, import_node_path13.join)(
1678
+ (0, import_node_path14.join)(
1628
1679
  baseDir,
1629
1680
  this.getSettablePaths().relativeDirPath,
1630
1681
  this.getSettablePaths().relativeFilePath
@@ -1641,7 +1692,7 @@ var AugmentcodeIgnore = class _AugmentcodeIgnore extends ToolIgnore {
1641
1692
  };
1642
1693
 
1643
1694
  // src/ignore/claudecode-ignore.ts
1644
- var import_node_path14 = require("path");
1695
+ var import_node_path15 = require("path");
1645
1696
  var import_es_toolkit = require("es-toolkit");
1646
1697
  var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
1647
1698
  constructor(params) {
@@ -1677,7 +1728,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
1677
1728
  const fileContent = rulesyncIgnore.getFileContent();
1678
1729
  const patterns = fileContent.split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
1679
1730
  const deniedValues = patterns.map((pattern) => `Read(${pattern})`);
1680
- const filePath = (0, import_node_path14.join)(
1731
+ const filePath = (0, import_node_path15.join)(
1681
1732
  baseDir,
1682
1733
  this.getSettablePaths().relativeDirPath,
1683
1734
  this.getSettablePaths().relativeFilePath
@@ -1705,7 +1756,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
1705
1756
  validate = true
1706
1757
  }) {
1707
1758
  const fileContent = await readFileContent(
1708
- (0, import_node_path14.join)(
1759
+ (0, import_node_path15.join)(
1709
1760
  baseDir,
1710
1761
  this.getSettablePaths().relativeDirPath,
1711
1762
  this.getSettablePaths().relativeFilePath
@@ -1722,7 +1773,7 @@ var ClaudecodeIgnore = class _ClaudecodeIgnore extends ToolIgnore {
1722
1773
  };
1723
1774
 
1724
1775
  // src/ignore/cline-ignore.ts
1725
- var import_node_path15 = require("path");
1776
+ var import_node_path16 = require("path");
1726
1777
  var ClineIgnore = class _ClineIgnore extends ToolIgnore {
1727
1778
  static getSettablePaths() {
1728
1779
  return {
@@ -1759,7 +1810,7 @@ var ClineIgnore = class _ClineIgnore extends ToolIgnore {
1759
1810
  validate = true
1760
1811
  }) {
1761
1812
  const fileContent = await readFileContent(
1762
- (0, import_node_path15.join)(
1813
+ (0, import_node_path16.join)(
1763
1814
  baseDir,
1764
1815
  this.getSettablePaths().relativeDirPath,
1765
1816
  this.getSettablePaths().relativeFilePath
@@ -1776,7 +1827,7 @@ var ClineIgnore = class _ClineIgnore extends ToolIgnore {
1776
1827
  };
1777
1828
 
1778
1829
  // src/ignore/codexcli-ignore.ts
1779
- var import_node_path16 = require("path");
1830
+ var import_node_path17 = require("path");
1780
1831
  var CodexcliIgnore = class _CodexcliIgnore extends ToolIgnore {
1781
1832
  static getSettablePaths() {
1782
1833
  return {
@@ -1806,7 +1857,7 @@ var CodexcliIgnore = class _CodexcliIgnore extends ToolIgnore {
1806
1857
  validate = true
1807
1858
  }) {
1808
1859
  const fileContent = await readFileContent(
1809
- (0, import_node_path16.join)(
1860
+ (0, import_node_path17.join)(
1810
1861
  baseDir,
1811
1862
  this.getSettablePaths().relativeDirPath,
1812
1863
  this.getSettablePaths().relativeFilePath
@@ -1823,7 +1874,7 @@ var CodexcliIgnore = class _CodexcliIgnore extends ToolIgnore {
1823
1874
  };
1824
1875
 
1825
1876
  // src/ignore/cursor-ignore.ts
1826
- var import_node_path17 = require("path");
1877
+ var import_node_path18 = require("path");
1827
1878
  var CursorIgnore = class _CursorIgnore extends ToolIgnore {
1828
1879
  static getSettablePaths() {
1829
1880
  return {
@@ -1856,7 +1907,7 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
1856
1907
  validate = true
1857
1908
  }) {
1858
1909
  const fileContent = await readFileContent(
1859
- (0, import_node_path17.join)(
1910
+ (0, import_node_path18.join)(
1860
1911
  baseDir,
1861
1912
  this.getSettablePaths().relativeDirPath,
1862
1913
  this.getSettablePaths().relativeFilePath
@@ -1873,7 +1924,7 @@ var CursorIgnore = class _CursorIgnore extends ToolIgnore {
1873
1924
  };
1874
1925
 
1875
1926
  // src/ignore/geminicli-ignore.ts
1876
- var import_node_path18 = require("path");
1927
+ var import_node_path19 = require("path");
1877
1928
  var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
1878
1929
  static getSettablePaths() {
1879
1930
  return {
@@ -1900,7 +1951,7 @@ var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
1900
1951
  validate = true
1901
1952
  }) {
1902
1953
  const fileContent = await readFileContent(
1903
- (0, import_node_path18.join)(
1954
+ (0, import_node_path19.join)(
1904
1955
  baseDir,
1905
1956
  this.getSettablePaths().relativeDirPath,
1906
1957
  this.getSettablePaths().relativeFilePath
@@ -1917,7 +1968,7 @@ var GeminiCliIgnore = class _GeminiCliIgnore extends ToolIgnore {
1917
1968
  };
1918
1969
 
1919
1970
  // src/ignore/junie-ignore.ts
1920
- var import_node_path19 = require("path");
1971
+ var import_node_path20 = require("path");
1921
1972
  var JunieIgnore = class _JunieIgnore extends ToolIgnore {
1922
1973
  static getSettablePaths() {
1923
1974
  return {
@@ -1944,7 +1995,7 @@ var JunieIgnore = class _JunieIgnore extends ToolIgnore {
1944
1995
  validate = true
1945
1996
  }) {
1946
1997
  const fileContent = await readFileContent(
1947
- (0, import_node_path19.join)(
1998
+ (0, import_node_path20.join)(
1948
1999
  baseDir,
1949
2000
  this.getSettablePaths().relativeDirPath,
1950
2001
  this.getSettablePaths().relativeFilePath
@@ -1961,7 +2012,7 @@ var JunieIgnore = class _JunieIgnore extends ToolIgnore {
1961
2012
  };
1962
2013
 
1963
2014
  // src/ignore/kiro-ignore.ts
1964
- var import_node_path20 = require("path");
2015
+ var import_node_path21 = require("path");
1965
2016
  var KiroIgnore = class _KiroIgnore extends ToolIgnore {
1966
2017
  static getSettablePaths() {
1967
2018
  return {
@@ -1988,7 +2039,7 @@ var KiroIgnore = class _KiroIgnore extends ToolIgnore {
1988
2039
  validate = true
1989
2040
  }) {
1990
2041
  const fileContent = await readFileContent(
1991
- (0, import_node_path20.join)(
2042
+ (0, import_node_path21.join)(
1992
2043
  baseDir,
1993
2044
  this.getSettablePaths().relativeDirPath,
1994
2045
  this.getSettablePaths().relativeFilePath
@@ -2005,7 +2056,7 @@ var KiroIgnore = class _KiroIgnore extends ToolIgnore {
2005
2056
  };
2006
2057
 
2007
2058
  // src/ignore/qwencode-ignore.ts
2008
- var import_node_path21 = require("path");
2059
+ var import_node_path22 = require("path");
2009
2060
  var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2010
2061
  static getSettablePaths() {
2011
2062
  return {
@@ -2032,7 +2083,7 @@ var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2032
2083
  validate = true
2033
2084
  }) {
2034
2085
  const fileContent = await readFileContent(
2035
- (0, import_node_path21.join)(
2086
+ (0, import_node_path22.join)(
2036
2087
  baseDir,
2037
2088
  this.getSettablePaths().relativeDirPath,
2038
2089
  this.getSettablePaths().relativeFilePath
@@ -2049,7 +2100,7 @@ var QwencodeIgnore = class _QwencodeIgnore extends ToolIgnore {
2049
2100
  };
2050
2101
 
2051
2102
  // src/ignore/roo-ignore.ts
2052
- var import_node_path22 = require("path");
2103
+ var import_node_path23 = require("path");
2053
2104
  var RooIgnore = class _RooIgnore extends ToolIgnore {
2054
2105
  static getSettablePaths() {
2055
2106
  return {
@@ -2076,7 +2127,7 @@ var RooIgnore = class _RooIgnore extends ToolIgnore {
2076
2127
  validate = true
2077
2128
  }) {
2078
2129
  const fileContent = await readFileContent(
2079
- (0, import_node_path22.join)(
2130
+ (0, import_node_path23.join)(
2080
2131
  baseDir,
2081
2132
  this.getSettablePaths().relativeDirPath,
2082
2133
  this.getSettablePaths().relativeFilePath
@@ -2093,7 +2144,7 @@ var RooIgnore = class _RooIgnore extends ToolIgnore {
2093
2144
  };
2094
2145
 
2095
2146
  // src/ignore/windsurf-ignore.ts
2096
- var import_node_path23 = require("path");
2147
+ var import_node_path24 = require("path");
2097
2148
  var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2098
2149
  static getSettablePaths() {
2099
2150
  return {
@@ -2120,7 +2171,7 @@ var WindsurfIgnore = class _WindsurfIgnore extends ToolIgnore {
2120
2171
  validate = true
2121
2172
  }) {
2122
2173
  const fileContent = await readFileContent(
2123
- (0, import_node_path23.join)(
2174
+ (0, import_node_path24.join)(
2124
2175
  baseDir,
2125
2176
  this.getSettablePaths().relativeDirPath,
2126
2177
  this.getSettablePaths().relativeFilePath
@@ -2330,10 +2381,10 @@ var IgnoreProcessor = class extends FeatureProcessor {
2330
2381
  var import_mini11 = require("zod/mini");
2331
2382
 
2332
2383
  // src/mcp/amazonqcli-mcp.ts
2333
- var import_node_path25 = require("path");
2384
+ var import_node_path26 = require("path");
2334
2385
 
2335
2386
  // src/mcp/rulesync-mcp.ts
2336
- var import_node_path24 = require("path");
2387
+ var import_node_path25 = require("path");
2337
2388
  var import_mini10 = require("zod/mini");
2338
2389
  var McpTransportTypeSchema = import_mini10.z.enum(["stdio", "sse", "http"]);
2339
2390
  var McpServerBaseSchema = import_mini10.z.object({
@@ -2384,7 +2435,7 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
2384
2435
  }
2385
2436
  static async fromFile({ validate = true }) {
2386
2437
  const fileContent = await readFileContent(
2387
- (0, import_node_path24.join)(this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath)
2438
+ (0, import_node_path25.join)(this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath)
2388
2439
  );
2389
2440
  return new _RulesyncMcp({
2390
2441
  baseDir: ".",
@@ -2451,7 +2502,7 @@ var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2451
2502
  validate = true
2452
2503
  }) {
2453
2504
  const fileContent = await readFileContent(
2454
- (0, import_node_path25.join)(
2505
+ (0, import_node_path26.join)(
2455
2506
  baseDir,
2456
2507
  this.getSettablePaths().relativeDirPath,
2457
2508
  this.getSettablePaths().relativeFilePath
@@ -2487,7 +2538,7 @@ var AmazonqcliMcp = class _AmazonqcliMcp extends ToolMcp {
2487
2538
  };
2488
2539
 
2489
2540
  // src/mcp/claudecode-mcp.ts
2490
- var import_node_path26 = require("path");
2541
+ var import_node_path27 = require("path");
2491
2542
  var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
2492
2543
  static getSettablePaths() {
2493
2544
  return {
@@ -2500,7 +2551,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
2500
2551
  validate = true
2501
2552
  }) {
2502
2553
  const fileContent = await readFileContent(
2503
- (0, import_node_path26.join)(
2554
+ (0, import_node_path27.join)(
2504
2555
  baseDir,
2505
2556
  this.getSettablePaths().relativeDirPath,
2506
2557
  this.getSettablePaths().relativeFilePath
@@ -2536,7 +2587,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
2536
2587
  };
2537
2588
 
2538
2589
  // src/mcp/cline-mcp.ts
2539
- var import_node_path27 = require("path");
2590
+ var import_node_path28 = require("path");
2540
2591
  var ClineMcp = class _ClineMcp extends ToolMcp {
2541
2592
  static getSettablePaths() {
2542
2593
  return {
@@ -2549,7 +2600,7 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
2549
2600
  validate = true
2550
2601
  }) {
2551
2602
  const fileContent = await readFileContent(
2552
- (0, import_node_path27.join)(
2603
+ (0, import_node_path28.join)(
2553
2604
  baseDir,
2554
2605
  this.getSettablePaths().relativeDirPath,
2555
2606
  this.getSettablePaths().relativeFilePath
@@ -2585,7 +2636,7 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
2585
2636
  };
2586
2637
 
2587
2638
  // src/mcp/copilot-mcp.ts
2588
- var import_node_path28 = require("path");
2639
+ var import_node_path29 = require("path");
2589
2640
  var CopilotMcp = class _CopilotMcp extends ToolMcp {
2590
2641
  static getSettablePaths() {
2591
2642
  return {
@@ -2598,7 +2649,7 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
2598
2649
  validate = true
2599
2650
  }) {
2600
2651
  const fileContent = await readFileContent(
2601
- (0, import_node_path28.join)(
2652
+ (0, import_node_path29.join)(
2602
2653
  baseDir,
2603
2654
  this.getSettablePaths().relativeDirPath,
2604
2655
  this.getSettablePaths().relativeFilePath
@@ -2634,7 +2685,7 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
2634
2685
  };
2635
2686
 
2636
2687
  // src/mcp/cursor-mcp.ts
2637
- var import_node_path29 = require("path");
2688
+ var import_node_path30 = require("path");
2638
2689
  var CursorMcp = class _CursorMcp extends ToolMcp {
2639
2690
  static getSettablePaths() {
2640
2691
  return {
@@ -2647,7 +2698,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
2647
2698
  validate = true
2648
2699
  }) {
2649
2700
  const fileContent = await readFileContent(
2650
- (0, import_node_path29.join)(
2701
+ (0, import_node_path30.join)(
2651
2702
  baseDir,
2652
2703
  this.getSettablePaths().relativeDirPath,
2653
2704
  this.getSettablePaths().relativeFilePath
@@ -2694,7 +2745,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
2694
2745
  };
2695
2746
 
2696
2747
  // src/mcp/roo-mcp.ts
2697
- var import_node_path30 = require("path");
2748
+ var import_node_path31 = require("path");
2698
2749
  var RooMcp = class _RooMcp extends ToolMcp {
2699
2750
  static getSettablePaths() {
2700
2751
  return {
@@ -2707,7 +2758,7 @@ var RooMcp = class _RooMcp extends ToolMcp {
2707
2758
  validate = true
2708
2759
  }) {
2709
2760
  const fileContent = await readFileContent(
2710
- (0, import_node_path30.join)(
2761
+ (0, import_node_path31.join)(
2711
2762
  baseDir,
2712
2763
  this.getSettablePaths().relativeDirPath,
2713
2764
  this.getSettablePaths().relativeFilePath
@@ -2918,14 +2969,6 @@ var import_node_path55 = require("path");
2918
2969
  var import_fast_xml_parser = require("fast-xml-parser");
2919
2970
  var import_mini20 = require("zod/mini");
2920
2971
 
2921
- // src/constants/paths.ts
2922
- var import_node_path31 = require("path");
2923
- var RULESYNC_DIR = ".rulesync";
2924
- var RULESYNC_RULES_DIR = (0, import_node_path31.join)(".rulesync", "rules");
2925
- var RULESYNC_RULES_DIR_LEGACY = ".rulesync";
2926
- var RULESYNC_MCP_FILE = (0, import_node_path31.join)(".rulesync", ".mcp.json");
2927
- var RULESYNC_SUBAGENTS_DIR = (0, import_node_path31.join)(".rulesync", "subagents");
2928
-
2929
2972
  // src/subagents/simulated-subagent.ts
2930
2973
  var import_node_path32 = require("path");
2931
2974
  var import_mini12 = require("zod/mini");
@@ -3225,7 +3268,7 @@ var RulesyncSubagent = class _RulesyncSubagent extends RulesyncFile {
3225
3268
  static async fromFile({
3226
3269
  relativeFilePath
3227
3270
  }) {
3228
- const fileContent = await readFileContent((0, import_node_path33.join)(RULESYNC_SUBAGENTS_DIR, relativeFilePath));
3271
+ const fileContent = await readFileContent((0, import_node_path33.join)(".rulesync/subagents", relativeFilePath));
3229
3272
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
3230
3273
  const result = RulesyncSubagentFrontmatterSchema.safeParse(frontmatter);
3231
3274
  if (!result.success) {
@@ -3759,6 +3802,12 @@ var ToolRule = class extends ToolFile {
3759
3802
  this.description = description;
3760
3803
  this.globs = globs;
3761
3804
  }
3805
+ static getSettablePaths() {
3806
+ throw new Error("Please implement this method in the subclass.");
3807
+ }
3808
+ static getSettablePathsGlobal() {
3809
+ throw new Error("Please implement this method in the subclass.");
3810
+ }
3762
3811
  static async fromFile(_params) {
3763
3812
  throw new Error("Please implement this method in the subclass.");
3764
3813
  }
@@ -3770,16 +3819,32 @@ var ToolRule = class extends ToolFile {
3770
3819
  rulesyncRule,
3771
3820
  validate = true,
3772
3821
  rootPath = { relativeDirPath: ".", relativeFilePath: "AGENTS.md" },
3773
- nonRootPath = { relativeDirPath: ".agents/memories" }
3822
+ nonRootPath
3774
3823
  }) {
3775
3824
  const fileContent = rulesyncRule.getBody();
3825
+ const isRoot = rulesyncRule.getFrontmatter().root ?? false;
3826
+ if (isRoot) {
3827
+ return {
3828
+ baseDir,
3829
+ relativeDirPath: rootPath.relativeDirPath,
3830
+ relativeFilePath: rootPath.relativeFilePath,
3831
+ fileContent,
3832
+ validate,
3833
+ root: true,
3834
+ description: rulesyncRule.getFrontmatter().description,
3835
+ globs: rulesyncRule.getFrontmatter().globs
3836
+ };
3837
+ }
3838
+ if (!nonRootPath) {
3839
+ throw new Error("nonRootPath is not set");
3840
+ }
3776
3841
  return {
3777
3842
  baseDir,
3778
- relativeDirPath: rulesyncRule.getFrontmatter().root ? rootPath.relativeDirPath : nonRootPath.relativeDirPath,
3779
- relativeFilePath: rulesyncRule.getFrontmatter().root ? rootPath.relativeFilePath : rulesyncRule.getRelativeFilePath(),
3843
+ relativeDirPath: nonRootPath.relativeDirPath,
3844
+ relativeFilePath: rulesyncRule.getRelativeFilePath(),
3780
3845
  fileContent,
3781
3846
  validate,
3782
- root: rulesyncRule.getFrontmatter().root ?? false,
3847
+ root: false,
3783
3848
  description: rulesyncRule.getFrontmatter().description,
3784
3849
  globs: rulesyncRule.getFrontmatter().globs
3785
3850
  };
@@ -3808,7 +3873,7 @@ var ToolRule = class extends ToolFile {
3808
3873
  toRulesyncRuleDefault() {
3809
3874
  return new RulesyncRule({
3810
3875
  baseDir: this.getBaseDir(),
3811
- relativeDirPath: RULESYNC_RULES_DIR,
3876
+ relativeDirPath: ".rulesync/rules",
3812
3877
  relativeFilePath: this.getRelativeFilePath(),
3813
3878
  frontmatter: {
3814
3879
  root: this.isRoot(),
@@ -3984,7 +4049,7 @@ var AugmentcodeLegacyRule = class _AugmentcodeLegacyRule extends ToolRule {
3984
4049
  baseDir: this.getBaseDir(),
3985
4050
  frontmatter: rulesyncFrontmatter,
3986
4051
  body: this.getFileContent(),
3987
- relativeDirPath: RULESYNC_RULES_DIR,
4052
+ relativeDirPath: ".rulesync/rules",
3988
4053
  relativeFilePath: this.getRelativeFilePath(),
3989
4054
  validate: true
3990
4055
  });
@@ -4109,39 +4174,68 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
4109
4174
  relativeFilePath: "CLAUDE.md"
4110
4175
  },
4111
4176
  nonRoot: {
4112
- relativeDirPath: ".claude/memories"
4177
+ relativeDirPath: (0, import_node_path42.join)(".claude", "memories")
4178
+ }
4179
+ };
4180
+ }
4181
+ static getSettablePathsGlobal() {
4182
+ return {
4183
+ root: {
4184
+ relativeDirPath: ".claude",
4185
+ relativeFilePath: "CLAUDE.md"
4113
4186
  }
4114
4187
  };
4115
4188
  }
4116
4189
  static async fromFile({
4117
4190
  baseDir = ".",
4118
4191
  relativeFilePath,
4119
- validate = true
4192
+ validate = true,
4193
+ global = false
4120
4194
  }) {
4121
- const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
4122
- const relativePath = isRoot ? this.getSettablePaths().root.relativeFilePath : (0, import_node_path42.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4195
+ const paths = global ? this.getSettablePathsGlobal() : this.getSettablePaths();
4196
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
4197
+ if (isRoot) {
4198
+ const relativePath2 = paths.root.relativeFilePath;
4199
+ const fileContent2 = await readFileContent(
4200
+ (0, import_node_path42.join)(baseDir, paths.root.relativeDirPath, relativePath2)
4201
+ );
4202
+ return new _ClaudecodeRule({
4203
+ baseDir,
4204
+ relativeDirPath: paths.root.relativeDirPath,
4205
+ relativeFilePath: paths.root.relativeFilePath,
4206
+ fileContent: fileContent2,
4207
+ validate,
4208
+ root: true
4209
+ });
4210
+ }
4211
+ if (!paths.nonRoot) {
4212
+ throw new Error("nonRoot path is not set");
4213
+ }
4214
+ const relativePath = (0, import_node_path42.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
4123
4215
  const fileContent = await readFileContent((0, import_node_path42.join)(baseDir, relativePath));
4124
4216
  return new _ClaudecodeRule({
4125
4217
  baseDir,
4126
- relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
4127
- relativeFilePath: isRoot ? this.getSettablePaths().root.relativeFilePath : relativeFilePath,
4218
+ relativeDirPath: paths.nonRoot.relativeDirPath,
4219
+ relativeFilePath,
4128
4220
  fileContent,
4129
4221
  validate,
4130
- root: isRoot
4222
+ root: false
4131
4223
  });
4132
4224
  }
4133
4225
  static fromRulesyncRule({
4134
4226
  baseDir = ".",
4135
4227
  rulesyncRule,
4136
- validate = true
4228
+ validate = true,
4229
+ global = false
4137
4230
  }) {
4231
+ const paths = global ? this.getSettablePathsGlobal() : this.getSettablePaths();
4138
4232
  return new _ClaudecodeRule(
4139
4233
  this.buildToolRuleParamsDefault({
4140
4234
  baseDir,
4141
4235
  rulesyncRule,
4142
4236
  validate,
4143
- rootPath: this.getSettablePaths().root,
4144
- nonRootPath: this.getSettablePaths().nonRoot
4237
+ rootPath: paths.root,
4238
+ nonRootPath: paths.nonRoot
4145
4239
  })
4146
4240
  );
4147
4241
  }
@@ -4231,35 +4325,64 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
4231
4325
  }
4232
4326
  };
4233
4327
  }
4328
+ static getSettablePathsGlobal() {
4329
+ return {
4330
+ root: {
4331
+ relativeDirPath: ".codex",
4332
+ relativeFilePath: "AGENTS.md"
4333
+ }
4334
+ };
4335
+ }
4234
4336
  static async fromFile({
4235
4337
  baseDir = ".",
4236
4338
  relativeFilePath,
4237
- validate = true
4339
+ validate = true,
4340
+ global = false
4238
4341
  }) {
4239
- const isRoot = relativeFilePath === "AGENTS.md";
4240
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path44.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
4342
+ const paths = global ? this.getSettablePathsGlobal() : this.getSettablePaths();
4343
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
4344
+ if (isRoot) {
4345
+ const relativePath2 = paths.root.relativeFilePath;
4346
+ const fileContent2 = await readFileContent(
4347
+ (0, import_node_path44.join)(baseDir, paths.root.relativeDirPath, relativePath2)
4348
+ );
4349
+ return new _CodexcliRule({
4350
+ baseDir,
4351
+ relativeDirPath: paths.root.relativeDirPath,
4352
+ relativeFilePath: paths.root.relativeFilePath,
4353
+ fileContent: fileContent2,
4354
+ validate,
4355
+ root: true
4356
+ });
4357
+ }
4358
+ if (!paths.nonRoot) {
4359
+ throw new Error("nonRoot path is not set");
4360
+ }
4361
+ const relativePath = (0, import_node_path44.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
4241
4362
  const fileContent = await readFileContent((0, import_node_path44.join)(baseDir, relativePath));
4242
4363
  return new _CodexcliRule({
4243
4364
  baseDir,
4244
- relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
4245
- relativeFilePath: isRoot ? "AGENTS.md" : relativeFilePath,
4365
+ relativeDirPath: paths.nonRoot.relativeDirPath,
4366
+ relativeFilePath,
4246
4367
  fileContent,
4247
4368
  validate,
4248
- root: isRoot
4369
+ root: false
4249
4370
  });
4250
4371
  }
4251
4372
  static fromRulesyncRule({
4252
4373
  baseDir = ".",
4253
4374
  rulesyncRule,
4254
- validate = true
4375
+ validate = true,
4376
+ global = false
4255
4377
  }) {
4378
+ const paths = global ? this.getSettablePathsGlobal() : this.getSettablePaths();
4256
4379
  return new _CodexcliRule(
4257
4380
  this.buildToolRuleParamsAgentsmd({
4258
4381
  baseDir,
4259
4382
  rulesyncRule,
4260
4383
  validate,
4261
- rootPath: this.getSettablePaths().root,
4262
- nonRootPath: this.getSettablePaths().nonRoot
4384
+ rootPath: paths.root,
4385
+ nonRootPath: paths.nonRoot
4263
4386
  })
4264
4387
  );
4265
4388
  }
@@ -4324,7 +4447,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
4324
4447
  baseDir: this.getBaseDir(),
4325
4448
  frontmatter: rulesyncFrontmatter,
4326
4449
  body: this.body,
4327
- relativeDirPath: RULESYNC_RULES_DIR,
4450
+ relativeDirPath: ".rulesync/rules",
4328
4451
  relativeFilePath: this.getRelativeFilePath(),
4329
4452
  validate: true
4330
4453
  });
@@ -5107,18 +5230,22 @@ var rulesProcessorToolTargets = [
5107
5230
  "windsurf"
5108
5231
  ];
5109
5232
  var RulesProcessorToolTargetSchema = import_mini20.z.enum(rulesProcessorToolTargets);
5233
+ var rulesProcessorToolTargetsGlobal = ["claudecode", "codexcli"];
5110
5234
  var RulesProcessor = class extends FeatureProcessor {
5111
5235
  toolTarget;
5112
5236
  simulateCommands;
5113
5237
  simulateSubagents;
5238
+ global;
5114
5239
  constructor({
5115
- baseDir = process.cwd(),
5240
+ baseDir = ".",
5116
5241
  toolTarget,
5117
5242
  simulateCommands = false,
5118
- simulateSubagents = false
5243
+ simulateSubagents = false,
5244
+ global = false
5119
5245
  }) {
5120
5246
  super({ baseDir });
5121
5247
  this.toolTarget = RulesProcessorToolTargetSchema.parse(toolTarget);
5248
+ this.global = global;
5122
5249
  this.simulateCommands = simulateCommands;
5123
5250
  this.simulateSubagents = simulateSubagents;
5124
5251
  }
@@ -5171,7 +5298,8 @@ var RulesProcessor = class extends FeatureProcessor {
5171
5298
  return ClaudecodeRule.fromRulesyncRule({
5172
5299
  baseDir: this.baseDir,
5173
5300
  rulesyncRule,
5174
- validate: true
5301
+ validate: true,
5302
+ global: this.global
5175
5303
  });
5176
5304
  case "cline":
5177
5305
  if (!ClineRule.isTargetedByRulesyncRule(rulesyncRule)) {
@@ -5189,7 +5317,8 @@ var RulesProcessor = class extends FeatureProcessor {
5189
5317
  return CodexcliRule.fromRulesyncRule({
5190
5318
  baseDir: this.baseDir,
5191
5319
  rulesyncRule,
5192
- validate: true
5320
+ validate: true,
5321
+ global: this.global
5193
5322
  });
5194
5323
  case "copilot":
5195
5324
  if (!CopilotRule.isTargetedByRulesyncRule(rulesyncRule)) {
@@ -5427,14 +5556,28 @@ var RulesProcessor = class extends FeatureProcessor {
5427
5556
  * Load and parse rulesync rule files from .rulesync/rules/ directory
5428
5557
  */
5429
5558
  async loadRulesyncFiles() {
5430
- const files = await findFilesByGlobs((0, import_node_path55.join)(RULESYNC_RULES_DIR, "*.md"));
5559
+ const files = await findFilesByGlobs((0, import_node_path55.join)(".rulesync/rules", "*.md"));
5431
5560
  logger.debug(`Found ${files.length} rulesync files`);
5432
- return Promise.all(
5561
+ const rulesyncRules = await Promise.all(
5433
5562
  files.map((file) => RulesyncRule.fromFile({ relativeFilePath: (0, import_node_path55.basename)(file) }))
5434
5563
  );
5564
+ const rootRules = rulesyncRules.filter((rule) => rule.getFrontmatter().root);
5565
+ if (rootRules.length > 1) {
5566
+ throw new Error("Multiple root rulesync rules found");
5567
+ }
5568
+ if (this.global) {
5569
+ const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root);
5570
+ if (nonRootRules.length > 0) {
5571
+ logger.warn(
5572
+ `${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them`
5573
+ );
5574
+ }
5575
+ return rootRules;
5576
+ }
5577
+ return rulesyncRules;
5435
5578
  }
5436
5579
  async loadRulesyncFilesLegacy() {
5437
- const legacyFiles = await findFilesByGlobs((0, import_node_path55.join)(RULESYNC_RULES_DIR_LEGACY, "*.md"));
5580
+ const legacyFiles = await findFilesByGlobs((0, import_node_path55.join)(".rulesync", "*.md"));
5438
5581
  logger.debug(`Found ${legacyFiles.length} legacy rulesync files`);
5439
5582
  return Promise.all(
5440
5583
  legacyFiles.map((file) => RulesyncRule.fromFileLegacy({ relativeFilePath: (0, import_node_path55.basename)(file) }))
@@ -5507,7 +5650,8 @@ var RulesProcessor = class extends FeatureProcessor {
5507
5650
  rootFilePaths.map(
5508
5651
  (filePath) => root.fromFile({
5509
5652
  baseDir: this.baseDir,
5510
- relativeFilePath: (0, import_node_path55.basename)(filePath)
5653
+ relativeFilePath: (0, import_node_path55.basename)(filePath),
5654
+ global: this.global
5511
5655
  })
5512
5656
  )
5513
5657
  );
@@ -5524,7 +5668,8 @@ var RulesProcessor = class extends FeatureProcessor {
5524
5668
  nonRootFilePaths.map(
5525
5669
  (filePath) => nonRoot.fromFile({
5526
5670
  baseDir: this.baseDir,
5527
- relativeFilePath: (0, import_node_path55.basename)(filePath)
5671
+ relativeFilePath: (0, import_node_path55.basename)(filePath),
5672
+ global: this.global
5528
5673
  })
5529
5674
  )
5530
5675
  );
@@ -5613,18 +5758,20 @@ var RulesProcessor = class extends FeatureProcessor {
5613
5758
  * Load Claude Code rule configuration from CLAUDE.md file
5614
5759
  */
5615
5760
  async loadClaudecodeRules() {
5616
- const settablePaths = ClaudecodeRule.getSettablePaths();
5617
- return await this.loadToolRulesDefault({
5761
+ const settablePaths = this.global ? ClaudecodeRule.getSettablePathsGlobal() : ClaudecodeRule.getSettablePaths();
5762
+ return this.loadToolRulesDefault({
5618
5763
  root: {
5619
5764
  relativeDirPath: settablePaths.root.relativeDirPath,
5620
5765
  relativeFilePath: settablePaths.root.relativeFilePath,
5621
5766
  fromFile: (params) => ClaudecodeRule.fromFile(params)
5622
5767
  },
5623
- nonRoot: {
5624
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5625
- fromFile: (params) => ClaudecodeRule.fromFile(params),
5626
- extension: "md"
5627
- }
5768
+ ...settablePaths.nonRoot ? {
5769
+ nonRoot: {
5770
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5771
+ fromFile: (params) => ClaudecodeRule.fromFile(params),
5772
+ extension: "md"
5773
+ }
5774
+ } : {}
5628
5775
  });
5629
5776
  }
5630
5777
  /**
@@ -5644,18 +5791,20 @@ var RulesProcessor = class extends FeatureProcessor {
5644
5791
  * Load OpenAI Codex CLI rule configuration from AGENTS.md and .codex/memories/*.md files
5645
5792
  */
5646
5793
  async loadCodexcliRules() {
5647
- const settablePaths = CodexcliRule.getSettablePaths();
5794
+ const settablePaths = this.global ? CodexcliRule.getSettablePathsGlobal() : CodexcliRule.getSettablePaths();
5648
5795
  return await this.loadToolRulesDefault({
5649
5796
  root: {
5650
5797
  relativeDirPath: settablePaths.root.relativeDirPath,
5651
5798
  relativeFilePath: settablePaths.root.relativeFilePath,
5652
5799
  fromFile: (params) => CodexcliRule.fromFile(params)
5653
5800
  },
5654
- nonRoot: {
5655
- relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5656
- fromFile: (params) => CodexcliRule.fromFile(params),
5657
- extension: "md"
5658
- }
5801
+ ...settablePaths.nonRoot ? {
5802
+ nonRoot: {
5803
+ relativeDirPath: settablePaths.nonRoot.relativeDirPath,
5804
+ fromFile: (params) => CodexcliRule.fromFile(params),
5805
+ extension: "md"
5806
+ }
5807
+ } : {}
5659
5808
  });
5660
5809
  }
5661
5810
  /**
@@ -5807,6 +5956,9 @@ var RulesProcessor = class extends FeatureProcessor {
5807
5956
  static getToolTargets() {
5808
5957
  return rulesProcessorToolTargets;
5809
5958
  }
5959
+ static getToolTargetsGlobal() {
5960
+ return rulesProcessorToolTargetsGlobal;
5961
+ }
5810
5962
  generateXmlReferencesSection(toolRules) {
5811
5963
  const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
5812
5964
  if (toolRulesWithoutRoot.length === 0) {
@@ -5911,52 +6063,76 @@ async function generateCommand(options) {
5911
6063
  process.exit(1);
5912
6064
  }
5913
6065
  logger.info(`Base directories: ${config.getBaseDirs().join(", ")}`);
6066
+ const totalRulesOutputs = await generateRules(config);
6067
+ const totalIgnoreOutputs = await generateIgnore(config);
6068
+ const totalMcpOutputs = await generateMcp(config);
6069
+ const totalCommandOutputs = await generateCommands(config);
6070
+ const totalSubagentOutputs = await generateSubagents(config);
6071
+ const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs;
6072
+ if (totalGenerated === 0) {
6073
+ const enabledFeatures = config.getFeatures().join(", ");
6074
+ logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
6075
+ return;
6076
+ }
6077
+ if (totalGenerated > 0) {
6078
+ const parts = [];
6079
+ if (totalRulesOutputs > 0) parts.push(`${totalRulesOutputs} rules`);
6080
+ if (totalIgnoreOutputs > 0) parts.push(`${totalIgnoreOutputs} ignore files`);
6081
+ if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
6082
+ if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
6083
+ if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
6084
+ logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
6085
+ }
6086
+ }
6087
+ async function generateRules(config) {
6088
+ if (!config.getFeatures().includes("rules")) {
6089
+ logger.debug("Skipping rule generation (not in --features)");
6090
+ return 0;
6091
+ }
5914
6092
  let totalRulesOutputs = 0;
5915
- if (config.getFeatures().includes("rules")) {
5916
- logger.info("Generating rule files...");
5917
- for (const baseDir of config.getBaseDirs()) {
5918
- for (const toolTarget of (0, import_es_toolkit2.intersection)(config.getTargets(), RulesProcessor.getToolTargets())) {
5919
- const processor = new RulesProcessor({
5920
- baseDir,
5921
- toolTarget,
5922
- simulateCommands: config.getExperimentalSimulateCommands(),
5923
- simulateSubagents: config.getExperimentalSimulateSubagents()
5924
- });
5925
- if (config.getDelete()) {
5926
- const oldToolFiles = await processor.loadToolFilesToDelete();
5927
- await processor.removeAiFiles(oldToolFiles);
5928
- }
5929
- let rulesyncFiles = await processor.loadRulesyncFiles();
5930
- if (rulesyncFiles.length === 0) {
5931
- rulesyncFiles = await processor.loadRulesyncFilesLegacy();
5932
- }
5933
- const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
5934
- const writtenCount = await processor.writeAiFiles(toolFiles);
5935
- totalRulesOutputs += writtenCount;
5936
- logger.success(`Generated ${writtenCount} ${toolTarget} rule(s) in ${baseDir}`);
6093
+ logger.info("Generating rule files...");
6094
+ const toolTargets = config.getExperimentalGlobal() ? (0, import_es_toolkit2.intersection)(config.getTargets(), RulesProcessor.getToolTargetsGlobal()) : (0, import_es_toolkit2.intersection)(config.getTargets(), RulesProcessor.getToolTargets());
6095
+ for (const baseDir of config.getBaseDirs()) {
6096
+ for (const toolTarget of toolTargets) {
6097
+ const processor = new RulesProcessor({
6098
+ baseDir,
6099
+ toolTarget,
6100
+ global: config.getExperimentalGlobal(),
6101
+ simulateCommands: config.getExperimentalSimulateCommands(),
6102
+ simulateSubagents: config.getExperimentalSimulateSubagents()
6103
+ });
6104
+ if (config.getDelete()) {
6105
+ const oldToolFiles = await processor.loadToolFilesToDelete();
6106
+ await processor.removeAiFiles(oldToolFiles);
6107
+ }
6108
+ let rulesyncFiles = await processor.loadRulesyncFiles();
6109
+ if (rulesyncFiles.length === 0) {
6110
+ rulesyncFiles = await processor.loadRulesyncFilesLegacy();
5937
6111
  }
6112
+ const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6113
+ const writtenCount = await processor.writeAiFiles(toolFiles);
6114
+ totalRulesOutputs += writtenCount;
6115
+ logger.success(`Generated ${writtenCount} ${toolTarget} rule(s) in ${baseDir}`);
5938
6116
  }
5939
- } else {
5940
- logger.info("Skipping rule generation (not in --features)");
5941
6117
  }
5942
- let totalMcpOutputs = 0;
5943
- if (config.getFeatures().includes("mcp")) {
5944
- logger.info("Generating MCP files...");
5945
- const supportedMcpTargets = [
5946
- "amazonqcli",
5947
- "claudecode",
5948
- "cline",
5949
- "copilot",
5950
- "cursor",
5951
- "roo"
5952
- ];
5953
- const mcpSupportedTargets = config.getTargets().filter((target) => {
5954
- return supportedMcpTargets.some((supportedTarget) => supportedTarget === target);
5955
- });
6118
+ return totalRulesOutputs;
6119
+ }
6120
+ async function generateIgnore(config) {
6121
+ if (!config.getFeatures().includes("ignore")) {
6122
+ logger.debug("Skipping ignore file generation (not in --features)");
6123
+ return 0;
6124
+ }
6125
+ if (config.getExperimentalGlobal()) {
6126
+ logger.debug("Skipping ignore file generation (not supported in global mode)");
6127
+ return 0;
6128
+ }
6129
+ let totalIgnoreOutputs = 0;
6130
+ logger.info("Generating ignore files...");
6131
+ for (const toolTarget of (0, import_es_toolkit2.intersection)(config.getTargets(), IgnoreProcessor.getToolTargets())) {
5956
6132
  for (const baseDir of config.getBaseDirs()) {
5957
- for (const toolTarget of (0, import_es_toolkit2.intersection)(mcpSupportedTargets, McpProcessor.getToolTargets())) {
5958
- const processor = new McpProcessor({
5959
- baseDir,
6133
+ try {
6134
+ const processor = new IgnoreProcessor({
6135
+ baseDir: baseDir === process.cwd() ? "." : baseDir,
5960
6136
  toolTarget
5961
6137
  });
5962
6138
  if (config.getDelete()) {
@@ -5964,117 +6140,133 @@ async function generateCommand(options) {
5964
6140
  await processor.removeAiFiles(oldToolFiles);
5965
6141
  }
5966
6142
  const rulesyncFiles = await processor.loadRulesyncFiles();
5967
- const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
5968
- const writtenCount = await processor.writeAiFiles(toolFiles);
5969
- totalMcpOutputs += writtenCount;
5970
- logger.success(
5971
- `Generated ${writtenCount} ${toolTarget} MCP configuration(s) in ${baseDir}`
6143
+ if (rulesyncFiles.length > 0) {
6144
+ const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6145
+ const writtenCount = await processor.writeAiFiles(toolFiles);
6146
+ totalIgnoreOutputs += writtenCount;
6147
+ logger.success(`Generated ${writtenCount} ${toolTarget} ignore file(s) in ${baseDir}`);
6148
+ }
6149
+ } catch (error) {
6150
+ logger.warn(
6151
+ `Failed to generate ${toolTarget} ignore files for ${baseDir}:`,
6152
+ error instanceof Error ? error.message : String(error)
5972
6153
  );
6154
+ continue;
5973
6155
  }
5974
6156
  }
5975
- } else {
5976
- logger.info("Skipping MCP configuration generation (not in --features)");
5977
6157
  }
5978
- let totalCommandOutputs = 0;
5979
- if (config.getFeatures().includes("commands")) {
5980
- logger.info("Generating command files...");
5981
- for (const baseDir of config.getBaseDirs()) {
5982
- for (const toolTarget of (0, import_es_toolkit2.intersection)(
5983
- config.getTargets(),
5984
- CommandsProcessor.getToolTargets({
5985
- includeSimulated: config.getExperimentalSimulateCommands()
5986
- })
5987
- )) {
5988
- const processor = new CommandsProcessor({
5989
- baseDir,
5990
- toolTarget
5991
- });
5992
- if (config.getDelete()) {
5993
- const oldToolFiles = await processor.loadToolFilesToDelete();
5994
- await processor.removeAiFiles(oldToolFiles);
5995
- }
5996
- const rulesyncFiles = await processor.loadRulesyncFiles();
5997
- const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
5998
- const writtenCount = await processor.writeAiFiles(toolFiles);
5999
- totalCommandOutputs += writtenCount;
6000
- logger.success(`Generated ${writtenCount} ${toolTarget} command(s) in ${baseDir}`);
6158
+ return totalIgnoreOutputs;
6159
+ }
6160
+ async function generateMcp(config) {
6161
+ if (!config.getFeatures().includes("mcp")) {
6162
+ logger.debug("Skipping MCP configuration generation (not in --features)");
6163
+ return 0;
6164
+ }
6165
+ if (config.getExperimentalGlobal()) {
6166
+ logger.debug("Skipping MCP configuration generation (not supported in global mode)");
6167
+ return 0;
6168
+ }
6169
+ let totalMcpOutputs = 0;
6170
+ logger.info("Generating MCP files...");
6171
+ const supportedMcpTargets = [
6172
+ "amazonqcli",
6173
+ "claudecode",
6174
+ "cline",
6175
+ "copilot",
6176
+ "cursor",
6177
+ "roo"
6178
+ ];
6179
+ const mcpSupportedTargets = config.getTargets().filter((target) => {
6180
+ return supportedMcpTargets.some((supportedTarget) => supportedTarget === target);
6181
+ });
6182
+ for (const baseDir of config.getBaseDirs()) {
6183
+ for (const toolTarget of (0, import_es_toolkit2.intersection)(mcpSupportedTargets, McpProcessor.getToolTargets())) {
6184
+ const processor = new McpProcessor({
6185
+ baseDir,
6186
+ toolTarget
6187
+ });
6188
+ if (config.getDelete()) {
6189
+ const oldToolFiles = await processor.loadToolFilesToDelete();
6190
+ await processor.removeAiFiles(oldToolFiles);
6001
6191
  }
6192
+ const rulesyncFiles = await processor.loadRulesyncFiles();
6193
+ const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6194
+ const writtenCount = await processor.writeAiFiles(toolFiles);
6195
+ totalMcpOutputs += writtenCount;
6196
+ logger.success(`Generated ${writtenCount} ${toolTarget} MCP configuration(s) in ${baseDir}`);
6002
6197
  }
6003
- } else {
6004
- logger.info("Skipping command file generation (not in --features)");
6005
6198
  }
6006
- let totalIgnoreOutputs = 0;
6007
- if (config.getFeatures().includes("ignore")) {
6008
- logger.info("Generating ignore files...");
6009
- for (const toolTarget of (0, import_es_toolkit2.intersection)(config.getTargets(), IgnoreProcessor.getToolTargets())) {
6010
- for (const baseDir of config.getBaseDirs()) {
6011
- try {
6012
- const processor = new IgnoreProcessor({
6013
- baseDir: baseDir === process.cwd() ? "." : baseDir,
6014
- toolTarget
6015
- });
6016
- if (config.getDelete()) {
6017
- const oldToolFiles = await processor.loadToolFilesToDelete();
6018
- await processor.removeAiFiles(oldToolFiles);
6019
- }
6020
- const rulesyncFiles = await processor.loadRulesyncFiles();
6021
- if (rulesyncFiles.length > 0) {
6022
- const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6023
- const writtenCount = await processor.writeAiFiles(toolFiles);
6024
- totalIgnoreOutputs += writtenCount;
6025
- logger.success(`Generated ${writtenCount} ${toolTarget} ignore file(s) in ${baseDir}`);
6026
- }
6027
- } catch (error) {
6028
- logger.warn(
6029
- `Failed to generate ${toolTarget} ignore files for ${baseDir}:`,
6030
- error instanceof Error ? error.message : String(error)
6031
- );
6032
- continue;
6033
- }
6199
+ return totalMcpOutputs;
6200
+ }
6201
+ async function generateCommands(config) {
6202
+ if (!config.getFeatures().includes("commands")) {
6203
+ logger.debug("Skipping command file generation (not in --features)");
6204
+ return 0;
6205
+ }
6206
+ if (config.getExperimentalGlobal()) {
6207
+ logger.debug("Skipping command file generation (not supported in global mode)");
6208
+ return 0;
6209
+ }
6210
+ let totalCommandOutputs = 0;
6211
+ logger.info("Generating command files...");
6212
+ for (const baseDir of config.getBaseDirs()) {
6213
+ for (const toolTarget of (0, import_es_toolkit2.intersection)(
6214
+ config.getTargets(),
6215
+ CommandsProcessor.getToolTargets({
6216
+ includeSimulated: config.getExperimentalSimulateCommands()
6217
+ })
6218
+ )) {
6219
+ const processor = new CommandsProcessor({
6220
+ baseDir,
6221
+ toolTarget
6222
+ });
6223
+ if (config.getDelete()) {
6224
+ const oldToolFiles = await processor.loadToolFilesToDelete();
6225
+ await processor.removeAiFiles(oldToolFiles);
6034
6226
  }
6227
+ const rulesyncFiles = await processor.loadRulesyncFiles();
6228
+ const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6229
+ const writtenCount = await processor.writeAiFiles(toolFiles);
6230
+ totalCommandOutputs += writtenCount;
6231
+ logger.success(`Generated ${writtenCount} ${toolTarget} command(s) in ${baseDir}`);
6035
6232
  }
6036
6233
  }
6234
+ return totalCommandOutputs;
6235
+ }
6236
+ async function generateSubagents(config) {
6237
+ if (!config.getFeatures().includes("subagents")) {
6238
+ logger.debug("Skipping subagent file generation (not in --features)");
6239
+ return 0;
6240
+ }
6241
+ if (config.getExperimentalGlobal()) {
6242
+ logger.debug("Skipping subagent file generation (not supported in global mode)");
6243
+ return 0;
6244
+ }
6037
6245
  let totalSubagentOutputs = 0;
6038
- if (config.getFeatures().includes("subagents")) {
6039
- logger.info("Generating subagent files...");
6040
- for (const baseDir of config.getBaseDirs()) {
6041
- for (const toolTarget of (0, import_es_toolkit2.intersection)(
6042
- config.getTargets(),
6043
- SubagentsProcessor.getToolTargets({
6044
- includeSimulated: config.getExperimentalSimulateSubagents()
6045
- })
6046
- )) {
6047
- const processor = new SubagentsProcessor({
6048
- baseDir,
6049
- toolTarget
6050
- });
6051
- if (config.getDelete()) {
6052
- const oldToolFiles = await processor.loadToolFilesToDelete();
6053
- await processor.removeAiFiles(oldToolFiles);
6054
- }
6055
- const rulesyncFiles = await processor.loadRulesyncFiles();
6056
- const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6057
- const writtenCount = await processor.writeAiFiles(toolFiles);
6058
- totalSubagentOutputs += writtenCount;
6059
- logger.success(`Generated ${writtenCount} ${toolTarget} subagent(s) in ${baseDir}`);
6246
+ logger.info("Generating subagent files...");
6247
+ for (const baseDir of config.getBaseDirs()) {
6248
+ for (const toolTarget of (0, import_es_toolkit2.intersection)(
6249
+ config.getTargets(),
6250
+ SubagentsProcessor.getToolTargets({
6251
+ includeSimulated: config.getExperimentalSimulateSubagents()
6252
+ })
6253
+ )) {
6254
+ const processor = new SubagentsProcessor({
6255
+ baseDir,
6256
+ toolTarget
6257
+ });
6258
+ if (config.getDelete()) {
6259
+ const oldToolFiles = await processor.loadToolFilesToDelete();
6260
+ await processor.removeAiFiles(oldToolFiles);
6060
6261
  }
6262
+ const rulesyncFiles = await processor.loadRulesyncFiles();
6263
+ const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
6264
+ const writtenCount = await processor.writeAiFiles(toolFiles);
6265
+ totalSubagentOutputs += writtenCount;
6266
+ logger.success(`Generated ${writtenCount} ${toolTarget} subagent(s) in ${baseDir}`);
6061
6267
  }
6062
6268
  }
6063
- const totalGenerated = totalRulesOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs;
6064
- if (totalGenerated === 0) {
6065
- const enabledFeatures = config.getFeatures().join(", ");
6066
- logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
6067
- return;
6068
- }
6069
- if (totalGenerated > 0) {
6070
- const parts = [];
6071
- if (totalRulesOutputs > 0) parts.push(`${totalRulesOutputs} rules`);
6072
- if (totalIgnoreOutputs > 0) parts.push(`${totalIgnoreOutputs} ignore files`);
6073
- if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP files`);
6074
- if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
6075
- if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
6076
- logger.success(`\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`);
6077
- }
6269
+ return totalSubagentOutputs;
6078
6270
  }
6079
6271
 
6080
6272
  // src/cli/commands/gitignore.ts
@@ -6171,116 +6363,186 @@ async function importCommand(options) {
6171
6363
  const config = await ConfigResolver.resolve(options);
6172
6364
  logger.setVerbose(config.getVerbose());
6173
6365
  const tool = config.getTargets()[0];
6174
- let rulesCreated = 0;
6175
- if (config.getFeatures().includes("rules")) {
6176
- if (RulesProcessor.getToolTargets().includes(tool)) {
6177
- const rulesProcessor = new RulesProcessor({
6178
- baseDir: ".",
6179
- toolTarget: tool
6180
- });
6181
- const toolFiles = await rulesProcessor.loadToolFiles();
6182
- if (toolFiles.length > 0) {
6183
- const rulesyncFiles = await rulesProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6184
- const writtenCount = await rulesProcessor.writeAiFiles(rulesyncFiles);
6185
- rulesCreated = writtenCount;
6186
- }
6187
- if (config.getVerbose() && rulesCreated > 0) {
6188
- logger.success(`Created ${rulesCreated} rule files`);
6189
- }
6190
- }
6366
+ await importRules(config, tool);
6367
+ await importIgnore(config, tool);
6368
+ await importMcp(config, tool);
6369
+ await importCommands(config, tool);
6370
+ await importSubagents(config, tool);
6371
+ }
6372
+ async function importRules(config, tool) {
6373
+ if (!config.getFeatures().includes("rules")) {
6374
+ return 0;
6375
+ }
6376
+ if (!RulesProcessor.getToolTargets().includes(tool)) {
6377
+ return 0;
6378
+ }
6379
+ const global = config.getExperimentalGlobal();
6380
+ if (global && !RulesProcessor.getToolTargetsGlobal().includes(tool)) {
6381
+ logger.error(`${tool} is not supported in global mode`);
6382
+ return 0;
6383
+ }
6384
+ const rulesProcessor = new RulesProcessor({
6385
+ baseDir: ".",
6386
+ toolTarget: tool,
6387
+ global
6388
+ });
6389
+ const toolFiles = await rulesProcessor.loadToolFiles();
6390
+ if (toolFiles.length === 0) {
6391
+ return 0;
6191
6392
  }
6192
- let ignoreFileCreated = 0;
6193
- if (config.getFeatures().includes("ignore")) {
6194
- if (IgnoreProcessor.getToolTargets().includes(tool)) {
6195
- const ignoreProcessor = new IgnoreProcessor({
6196
- baseDir: ".",
6197
- toolTarget: tool
6198
- });
6199
- const toolFiles = await ignoreProcessor.loadToolFiles();
6200
- if (toolFiles.length > 0) {
6201
- const rulesyncFiles = await ignoreProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6202
- const writtenCount = await ignoreProcessor.writeAiFiles(rulesyncFiles);
6203
- ignoreFileCreated = writtenCount;
6204
- if (config.getVerbose()) {
6205
- logger.success(
6206
- `Created ignore files from ${toolFiles.length} tool ignore configurations`
6207
- );
6208
- }
6209
- }
6210
- }
6211
- if (config.getVerbose() && ignoreFileCreated > 0) {
6212
- logger.success(`Created ${ignoreFileCreated} ignore files`);
6213
- }
6393
+ const rulesyncFiles = await rulesProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6394
+ const writtenCount = await rulesProcessor.writeAiFiles(rulesyncFiles);
6395
+ if (config.getVerbose() && writtenCount > 0) {
6396
+ logger.success(`Created ${writtenCount} rule files`);
6214
6397
  }
6215
- let mcpCreated = 0;
6216
- if (config.getFeatures().includes("mcp")) {
6217
- if (McpProcessor.getToolTargets().includes(tool)) {
6218
- const mcpProcessor = new McpProcessor({
6219
- baseDir: ".",
6220
- toolTarget: tool
6221
- });
6222
- const toolFiles = await mcpProcessor.loadToolFiles();
6223
- if (toolFiles.length > 0) {
6224
- const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6225
- const writtenCount = await mcpProcessor.writeAiFiles(rulesyncFiles);
6226
- mcpCreated = writtenCount;
6227
- }
6228
- }
6398
+ return writtenCount;
6399
+ }
6400
+ async function importIgnore(config, tool) {
6401
+ if (!config.getFeatures().includes("ignore")) {
6402
+ return 0;
6229
6403
  }
6230
- if (config.getVerbose() && mcpCreated > 0) {
6231
- logger.success(`Created ${mcpCreated} MCP files`);
6404
+ if (config.getExperimentalGlobal()) {
6405
+ logger.debug("Skipping ignore file import (not supported in global mode)");
6406
+ return 0;
6232
6407
  }
6233
- let subagentsCreated = 0;
6234
- if (config.getFeatures().includes("subagents")) {
6235
- const supportedTargets = SubagentsProcessor.getToolTargets({ includeSimulated: false });
6236
- if (supportedTargets.includes(tool)) {
6237
- const subagentsProcessor = new SubagentsProcessor({
6238
- baseDir: ".",
6239
- toolTarget: tool
6240
- });
6241
- const toolFiles = await subagentsProcessor.loadToolFiles();
6242
- if (toolFiles.length > 0) {
6243
- const rulesyncFiles = await subagentsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6244
- const writtenCount = await subagentsProcessor.writeAiFiles(rulesyncFiles);
6245
- subagentsCreated += writtenCount;
6246
- }
6247
- }
6248
- if (config.getVerbose() && subagentsCreated > 0) {
6249
- logger.success(`Created ${subagentsCreated} subagent files`);
6250
- }
6408
+ if (!IgnoreProcessor.getToolTargets().includes(tool)) {
6409
+ return 0;
6251
6410
  }
6252
- let commandsCreated = 0;
6253
- if (config.getFeatures().includes("commands")) {
6254
- const supportedTargets = CommandsProcessor.getToolTargets({ includeSimulated: false });
6255
- if (supportedTargets.includes(tool)) {
6256
- const commandsProcessor = new CommandsProcessor({
6257
- baseDir: ".",
6258
- toolTarget: tool
6259
- });
6260
- const toolFiles = await commandsProcessor.loadToolFiles();
6261
- if (toolFiles.length > 0) {
6262
- const rulesyncFiles = await commandsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6263
- const writtenCount = await commandsProcessor.writeAiFiles(rulesyncFiles);
6264
- commandsCreated = writtenCount;
6265
- }
6266
- }
6267
- if (config.getVerbose() && commandsCreated > 0) {
6268
- logger.success(`Created ${commandsCreated} command files`);
6269
- }
6411
+ const ignoreProcessor = new IgnoreProcessor({
6412
+ baseDir: ".",
6413
+ toolTarget: tool
6414
+ });
6415
+ const toolFiles = await ignoreProcessor.loadToolFiles();
6416
+ if (toolFiles.length === 0) {
6417
+ return 0;
6418
+ }
6419
+ const rulesyncFiles = await ignoreProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6420
+ const writtenCount = await ignoreProcessor.writeAiFiles(rulesyncFiles);
6421
+ if (config.getVerbose()) {
6422
+ logger.success(`Created ignore files from ${toolFiles.length} tool ignore configurations`);
6423
+ }
6424
+ if (config.getVerbose() && writtenCount > 0) {
6425
+ logger.success(`Created ${writtenCount} ignore files`);
6426
+ }
6427
+ return writtenCount;
6428
+ }
6429
+ async function importMcp(config, tool) {
6430
+ if (!config.getFeatures().includes("mcp")) {
6431
+ return 0;
6432
+ }
6433
+ if (config.getExperimentalGlobal()) {
6434
+ logger.debug("Skipping MCP file import (not supported in global mode)");
6435
+ return 0;
6436
+ }
6437
+ if (!McpProcessor.getToolTargets().includes(tool)) {
6438
+ return 0;
6439
+ }
6440
+ const mcpProcessor = new McpProcessor({
6441
+ baseDir: ".",
6442
+ toolTarget: tool
6443
+ });
6444
+ const toolFiles = await mcpProcessor.loadToolFiles();
6445
+ if (toolFiles.length === 0) {
6446
+ return 0;
6270
6447
  }
6448
+ const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6449
+ const writtenCount = await mcpProcessor.writeAiFiles(rulesyncFiles);
6450
+ if (config.getVerbose() && writtenCount > 0) {
6451
+ logger.success(`Created ${writtenCount} MCP files`);
6452
+ }
6453
+ return writtenCount;
6454
+ }
6455
+ async function importCommands(config, tool) {
6456
+ if (!config.getFeatures().includes("commands")) {
6457
+ return 0;
6458
+ }
6459
+ if (config.getExperimentalGlobal()) {
6460
+ logger.debug("Skipping command file import (not supported in global mode)");
6461
+ return 0;
6462
+ }
6463
+ const supportedTargets = CommandsProcessor.getToolTargets({ includeSimulated: false });
6464
+ if (!supportedTargets.includes(tool)) {
6465
+ return 0;
6466
+ }
6467
+ const commandsProcessor = new CommandsProcessor({
6468
+ baseDir: ".",
6469
+ toolTarget: tool
6470
+ });
6471
+ const toolFiles = await commandsProcessor.loadToolFiles();
6472
+ if (toolFiles.length === 0) {
6473
+ return 0;
6474
+ }
6475
+ const rulesyncFiles = await commandsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6476
+ const writtenCount = await commandsProcessor.writeAiFiles(rulesyncFiles);
6477
+ if (config.getVerbose() && writtenCount > 0) {
6478
+ logger.success(`Created ${writtenCount} command files`);
6479
+ }
6480
+ return writtenCount;
6481
+ }
6482
+ async function importSubagents(config, tool) {
6483
+ if (!config.getFeatures().includes("subagents")) {
6484
+ return 0;
6485
+ }
6486
+ if (config.getExperimentalGlobal()) {
6487
+ logger.debug("Skipping subagent file import (not supported in global mode)");
6488
+ return 0;
6489
+ }
6490
+ const supportedTargets = SubagentsProcessor.getToolTargets({ includeSimulated: false });
6491
+ if (!supportedTargets.includes(tool)) {
6492
+ return 0;
6493
+ }
6494
+ const subagentsProcessor = new SubagentsProcessor({
6495
+ baseDir: ".",
6496
+ toolTarget: tool
6497
+ });
6498
+ const toolFiles = await subagentsProcessor.loadToolFiles();
6499
+ if (toolFiles.length === 0) {
6500
+ return 0;
6501
+ }
6502
+ const rulesyncFiles = await subagentsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
6503
+ const writtenCount = await subagentsProcessor.writeAiFiles(rulesyncFiles);
6504
+ if (config.getVerbose() && writtenCount > 0) {
6505
+ logger.success(`Created ${writtenCount} subagent files`);
6506
+ }
6507
+ return writtenCount;
6271
6508
  }
6272
6509
 
6273
6510
  // src/cli/commands/init.ts
6274
6511
  var import_node_path57 = require("path");
6275
6512
  async function initCommand() {
6276
6513
  logger.info("Initializing rulesync...");
6277
- await ensureDir(RULESYNC_DIR);
6514
+ await ensureDir(".rulesync");
6278
6515
  await createSampleFiles();
6516
+ await createConfigFile();
6279
6517
  logger.success("rulesync initialized successfully!");
6280
6518
  logger.info("Next steps:");
6281
- logger.info(`1. Edit rule files in ${RULESYNC_RULES_DIR}/`);
6519
+ logger.info(`1. Edit rule files in .rulesync/rules/`);
6282
6520
  logger.info("2. Run 'rulesync generate' to create configuration files");
6283
6521
  }
6522
+ async function createConfigFile() {
6523
+ if (await fileExists("rulesync.jsonc")) {
6524
+ logger.info("Skipped rulesync.jsonc (already exists)");
6525
+ return;
6526
+ }
6527
+ await writeFileContent(
6528
+ "rulesync.jsonc",
6529
+ JSON.stringify(
6530
+ {
6531
+ targets: ["copilot", "cursor", "claudecode", "codexcli"],
6532
+ features: ["rules", "ignore", "mcp", "commands", "subagents"],
6533
+ baseDirs: ["."],
6534
+ delete: true,
6535
+ verbose: false,
6536
+ experimentalGlobal: false,
6537
+ experimentalSimulateCommands: false,
6538
+ experimentalSimulateSubagents: false
6539
+ },
6540
+ null,
6541
+ 2
6542
+ )
6543
+ );
6544
+ logger.success("Created rulesync.jsonc");
6545
+ }
6284
6546
  async function createSampleFiles() {
6285
6547
  const sampleFile = {
6286
6548
  filename: "overview.md",
@@ -6317,10 +6579,10 @@ globs: ["**/*"]
6317
6579
  - Follow single responsibility principle
6318
6580
  `
6319
6581
  };
6320
- const filepath = (0, import_node_path57.join)(RULESYNC_RULES_DIR, sampleFile.filename);
6321
- await ensureDir(RULESYNC_RULES_DIR);
6582
+ const filepath = (0, import_node_path57.join)(".rulesync/rules", sampleFile.filename);
6583
+ await ensureDir(".rulesync/rules");
6322
6584
  await ensureDir(RulesyncCommand.getSettablePaths().relativeDirPath);
6323
- await ensureDir(RULESYNC_SUBAGENTS_DIR);
6585
+ await ensureDir(".rulesync/subagents");
6324
6586
  if (!await fileExists(filepath)) {
6325
6587
  await writeFileContent(filepath, sampleFile.content);
6326
6588
  logger.success(`Created ${filepath}`);
@@ -6330,7 +6592,7 @@ globs: ["**/*"]
6330
6592
  }
6331
6593
 
6332
6594
  // src/cli/index.ts
6333
- var getVersion = () => "1.2.5";
6595
+ var getVersion = () => "2.0.0";
6334
6596
  var main = async () => {
6335
6597
  const program = new import_commander.Command();
6336
6598
  const version = getVersion();
@@ -6354,7 +6616,7 @@ var main = async () => {
6354
6616
  (value) => {
6355
6617
  return value.split(",").map((f) => f.trim());
6356
6618
  }
6357
- ).option("-V, --verbose", "Verbose output").action(async (options) => {
6619
+ ).option("-V, --verbose", "Verbose output").option("-g, --experimental-global", "Import for global(user scope) configuration files").action(async (options) => {
6358
6620
  try {
6359
6621
  await importCommand({
6360
6622
  targets: options.targets,
@@ -6367,7 +6629,7 @@ var main = async () => {
6367
6629
  process.exit(1);
6368
6630
  }
6369
6631
  });
6370
- program.command("generate").description("Generate configuration files for AI tools").option("--all", "[DEPRECATED] Generate for all supported AI tools (use --targets * instead)").option(
6632
+ program.command("generate").description("Generate configuration files for AI tools").option(
6371
6633
  "-t, --targets <tools>",
6372
6634
  "Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)",
6373
6635
  (value) => {
@@ -6382,7 +6644,7 @@ var main = async () => {
6382
6644
  ).option("--delete", "Delete all existing files in output directories before generating").option(
6383
6645
  "-b, --base-dir <paths>",
6384
6646
  "Base directories to generate files (comma-separated for multiple paths)"
6385
- ).option("-V, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option(
6647
+ ).option("-V, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("-g, --experimental-global", "Generate for global(user scope) configuration files").option(
6386
6648
  "--experimental-simulate-commands",
6387
6649
  "Generate simulated commands (experimental feature). This feature is only available for copilot, cursor and codexcli."
6388
6650
  ).option(
@@ -6397,6 +6659,7 @@ var main = async () => {
6397
6659
  delete: options.delete,
6398
6660
  baseDirs: options.baseDirs,
6399
6661
  configPath: options.config,
6662
+ experimentalGlobal: options.experimentalGlobal,
6400
6663
  experimentalSimulateCommands: options.experimentalSimulateCommands,
6401
6664
  experimentalSimulateSubagents: options.experimentalSimulateSubagents
6402
6665
  });
@@ -6405,7 +6668,6 @@ var main = async () => {
6405
6668
  process.exit(1);
6406
6669
  }
6407
6670
  });
6408
- program.command("config").description("Show or initialize rulesync configuration").option("--init", "Initialize a new configuration file").action(configCommand);
6409
6671
  program.parse();
6410
6672
  };
6411
6673
  main().catch((error) => {