rulesync 8.16.0 → 8.17.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.
@@ -7610,6 +7610,16 @@ var McpServerSchema = z24.looseObject({
7610
7610
  tools: z24.optional(z24.array(z24.string())),
7611
7611
  kiroAutoApprove: z24.optional(z24.array(z24.string())),
7612
7612
  kiroAutoBlock: z24.optional(z24.array(z24.string())),
7613
+ // Codex CLI-specific: list of shell env var names that codex should pass
7614
+ // through from the user's environment to the MCP server process.
7615
+ // Distinct from `env` (a literal name→value map): `envVars` is a list of
7616
+ // variable NAMES whose values come from the user's shell at runtime.
7617
+ // Only honoured by the codex generator (renamed to `env_vars` in codex
7618
+ // TOML output, matching codex's native field name — see the
7619
+ // `enabledTools`→`enabled_tools` precedent in `codexcli-mcp.ts`).
7620
+ // Stripped by `RulesyncMcp.getMcpServers()` so it does not leak into
7621
+ // other tools' configs.
7622
+ envVars: z24.optional(z24.array(z24.string())),
7613
7623
  headers: z24.optional(z24.record(z24.string(), z24.string())),
7614
7624
  enabledTools: z24.optional(z24.array(z24.string())),
7615
7625
  disabledTools: z24.optional(z24.array(z24.string()))
@@ -7712,10 +7722,11 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
7712
7722
  });
7713
7723
  }
7714
7724
  getMcpServers() {
7715
- const entries = Object.entries(this.json.mcpServers);
7725
+ const mcpServers = this.json.mcpServers ?? {};
7726
+ const entries = Object.entries(mcpServers);
7716
7727
  return Object.fromEntries(
7717
7728
  entries.map(([serverName, serverConfig]) => {
7718
- return [serverName, omit(serverConfig, ["targets", "description", "exposed"])];
7729
+ return [serverName, omit(serverConfig, ["targets", "description", "exposed", "envVars"])];
7719
7730
  })
7720
7731
  );
7721
7732
  }
@@ -7934,11 +7945,17 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
7934
7945
  rulesyncMcp,
7935
7946
  validate = true
7936
7947
  }) {
7948
+ const json = rulesyncMcp.getJson();
7949
+ const fileContent = JSON.stringify(
7950
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
7951
+ null,
7952
+ 2
7953
+ );
7937
7954
  return new _ClineMcp({
7938
7955
  outputRoot,
7939
7956
  relativeDirPath: this.getSettablePaths().relativeDirPath,
7940
7957
  relativeFilePath: this.getSettablePaths().relativeFilePath,
7941
- fileContent: rulesyncMcp.getFileContent(),
7958
+ fileContent,
7942
7959
  validate
7943
7960
  });
7944
7961
  }
@@ -7982,6 +7999,8 @@ function convertFromCodexFormat(codexMcp) {
7982
7999
  converted["enabledTools"] = value;
7983
8000
  } else if (key === "disabled_tools") {
7984
8001
  converted["disabledTools"] = value;
8002
+ } else if (key === "env_vars") {
8003
+ converted["envVars"] = value;
7985
8004
  } else {
7986
8005
  converted[key] = value;
7987
8006
  }
@@ -8003,6 +8022,8 @@ function convertToCodexFormat(mcpServers) {
8003
8022
  converted["enabled_tools"] = value;
8004
8023
  } else if (key === "disabledTools") {
8005
8024
  converted["disabled_tools"] = value;
8025
+ } else if (key === "envVars") {
8026
+ converted["env_vars"] = value;
8006
8027
  } else {
8007
8028
  converted[key] = value;
8008
8029
  }
@@ -8098,7 +8119,12 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
8098
8119
  const filtered = {};
8099
8120
  for (const [key, value] of Object.entries(obj)) {
8100
8121
  if (value === null) continue;
8101
- if (typeof value === "object" && Object.keys(value).length === 0) continue;
8122
+ if (typeof value === "object" && !Array.isArray(value)) {
8123
+ const cleaned = this.removeEmptyEntries(value);
8124
+ if (Object.keys(cleaned).length === 0) continue;
8125
+ filtered[key] = cleaned;
8126
+ continue;
8127
+ }
8102
8128
  filtered[key] = value;
8103
8129
  }
8104
8130
  return filtered;
@@ -8475,8 +8501,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
8475
8501
  { cause: error }
