rulesync 7.24.0 → 7.26.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
@@ -115,6 +115,9 @@ async function readOrInitializeFileContent(filePath, initialContent = "") {
115
115
  return initialContent;
116
116
  }
117
117
  }
118
+ function toPosixPath(p) {
119
+ return p.replace(/\\/g, "/");
120
+ }
118
121
  function checkPathTraversal({
119
122
  relativePath,
120
123
  intendedRootDir
@@ -951,8 +954,11 @@ var AiFile = class {
951
954
  getFileContent() {
952
955
  return this.fileContent;
953
956
  }
957
+ /**
958
+ * Returns the relative path from CWD with POSIX separators for consistent cross-platform output.
959
+ */
954
960
  getRelativePathFromCwd() {
955
- return import_node_path6.default.join(this.relativeDirPath, this.relativeFilePath).replace(/\\/g, "/");
961
+ return toPosixPath(import_node_path6.default.join(this.relativeDirPath, this.relativeFilePath));
956
962
  }
957
963
  setFileContent(newFileContent) {
958
964
  this.fileContent = newFileContent;
@@ -6129,7 +6135,7 @@ var import_mini21 = require("zod/mini");
6129
6135
  // src/types/mcp.ts
6130
6136
  var import_mini20 = require("zod/mini");
6131
6137
  var McpServerSchema = import_mini20.z.looseObject({
6132
- type: import_mini20.z.optional(import_mini20.z.enum(["stdio", "sse", "http"])),
6138
+ type: import_mini20.z.optional(import_mini20.z.enum(["local", "stdio", "sse", "http"])),
6133
6139
  command: import_mini20.z.optional(import_mini20.z.union([import_mini20.z.string(), import_mini20.z.array(import_mini20.z.string())])),
6134
6140
  args: import_mini20.z.optional(import_mini20.z.array(import_mini20.z.string())),
6135
6141
  url: import_mini20.z.optional(import_mini20.z.string()),
@@ -6140,7 +6146,7 @@ var McpServerSchema = import_mini20.z.looseObject({
6140
6146
  timeout: import_mini20.z.optional(import_mini20.z.number()),
6141
6147
  trust: import_mini20.z.optional(import_mini20.z.boolean()),
6142
6148
  cwd: import_mini20.z.optional(import_mini20.z.string()),
6143
- transport: import_mini20.z.optional(import_mini20.z.enum(["stdio", "sse", "http"])),
6149
+ transport: import_mini20.z.optional(import_mini20.z.enum(["local", "stdio", "sse", "http"])),
6144
6150
  alwaysAllow: import_mini20.z.optional(import_mini20.z.array(import_mini20.z.string())),
6145
6151
  tools: import_mini20.z.optional(import_mini20.z.array(import_mini20.z.string())),
6146
6152
  kiroAutoApprove: import_mini20.z.optional(import_mini20.z.array(import_mini20.z.string())),
@@ -6725,13 +6731,38 @@ var CopilotMcp = class _CopilotMcp extends ToolMcp {
6725
6731
 
6726
6732
  // src/features/mcp/copilotcli-mcp.ts
6727
6733
  var import_node_path51 = require("path");
6734
+ var isRemoteServerType = (type) => {
6735
+ return type === "http" || type === "sse";
6736
+ };
6737
+ var resolveCopilotcliServerType = (server) => {
6738
+ if (server.type) {
6739
+ return server.type;
6740
+ }
6741
+ if (server.transport === "http" || server.transport === "sse" || server.transport === "local") {
6742
+ return server.transport;
6743
+ }
6744
+ return "stdio";
6745
+ };
6728
6746
  function addTypeField(mcpServers) {
6729
6747
  const result = {};
6730
6748
  for (const [name, server] of Object.entries(mcpServers)) {
6731
6749
  const parsed = McpServerSchema.parse(server);
6750
+ const type = resolveCopilotcliServerType(parsed);
6751
+ if (isRemoteServerType(type)) {
6752
+ if (!parsed.url && !parsed.httpUrl) {
6753
+ throw new Error(
6754
+ `MCP server "${name}" is missing a url or httpUrl. GitHub Copilot CLI ${type} servers require a non-empty url or httpUrl.`
6755
+ );
6756
+ }
6757
+ result[name] = {
6758
+ ...parsed,
6759
+ type
6760
+ };
6761
+ continue;
6762
+ }
6732
6763
  if (!parsed.command) {
6733
6764
  throw new Error(
6734
- `MCP server "${name}" is missing a command. GitHub Copilot CLI stdio servers require a non-empty command.`
6765
+ `MCP server "${name}" is missing a command. GitHub Copilot CLI ${type} servers require a non-empty command.`
6735
6766
  );
6736
6767
  }
6737
6768
  let command;
@@ -6748,10 +6779,10 @@ function addTypeField(mcpServers) {
6748
6779
  args = cmdArgs.length > 0 ? [...cmdArgs, ...parsed.args ?? []] : parsed.args;
6749
6780
  }
6750
6781
  result[name] = {
6751
- type: "stdio",
6782
+ ...parsed,
6783
+ type,
6752
6784
  command,
6753
- ...args && { args },
6754
- ...parsed.env && { env: parsed.env }
6785
+ ...args && { args }
6755
6786
  };
6756
6787
  }
6757
6788
  return result;
@@ -6759,6 +6790,10 @@ function addTypeField(mcpServers) {
6759
6790
  function removeTypeField(config) {
6760
6791
  const result = {};
6761
6792
  for (const [name, server] of Object.entries(config.mcpServers ?? {})) {
6793
+ if (server.type !== "stdio") {
6794
+ result[name] = server;
6795
+ continue;
6796
+ }
6762
6797
  const { type: _, ...rest } = server;
6763
6798
  result[name] = rest;
6764
6799
  }
@@ -6781,13 +6816,7 @@ var CopilotcliMcp = class _CopilotcliMcp extends ToolMcp {
6781
6816
  isDeletable() {
6782
6817
  return !this.global;
6783
6818
  }
6784
- static getSettablePaths({ global } = {}) {
6785
- if (global) {
6786
- return {
6787
- relativeDirPath: ".copilot",
6788
- relativeFilePath: "mcp-config.json"
6789
- };
6790
- }
6819
+ static getSettablePaths(_options = {}) {
6791
6820
  return {
6792
6821
  relativeDirPath: ".copilot",
6793
6822
  relativeFilePath: "mcp-config.json"
@@ -8403,8 +8432,11 @@ var AiDir = class {
8403
8432
  getOtherFiles() {
8404
8433
  return this.otherFiles;
8405
8434
  }
8435
+ /**
8436
+ * Returns the relative path from CWD with POSIX separators for consistent cross-platform output.
8437
+ */
8406
8438
  getRelativePathFromCwd() {
8407
- return import_node_path62.default.join(this.relativeDirPath, this.dirName).replace(/\\/g, "/");
8439
+ return toPosixPath(import_node_path62.default.join(this.relativeDirPath, this.dirName));
8408
8440
  }
8409
8441
  getGlobal() {
8410
8442
  return this.global;
@@ -15762,6 +15794,42 @@ var CopilotRule = class _CopilotRule extends ToolRule {
15762
15794
  }
15763
15795
  };
15764
15796
 
15797
+ // src/features/rules/copilotcli-rule.ts
15798
+ var CopilotcliRule = class _CopilotcliRule extends CopilotRule {
15799
+ static fromCopilotRule(copilotRule, validate = true) {
15800
+ return new _CopilotcliRule({
15801
+ baseDir: copilotRule.getBaseDir(),
15802
+ relativeDirPath: copilotRule.getRelativeDirPath(),
15803
+ relativeFilePath: copilotRule.getRelativeFilePath(),
15804
+ frontmatter: copilotRule.getFrontmatter(),
15805
+ body: copilotRule.getBody(),
15806
+ validate,
15807
+ root: copilotRule.isRoot()
15808
+ });
15809
+ }
15810
+ static fromRulesyncRule({
15811
+ validate = true,
15812
+ ...rest
15813
+ }) {
15814
+ return this.fromCopilotRule(CopilotRule.fromRulesyncRule({ validate, ...rest }), validate);
15815
+ }
15816
+ static async fromFile({
15817
+ validate = true,
15818
+ ...rest
15819
+ }) {
15820
+ return this.fromCopilotRule(await CopilotRule.fromFile({ validate, ...rest }), validate);
15821
+ }
15822
+ static forDeletion(params) {
15823
+ return this.fromCopilotRule(CopilotRule.forDeletion(params), false);
15824
+ }
15825
+ static isTargetedByRulesyncRule(rulesyncRule) {
15826
+ return this.isTargetedByRulesyncRuleDefault({
15827
+ rulesyncRule,
15828
+ toolTarget: "copilotcli"
15829
+ });
15830
+ }
15831
+ };
15832
+
15765
15833
  // src/features/rules/cursor-rule.ts
15766
15834
  var import_node_path114 = require("path");
15767
15835
  var import_mini60 = require("zod/mini");
@@ -16947,7 +17015,7 @@ var RooRule = class _RooRule extends ToolRule {
16947
17015
 
16948
17016
  // src/features/rules/rovodev-rule.ts
16949
17017
  var import_node_path126 = require("path");
16950
- var DISALLOWED_ROVODEV_MODULAR_RULE_BASENAMES = /* @__PURE__ */ new Set(["AGENTS.md", "AGENTS.local.md"]);
17018
+ var DISALLOWED_ROVODEV_MODULAR_RULE_BASENAMES = /* @__PURE__ */ new Set(["agents.md", "agents.local.md"]);
16951
17019
  var RovodevRule = class _RovodevRule extends ToolRule {
16952
17020
  /**
16953
17021
  * Whether `relativePath` (posix-style path relative to modular-rules root) may be imported as a modular rule.
@@ -16961,7 +17029,7 @@ var RovodevRule = class _RovodevRule extends ToolRule {
16961
17029
  if (segment === "" || segment === "." || segment === "..") {
16962
17030
  continue;
16963
17031
  }
16964
- if (DISALLOWED_ROVODEV_MODULAR_RULE_BASENAMES.has(segment)) {
17032
+ if (DISALLOWED_ROVODEV_MODULAR_RULE_BASENAMES.has(segment.toLowerCase())) {
16965
17033
  return false;
16966
17034
  }
16967
17035
  }
@@ -17003,22 +17071,54 @@ var RovodevRule = class _RovodevRule extends ToolRule {
17003
17071
  }) {
17004
17072
  const paths = this.getSettablePaths({ global });
17005
17073
  if (!global && "nonRoot" in paths && paths.nonRoot && overrideDirPath === paths.nonRoot.relativeDirPath) {
17006
- if (!this.isAllowedModularRulesRelativePath(relativeFilePath)) {
17007
- throw new Error(
17008
- `Reserved Rovodev memory basename under modular-rules (not a modular rule): ${(0, import_node_path126.join)(overrideDirPath, relativeFilePath)}`
17009
- );
17010
- }
17011
- const fileContent2 = await readFileContent((0, import_node_path126.join)(baseDir, overrideDirPath, relativeFilePath));
17012
- return new _RovodevRule({
17074
+ return this.fromModularFile({
17013
17075
  baseDir,
17014
- relativeDirPath: overrideDirPath,
17015
17076
  relativeFilePath,
17016
- fileContent: fileContent2,
17077
+ relativeDirPath: overrideDirPath,
17017
17078
  validate,
17018
- global,
17019
- root: false
17079
+ global
17020
17080
  });
17021
17081
  }
17082
+ return this.fromRootFile({
17083
+ baseDir,
17084
+ relativeFilePath,
17085
+ overrideDirPath,
17086
+ validate,
17087
+ global,
17088
+ paths
17089
+ });
17090
+ }
17091
+ static async fromModularFile({
17092
+ baseDir,
17093
+ relativeFilePath,
17094
+ relativeDirPath,
17095
+ validate,
17096
+ global
17097
+ }) {
17098
+ if (!this.isAllowedModularRulesRelativePath(relativeFilePath)) {
17099
+ throw new Error(
17100
+ `Reserved Rovodev memory basename under modular-rules (not a modular rule): ${(0, import_node_path126.join)(relativeDirPath, relativeFilePath)}`
17101
+ );
17102
+ }
17103
+ const fileContent = await readFileContent((0, import_node_path126.join)(baseDir, relativeDirPath, relativeFilePath));
17104
+ return new _RovodevRule({
17105
+ baseDir,
17106
+ relativeDirPath,
17107
+ relativeFilePath,
17108
+ fileContent,
17109
+ validate,
17110
+ global,
17111
+ root: false
17112
+ });
17113
+ }
17114
+ static async fromRootFile({
17115
+ baseDir,
17116
+ relativeFilePath,
17117
+ overrideDirPath,
17118
+ validate,
17119
+ global,
17120
+ paths
17121
+ }) {
17022
17122
  const relativeDirPath = overrideDirPath ?? paths.root.relativeDirPath;
17023
17123
  const agentsMdExpectedLocationsDescription = "alternativeRoots" in paths && paths.alternativeRoots && paths.alternativeRoots.length > 0 ? `${(0, import_node_path126.join)(paths.root.relativeDirPath, paths.root.relativeFilePath)} or project root` : (0, import_node_path126.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
17024
17124
  if (relativeFilePath !== "AGENTS.md") {
@@ -17307,6 +17407,7 @@ var rulesProcessorToolTargets = [
17307
17407
  "cline",
17308
17408
  "codexcli",
17309
17409
  "copilot",
17410
+ "copilotcli",
17310
17411
  "cursor",
17311
17412
  "deepagents",
17312
17413
  "factorydroid",
@@ -17430,6 +17531,17 @@ var toolRuleFactories = /* @__PURE__ */ new Map([
17430
17531
  }
17431
17532
  }
17432
17533
  ],
17534
+ [
17535
+ "copilotcli",
17536
+ {
17537
+ class: CopilotcliRule,
17538
+ meta: {
17539
+ extension: "md",
17540
+ supportsGlobal: true,
17541
+ ruleDiscoveryMode: "auto"
17542
+ }
17543
+ }
17544
+ ],
17433
17545
  [
17434
17546
  "cursor",
17435
17547
  {
@@ -17949,6 +18061,24 @@ var RulesProcessor = class extends FeatureProcessor {
17949
18061
  const dirName = (0, import_node_path129.dirname)((0, import_node_path129.relative)(this.baseDir, filePath));
17950
18062
  return dirName === "" ? "." : dirName;
17951
18063
  };
18064
+ const buildDeletionRulesFromPaths = (filePaths, opts) => {
18065
+ const isNonRoot = opts !== void 0;
18066
+ const effectiveBaseDir = isNonRoot ? opts.baseDirOverride : this.baseDir;
18067
+ return filePaths.map((filePath) => {
18068
+ const relativeDirPath = isNonRoot ? opts.relativeDirPathOverride : resolveRelativeDirPath(filePath);
18069
+ const relativeFilePath = isNonRoot ? (0, import_node_path129.relative)(effectiveBaseDir, filePath) : (0, import_node_path129.basename)(filePath);
18070
+ checkPathTraversal({
18071
+ relativePath: isNonRoot ? relativeFilePath : relativeDirPath,
18072
+ intendedRootDir: effectiveBaseDir
18073
+ });
18074
+ return factory.class.forDeletion({
18075
+ baseDir: this.baseDir,
18076
+ relativeDirPath,
18077
+ relativeFilePath,
18078
+ global: this.global
18079
+ });
18080
+ }).filter((rule) => rule.isDeletable());
18081
+ };
17952
18082
  const findFilesWithFallback = async (primaryGlob, alternativeRoots, buildAltGlob) => {
17953
18083
  const primaryFilePaths = await findFilesByGlobs(primaryGlob);
17954
18084
  if (primaryFilePaths.length > 0) {
@@ -17973,19 +18103,7 @@ var RulesProcessor = class extends FeatureProcessor {
17973
18103
  (alt) => (0, import_node_path129.join)(this.baseDir, alt.relativeDirPath, alt.relativeFilePath)
17974
18104
  );
17975
18105
  if (forDeletion) {
17976
- return uniqueRootFilePaths.map((filePath) => {
17977
- const relativeDirPath = resolveRelativeDirPath(filePath);
17978
- checkPathTraversal({
17979
- relativePath: relativeDirPath,
17980
- intendedRootDir: this.baseDir
17981
- });
17982
- return factory.class.forDeletion({
17983
- baseDir: this.baseDir,
17984
- relativeDirPath,
17985
- relativeFilePath: (0, import_node_path129.basename)(filePath),
17986
- global: this.global
17987
- });
17988
- }).filter((rule) => rule.isDeletable());
18106
+ return buildDeletionRulesFromPaths(uniqueRootFilePaths);
17989
18107
  }
17990
18108
  return await Promise.all(
17991
18109
  uniqueRootFilePaths.map((filePath) => {
@@ -18015,19 +18133,7 @@ var RulesProcessor = class extends FeatureProcessor {
18015
18133
  const uniqueLocalRootFilePaths2 = await findFilesByGlobs(
18016
18134
  (0, import_node_path129.join)(this.baseDir, "AGENTS.local.md")
18017
18135
  );
18018
- return uniqueLocalRootFilePaths2.map((filePath) => {
18019
- const relativeDirPath = resolveRelativeDirPath(filePath);
18020
- checkPathTraversal({
18021
- relativePath: relativeDirPath,
18022
- intendedRootDir: this.baseDir
18023
- });
18024
- return factory.class.forDeletion({
18025
- baseDir: this.baseDir,
18026
- relativeDirPath,
18027
- relativeFilePath: (0, import_node_path129.basename)(filePath),
18028
- global: this.global
18029
- });
18030
- }).filter((rule) => rule.isDeletable());
18136
+ return buildDeletionRulesFromPaths(uniqueLocalRootFilePaths2);
18031
18137
  }
18032
18138
  if (this.toolTarget !== "claudecode" && this.toolTarget !== "claudecode-legacy") {
18033
18139
  return [];
@@ -18040,19 +18146,7 @@ var RulesProcessor = class extends FeatureProcessor {
18040
18146
  settablePaths.alternativeRoots,
18041
18147
  (alt) => (0, import_node_path129.join)(this.baseDir, alt.relativeDirPath, "CLAUDE.local.md")
18042
18148
  );
18043
- return uniqueLocalRootFilePaths.map((filePath) => {
18044
- const relativeDirPath = resolveRelativeDirPath(filePath);
18045
- checkPathTraversal({
18046
- relativePath: relativeDirPath,
18047
- intendedRootDir: this.baseDir
18048
- });
18049
- return factory.class.forDeletion({
18050
- baseDir: this.baseDir,
18051
- relativeDirPath,
18052
- relativeFilePath: (0, import_node_path129.basename)(filePath),
18053
- global: this.global
18054
- });
18055
- }).filter((rule) => rule.isDeletable());
18149
+ return buildDeletionRulesFromPaths(uniqueLocalRootFilePaths);
18056
18150
  })();
18057
18151
  this.logger.debug(
18058
18152
  `Found ${localRootToolRules.length} local root tool rule files for deletion`
@@ -18066,19 +18160,7 @@ var RulesProcessor = class extends FeatureProcessor {
18066
18160
  return [];
18067
18161
  }
18068
18162
  const mirrorPaths = await findFilesByGlobs((0, import_node_path129.join)(this.baseDir, "AGENTS.md"));
18069
- return mirrorPaths.map((filePath) => {
18070
- const relativeDirPath = resolveRelativeDirPath(filePath);
18071
- checkPathTraversal({
18072
- relativePath: relativeDirPath,
18073
- intendedRootDir: this.baseDir
18074
- });
18075
- return factory.class.forDeletion({
18076
- baseDir: this.baseDir,
18077
- relativeDirPath,
18078
- relativeFilePath: (0, import_node_path129.basename)(filePath),
18079
- global: this.global
18080
- });
18081
- }).filter((rule) => rule.isDeletable());
18163
+ return buildDeletionRulesFromPaths(mirrorPaths);
18082
18164
  })();
18083
18165
  const nonRootToolRules = await (async () => {
18084
18166
  if (!settablePaths.nonRoot) {
@@ -18088,8 +18170,14 @@ var RulesProcessor = class extends FeatureProcessor {
18088
18170
  const nonRootFilePaths = await findFilesByGlobs(
18089
18171
  (0, import_node_path129.join)(nonRootBaseDir, "**", `*.${factory.meta.extension}`)
18090
18172
  );
18173
+ if (forDeletion) {
18174
+ return buildDeletionRulesFromPaths(nonRootFilePaths, {
18175
+ baseDirOverride: nonRootBaseDir,
18176
+ relativeDirPathOverride: settablePaths.nonRoot.relativeDirPath
18177
+ });
18178
+ }
18091
18179
  const modularRootRelative = settablePaths.nonRoot.relativeDirPath;
18092
- const nonRootPathsForImport = !forDeletion && this.toolTarget === "rovodev" ? nonRootFilePaths.filter((filePath) => {
18180
+ const nonRootPathsForImport = this.toolTarget === "rovodev" ? nonRootFilePaths.filter((filePath) => {
18093
18181
  const relativeFilePath = (0, import_node_path129.relative)(nonRootBaseDir, filePath);
18094
18182
  const ok = RovodevRule.isAllowedModularRulesRelativePath(relativeFilePath);
18095
18183
  if (!ok) {
@@ -18099,21 +18187,6 @@ var RulesProcessor = class extends FeatureProcessor {
18099
18187
  }
18100
18188
  return ok;
18101
18189
  }) : nonRootFilePaths;
18102
- if (forDeletion) {
18103
- return nonRootFilePaths.map((filePath) => {
18104
- const relativeFilePath = (0, import_node_path129.relative)(nonRootBaseDir, filePath);
18105
- checkPathTraversal({
18106
- relativePath: relativeFilePath,
18107
- intendedRootDir: nonRootBaseDir
18108
- });
18109
- return factory.class.forDeletion({
18110
- baseDir: this.baseDir,
18111
- relativeDirPath: settablePaths.nonRoot?.relativeDirPath ?? ".",
18112
- relativeFilePath,
18113
- global: this.global
18114
- });
18115
- }).filter((rule) => rule.isDeletable());
18116
- }
18117
18190
  return await Promise.all(
18118
18191
  nonRootPathsForImport.map((filePath) => {
18119
18192
  const relativeFilePath = (0, import_node_path129.relative)(nonRootBaseDir, filePath);
package/dist/index.d.cts CHANGED
@@ -120,6 +120,9 @@ declare abstract class AiDir {
120
120
  frontmatter?: Record<string, unknown>;
121
121
  } | undefined;
122
122
  getOtherFiles(): AiDirFile[];
123
+ /**
124
+ * Returns the relative path from CWD with POSIX separators for consistent cross-platform output.
125
+ */
123
126
  getRelativePathFromCwd(): string;
124
127
  getGlobal(): boolean;
125
128
  setMainFile(name: string, body: string, frontmatter?: Record<string, unknown>): void;
package/dist/index.d.ts CHANGED
@@ -120,6 +120,9 @@ declare abstract class AiDir {
120
120
  frontmatter?: Record<string, unknown>;
121
121
  } | undefined;
122
122
  getOtherFiles(): AiDirFile[];
123
+ /**
124
+ * Returns the relative path from CWD with POSIX separators for consistent cross-platform output.
125
+ */
123
126
  getRelativePathFromCwd(): string;
124
127
  getGlobal(): boolean;
125
128
  setMainFile(name: string, body: string, frontmatter?: Record<string, unknown>): void;
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  checkRulesyncDirExists,
7
7
  generate,
8
8
  importFromTool
9
- } from "./chunk-A4FZT3JT.js";
9
+ } from "./chunk-MMC5VK27.js";
10
10
 
11
11
  // src/index.ts
12
12
  async function generate2(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "7.24.0",
3
+ "version": "7.26.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",