rulesync 8.17.0 → 8.19.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.
@@ -1158,11 +1158,18 @@ import * as smolToml from "smol-toml";
1158
1158
  // src/utils/frontmatter.ts
1159
1159
  import matter from "gray-matter";
1160
1160
  import { dump, load } from "js-yaml";
1161
+
1162
+ // src/utils/type-guards.ts
1163
+ function isRecord(value) {
1164
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1165
+ }
1161
1166
  function isPlainObject(value) {
1162
- if (value === null || typeof value !== "object") return false;
1163
- const prototype = Object.getPrototypeOf(value);
1164
- return prototype === Object.prototype || prototype === null;
1167
+ if (!isRecord(value)) return false;
1168
+ const proto = Object.getPrototypeOf(value);
1169
+ return proto === null || proto === Object.prototype;
1165
1170
  }
1171
+
1172
+ // src/utils/frontmatter.ts
1166
1173
  function deepRemoveNullishValue(value) {
1167
1174
  if (value === null || value === void 0) {
1168
1175
  return void 0;
@@ -1753,11 +1760,6 @@ var AgentsmdCommand = class _AgentsmdCommand extends SimulatedCommand {
1753
1760
  import { basename, join as join7 } from "path";
1754
1761
  import { z as z6 } from "zod/mini";
1755
1762
 
1756
- // src/utils/type-guards.ts
1757
- function isRecord(value) {
1758
- return typeof value === "object" && value !== null && !Array.isArray(value);
1759
- }
1760
-
1761
1763
  // src/features/commands/rulesync-command.ts
1762
1764
  import { join as join6 } from "path";
1763
1765
  import { z as z5 } from "zod/mini";
@@ -7760,7 +7762,7 @@ var ToolMcp = class extends ToolFile {
7760
7762
  super({
7761
7763
  ...rest,
7762
7764
  validate: true
7763
- // Skip validation during construction
7765
+ // ToolMcp runs subclass validation below when requested
7764
7766
  });
7765
7767
  if (rest.validate) {
7766
7768
  const result = this.validate();
@@ -7818,17 +7820,26 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
7818
7820
  return this.json;
7819
7821
  }
7820
7822
  /**
7821
- * In global mode, ~/.claude/.claude.json should not be deleted
7822
- * as it may contain other user settings.
7823
+ * In global mode, ~/.claude.json should not be deleted as it is the
7824
+ * user's primary Claude Code config and contains many other settings
7825
+ * managed by Claude Code itself (feature flags, project trust list,
7826
+ * hooks, user settings, model selection, etc.).
7823
7827
  * In local mode, .mcp.json can be safely deleted.
7824
7828
  */
7825
7829
  isDeletable() {
7826
7830
  return !this.global;
7827
7831
  }
7832
+ /**
7833
+ * Legacy global path used by rulesync ≤ v8.17.0. The documented store
7834
+ * is `~/.claude.json`; `fromFile` falls back here with a deprecation
7835
+ * warning (mirrors PR #333). Never modified or removed by rulesync.
7836
+ */
7837
+ static LEGACY_GLOBAL_DIR = ".claude";
7838
+ static LEGACY_GLOBAL_FILE = ".claude.json";
7828
7839
  static getSettablePaths({ global } = {}) {
7829
7840
  if (global) {
7830
7841
  return {
7831
- relativeDirPath: ".claude",
7842
+ relativeDirPath: ".",
7832
7843
  relativeFilePath: ".claude.json"
7833
7844
  };
7834
7845
  }
@@ -7840,19 +7851,52 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
7840
7851
  static async fromFile({
7841
7852
  outputRoot = process.cwd(),
7842
7853
  validate = true,
7843
- global = false
7854
+ global = false,
7855
+ logger
7844
7856
  }) {
7845
7857
  const paths = this.getSettablePaths({ global });
7846
- const fileContent = await readFileContentOrNull(
7847
- join49(outputRoot, paths.relativeDirPath, paths.relativeFilePath)
7848
- ) ?? '{"mcpServers":{}}';
7849
- const json = JSON.parse(fileContent);
7850
- const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
7858
+ const recommendedPath = join49(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
7859
+ if (await fileExists(recommendedPath)) {
7860
+ const fileContent = await readFileContent(recommendedPath);
7861
+ const json = JSON.parse(fileContent);
7862
+ const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
7863
+ return new _ClaudecodeMcp({
7864
+ outputRoot,
7865
+ relativeDirPath: paths.relativeDirPath,
7866
+ relativeFilePath: paths.relativeFilePath,
7867
+ fileContent: JSON.stringify(newJson, null, 2),
7868
+ validate,
7869
+ global
7870
+ });
7871
+ }
7872
+ if (global) {
7873
+ const legacyPath = join49(
7874
+ outputRoot,
7875
+ _ClaudecodeMcp.LEGACY_GLOBAL_DIR,
7876
+ _ClaudecodeMcp.LEGACY_GLOBAL_FILE
7877
+ );
7878
+ if (await fileExists(legacyPath)) {
7879
+ logger?.warn(
7880
+ `Warning: using deprecated path "${legacyPath}". Please migrate to "${recommendedPath}"`
7881
+ );
7882
+ const fileContent = await readFileContent(legacyPath);
7883
+ const json = JSON.parse(fileContent);
7884
+ const newJson = { ...json, mcpServers: json.mcpServers ?? {} };
7885
+ return new _ClaudecodeMcp({
7886
+ outputRoot,
7887
+ relativeDirPath: _ClaudecodeMcp.LEGACY_GLOBAL_DIR,
7888
+ relativeFilePath: _ClaudecodeMcp.LEGACY_GLOBAL_FILE,
7889
+ fileContent: JSON.stringify(newJson, null, 2),
7890
+ validate,
7891
+ global
7892
+ });
7893
+ }
7894
+ }
7851
7895
  return new _ClaudecodeMcp({
7852
7896
  outputRoot,
7853
7897
  relativeDirPath: paths.relativeDirPath,
7854
7898
  relativeFilePath: paths.relativeFilePath,
7855
- fileContent: JSON.stringify(newJson, null, 2),
7899
+ fileContent: JSON.stringify({ mcpServers: {} }, null, 2),
7856
7900
  validate,
7857
7901
  global
7858
7902
  });
@@ -7881,7 +7925,7 @@ var ClaudecodeMcp = class _ClaudecodeMcp extends ToolMcp {
7881
7925
  }
7882
7926
  toRulesyncMcp() {
7883
7927
  return this.toRulesyncMcpDefault({
7884
- fileContent: JSON.stringify({ mcpServers: this.json.mcpServers }, null, 2)
7928
+ fileContent: JSON.stringify({ mcpServers: this.json.mcpServers ?? {} }, null, 2)
7885
7929
  });
7886
7930
  }
7887
7931
  validate() {
@@ -7983,14 +8027,16 @@ var ClineMcp = class _ClineMcp extends ToolMcp {
7983
8027
  // src/features/mcp/codexcli-mcp.ts
7984
8028
  import { join as join51 } from "path";
7985
8029
  import * as smolToml3 from "smol-toml";
8030
+ var MAX_REMOVE_EMPTY_ENTRIES_DEPTH = 32;
8031
+ var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
7986
8032
  function convertFromCodexFormat(codexMcp) {
7987
8033
  const result = {};
7988
8034
  for (const [name, config] of Object.entries(codexMcp)) {
7989
- if (typeof config !== "object" || config === null || Array.isArray(config)) {
7990
- continue;
7991
- }
8035
+ if (PROTOTYPE_POLLUTION_KEYS.has(name)) continue;
8036
+ if (!isRecord(config)) continue;
7992
8037
  const converted = {};
7993
8038
  for (const [key, value] of Object.entries(config)) {
8039
+ if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
7994
8040
  if (key === "enabled") {
7995
8041
  if (value === false) {
7996
8042
  converted["disabled"] = true;
@@ -8012,8 +8058,11 @@ function convertFromCodexFormat(codexMcp) {
8012
8058
  function convertToCodexFormat(mcpServers) {
8013
8059
  const result = {};
8014
8060
  for (const [name, config] of Object.entries(mcpServers)) {
8061
+ if (PROTOTYPE_POLLUTION_KEYS.has(name)) continue;
8062
+ if (!isRecord(config)) continue;
8015
8063
  const converted = {};
8016
8064
  for (const [key, value] of Object.entries(config)) {
8065
+ if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
8017
8066
  if (key === "disabled") {
8018
8067
  if (value === true) {
8019
8068
  converted["enabled"] = false;
@@ -8095,6 +8144,14 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
8095
8144
  const mcpServers = rulesyncMcp.getJson().mcpServers;
8096
8145
  const converted = convertToCodexFormat(mcpServers);
8097
8146
  const filteredMcpServers = this.removeEmptyEntries(converted);
8147
+ for (const name of Object.keys(converted)) {
8148
+ if (!Object.hasOwn(filteredMcpServers, name)) {
8149
+ warnWithFallback(
8150
+ void 0,
8151
+ `MCP server "${name}" had no non-empty configuration and was dropped from the codex CLI config`
8152
+ );
8153
+ }
8154
+ }
8098
8155
  configToml["mcp_servers"] = filteredMcpServers;
8099
8156
  return new _CodexcliMcp({
8100
8157
  outputRoot,
@@ -8114,13 +8171,21 @@ var CodexcliMcp = class _CodexcliMcp extends ToolMcp {
8114
8171
  validate() {
8115
8172
  return { success: true, error: null };
8116
8173
  }
8117
- static removeEmptyEntries(obj) {
8174
+ static removeEmptyEntries(obj, depth = 0) {
8118
8175
  if (!obj) return {};
8176
+ if (depth > MAX_REMOVE_EMPTY_ENTRIES_DEPTH) {
8177
+ warnWithFallback(
8178
+ void 0,
8179
+ `removeEmptyEntries: maximum recursion depth (${MAX_REMOVE_EMPTY_ENTRIES_DEPTH}) exceeded; empty nested objects may remain`
8180
+ );
8181
+ return obj;
8182
+ }
8119
8183
  const filtered = {};
8120
8184
  for (const [key, value] of Object.entries(obj)) {
8185
+ if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
8121
8186
  if (value === null) continue;
8122
- if (typeof value === "object" && !Array.isArray(value)) {
8123
- const cleaned = this.removeEmptyEntries(value);
8187
+ if (isPlainObject(value)) {
8188
+ const cleaned = this.removeEmptyEntries(value, depth + 1);
8124
8189
  if (Object.keys(cleaned).length === 0) continue;
8125
8190
  filtered[key] = cleaned;
8126
8191
  continue;
@@ -9813,7 +9878,13 @@ var toolMcpFactories = /* @__PURE__ */ new Map([
9813
9878
  class: KiloMcp,
9814
9879
  meta: {
9815
9880
  supportsProject: true,
9816
- supportsGlobal: false,
9881
+ // Kilo CLI reads global MCP from `~/.config/kilo/kilo.json` (or
9882
+ // `kilo.jsonc`). The path machinery in `KiloMcp.getSettablePaths`
9883
+ // already routes global mode to that location; only this flag
9884
+ // was gating it off. Kilo is an OpenCode fork and uses an
9885
+ // identical native MCP schema, so global parity with opencode
9886
+ // is the natural state.
9887
+ supportsGlobal: true,
9817
9888
  supportsEnabledTools: false,
9818
9889
  supportsDisabledTools: false
9819
9890
  }
@@ -9959,7 +10030,8 @@ var McpProcessor = class extends FeatureProcessor {
9959
10030
  await factory.class.fromFile({
9960
10031
  outputRoot: this.outputRoot,
9961
10032
  validate: true,
9962
- global: this.global
10033
+ global: this.global,
10034
+ logger: this.logger
9963
10035
  })
9964
10036
  ];
9965
10037
  this.logger.debug(`Successfully loaded ${toolMcps.length} ${this.toolTarget} MCP files`);
@@ -12934,7 +13006,7 @@ var PermissionsProcessor = class extends FeatureProcessor {
12934
13006
  // src/features/rules/rules-processor.ts
12935
13007
  import { basename as basename10, dirname as dirname3, join as join151, relative as relative6 } from "path";
12936
13008
  import { encode } from "@toon-format/toon";
12937
- import { z as z79 } from "zod/mini";
13009
+ import { z as z80 } from "zod/mini";
12938
13010
 
12939
13011
  // src/constants/general.ts
12940
13012
  var SKILL_FILE_NAME = "SKILL.md";
@@ -17886,7 +17958,7 @@ var RovodevSubagent = class _RovodevSubagent extends ToolSubagent {
17886
17958
 
17887
17959
  // src/features/subagents/subagents-processor.ts
17888
17960
  import { basename as basename9, join as join122 } from "path";
17889
- import { z as z72 } from "zod/mini";
17961
+ import { z as z73 } from "zod/mini";
17890
17962
 
17891
17963
  // src/features/subagents/claudecode-subagent.ts
17892
17964
  import { join as join110 } from "path";
@@ -19046,6 +19118,7 @@ var JunieSubagent = class _JunieSubagent extends ToolSubagent {
19046
19118
 
19047
19119
  // src/features/subagents/kilo-subagent.ts
19048
19120
  import { join as join118 } from "path";
19121
+ import { z as z71 } from "zod/mini";
19049
19122
 
19050
19123
  // src/features/subagents/opencode-style-subagent.ts
19051
19124
  import { basename as basename8, join as join117 } from "path";
@@ -19112,11 +19185,54 @@ var OpenCodeStyleSubagent = class extends ToolSubagent {
19112
19185
  };
19113
19186
 
19114
19187
  // src/features/subagents/kilo-subagent.ts
19115
- var KiloSubagentFrontmatterSchema = OpenCodeStyleSubagentFrontmatterSchema;
19188
+ var KiloSubagentFrontmatterSchema = z71.looseObject({
19189
+ description: z71.optional(z71.string()),
19190
+ mode: z71._default(z71.string(), "all"),
19191
+ name: z71.optional(z71.string()),
19192
+ displayName: z71.optional(z71.string()),
19193
+ deprecated: z71.optional(z71.boolean()),
19194
+ native: z71.optional(z71.boolean()),
19195
+ hidden: z71.optional(z71.boolean()),
19196
+ top_p: z71.optional(z71.number()),
19197
+ temperature: z71.optional(z71.number()),
19198
+ color: z71.optional(z71.string()),
19199
+ permission: z71.optional(z71.string()),
19200
+ model: z71.optional(z71.string()),
19201
+ variant: z71.optional(z71.string()),
19202
+ prompt: z71.optional(z71.string()),
19203
+ options: z71.optional(z71.looseObject({})),
19204
+ steps: z71.optional(z71.array(z71.looseObject({}))),
19205
+ disable: z71.optional(z71.boolean())
19206
+ });
19116
19207
  var KiloSubagent = class _KiloSubagent extends OpenCodeStyleSubagent {
19208
+ constructor(params) {
19209
+ super(params);
19210
+ if (params.validate !== false) {
19211
+ const result = this.validate();
19212
+ if (!result.success) {
19213
+ throw result.error;
19214
+ }
19215
+ }
19216
+ }
19117
19217
  getToolTarget() {
19118
19218
  return "kilo";
19119
19219
  }
19220
+ getFrontmatter() {
19221
+ return this.frontmatter;
19222
+ }
19223
+ validate() {
19224
+ const result = KiloSubagentFrontmatterSchema.safeParse(this.frontmatter);
19225
+ if (result.success) {
19226
+ this.frontmatter = result.data;
19227
+ return { success: true, error: null };
19228
+ }
19229
+ return {
19230
+ success: false,
19231
+ error: new Error(
19232
+ `Invalid frontmatter in ${join118(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`
19233
+ )
19234
+ };
19235
+ }
19120
19236
  static getSettablePaths({
19121
19237
  global = false
19122
19238
  } = {}) {
@@ -19132,12 +19248,17 @@ var KiloSubagent = class _KiloSubagent extends OpenCodeStyleSubagent {
19132
19248
  }) {
19133
19249
  const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
19134
19250
  const kiloSection = rulesyncFrontmatter.kilo ?? {};
19135
- const kiloFrontmatter = {
19251
+ const parseResult = KiloSubagentFrontmatterSchema.safeParse({
19136
19252
  ...kiloSection,
19137
19253
  description: rulesyncFrontmatter.description,
19138
- mode: typeof kiloSection.mode === "string" ? kiloSection.mode : "subagent",
19139
19254
  ...rulesyncFrontmatter.name && { name: rulesyncFrontmatter.name }
19140
- };
19255
+ });
19256
+ if (!parseResult.success) {
19257
+ throw new Error(
19258
+ `Invalid frontmatter in ${rulesyncSubagent.getRelativeFilePath()}: ${formatError(parseResult.error)}`
19259
+ );
19260
+ }
19261
+ const kiloFrontmatter = parseResult.data;
19141
19262
  const body = rulesyncSubagent.getBody();
19142
19263
  const fileContent = stringifyFrontmatter(body, kiloFrontmatter);
19143
19264
  const paths = this.getSettablePaths({ global });
@@ -19186,38 +19307,40 @@ var KiloSubagent = class _KiloSubagent extends OpenCodeStyleSubagent {
19186
19307
  static forDeletion({
19187
19308
  outputRoot = process.cwd(),
19188
19309
  relativeDirPath,
19189
- relativeFilePath
19310
+ relativeFilePath,
19311
+ global = false
19190
19312
  }) {
19191
19313
  return new _KiloSubagent({
19192
19314
  outputRoot,
19193
19315
  relativeDirPath,
19194
19316
  relativeFilePath,
19195
- frontmatter: { description: "", mode: "subagent" },
19317
+ frontmatter: { description: "", mode: "all" },
19196
19318
  body: "",
19197
19319
  fileContent: "",
19198
- validate: false
19320
+ validate: false,
19321
+ global
19199
19322
  });
19200
19323
  }
19201
19324
  };
19202
19325
 
19203
19326
  // src/features/subagents/kiro-subagent.ts
19204
19327
  import { join as join119 } from "path";
19205
- import { z as z71 } from "zod/mini";
19206
- var KiroCliSubagentJsonSchema = z71.looseObject({
19207
- name: z71.string(),
19208
- description: z71.optional(z71.nullable(z71.string())),
19209
- prompt: z71.optional(z71.nullable(z71.string())),
19210
- tools: z71.optional(z71.nullable(z71.array(z71.string()))),
19211
- toolAliases: z71.optional(z71.nullable(z71.record(z71.string(), z71.string()))),
19212
- toolSettings: z71.optional(z71.nullable(z71.unknown())),
19213
- toolSchema: z71.optional(z71.nullable(z71.unknown())),
19214
- hooks: z71.optional(z71.nullable(z71.record(z71.string(), z71.array(z71.unknown())))),
19215
- model: z71.optional(z71.nullable(z71.string())),
19216
- mcpServers: z71.optional(z71.nullable(z71.record(z71.string(), z71.unknown()))),
19217
- useLegacyMcpJson: z71.optional(z71.nullable(z71.boolean())),
19218
- resources: z71.optional(z71.nullable(z71.array(z71.string()))),
19219
- allowedTools: z71.optional(z71.nullable(z71.array(z71.string()))),
19220
- includeMcpJson: z71.optional(z71.nullable(z71.boolean()))
19328
+ import { z as z72 } from "zod/mini";
19329
+ var KiroCliSubagentJsonSchema = z72.looseObject({
19330
+ name: z72.string(),
19331
+ description: z72.optional(z72.nullable(z72.string())),
19332
+ prompt: z72.optional(z72.nullable(z72.string())),
19333
+ tools: z72.optional(z72.nullable(z72.array(z72.string()))),
19334
+ toolAliases: z72.optional(z72.nullable(z72.record(z72.string(), z72.string()))),
19335
+ toolSettings: z72.optional(z72.nullable(z72.unknown())),
19336
+ toolSchema: z72.optional(z72.nullable(z72.unknown())),
19337
+ hooks: z72.optional(z72.nullable(z72.record(z72.string(), z72.array(z72.unknown())))),
19338
+ model: z72.optional(z72.nullable(z72.string())),
19339
+ mcpServers: z72.optional(z72.nullable(z72.record(z72.string(), z72.unknown()))),
19340
+ useLegacyMcpJson: z72.optional(z72.nullable(z72.boolean())),
19341
+ resources: z72.optional(z72.nullable(z72.array(z72.string()))),
19342
+ allowedTools: z72.optional(z72.nullable(z72.array(z72.string()))),
19343
+ includeMcpJson: z72.optional(z72.nullable(z72.boolean()))
19221
19344
  });
19222
19345
  var KiroSubagent = class _KiroSubagent extends ToolSubagent {
19223
19346
  body;
@@ -19446,7 +19569,8 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends OpenCodeStyleSubagent {
19446
19569
  static forDeletion({
19447
19570
  outputRoot = process.cwd(),
19448
19571
  relativeDirPath,
19449
- relativeFilePath
19572
+ relativeFilePath,
19573
+ global = false
19450
19574
  }) {
19451
19575
  return new _OpenCodeSubagent({
19452
19576
  outputRoot,
@@ -19455,7 +19579,8 @@ var OpenCodeSubagent = class _OpenCodeSubagent extends OpenCodeStyleSubagent {
19455
19579
  frontmatter: { description: "", mode: "subagent" },
19456
19580
  body: "",
19457
19581
  fileContent: "",
19458
- validate: false
19582
+ validate: false,
19583
+ global
19459
19584
  });
19460
19585
  }
19461
19586
  };
@@ -19583,7 +19708,7 @@ var subagentsProcessorToolTargetTuple = [
19583
19708
  "rovodev",
19584
19709
  "takt"
19585
19710
  ];
19586
- var SubagentsProcessorToolTargetSchema = z72.enum(subagentsProcessorToolTargetTuple);
19711
+ var SubagentsProcessorToolTargetSchema = z73.enum(subagentsProcessorToolTargetTuple);
19587
19712
  var toolSubagentFactories = /* @__PURE__ */ new Map([
19588
19713
  [
19589
19714
  "agentsmd",
@@ -19912,48 +20037,48 @@ import { join as join124 } from "path";
19912
20037
 
19913
20038
  // src/features/rules/rulesync-rule.ts
19914
20039
  import { join as join123 } from "path";
19915
- import { z as z73 } from "zod/mini";
19916
- var RulesyncRuleFrontmatterSchema = z73.object({
19917
- root: z73.optional(z73.boolean()),
19918
- localRoot: z73.optional(z73.boolean()),
19919
- targets: z73._default(RulesyncTargetsSchema, ["*"]),
19920
- description: z73.optional(z73.string()),
19921
- globs: z73.optional(z73.array(z73.string())),
19922
- agentsmd: z73.optional(
19923
- z73.looseObject({
20040
+ import { z as z74 } from "zod/mini";
20041
+ var RulesyncRuleFrontmatterSchema = z74.object({
20042
+ root: z74.optional(z74.boolean()),
20043
+ localRoot: z74.optional(z74.boolean()),
20044
+ targets: z74._default(RulesyncTargetsSchema, ["*"]),
20045
+ description: z74.optional(z74.string()),
20046
+ globs: z74.optional(z74.array(z74.string())),
20047
+ agentsmd: z74.optional(
20048
+ z74.looseObject({
19924
20049
  // @example "path/to/subproject"
19925
- subprojectPath: z73.optional(z73.string())
20050
+ subprojectPath: z74.optional(z74.string())
19926
20051
  })
19927
20052
  ),
19928
- claudecode: z73.optional(
19929
- z73.looseObject({
20053
+ claudecode: z74.optional(
20054
+ z74.looseObject({
19930
20055
  // Glob patterns for conditional rules (takes precedence over globs)
19931
20056
  // @example ["src/**/*.ts", "tests/**/*.test.ts"]
19932
- paths: z73.optional(z73.array(z73.string()))
20057
+ paths: z74.optional(z74.array(z74.string()))
19933
20058
  })
19934
20059
  ),
19935
- cursor: z73.optional(
19936
- z73.looseObject({
19937
- alwaysApply: z73.optional(z73.boolean()),
19938
- description: z73.optional(z73.string()),
19939
- globs: z73.optional(z73.array(z73.string()))
20060
+ cursor: z74.optional(
20061
+ z74.looseObject({
20062
+ alwaysApply: z74.optional(z74.boolean()),
20063
+ description: z74.optional(z74.string()),
20064
+ globs: z74.optional(z74.array(z74.string()))
19940
20065
  })
19941
20066
  ),
19942
- copilot: z73.optional(
19943
- z73.looseObject({
19944
- excludeAgent: z73.optional(z73.union([z73.literal("code-review"), z73.literal("coding-agent")]))
20067
+ copilot: z74.optional(
20068
+ z74.looseObject({
20069
+ excludeAgent: z74.optional(z74.union([z74.literal("code-review"), z74.literal("coding-agent")]))
19945
20070
  })
19946
20071
  ),
19947
- antigravity: z73.optional(
19948
- z73.looseObject({
19949
- trigger: z73.optional(z73.string()),
19950
- globs: z73.optional(z73.array(z73.string()))
20072
+ antigravity: z74.optional(
20073
+ z74.looseObject({
20074
+ trigger: z74.optional(z74.string()),
20075
+ globs: z74.optional(z74.array(z74.string()))
19951
20076
  })
19952
20077
  ),
19953
- takt: z73.optional(
19954
- z73.looseObject({
20078
+ takt: z74.optional(
20079
+ z74.looseObject({
19955
20080
  // Rename the emitted file stem (e.g. "coder.md" → "{name}.md").
19956
- name: z73.optional(z73.string())
20081
+ name: z74.optional(z74.string())
19957
20082
  })
19958
20083
  )
19959
20084
  });
@@ -20254,20 +20379,20 @@ var AgentsMdRule = class _AgentsMdRule extends ToolRule {
20254
20379
 
20255
20380
  // src/features/rules/antigravity-rule.ts
20256
20381
  import { join as join126 } from "path";
20257
- import { z as z74 } from "zod/mini";
20258
- var AntigravityRuleFrontmatterSchema = z74.looseObject({
20259
- trigger: z74.optional(
20260
- z74.union([
20261
- z74.literal("always_on"),
20262
- z74.literal("glob"),
20263
- z74.literal("manual"),
20264
- z74.literal("model_decision"),
20265
- z74.string()
20382
+ import { z as z75 } from "zod/mini";
20383
+ var AntigravityRuleFrontmatterSchema = z75.looseObject({
20384
+ trigger: z75.optional(
20385
+ z75.union([
20386
+ z75.literal("always_on"),
20387
+ z75.literal("glob"),
20388
+ z75.literal("manual"),
20389
+ z75.literal("model_decision"),
20390
+ z75.string()
20266
20391
  // accepts any string for forward compatibility
20267
20392
  ])
20268
20393
  ),
20269
- globs: z74.optional(z74.string()),
20270
- description: z74.optional(z74.string())
20394
+ globs: z75.optional(z75.string()),
20395
+ description: z75.optional(z75.string())
20271
20396
  });
20272
20397
  function parseGlobsString(globs) {
20273
20398
  if (!globs) {
@@ -20854,9 +20979,9 @@ var ClaudecodeLegacyRule = class _ClaudecodeLegacyRule extends ToolRule {
20854
20979
 
20855
20980
  // src/features/rules/claudecode-rule.ts
20856
20981
  import { join as join130 } from "path";
20857
- import { z as z75 } from "zod/mini";
20858
- var ClaudecodeRuleFrontmatterSchema = z75.object({
20859
- paths: z75.optional(z75.array(z75.string()))
20982
+ import { z as z76 } from "zod/mini";
20983
+ var ClaudecodeRuleFrontmatterSchema = z76.object({
20984
+ paths: z76.optional(z76.array(z76.string()))
20860
20985
  });
20861
20986
  var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
20862
20987
  frontmatter;
@@ -21072,9 +21197,9 @@ var ClaudecodeRule = class _ClaudecodeRule extends ToolRule {
21072
21197
 
21073
21198
  // src/features/rules/cline-rule.ts
21074
21199
  import { join as join131 } from "path";
21075
- import { z as z76 } from "zod/mini";
21076
- var ClineRuleFrontmatterSchema = z76.object({
21077
- description: z76.string()
21200
+ import { z as z77 } from "zod/mini";
21201
+ var ClineRuleFrontmatterSchema = z77.object({
21202
+ description: z77.string()
21078
21203
  });
21079
21204
  var ClineRule = class _ClineRule extends ToolRule {
21080
21205
  static getSettablePaths(_options = {}) {
@@ -21253,14 +21378,14 @@ var CodexcliRule = class _CodexcliRule extends ToolRule {
21253
21378
 
21254
21379
  // src/features/rules/copilot-rule.ts
21255
21380
  import { join as join133 } from "path";
21256
- import { z as z77 } from "zod/mini";
21257
- var CopilotRuleFrontmatterSchema = z77.object({
21258
- description: z77.optional(z77.string()),
21259
- applyTo: z77.optional(z77.string()),
21260
- excludeAgent: z77.optional(z77.union([z77.literal("code-review"), z77.literal("coding-agent")]))
21381
+ import { z as z78 } from "zod/mini";
21382
+ var CopilotRuleFrontmatterSchema = z78.object({
21383
+ description: z78.optional(z78.string()),
21384
+ applyTo: z78.optional(z78.string()),
21385
+ excludeAgent: z78.optional(z78.union([z78.literal("code-review"), z78.literal("coding-agent")]))
21261
21386
  });
21262
- var normalizeRelativePath = (path4) => path4.replace(/\\/g, "/").replace(/\/+/g, "/");
21263
- var sameRelativePath = (leftDir, leftFile, rightDir, rightFile) => normalizeRelativePath(join133(leftDir, leftFile)) === normalizeRelativePath(join133(rightDir, rightFile));
21387
+ var normalizeRelativePath = (p) => toPosixPath(p).replace(/\/+/g, "/");
21388
+ var sameRelativePath = (left, right) => normalizeRelativePath(join133(left.dir, left.file)) === normalizeRelativePath(join133(right.dir, right.file));
21264
21389
  var CopilotRule = class _CopilotRule extends ToolRule {
21265
21390
  frontmatter;
21266
21391
  body;
@@ -21379,10 +21504,8 @@ var CopilotRule = class _CopilotRule extends ToolRule {
21379
21504
  }) {
21380
21505
  const paths = this.getSettablePaths({ global });
21381
21506
  const isRoot = relativeDirPath ? sameRelativePath(
21382
- relativeDirPath,
21383
- relativeFilePath,
21384
- paths.root.relativeDirPath,
21385
- paths.root.relativeFilePath
21507
+ { dir: relativeDirPath, file: relativeFilePath },
21508
+ { dir: paths.root.relativeDirPath, file: paths.root.relativeFilePath }
21386
21509
  ) : relativeFilePath === paths.root.relativeFilePath;
21387
21510
  const resolvedRelativeDirPath = relativeDirPath ?? (isRoot ? paths.root.relativeDirPath : paths.nonRoot?.relativeDirPath ?? paths.root.relativeDirPath);
21388
21511
  if (isRoot) {
@@ -21428,10 +21551,8 @@ var CopilotRule = class _CopilotRule extends ToolRule {
21428
21551
  }) {
21429
21552
  const paths = this.getSettablePaths({ global });
21430
21553
  const isRoot = sameRelativePath(
21431
- relativeDirPath,
21432
- relativeFilePath,
21433
- paths.root.relativeDirPath,
21434
- paths.root.relativeFilePath
21554
+ { dir: relativeDirPath, file: relativeFilePath },
21555
+ { dir: paths.root.relativeDirPath, file: paths.root.relativeFilePath }
21435
21556
  );
21436
21557
  return new _CopilotRule({
21437
21558
  outputRoot,
@@ -21511,11 +21632,11 @@ var CopilotcliRule = class _CopilotcliRule extends CopilotRule {
21511
21632
 
21512
21633
  // src/features/rules/cursor-rule.ts
21513
21634
  import { join as join134 } from "path";
21514
- import { z as z78 } from "zod/mini";
21515
- var CursorRuleFrontmatterSchema = z78.object({
21516
- description: z78.optional(z78.string()),
21517
- globs: z78.optional(z78.string()),
21518
- alwaysApply: z78.optional(z78.boolean())
21635
+ import { z as z79 } from "zod/mini";
21636
+ var CursorRuleFrontmatterSchema = z79.object({
21637
+ description: z79.optional(z79.string()),
21638
+ globs: z79.optional(z79.string()),
21639
+ alwaysApply: z79.optional(z79.boolean())
21519
21640
  });
21520
21641
  var CursorRule = class _CursorRule extends ToolRule {
21521
21642
  frontmatter;
@@ -23398,11 +23519,11 @@ var rulesProcessorToolTargets = [
23398
23519
  "warp",
23399
23520
  "windsurf"
23400
23521
  ];
23401
- var RulesProcessorToolTargetSchema = z79.enum(rulesProcessorToolTargets);
23522
+ var RulesProcessorToolTargetSchema = z80.enum(rulesProcessorToolTargets);
23402
23523
  var formatRulePaths = (rules) => rules.map((r) => join151(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ");
23403
- var RulesFeatureOptionsSchema = z79.looseObject({
23404
- ruleDiscoveryMode: z79.optional(z79.enum(["none", "explicit"])),
23405
- includeLocalRoot: z79.optional(z79.boolean())
23524
+ var RulesFeatureOptionsSchema = z80.looseObject({
23525
+ ruleDiscoveryMode: z80.optional(z80.enum(["none", "explicit"])),
23526
+ includeLocalRoot: z80.optional(z80.boolean())
23406
23527
  });
23407
23528
  var resolveRuleDiscoveryMode = ({
23408
23529
  defaultMode,
@@ -23423,8 +23544,8 @@ var resolveRuleDiscoveryMode = ({
23423
23544
  }
23424
23545
  return parsed.data.ruleDiscoveryMode === "none" ? "auto" : "toon";
23425
23546
  };
23426
- var IncludeLocalRootSchema = z79.looseObject({
23427
- includeLocalRoot: z79.optional(z79.boolean())
23547
+ var IncludeLocalRootSchema = z80.looseObject({
23548
+ includeLocalRoot: z80.optional(z80.boolean())
23428
23549
  });
23429
23550
  var resolveIncludeLocalRoot = (options) => {
23430
23551
  if (!options) return true;