8476
8502
  );
8477
8503
  }
8478
- const rulesyncJson = rulesyncMcp.getJson();
8479
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
8504
+ const mcpServers = rulesyncMcp.getMcpServers();
8480
8505
  const transformedServers = convertEnvToCursorFormat(mcpServers);
8481
8506
  const cursorConfig = { ...json, mcpServers: transformedServers };
8482
8507
  return new _CursorMcp({
@@ -8645,9 +8670,9 @@ var FactorydroidMcp = class _FactorydroidMcp extends ToolMcp {
8645
8670
  rulesyncMcp,
8646
8671
  validate = true
8647
8672
  }) {
8648
- const json = rulesyncMcp.getJson();
8673
+ const mcpServers = rulesyncMcp.getMcpServers();
8649
8674
  const factorydroidConfig = {
8650
- mcpServers: json.mcpServers || {}
8675
+ mcpServers
8651
8676
  };
8652
8677
  const fileContent = JSON.stringify(factorydroidConfig, null, 2);
8653
8678
  return new _FactorydroidMcp({
@@ -8733,7 +8758,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
8733
8758
  JSON.stringify({ mcpServers: {} }, null, 2)
8734
8759
  );
8735
8760
  const json = JSON.parse(fileContent);
8736
- const newJson = { ...json, mcpServers: rulesyncMcp.getJson().mcpServers };
8761
+ const newJson = { ...json, mcpServers: rulesyncMcp.getMcpServers() };
8737
8762
  return new _GeminiCliMcp({
8738
8763
  outputRoot,
8739
8764
  relativeDirPath: paths.relativeDirPath,
@@ -8814,11 +8839,17 @@ var JunieMcp = class _JunieMcp extends ToolMcp {
8814
8839
  rulesyncMcp,
8815
8840
  validate = true
8816
8841
  }) {
8842
+ const json = rulesyncMcp.getJson();
8843
+ const fileContent = JSON.stringify(
8844
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
8845
+ null,
8846
+ 2
8847
+ );
8817
8848
  return new _JunieMcp({
8818
8849
  outputRoot,
8819
8850
  relativeDirPath: this.getSettablePaths().relativeDirPath,
8820
8851
  relativeFilePath: this.getSettablePaths().relativeFilePath,
8821
- fileContent: rulesyncMcp.getFileContent(),
8852
+ fileContent,
8822
8853
  validate
8823
8854
  });
8824
8855
  }
@@ -9598,8 +9629,7 @@ var RovodevMcp = class _RovodevMcp extends ToolMcp {
9598
9629
  JSON.stringify({ mcpServers: {} }, null, 2)
9599
9630
  );
9600
9631
  const json = parseRovodevMcpJson(fileContent, paths.relativeDirPath, paths.relativeFilePath);
9601
- const rulesyncJson = rulesyncMcp.getJson();
9602
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
9632
+ const mcpServers = rulesyncMcp.getMcpServers();
9603
9633
  const rovodevConfig = { ...json, mcpServers };
9604
9634
  return new _RovodevMcp({
9605
9635
  outputRoot,
@@ -11024,7 +11054,8 @@ function convertRulesyncToCodexProfile({
11024
11054
  filesystem,
11025
11055
  projectRootFilesystem,
11026
11056
  pattern,
11027
- access: mapReadAction(action)
11057
+ access: mapReadAction(action),
11058
+ logger
11028
11059
  });
11029
11060
  }
11030
11061
  continue;
@@ -11035,7 +11066,8 @@ function convertRulesyncToCodexProfile({
11035
11066
  filesystem,
11036
11067
  projectRootFilesystem,
11037
11068
  pattern,
11038
- access: mapWriteAction(action)
11069
+ access: mapWriteAction(action),
11070
+ logger
11039
11071
  });
11040
11072
  }
11041
11073
  continue;
@@ -11057,6 +11089,11 @@ function convertRulesyncToCodexProfile({
11057
11089
  );
11058
11090
  }
11059
11091
  if (Object.keys(projectRootFilesystem).length > 0) {
11092
+ if (typeof filesystem[CODEX_PROJECT_ROOTS_KEY] === "string") {
11093
+ logger?.warn(
11094
+ `"${CODEX_PROJECT_ROOTS_KEY}" is set as a direct filesystem access rule in the permissions, but it will be overwritten by project-root rules. Consider removing the direct "${CODEX_PROJECT_ROOTS_KEY}" entry.`
11095
+ );
11096
+ }
11060
11097
  if (Object.keys(projectRootFilesystem).some((pattern) => pattern.includes("**"))) {
11061
11098
  filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
11062
11099
  }
@@ -11107,8 +11144,13 @@ function addFilesystemRule({
11107
11144
  filesystem,
11108
11145
  projectRootFilesystem,
11109
11146
  pattern,
11110
- access
11147
+ access,
11148
+ logger
11111
11149
  }) {
11150
+ if (pattern.trim() === "") {
11151
+ logger?.warn("Skipping empty pattern in filesystem permissions.");
11152
+ return;
11153
+ }
11112
11154
  if (canBeCodexFilesystemRoot(pattern)) {
11113
11155
  filesystem[pattern] = access;
11114
11156
  return;
@@ -7643,6 +7643,16 @@ var McpServerSchema = import_mini24.z.looseObject({
7643
7643
  tools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7644
7644
  kiroAutoApprove: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7645
7645
  kiroAutoBlock: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7646
+ // Codex CLI-specific: list of shell env var names that codex should pass
7647
+ // through from the user's environment to the MCP server process.
7648
+ // Distinct from `env` (a literal name→value map): `envVars` is a list of
7649
+ // variable NAMES whose values come from the user's shell at runtime.
7650
+ // Only honoured by the codex generator (renamed to `env_vars` in codex
7651
+ // TOML output, matching codex's native field name — see the
7652
+ // `enabledTools`→`enabled_tools` precedent in `codexcli-mcp.ts`).
7653
+ // Stripped by `RulesyncMcp.getMcpServers()` so it does not leak into
7654
+ // other tools' configs.
7655
+ envVars: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7646
7656
  headers: import_mini24.z.optional(import_mini24.z.record(import_mini24.z.string(), import_mini24.z.string())),
7647
7657
  enabledTools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7648
7658
  disabledTools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string()))
@@ -7745,10 +7755,11 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
7745
7755
  });
7746
7756
  }
7747
7757
  getMcpServers() {
7748
- const entries = Object.entries(this.json.mcpServers);
7758
+ const mcpServers = this.json.mcpServers ?? {};
7759
+ const entries = Object.entries(mcpServers);
7749
7760
  return Object.fromEntries(
7750
7761
  entries.map(([serverName, serverConfig]) => {
7751
- return [serverName, (0, import_object.omit)(serverConfig, ["targets", "description", "exposed"])];
7762
+ return [serverName, (0, import_object.omit)(serverConfig, ["targets", "description", "exposed", "envVars"])];
7752
7763
  })
7753
7764
  );
7754
7765
  }
@@ -7967,11 +7978,17 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
7967
7978
  rulesyncMcp,
7968
7979
  validate = true
7969
7980
  }) {
7981
+ const json = rulesyncMcp.getJson();
7982
+ const fileContent = JSON.stringify(
7983
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
7984
+ null,
7985
+ 2
7986
+ );
7970
7987
  return new _ClineMcp({
7971
7988
  outputRoot,
7972
7989
  relativeDirPath: this.getSettablePaths().relativeDirPath,
7973
7990
  relativeFilePath: this.getSettablePaths().relativeFilePath,
7974
- fileContent: rulesyncMcp.getFileContent(),
7991
+ fileContent,
7975
7992
  validate
7976
7993
  });
7977
7994
  }
@@ -8015,6 +8032,8 @@ function convertFromCodexFormat(codexMcp) {
8015
8032
  converted["enabledTools"] = value;
8016
8033
  } else if (key === "disabled_tools") {
8017
8034
  converted["disabledTools"] = value;
8035
+ } else if (key === "env_vars") {
8036
+ converted["envVars"] = value;
8018
8037
  } else {
8019
8038
  converted[key] = value;
8020
8039
  }
@@ -8036,6 +8055,8 @@ function convertToCodexFormat(mcpServers) {
8036
8055
  converted["enabled_tools"] = value;
8037
8056
  } else if (key === "disabledTools") {
8038
8057
  converted["disabled_tools"] = value;
8058
+ } else if (key === "envVars") {
8059
+ converted["env_vars"] = value;
8039
8060
  } else {
8040
8061
  converted[key] = value;
8041
8062
  }
@@ -8131,7 +8152,12 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
8131
8152
  const filtered = {};
8132
8153
  for (const [key, value] of Object.entries(obj)) {
8133
8154
  if (value === null) continue;
8134
- if (typeof value === "object" && Object.keys(value).length === 0) continue;
8155
+ if (typeof value === "object" && !Array.isArray(value)) {
8156
+ const cleaned = this.removeEmptyEntries(value);
8157
+ if (Object.keys(cleaned).length === 0) continue;
8158
+ filtered[key] = cleaned;
8159
+ continue;
8160
+ }
8135
8161
  filtered[key] = value;
8136
8162
  }
8137
8163
  return filtered;
@@ -8508,8 +8534,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
8508
8534
  { cause: error }
8509
8535
  );
8510
8536
  }
