rulesync 7.3.0 → 7.5.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.
@@ -675,7 +675,7 @@ var SimulatedCommand = class _SimulatedCommand extends ToolCommand {
675
675
  return {
676
676
  baseDir,
677
677
  relativeDirPath: _SimulatedCommand.getSettablePaths().relativeDirPath,
678
- relativeFilePath: (0, import_node_path4.basename)(relativeFilePath),
678
+ relativeFilePath,
679
679
  frontmatter: result.data,
680
680
  body: content.trim(),
681
681
  validate
@@ -732,7 +732,7 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
732
732
  return new _AgentsmdCommand({
733
733
  baseDir,
734
734
  relativeDirPath: _AgentsmdCommand.getSettablePaths().relativeDirPath,
735
- relativeFilePath: (0, import_node_path5.basename)(relativeFilePath),
735
+ relativeFilePath,
736
736
  frontmatter: result.data,
737
737
  body: content.trim(),
738
738
  validate
@@ -841,6 +841,16 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
841
841
  getBody() {
842
842
  return this.body;
843
843
  }
844
+ withRelativeFilePath(newRelativeFilePath) {
845
+ return new _RulesyncCommand({
846
+ baseDir: this.getBaseDir(),
847
+ relativeDirPath: this.getRelativeDirPath(),
848
+ relativeFilePath: newRelativeFilePath,
849
+ frontmatter: this.getFrontmatter(),
850
+ body: this.getBody(),
851
+ fileContent: this.getFileContent()
852
+ });
853
+ }
844
854
  validate() {
845
855
  if (!this.frontmatter) {
846
856
  return { success: true, error: null };
@@ -871,11 +881,10 @@ var RulesyncCommand = class _RulesyncCommand extends RulesyncFile {
871
881
  if (!result.success) {
872
882
  throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
873
883
  }
874
- const filename = (0, import_node_path6.basename)(relativeFilePath);
875
884
  return new _RulesyncCommand({
876
885
  baseDir: process.cwd(),
877
886
  relativeDirPath: _RulesyncCommand.getSettablePaths().relativeDirPath,
878
- relativeFilePath: filename,
887
+ relativeFilePath,
879
888
  frontmatter: result.data,
880
889
  body: content.trim(),
881
890
  fileContent
@@ -1034,7 +1043,7 @@ ${body}${turboDirective}`;
1034
1043
  return new _AntigravityCommand({
1035
1044
  baseDir,
1036
1045
  relativeDirPath: _AntigravityCommand.getSettablePaths().relativeDirPath,
1037
- relativeFilePath: (0, import_node_path7.basename)(relativeFilePath),
1046
+ relativeFilePath,
1038
1047
  frontmatter: result.data,
1039
1048
  body: content.trim(),
1040
1049
  fileContent,
@@ -1180,7 +1189,7 @@ var ClaudecodeCommand = class _ClaudecodeCommand extends ToolCommand {
1180
1189
  return new _ClaudecodeCommand({
1181
1190
  baseDir,
1182
1191
  relativeDirPath: paths.relativeDirPath,
1183
- relativeFilePath: (0, import_node_path8.basename)(relativeFilePath),
1192
+ relativeFilePath,
1184
1193
  frontmatter: result.data,
1185
1194
  body: content.trim(),
1186
1195
  validate
@@ -1270,7 +1279,7 @@ var ClineCommand = class _ClineCommand extends ToolCommand {
1270
1279
  return new _ClineCommand({
1271
1280
  baseDir,
1272
1281
  relativeDirPath: paths.relativeDirPath,
1273
- relativeFilePath: (0, import_node_path9.basename)(relativeFilePath),
1282
+ relativeFilePath,
1274
1283
  fileContent: content.trim(),
1275
1284
  validate
1276
1285
  });
@@ -1357,7 +1366,7 @@ var CodexcliCommand = class _CodexcliCommand extends ToolCommand {
1357
1366
  return new _CodexcliCommand({
1358
1367
  baseDir,
1359
1368
  relativeDirPath: paths.relativeDirPath,
1360
- relativeFilePath: (0, import_node_path10.basename)(relativeFilePath),
1369
+ relativeFilePath,
1361
1370
  fileContent: content.trim(),
1362
1371
  validate
1363
1372
  });
@@ -1490,7 +1499,7 @@ var CopilotCommand = class _CopilotCommand extends ToolCommand {
1490
1499
  return new _CopilotCommand({
1491
1500
  baseDir,
1492
1501
  relativeDirPath: paths.relativeDirPath,
1493
- relativeFilePath: (0, import_node_path11.basename)(relativeFilePath),
1502
+ relativeFilePath,
1494
1503
  frontmatter: result.data,
1495
1504
  body: content.trim(),
1496
1505
  validate
@@ -1582,7 +1591,7 @@ var CursorCommand = class _CursorCommand extends ToolCommand {
1582
1591
  return new _CursorCommand({
1583
1592
  baseDir,
1584
1593
  relativeDirPath: paths.relativeDirPath,
1585
- relativeFilePath: (0, import_node_path12.basename)(relativeFilePath),
1594
+ relativeFilePath,
1586
1595
  fileContent: content.trim(),
1587
1596
  validate
1588
1597
  });
@@ -1637,7 +1646,7 @@ var FactorydroidCommand = class _FactorydroidCommand extends SimulatedCommand {
1637
1646
  return new _FactorydroidCommand({
1638
1647
  baseDir,
1639
1648
  relativeDirPath: paths.relativeDirPath,
1640
- relativeFilePath: (0, import_node_path13.basename)(relativeFilePath),
1649
+ relativeFilePath,
1641
1650
  frontmatter: result.data,
1642
1651
  body: content.trim(),
1643
1652
  validate
@@ -1769,7 +1778,7 @@ ${geminiFrontmatter.prompt}
1769
1778
  return new _GeminiCliCommand({
1770
1779
  baseDir,
1771
1780
  relativeDirPath: paths.relativeDirPath,
1772
- relativeFilePath: (0, import_node_path14.basename)(relativeFilePath),
1781
+ relativeFilePath,
1773
1782
  fileContent,
1774
1783
  validate
1775
1784
  });
@@ -1866,7 +1875,7 @@ var KiloCommand = class _KiloCommand extends ToolCommand {
1866
1875
  return new _KiloCommand({
1867
1876
  baseDir,
1868
1877
  relativeDirPath: paths.relativeDirPath,
1869
- relativeFilePath: (0, import_node_path15.basename)(relativeFilePath),
1878
+ relativeFilePath,
1870
1879
  fileContent: content.trim(),
1871
1880
  validate
1872
1881
  });
@@ -1947,7 +1956,7 @@ var KiroCommand = class _KiroCommand extends ToolCommand {
1947
1956
  return new _KiroCommand({
1948
1957
  baseDir,
1949
1958
  relativeDirPath: paths.relativeDirPath,
1950
- relativeFilePath: (0, import_node_path16.basename)(relativeFilePath),
1959
+ relativeFilePath,
1951
1960
  fileContent: content.trim(),
1952
1961
  validate
1953
1962
  });
@@ -2079,7 +2088,7 @@ var OpenCodeCommand = class _OpenCodeCommand extends ToolCommand {
2079
2088
  return new _OpenCodeCommand({
2080
2089
  baseDir,
2081
2090
  relativeDirPath: paths.relativeDirPath,
2082
- relativeFilePath: (0, import_node_path17.basename)(relativeFilePath),
2091
+ relativeFilePath,
2083
2092
  frontmatter: result.data,
2084
2093
  body: content.trim(),
2085
2094
  validate
@@ -2224,7 +2233,7 @@ var RooCommand = class _RooCommand extends ToolCommand {
2224
2233
  return new _RooCommand({
2225
2234
  baseDir,
2226
2235
  relativeDirPath: _RooCommand.getSettablePaths().relativeDirPath,
2227
- relativeFilePath: (0, import_node_path18.basename)(relativeFilePath),
2236
+ relativeFilePath,
2228
2237
  frontmatter: result.data,
2229
2238
  body: content.trim(),
2230
2239
  fileContent,
@@ -2271,42 +2280,78 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2271
2280
  "agentsmd",
2272
2281
  {
2273
2282
  class: AgentsmdCommand,
2274
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: true }
2283
+ meta: {
2284
+ extension: "md",
2285
+ supportsProject: true,
2286
+ supportsGlobal: false,
2287
+ isSimulated: true,
2288
+ supportsSubdirectory: false
2289
+ }
2275
2290
  }
2276
2291
  ],
2277
2292
  [
2278
2293
  "antigravity",
2279
2294
  {
2280
2295
  class: AntigravityCommand,
2281
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2296
+ meta: {
2297
+ extension: "md",
2298
+ supportsProject: true,
2299
+ supportsGlobal: false,
2300
+ isSimulated: false,
2301
+ supportsSubdirectory: false
2302
+ }
2282
2303
  }
2283
2304
  ],
2284
2305
  [
2285
2306
  "claudecode",
2286
2307
  {
2287
2308
  class: ClaudecodeCommand,
2288
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2309
+ meta: {
2310
+ extension: "md",
2311
+ supportsProject: true,
2312
+ supportsGlobal: true,
2313
+ isSimulated: false,
2314
+ supportsSubdirectory: true
2315
+ }
2289
2316
  }
2290
2317
  ],
2291
2318
  [
2292
2319
  "claudecode-legacy",
2293
2320
  {
2294
2321
  class: ClaudecodeCommand,
2295
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2322
+ meta: {
2323
+ extension: "md",
2324
+ supportsProject: true,
2325
+ supportsGlobal: true,
2326
+ isSimulated: false,
2327
+ supportsSubdirectory: true
2328
+ }
2296
2329
  }
2297
2330
  ],
2298
2331
  [
2299
2332
  "cline",
2300
2333
  {
2301
2334
  class: ClineCommand,
2302
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2335
+ meta: {
2336
+ extension: "md",
2337
+ supportsProject: true,
2338
+ supportsGlobal: true,
2339
+ isSimulated: false,
2340
+ supportsSubdirectory: false
2341
+ }
2303
2342
  }
2304
2343
  ],
2305
2344
  [
2306
2345
  "codexcli",
2307
2346
  {
2308
2347
  class: CodexcliCommand,
2309
- meta: { extension: "md", supportsProject: false, supportsGlobal: true, isSimulated: false }
2348
+ meta: {
2349
+ extension: "md",
2350
+ supportsProject: false,
2351
+ supportsGlobal: true,
2352
+ isSimulated: false,
2353
+ supportsSubdirectory: false
2354
+ }
2310
2355
  }
2311
2356
  ],
2312
2357
  [
@@ -2317,7 +2362,8 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2317
2362
  extension: "prompt.md",
2318
2363
  supportsProject: true,
2319
2364
  supportsGlobal: false,
2320
- isSimulated: false
2365
+ isSimulated: false,
2366
+ supportsSubdirectory: false
2321
2367
  }
2322
2368
  }
2323
2369
  ],
@@ -2325,49 +2371,91 @@ var toolCommandFactories = /* @__PURE__ */ new Map([
2325
2371
  "cursor",
2326
2372
  {
2327
2373
  class: CursorCommand,
2328
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2374
+ meta: {
2375
+ extension: "md",
2376
+ supportsProject: true,
2377
+ supportsGlobal: true,
2378
+ isSimulated: false,
2379
+ supportsSubdirectory: false
2380
+ }
2329
2381
  }
2330
2382
  ],
2331
2383
  [
2332
2384
  "factorydroid",
2333
2385
  {
2334
2386
  class: FactorydroidCommand,
2335
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: true }
2387
+ meta: {
2388
+ extension: "md",
2389
+ supportsProject: true,
2390
+ supportsGlobal: true,
2391
+ isSimulated: true,
2392
+ supportsSubdirectory: false
2393
+ }
2336
2394
  }
2337
2395
  ],
2338
2396
  [
2339
2397
  "geminicli",
2340
2398
  {
2341
2399
  class: GeminiCliCommand,
2342
- meta: { extension: "toml", supportsProject: true, supportsGlobal: true, isSimulated: false }
2400
+ meta: {
2401
+ extension: "toml",
2402
+ supportsProject: true,
2403
+ supportsGlobal: true,
2404
+ isSimulated: false,
2405
+ supportsSubdirectory: true
2406
+ }
2343
2407
  }
2344
2408
  ],
2345
2409
  [
2346
2410
  "kilo",
2347
2411
  {
2348
2412
  class: KiloCommand,
2349
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2413
+ meta: {
2414
+ extension: "md",
2415
+ supportsProject: true,
2416
+ supportsGlobal: true,
2417
+ isSimulated: false,
2418
+ supportsSubdirectory: false
2419
+ }
2350
2420
  }
2351
2421
  ],
2352
2422
  [
2353
2423
  "kiro",
2354
2424
  {
2355
2425
  class: KiroCommand,
2356
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2426
+ meta: {
2427
+ extension: "md",
2428
+ supportsProject: true,
2429
+ supportsGlobal: false,
2430
+ isSimulated: false,
2431
+ supportsSubdirectory: false
2432
+ }
2357
2433
  }
2358
2434
  ],
2359
2435
  [
2360
2436
  "opencode",
2361
2437
  {
2362
2438
  class: OpenCodeCommand,
2363
- meta: { extension: "md", supportsProject: true, supportsGlobal: true, isSimulated: false }
2439
+ meta: {
2440
+ extension: "md",
2441
+ supportsProject: true,
2442
+ supportsGlobal: true,
2443
+ isSimulated: false,
2444
+ supportsSubdirectory: true
2445
+ }
2364
2446
  }
2365
2447
  ],
2366
2448
  [
2367
2449
  "roo",
2368
2450
  {
2369
2451
  class: RooCommand,
2370
- meta: { extension: "md", supportsProject: true, supportsGlobal: false, isSimulated: false }
2452
+ meta: {
2453
+ extension: "md",
2454
+ supportsProject: true,
2455
+ supportsGlobal: false,
2456
+ isSimulated: false,
2457
+ supportsSubdirectory: true
2458
+ }
2371
2459
  }
2372
2460
  ]
2373
2461
  ]);
@@ -2420,13 +2508,27 @@ var CommandsProcessor = class extends FeatureProcessor {
2420
2508
  (file) => file instanceof RulesyncCommand
2421
2509
  );
2422
2510
  const factory = this.getFactory(this.toolTarget);
2511
+ const flattenedPathOrigins = /* @__PURE__ */ new Map();
2423
2512
  const toolCommands = rulesyncCommands.map((rulesyncCommand) => {
2424
2513
  if (!factory.class.isTargetedByRulesyncCommand(rulesyncCommand)) {
2425
2514
  return null;
2426
2515
  }
2516
+ const originalRelativePath = rulesyncCommand.getRelativeFilePath();
2517
+ const commandToConvert = factory.meta.supportsSubdirectory ? rulesyncCommand : this.flattenRelativeFilePath(rulesyncCommand);
2518
+ if (!factory.meta.supportsSubdirectory) {
2519
+ const flattenedPath = commandToConvert.getRelativeFilePath();
2520
+ const firstOrigin = flattenedPathOrigins.get(flattenedPath);
2521
+ if (firstOrigin && firstOrigin !== originalRelativePath) {
2522
+ logger.warn(
2523
+ `Command path collision detected while flattening for ${this.toolTarget}: "${firstOrigin}" and "${originalRelativePath}" both map to "${flattenedPath}". The later command will overwrite the earlier one.`
2524
+ );
2525
+ } else if (!firstOrigin) {
2526
+ flattenedPathOrigins.set(flattenedPath, originalRelativePath);
2527
+ }
2528
+ }
2427
2529
  return factory.class.fromRulesyncCommand({
2428
2530
  baseDir: this.baseDir,
2429
- rulesyncCommand,
2531
+ rulesyncCommand: commandToConvert,
2430
2532
  global: this.global
2431
2533
  });
2432
2534
  }).filter((command) => command !== null);
@@ -2441,17 +2543,26 @@ var CommandsProcessor = class extends FeatureProcessor {
2441
2543
  });
2442
2544
  return rulesyncCommands;
2443
2545
  }
2546
+ flattenRelativeFilePath(rulesyncCommand) {
2547
+ const flatPath = (0, import_node_path19.basename)(rulesyncCommand.getRelativeFilePath());
2548
+ if (flatPath === rulesyncCommand.getRelativeFilePath()) return rulesyncCommand;
2549
+ return rulesyncCommand.withRelativeFilePath(flatPath);
2550
+ }
2551
+ safeRelativePath(basePath, fullPath) {
2552
+ const rel = (0, import_node_path19.relative)(basePath, fullPath);
2553
+ checkPathTraversal({ relativePath: rel, intendedRootDir: basePath });
2554
+ return rel;
2555
+ }
2444
2556
  /**
2445
2557
  * Implementation of abstract method from FeatureProcessor
2446
2558
  * Load and parse rulesync command files from .rulesync/commands/ directory
2447
2559
  */
2448
2560
  async loadRulesyncFiles() {
2449
- const rulesyncCommandPaths = await findFilesByGlobs(
2450
- (0, import_node_path19.join)(RulesyncCommand.getSettablePaths().relativeDirPath, "*.md")
2451
- );
2561
+ const basePath = RulesyncCommand.getSettablePaths().relativeDirPath;
2562
+ const rulesyncCommandPaths = await findFilesByGlobs((0, import_node_path19.join)(basePath, "**", "*.md"));
2452
2563
  const rulesyncCommands = await Promise.all(
2453
2564
  rulesyncCommandPaths.map(
2454
- (path4) => RulesyncCommand.fromFile({ relativeFilePath: (0, import_node_path19.basename)(path4) })
2565
+ (path4) => RulesyncCommand.fromFile({ relativeFilePath: this.safeRelativePath(basePath, path4) })
2455
2566
  )
2456
2567
  );
2457
2568
  logger.debug(`Successfully loaded ${rulesyncCommands.length} rulesync commands`);
@@ -2466,15 +2577,15 @@ var CommandsProcessor = class extends FeatureProcessor {
2466
2577
  } = {}) {
2467
2578
  const factory = this.getFactory(this.toolTarget);
2468
2579
  const paths = factory.class.getSettablePaths({ global: this.global });
2469
- const commandFilePaths = await findFilesByGlobs(
2470
- (0, import_node_path19.join)(this.baseDir, paths.relativeDirPath, `*.${factory.meta.extension}`)
2471
- );
2580
+ const baseDirFull = (0, import_node_path19.join)(this.baseDir, paths.relativeDirPath);
2581
+ const globPattern = factory.meta.supportsSubdirectory ? (0, import_node_path19.join)(baseDirFull, "**", `*.${factory.meta.extension}`) : (0, import_node_path19.join)(baseDirFull, `*.${factory.meta.extension}`);
2582
+ const commandFilePaths = await findFilesByGlobs(globPattern);
2472
2583
  if (forDeletion) {
2473
2584
  const toolCommands2 = commandFilePaths.map(
2474
2585
  (path4) => factory.class.forDeletion({
2475
2586
  baseDir: this.baseDir,
2476
2587
  relativeDirPath: paths.relativeDirPath,
2477
- relativeFilePath: (0, import_node_path19.basename)(path4),
2588
+ relativeFilePath: this.safeRelativePath(baseDirFull, path4),
2478
2589
  global: this.global
2479
2590
  })
2480
2591
  ).filter((cmd) => cmd.isDeletable());
@@ -2485,7 +2596,7 @@ var CommandsProcessor = class extends FeatureProcessor {
2485
2596
  commandFilePaths.map(
2486
2597
  (path4) => factory.class.fromFile({
2487
2598
  baseDir: this.baseDir,
2488
- relativeFilePath: (0, import_node_path19.basename)(path4),
2599
+ relativeFilePath: this.safeRelativePath(baseDirFull, path4),
2489
2600
  global: this.global
2490
2601
  })
2491
2602
  )
@@ -12175,14 +12286,22 @@ var CopilotRuleFrontmatterSchema = import_mini46.z.object({
12175
12286
  var CopilotRule = class _CopilotRule extends ToolRule {
12176
12287
  frontmatter;
12177
12288
  body;
12178
- static getSettablePaths(_options = {}) {
12289
+ static getSettablePaths(options = {}) {
12290
+ if (options.global) {
12291
+ return {
12292
+ root: {
12293
+ relativeDirPath: buildToolPath(".copilot", ".", options.excludeToolDir),
12294
+ relativeFilePath: "copilot-instructions.md"
12295
+ }
12296
+ };
12297
+ }
12179
12298
  return {
12180
12299
  root: {
12181
- relativeDirPath: buildToolPath(".github", ".", _options.excludeToolDir),
12300
+ relativeDirPath: buildToolPath(".github", ".", options.excludeToolDir),
12182
12301
  relativeFilePath: "copilot-instructions.md"
12183
12302
  },
12184
12303
  nonRoot: {
12185
- relativeDirPath: buildToolPath(".github", "instructions", _options.excludeToolDir)
12304
+ relativeDirPath: buildToolPath(".github", "instructions", options.excludeToolDir)
12186
12305
  }
12187
12306
  };
12188
12307
  }
@@ -12233,10 +12352,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12233
12352
  static fromRulesyncRule({
12234
12353
  baseDir = process.cwd(),
12235
12354
  rulesyncRule,
12236
- validate = true
12355
+ validate = true,
12356
+ global = false
12237
12357
  }) {
12238
12358
  const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
12239
12359
  const root = rulesyncFrontmatter.root;
12360
+ const paths = this.getSettablePaths({ global });
12240
12361
  const copilotFrontmatter = {
12241
12362
  description: rulesyncFrontmatter.description,
12242
12363
  applyTo: rulesyncFrontmatter.globs?.length ? rulesyncFrontmatter.globs.join(",") : void 0,
@@ -12248,12 +12369,15 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12248
12369
  baseDir,
12249
12370
  frontmatter: copilotFrontmatter,
12250
12371
  body,
12251
- relativeDirPath: this.getSettablePaths().root.relativeDirPath,
12252
- relativeFilePath: this.getSettablePaths().root.relativeFilePath,
12372
+ relativeDirPath: paths.root.relativeDirPath,
12373
+ relativeFilePath: paths.root.relativeFilePath,
12253
12374
  validate,
12254
12375
  root
12255
12376
  });
12256
12377
  }
12378
+ if (!paths.nonRoot) {
12379
+ throw new Error(`nonRoot path is not set for ${rulesyncRule.getRelativeFilePath()}`);
12380
+ }
12257
12381
  const originalFileName = rulesyncRule.getRelativeFilePath();
12258
12382
  const nameWithoutExt = originalFileName.replace(/\.md$/, "");
12259
12383
  const newFileName = `${nameWithoutExt}.instructions.md`;
@@ -12261,7 +12385,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12261
12385
  baseDir,
12262
12386
  frontmatter: copilotFrontmatter,
12263
12387
  body,
12264
- relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
12388
+ relativeDirPath: paths.nonRoot.relativeDirPath,
12265
12389
  relativeFilePath: newFileName,
12266
12390
  validate,
12267
12391
  root
@@ -12270,25 +12394,29 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12270
12394
  static async fromFile({
12271
12395
  baseDir = process.cwd(),
12272
12396
  relativeFilePath,
12273
- validate = true
12397
+ validate = true,
12398
+ global = false
12274
12399
  }) {
12275
- const isRoot = relativeFilePath === "copilot-instructions.md";
12276
- const relativePath = isRoot ? (0, import_node_path95.join)(
12277
- this.getSettablePaths().root.relativeDirPath,
12278
- this.getSettablePaths().root.relativeFilePath
12279
- ) : (0, import_node_path95.join)(this.getSettablePaths().nonRoot.relativeDirPath, relativeFilePath);
12280
- const fileContent = await readFileContent((0, import_node_path95.join)(baseDir, relativePath));
12400
+ const paths = this.getSettablePaths({ global });
12401
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
12281
12402
  if (isRoot) {
12403
+ const relativePath2 = (0, import_node_path95.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
12404
+ const fileContent2 = await readFileContent((0, import_node_path95.join)(baseDir, relativePath2));
12282
12405
  return new _CopilotRule({
12283
12406
  baseDir,
12284
- relativeDirPath: this.getSettablePaths().root.relativeDirPath,
12285
- relativeFilePath: this.getSettablePaths().root.relativeFilePath,
12407
+ relativeDirPath: paths.root.relativeDirPath,
12408
+ relativeFilePath: paths.root.relativeFilePath,
12286
12409
  frontmatter: {},
12287
- body: fileContent.trim(),
12410
+ body: fileContent2.trim(),
12288
12411
  validate,
12289
12412
  root: isRoot
12290
12413
  });
12291
12414
  }
12415
+ if (!paths.nonRoot) {
12416
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
12417
+ }
12418
+ const relativePath = (0, import_node_path95.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
12419
+ const fileContent = await readFileContent((0, import_node_path95.join)(baseDir, relativePath));
12292
12420
  const { frontmatter, body: content } = parseFrontmatter(fileContent);
12293
12421
  const result = CopilotRuleFrontmatterSchema.safeParse(frontmatter);
12294
12422
  if (!result.success) {
@@ -12298,7 +12426,7 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12298
12426
  }
12299
12427
  return new _CopilotRule({
12300
12428
  baseDir,
12301
- relativeDirPath: this.getSettablePaths().nonRoot.relativeDirPath,
12429
+ relativeDirPath: paths.nonRoot.relativeDirPath,
12302
12430
  relativeFilePath: relativeFilePath.endsWith(".instructions.md") ? relativeFilePath : relativeFilePath.replace(/\.md$/, ".instructions.md"),
12303
12431
  frontmatter: result.data,
12304
12432
  body: content.trim(),
@@ -12309,9 +12437,11 @@ var CopilotRule = class _CopilotRule extends ToolRule {
12309
12437
  static forDeletion({
12310
12438
  baseDir = process.cwd(),
12311
12439
  relativeDirPath,
12312
- relativeFilePath
12440
+ relativeFilePath,
12441
+ global = false
12313
12442
  }) {
12314
- const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
12443
+ const paths = this.getSettablePaths({ global });
12444
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
12315
12445
  return new _CopilotRule({
12316
12446
  baseDir,
12317
12447
  relativeDirPath,
@@ -12991,46 +13121,78 @@ var KiroRule = class _KiroRule extends ToolRule {
12991
13121
  // src/features/rules/opencode-rule.ts
12992
13122
  var import_node_path102 = require("path");
12993
13123
  var OpenCodeRule = class _OpenCodeRule extends ToolRule {
12994
- static getSettablePaths(_options = {}) {
13124
+ static getSettablePaths({
13125
+ global,
13126
+ excludeToolDir
13127
+ } = {}) {
13128
+ if (global) {
13129
+ return {
13130
+ root: {
13131
+ relativeDirPath: buildToolPath(".config/opencode", ".", excludeToolDir),
13132
+ relativeFilePath: "AGENTS.md"
13133
+ }
13134
+ };
13135
+ }
12995
13136
  return {
12996
13137
  root: {
12997
13138
  relativeDirPath: ".",
12998
13139
  relativeFilePath: "AGENTS.md"
12999
13140
  },
13000
13141
  nonRoot: {
13001
- relativeDirPath: buildToolPath(".opencode", "memories", _options.excludeToolDir)
13142
+ relativeDirPath: buildToolPath(".opencode", "memories", excludeToolDir)
13002
13143
  }
13003
13144
  };
13004
13145
  }
13005
13146
  static async fromFile({
13006
13147
  baseDir = process.cwd(),
13007
13148
  relativeFilePath,
13008
- validate = true
13149
+ validate = true,
13150
+ global = false
13009
13151
  }) {
13010
- const isRoot = relativeFilePath === "AGENTS.md";
13011
- const relativePath = isRoot ? "AGENTS.md" : (0, import_node_path102.join)(".opencode", "memories", relativeFilePath);
13152
+ const paths = this.getSettablePaths({ global });
13153
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
13154
+ if (isRoot) {
13155
+ const relativePath2 = paths.root.relativeFilePath;
13156
+ const fileContent2 = await readFileContent(
13157
+ (0, import_node_path102.join)(baseDir, paths.root.relativeDirPath, relativePath2)
13158
+ );
13159
+ return new _OpenCodeRule({
13160
+ baseDir,
13161
+ relativeDirPath: paths.root.relativeDirPath,
13162
+ relativeFilePath: paths.root.relativeFilePath,
13163
+ fileContent: fileContent2,
13164
+ validate,
13165
+ root: true
13166
+ });
13167
+ }
13168
+ if (!paths.nonRoot) {
13169
+ throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
13170
+ }
13171
+ const relativePath = (0, import_node_path102.join)(paths.nonRoot.relativeDirPath, relativeFilePath);
13012
13172
  const fileContent = await readFileContent((0, import_node_path102.join)(baseDir, relativePath));
13013
13173
  return new _OpenCodeRule({
13014
13174
  baseDir,
13015
- relativeDirPath: isRoot ? this.getSettablePaths().root.relativeDirPath : this.getSettablePaths().nonRoot.relativeDirPath,
13016
- relativeFilePath: isRoot ? "AGENTS.md" : relativeFilePath,
13175
+ relativeDirPath: paths.nonRoot.relativeDirPath,
13176
+ relativeFilePath,
13177
+ fileContent,
13017
13178
  validate,
13018
- root: isRoot,
13019
- fileContent
13179
+ root: false
13020
13180
  });
13021
13181
  }
13022
13182
  static fromRulesyncRule({
13023
13183
  baseDir = process.cwd(),
13024
13184
  rulesyncRule,
13025
- validate = true
13185
+ validate = true,
13186
+ global = false
13026
13187
  }) {
13188
+ const paths = this.getSettablePaths({ global });
13027
13189
  return new _OpenCodeRule(
13028
13190
  this.buildToolRuleParamsDefault({
13029
13191
  baseDir,
13030
13192
  rulesyncRule,
13031
13193
  validate,
13032
- rootPath: this.getSettablePaths().root,
13033
- nonRootPath: this.getSettablePaths().nonRoot
13194
+ rootPath: paths.root,
13195
+ nonRootPath: paths.nonRoot
13034
13196
  })
13035
13197
  );
13036
13198
  }
@@ -13043,9 +13205,11 @@ var OpenCodeRule = class _OpenCodeRule extends ToolRule {
13043
13205
  static forDeletion({
13044
13206
  baseDir = process.cwd(),
13045
13207
  relativeDirPath,
13046
- relativeFilePath
13208
+ relativeFilePath,
13209
+ global = false
13047
13210
  }) {
13048
- const isRoot = relativeFilePath === "AGENTS.md" && relativeDirPath === ".";
13211
+ const paths = this.getSettablePaths({ global });
13212
+ const isRoot = relativeFilePath === paths.root.relativeFilePath;
13049
13213
  return new _OpenCodeRule({
13050
13214
  baseDir,
13051
13215
  relativeDirPath,
@@ -13503,42 +13667,66 @@ var toolRuleFactories = /* @__PURE__ */ new Map([
13503
13667
  "antigravity",
13504
13668
  {
13505
13669
  class: AntigravityRule,
13506
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "auto" }
13670
+ meta: {
13671
+ extension: "md",
13672
+ supportsGlobal: false,
13673
+ ruleDiscoveryMode: "auto"
13674
+ }
13507
13675
  }
13508
13676
  ],
13509
13677
  [
13510
13678
  "augmentcode",
13511
13679
  {
13512
13680
  class: AugmentcodeRule,
13513
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "auto" }
13681
+ meta: {
13682
+ extension: "md",
13683
+ supportsGlobal: false,
13684
+ ruleDiscoveryMode: "auto"
13685
+ }
13514
13686
  }
13515
13687
  ],
13516
13688
  [
13517
13689
  "augmentcode-legacy",
13518
13690
  {
13519
13691
  class: AugmentcodeLegacyRule,
13520
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13692
+ meta: {
13693
+ extension: "md",
13694
+ supportsGlobal: false,
13695
+ ruleDiscoveryMode: "toon"
13696
+ }
13521
13697
  }
13522
13698
  ],
13523
13699
  [
13524
13700
  "claudecode",
13525
13701
  {
13526
13702
  class: ClaudecodeRule,
13527
- meta: { extension: "md", supportsGlobal: true, ruleDiscoveryMode: "auto" }
13703
+ meta: {
13704
+ extension: "md",
13705
+ supportsGlobal: true,
13706
+ ruleDiscoveryMode: "auto"
13707
+ }
13528
13708
  }
13529
13709
  ],
13530
13710
  [
13531
13711
  "claudecode-legacy",
13532
13712
  {
13533
13713
  class: ClaudecodeLegacyRule,
13534
- meta: { extension: "md", supportsGlobal: true, ruleDiscoveryMode: "claudecode-legacy" }
13714
+ meta: {
13715
+ extension: "md",
13716
+ supportsGlobal: true,
13717
+ ruleDiscoveryMode: "claudecode-legacy"
13718
+ }
13535
13719
  }
13536
13720
  ],
13537
13721
  [
13538
13722
  "cline",
13539
13723
  {
13540
13724
  class: ClineRule,
13541
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "auto" }
13725
+ meta: {
13726
+ extension: "md",
13727
+ supportsGlobal: false,
13728
+ ruleDiscoveryMode: "auto"
13729
+ }
13542
13730
  }
13543
13731
  ],
13544
13732
  [
@@ -13561,7 +13749,7 @@ var toolRuleFactories = /* @__PURE__ */ new Map([
13561
13749
  class: CopilotRule,
13562
13750
  meta: {
13563
13751
  extension: "md",
13564
- supportsGlobal: false,
13752
+ supportsGlobal: true,
13565
13753
  ruleDiscoveryMode: "auto"
13566
13754
  }
13567
13755
  }
@@ -13611,42 +13799,66 @@ var toolRuleFactories = /* @__PURE__ */ new Map([
13611
13799
  "junie",
13612
13800
  {
13613
13801
  class: JunieRule,
13614
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13802
+ meta: {
13803
+ extension: "md",
13804
+ supportsGlobal: false,
13805
+ ruleDiscoveryMode: "toon"
13806
+ }
13615
13807
  }
13616
13808
  ],
13617
13809
  [
13618
13810
  "kilo",
13619
13811
  {
13620
13812
  class: KiloRule,
13621
- meta: { extension: "md", supportsGlobal: true, ruleDiscoveryMode: "auto" }
13813
+ meta: {
13814
+ extension: "md",
13815
+ supportsGlobal: true,
13816
+ ruleDiscoveryMode: "auto"
13817
+ }
13622
13818
  }
13623
13819
  ],
13624
13820
  [
13625
13821
  "kiro",
13626
13822
  {
13627
13823
  class: KiroRule,
13628
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13824
+ meta: {
13825
+ extension: "md",
13826
+ supportsGlobal: false,
13827
+ ruleDiscoveryMode: "toon"
13828
+ }
13629
13829
  }
13630
13830
  ],
13631
13831
  [
13632
13832
  "opencode",
13633
13833
  {
13634
13834
  class: OpenCodeRule,
13635
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13835
+ meta: {
13836
+ extension: "md",
13837
+ supportsGlobal: true,
13838
+ ruleDiscoveryMode: "toon"
13839
+ }
13636
13840
  }
13637
13841
  ],
13638
13842
  [
13639
13843
  "qwencode",
13640
13844
  {
13641
13845
  class: QwencodeRule,
13642
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13846
+ meta: {
13847
+ extension: "md",
13848
+ supportsGlobal: false,
13849
+ ruleDiscoveryMode: "toon"
13850
+ }
13643
13851
  }
13644
13852
  ],
13645
13853
  [
13646
13854
  "replit",
13647
13855
  {
13648
13856
  class: ReplitRule,
13649
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "auto" }
13857
+ meta: {
13858
+ extension: "md",
13859
+ supportsGlobal: false,
13860
+ ruleDiscoveryMode: "auto"
13861
+ }
13650
13862
  }
13651
13863
  ],
13652
13864
  [
@@ -13668,14 +13880,22 @@ var toolRuleFactories = /* @__PURE__ */ new Map([
13668
13880
  "warp",
13669
13881
  {
13670
13882
  class: WarpRule,
13671
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "toon" }
13883
+ meta: {
13884
+ extension: "md",
13885
+ supportsGlobal: false,
13886
+ ruleDiscoveryMode: "toon"
13887
+ }
13672
13888
  }
13673
13889
  ],
13674
13890
  [
13675
13891
  "windsurf",
13676
13892
  {
13677
13893
  class: WindsurfRule,
13678
- meta: { extension: "md", supportsGlobal: false, ruleDiscoveryMode: "auto" }
13894
+ meta: {
13895
+ extension: "md",
13896
+ supportsGlobal: false,
13897
+ ruleDiscoveryMode: "auto"
13898
+ }
13679
13899
  }
13680
13900
  ]
13681
13901
  ]);
@@ -13823,7 +14043,9 @@ var RulesProcessor = class extends FeatureProcessor {
13823
14043
  })
13824
14044
  );
13825
14045
  } else if (this.toolTarget === "claudecode-legacy") {
13826
- const paths = ClaudecodeLegacyRule.getSettablePaths({ global: this.global });
14046
+ const paths = ClaudecodeLegacyRule.getSettablePaths({
14047
+ global: this.global
14048
+ });
13827
14049
  toolRules.push(
13828
14050
  new ClaudecodeLegacyRule({
13829
14051
  baseDir: this.baseDir,
@@ -13909,7 +14131,10 @@ var RulesProcessor = class extends FeatureProcessor {
13909
14131
  const rulesyncRules = await Promise.all(
13910
14132
  files.map((file) => {
13911
14133
  const relativeFilePath = (0, import_node_path108.relative)(rulesyncBaseDir, file);
13912
- checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: rulesyncBaseDir });
14134
+ checkPathTraversal({
14135
+ relativePath: relativeFilePath,
14136
+ intendedRootDir: rulesyncBaseDir
14137
+ });
13913
14138
  return RulesyncRule.fromFile({
13914
14139
  relativeFilePath
13915
14140
  });
@@ -13960,7 +14185,9 @@ var RulesProcessor = class extends FeatureProcessor {
13960
14185
  } = {}) {
13961
14186
  try {
13962
14187
  const factory = this.getFactory(this.toolTarget);
13963
- const settablePaths = factory.class.getSettablePaths({ global: this.global });
14188
+ const settablePaths = factory.class.getSettablePaths({
14189
+ global: this.global
14190
+ });
13964
14191
  const rootToolRules = await (async () => {
13965
14192
  if (!settablePaths.root) {
13966
14193
  return [];
@@ -14042,7 +14269,10 @@ var RulesProcessor = class extends FeatureProcessor {
14042
14269
  return await Promise.all(
14043
14270
  nonRootFilePaths.map((filePath) => {
14044
14271
  const relativeFilePath = (0, import_node_path108.relative)(nonRootBaseDir, filePath);
14045
- checkPathTraversal({ relativePath: relativeFilePath, intendedRootDir: nonRootBaseDir });
14272
+ checkPathTraversal({
14273
+ relativePath: relativeFilePath,
14274
+ intendedRootDir: nonRootBaseDir
14275
+ });
14046
14276
  return factory.class.fromFile({
14047
14277
  baseDir: this.baseDir,
14048
14278
  relativeFilePath,
@@ -16737,19 +16967,10 @@ async function resolveAndFetchSources(params) {
16737
16967
  let lock = options.updateSources ? createEmptyLock() : await readLockFile({ baseDir });
16738
16968
  if (options.frozen) {
16739
16969
  const missingKeys = [];
16740
- const missingSkills = [];
16741
- const curatedDir = (0, import_node_path115.join)(baseDir, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH);
16742
16970
  for (const source of sources) {
16743
16971
  const locked = getLockedSource(lock, source.source);
16744
16972
  if (!locked) {
16745
16973
  missingKeys.push(source.source);
16746
- continue;
16747
- }
16748
- const skillNames = getLockedSkillNames(locked);
16749
- for (const skillName of skillNames) {
16750
- if (!await directoryExists((0, import_node_path115.join)(curatedDir, skillName))) {
16751
- missingSkills.push(`${source.source}:${skillName}`);
16752
- }
16753
16974
  }
16754
16975
  }
16755
16976
  if (missingKeys.length > 0) {
@@ -16757,11 +16978,6 @@ async function resolveAndFetchSources(params) {
16757
16978
  `Frozen install failed: lockfile is missing entries for: ${missingKeys.join(", ")}. Run 'rulesync install' to update the lockfile.`
16758
16979
  );
16759
16980
  }
16760
- if (missingSkills.length > 0) {
16761
- throw new Error(
16762
- `Frozen install failed: locked skills missing from disk: ${missingSkills.join(", ")}. Run 'rulesync install' to fetch missing skills.`
16763
- );
16764
- }
16765
16981
  }
16766
16982
  const originalLockJson = JSON.stringify(lock);
16767
16983
  const token = GitHubClient.resolveToken(options.token);
@@ -18782,7 +18998,7 @@ async function updateCommand(currentVersion, options) {
18782
18998
  }
18783
18999
 
18784
19000
  // src/cli/index.ts
18785
- var getVersion = () => "7.3.0";
19001
+ var getVersion = () => "7.5.0";
18786
19002
  var main = async () => {
18787
19003
  const program = new import_commander.Command();
18788
19004
  const version = getVersion();
@@ -18855,7 +19071,10 @@ var main = async () => {
18855
19071
  process.exit(1);
18856
19072
  }
18857
19073
  });
18858
- program.command("install").description("Install skills from declarative sources in rulesync.jsonc").option("--update", "Force re-resolve all source refs, ignoring lockfile").option("--frozen", "Fail if lockfile is missing or out of sync (for CI)").option("--token <token>", "GitHub token for private repos").option("-c, --config <path>", "Path to configuration file").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(async (options) => {
19074
+ program.command("install").description("Install skills from declarative sources in rulesync.jsonc").option("--update", "Force re-resolve all source refs, ignoring lockfile").option(
19075
+ "--frozen",
19076
+ "Fail if lockfile is missing or out of sync (for CI); fetches missing skills using locked refs"
19077
+ ).option("--token <token>", "GitHub token for private repos").option("-c, --config <path>", "Path to configuration file").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(async (options) => {
18859
19078
  try {
18860
19079
  await installCommand({
18861
19080
  update: options.update,