8511
- const rulesyncJson = rulesyncMcp.getJson();
8512
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
8537
+ const mcpServers = rulesyncMcp.getMcpServers();
8513
8538
  const transformedServers = convertEnvToCursorFormat(mcpServers);
8514
8539
  const cursorConfig = { ...json, mcpServers: transformedServers };
8515
8540
  return new _CursorMcp({
@@ -8678,9 +8703,9 @@ var FactorydroidMcp = class _FactorydroidMcp extends ToolMcp {
8678
8703
  rulesyncMcp,
8679
8704
  validate = true
8680
8705
  }) {
8681
- const json = rulesyncMcp.getJson();
8706
+ const mcpServers = rulesyncMcp.getMcpServers();
8682
8707
  const factorydroidConfig = {
8683
- mcpServers: json.mcpServers || {}
8708
+ mcpServers
8684
8709
  };
8685
8710
  const fileContent = JSON.stringify(factorydroidConfig, null, 2);
8686
8711
  return new _FactorydroidMcp({
@@ -8766,7 +8791,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
8766
8791
  JSON.stringify({ mcpServers: {} }, null, 2)
8767
8792
  );
8768
8793
  const json = JSON.parse(fileContent);
8769
- const newJson = { ...json, mcpServers: rulesyncMcp.getJson().mcpServers };
8794
+ const newJson = { ...json, mcpServers: rulesyncMcp.getMcpServers() };
8770
8795
  return new _GeminiCliMcp({
8771
8796
  outputRoot,
8772
8797
  relativeDirPath: paths.relativeDirPath,
@@ -8847,11 +8872,17 @@ var JunieMcp = class _JunieMcp extends ToolMcp {
8847
8872
  rulesyncMcp,
8848
8873
  validate = true
8849
8874
  }) {
8875
+ const json = rulesyncMcp.getJson();
8876
+ const fileContent = JSON.stringify(
8877
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
8878
+ null,
8879
+ 2
8880
+ );
8850
8881
  return new _JunieMcp({
8851
8882
  outputRoot,
8852
8883
  relativeDirPath: this.getSettablePaths().relativeDirPath,
8853
8884
  relativeFilePath: this.getSettablePaths().relativeFilePath,
8854
- fileContent: rulesyncMcp.getFileContent(),
8885
+ fileContent,
8855
8886
  validate
8856
8887
  });
8857
8888
  }
@@ -9631,8 +9662,7 @@ var RovodevMcp = class _RovodevMcp extends ToolMcp {
9631
9662
  JSON.stringify({ mcpServers: {} }, null, 2)
9632
9663
  );
9633
9664
  const json = parseRovodevMcpJson(fileContent, paths.relativeDirPath, paths.relativeFilePath);
9634
- const rulesyncJson = rulesyncMcp.getJson();
9635
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
9665
+ const mcpServers = rulesyncMcp.getMcpServers();
9636
9666
  const rovodevConfig = { ...json, mcpServers };
9637
9667
  return new _RovodevMcp({
9638
9668
  outputRoot,
@@ -11057,7 +11087,8 @@ function convertRulesyncToCodexProfile({
11057
11087
  filesystem,
11058
11088
  projectRootFilesystem,
11059
11089
  pattern,
11060
- access: mapReadAction(action)
11090
+ access: mapReadAction(action),
11091
+ logger: logger5
11061
11092
  });
11062
11093
  }
11063
11094
  continue;
@@ -11068,7 +11099,8 @@ function convertRulesyncToCodexProfile({
11068
11099
  filesystem,
11069
11100
  projectRootFilesystem,
11070
11101
  pattern,
11071
- access: mapWriteAction(action)
11102
+ access: mapWriteAction(action),
11103
+ logger: logger5
11072
11104
  });
11073
11105
  }
11074
11106
  continue;
@@ -11090,6 +11122,11 @@ function convertRulesyncToCodexProfile({
11090
11122
  );
11091
11123
  }
11092
11124
  if (Object.keys(projectRootFilesystem).length > 0) {
11125
+ if (typeof filesystem[CODEX_PROJECT_ROOTS_KEY] === "string") {
11126
+ logger5?.warn(
11127
+ `"${CODEX_PROJECT_ROOTS_KEY}" is set as a direct filesystem access rule in the permissions, but it will be overwritten by project-root rules. Consider removing the direct "${CODEX_PROJECT_ROOTS_KEY}" entry.`
11128
+ );
11129
+ }
11093
11130
  if (Object.keys(projectRootFilesystem).some((pattern) => pattern.includes("**"))) {
11094
11131
  filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
11095
11132
  }
@@ -11140,8 +11177,13 @@ function addFilesystemRule({
11140
11177
  filesystem,
11141
11178
  projectRootFilesystem,
11142
11179
  pattern,
11143
- access
11180
+ access,
11181
+ logger: logger5
11144
11182
  }) {
11183
+ if (pattern.trim() === "") {
11184
+ logger5?.warn("Skipping empty pattern in filesystem permissions.");
11185
+ return;
11186
+ }
11145
11187
  if (canBeCodexFilesystemRoot(pattern)) {
11146
11188
  filesystem[pattern] = access;
11147
11189
  return;
@@ -31711,7 +31753,7 @@ function wrapCommand({
31711
31753
  }
31712
31754
 
31713
31755
  // src/cli/index.ts
31714
- var getVersion = () => "8.16.0";
31756
+ var getVersion = () => "8.17.0";
31715
31757
  function wrapCommand2(name, errorCode, handler) {
31716
31758
  return wrapCommand({ name, errorCode, handler, getVersion });
31717
31759
  }
package/dist/cli/index.js CHANGED
@@ -79,7 +79,7 @@ import {
79
79
  stringifyFrontmatter,
80
80
  toPosixPath,
81
81
  writeFileContent
82
- } from "../chunk-DOWXY74I.js";
82
+ } from "../chunk-RXCRO26Z.js";
83
83
 
84
84
  // src/cli/index.ts
85
85
  import { Command } from "commander";
@@ -6485,7 +6485,7 @@ function wrapCommand({
6485
6485
  }
6486
6486
 
6487
6487
  // src/cli/index.ts
6488
- var getVersion = () => "8.16.0";
6488
+ var getVersion = () => "8.17.0";
6489
6489
  function wrapCommand2(name, errorCode, handler) {
6490
6490
  return wrapCommand({ name, errorCode, handler, getVersion });
6491
6491
  }
package/dist/index.cjs CHANGED
@@ -7516,6 +7516,16 @@ var McpServerSchema = import_mini24.z.looseObject({
7516
7516
  tools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7517
7517
  kiroAutoApprove: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7518
7518
  kiroAutoBlock: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7519
+ // Codex CLI-specific: list of shell env var names that codex should pass
7520
+ // through from the user's environment to the MCP server process.
7521
+ // Distinct from `env` (a literal name→value map): `envVars` is a list of
7522
+ // variable NAMES whose values come from the user's shell at runtime.
7523
+ // Only honoured by the codex generator (renamed to `env_vars` in codex
7524
+ // TOML output, matching codex's native field name — see the
7525
+ // `enabledTools`→`enabled_tools` precedent in `codexcli-mcp.ts`).
7526
+ // Stripped by `RulesyncMcp.getMcpServers()` so it does not leak into
7527
+ // other tools' configs.
7528
+ envVars: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7519
7529
  headers: import_mini24.z.optional(import_mini24.z.record(import_mini24.z.string(), import_mini24.z.string())),
7520
7530
  enabledTools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string())),
7521
7531
  disabledTools: import_mini24.z.optional(import_mini24.z.array(import_mini24.z.string()))
@@ -7618,10 +7628,11 @@ var RulesyncMcp = class _RulesyncMcp extends RulesyncFile {
7618
7628
  });
7619
7629
  }
7620
7630
  getMcpServers() {
7621
- const entries = Object.entries(this.json.mcpServers);
7631
+ const mcpServers = this.json.mcpServers ?? {};
7632
+ const entries = Object.entries(mcpServers);
7622
7633
  return Object.fromEntries(
7623
7634
  entries.map(([serverName, serverConfig]) => {
7624
- return [serverName, (0, import_object.omit)(serverConfig, ["targets", "description", "exposed"])];
7635
+ return [serverName, (0, import_object.omit)(serverConfig, ["targets", "description", "exposed", "envVars"])];
7625
7636
  })
7626
7637
  );
7627
7638
  }
@@ -7840,11 +7851,17 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
7840
7851
  rulesyncMcp,
7841
7852
  validate = true
7842
7853
  }) {
7854
+ const json = rulesyncMcp.getJson();
7855
+ const fileContent = JSON.stringify(
7856
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
7857
+ null,
7858
+ 2
7859
+ );
7843
7860
  return new _ClineMcp({
7844
7861
  outputRoot,
7845
7862
  relativeDirPath: this.getSettablePaths().relativeDirPath,
7846
7863
  relativeFilePath: this.getSettablePaths().relativeFilePath,
7847
- fileContent: rulesyncMcp.getFileContent(),
7864
+ fileContent,
7848
7865
  validate
7849
7866
  });
7850
7867
  }
@@ -7888,6 +7905,8 @@ function convertFromCodexFormat(codexMcp) {
7888
7905
  converted["enabledTools"] = value;
7889
7906
  } else if (key === "disabled_tools") {
7890
7907
  converted["disabledTools"] = value;
7908
+ } else if (key === "env_vars") {
7909
+ converted["envVars"] = value;
7891
7910
  } else {
7892
7911
  converted[key] = value;
7893
7912
  }
@@ -7909,6 +7928,8 @@ function convertToCodexFormat(mcpServers) {
7909
7928
  converted["enabled_tools"] = value;
7910
7929
  } else if (key === "disabledTools") {
7911
7930
  converted["disabled_tools"] = value;
7931
+ } else if (key === "envVars") {
7932
+ converted["env_vars"] = value;
7912
7933
  } else {
7913
7934
  converted[key] = value;
7914
7935
  }
@@ -8004,7 +8025,12 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
8004
8025
  const filtered = {};
8005
8026
  for (const [key, value] of Object.entries(obj)) {
8006
8027
  if (value === null) continue;
8007
- if (typeof value === "object" && Object.keys(value).length === 0) continue;
8028
+ if (typeof value === "object" && !Array.isArray(value)) {
8029
+ const cleaned = this.removeEmptyEntries(value);
8030
+ if (Object.keys(cleaned).length === 0) continue;
8031
+ filtered[key] = cleaned;
8032
+ continue;
8033
+ }
8008
8034
  filtered[key] = value;
8009
8035
  }
8010
8036
  return filtered;
@@ -8381,8 +8407,7 @@ var CursorMcp = class _CursorMcp extends ToolMcp {
8381
8407
  { cause: error }
8382
8408
  );
8383
8409
  }
8384
- const rulesyncJson = rulesyncMcp.getJson();
8385
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
8410
+ const mcpServers = rulesyncMcp.getMcpServers();
8386
8411
  const transformedServers = convertEnvToCursorFormat(mcpServers);
8387
8412
  const cursorConfig = { ...json, mcpServers: transformedServers };
8388
8413
  return new _CursorMcp({
@@ -8551,9 +8576,9 @@ var FactorydroidMcp = class _FactorydroidMcp extends ToolMcp {
8551
8576
  rulesyncMcp,
8552
8577
  validate = true
8553
8578
  }) {
8554
- const json = rulesyncMcp.getJson();
8579
+ const mcpServers = rulesyncMcp.getMcpServers();
8555
8580
  const factorydroidConfig = {
8556
- mcpServers: json.mcpServers || {}
8581
+ mcpServers
8557
8582
  };
8558
8583
  const fileContent = JSON.stringify(factorydroidConfig, null, 2);
8559
8584
  return new _FactorydroidMcp({
@@ -8639,7 +8664,7 @@ var GeminiCliMcp = class _GeminiCliMcp extends ToolMcp {
8639
8664
  JSON.stringify({ mcpServers: {} }, null, 2)
8640
8665
  );
8641
8666
  const json = JSON.parse(fileContent);
8642
- const newJson = { ...json, mcpServers: rulesyncMcp.getJson().mcpServers };
8667
+ const newJson = { ...json, mcpServers: rulesyncMcp.getMcpServers() };
8643
8668
  return new _GeminiCliMcp({
8644
8669
  outputRoot,
8645
8670
  relativeDirPath: paths.relativeDirPath,
@@ -8720,11 +8745,17 @@ var JunieMcp = class _JunieMcp extends ToolMcp {
8720
8745
  rulesyncMcp,
8721
8746
  validate = true
8722
8747
  }) {
8748
+ const json = rulesyncMcp.getJson();
8749
+ const fileContent = JSON.stringify(
8750
+ { ...json, mcpServers: rulesyncMcp.getMcpServers() },
8751
+ null,
8752
+ 2
8753
+ );
8723
8754
  return new _JunieMcp({
8724
8755
  outputRoot,
8725
8756
  relativeDirPath: this.getSettablePaths().relativeDirPath,
8726
8757
  relativeFilePath: this.getSettablePaths().relativeFilePath,
8727
- fileContent: rulesyncMcp.getFileContent(),
8758
+ fileContent,
8728
8759
  validate
8729
8760
  });
8730
8761
  }
@@ -9504,8 +9535,7 @@ var RovodevMcp = class _RovodevMcp extends ToolMcp {
9504
9535
  JSON.stringify({ mcpServers: {} }, null, 2)
9505
9536
  );
9506
9537
  const json = parseRovodevMcpJson(fileContent, paths.relativeDirPath, paths.relativeFilePath);
9507
- const rulesyncJson = rulesyncMcp.getJson();
9508
- const mcpServers = isMcpServers(rulesyncJson.mcpServers) ? rulesyncJson.mcpServers : {};
9538
+ const mcpServers = rulesyncMcp.getMcpServers();
9509
9539
  const rovodevConfig = { ...json, mcpServers };
9510
9540
  return new _RovodevMcp({
9511
9541
  outputRoot,
@@ -10930,7 +10960,8 @@ function convertRulesyncToCodexProfile({
10930
10960
  filesystem,
10931
10961
  projectRootFilesystem,
10932
10962
  pattern,
10933
- access: mapReadAction(action)
10963
+ access: mapReadAction(action),
10964
+ logger
10934
10965
  });
10935
10966
  }
10936
10967
  continue;
@@ -10941,7 +10972,8 @@ function convertRulesyncToCodexProfile({
10941
10972
  filesystem,
10942
10973
  projectRootFilesystem,
10943
10974
  pattern,
10944
- access: mapWriteAction(action)
10975
+ access: mapWriteAction(action),
10976
+ logger
10945
10977
  });
10946
10978
  }
10947
10979
  continue;
@@ -10963,6 +10995,11 @@ function convertRulesyncToCodexProfile({
10963
10995
  );
10964
10996
  }
10965
10997
  if (Object.keys(projectRootFilesystem).length > 0) {
10998
+ if (typeof filesystem[CODEX_PROJECT_ROOTS_KEY] === "string") {
10999
+ logger?.warn(
11000
+ `"${CODEX_PROJECT_ROOTS_KEY}" is set as a direct filesystem access rule in the permissions, but it will be overwritten by project-root rules. Consider removing the direct "${CODEX_PROJECT_ROOTS_KEY}" entry.`
11001
+ );
11002
+ }
10966
11003
  if (Object.keys(projectRootFilesystem).some((pattern) => pattern.includes("**"))) {
10967
11004
  filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
10968
11005
  }
@@ -11013,8 +11050,13 @@ function addFilesystemRule({
11013
11050
  filesystem,
11014
11051
  projectRootFilesystem,
11015
11052
  pattern,
11016
- access
11053
+ access,
11054
+ logger
11017
11055
  }) {
11056
+ if (pattern.trim() === "") {
11057
+ logger?.warn("Skipping empty pattern in filesystem permissions.");
11058
+ return;
11059
+ }
11018
11060
  if (canBeCodexFilesystemRoot(pattern)) {
11019
11061
  filesystem[pattern] = access;
11020
11062
  return;
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  convertFromTool,
8
8
  generate,
9
9
  importFromTool
10
- } from "./chunk-DOWXY74I.js";
10
+ } from "./chunk-RXCRO26Z.js";
11
11
 
12
12
  // src/index.ts
13
13
  async function generate2(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "8.16.0",
3
+ "version": "8.17.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",