rulesync 14.2.0 → 15.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,8 +20,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
20
20
  enumerable: true
21
21
  }) : target, mod));
22
22
  //#endregion
23
- let zod_mini = require("zod/mini");
24
23
  let zod = require("zod");
24
+ let zod_mini = require("zod/mini");
25
25
  let node_fs_promises = require("node:fs/promises");
26
26
  let node_path = require("node:path");
27
27
  node_path = __toESM(node_path, 1);
@@ -39,10 +39,39 @@ let node_util = require("node:util");
39
39
  let smol_toml = require("smol-toml");
40
40
  smol_toml = __toESM(smol_toml, 1);
41
41
  let _toon_format_toon = require("@toon-format/toon");
42
+ //#region src/utils/error.ts
43
+ /**
44
+ * Convert various error types to a readable error message
45
+ * @param error Error instance (ZodError, Error, or unknown)
46
+ * @returns Human-readable error message
47
+ *
48
+ * @example
49
+ * // ZodError
50
+ * const result = schema.safeParse(data);
51
+ * if (!result.success) {
52
+ * throw new Error(`Validation failed: ${formatError(result.error)}`);
53
+ * }
54
+ *
55
+ * @example
56
+ * // Standard Error
57
+ * try {
58
+ * // some operation
59
+ * } catch (error) {
60
+ * console.error(formatError(error));
61
+ * }
62
+ */
63
+ function isZodErrorLike(error) {
64
+ return error !== null && typeof error === "object" && "issues" in error && Array.isArray(error.issues) && error.issues.every((issue) => issue !== null && typeof issue === "object" && "path" in issue && Array.isArray(issue.path) && "message" in issue && typeof issue.message === "string");
65
+ }
66
+ function formatError(error) {
67
+ if (error instanceof zod.ZodError || isZodErrorLike(error)) return `Zod raw error: ${JSON.stringify(error.issues)}`;
68
+ if (error instanceof Error) return `${error.name}: ${error.message}`;
69
+ return String(error);
70
+ }
71
+ //#endregion
42
72
  //#region src/types/features.ts
43
- const ALL_FEATURES = [
44
- "rules",
45
- "ignore",
73
+ const ACTIVE_FEATURES_BEFORE_IGNORE = ["rules"];
74
+ const ACTIVE_FEATURES_AFTER_IGNORE = [
46
75
  "mcp",
47
76
  "subagents",
48
77
  "commands",
@@ -51,9 +80,20 @@ const ALL_FEATURES = [
51
80
  "permissions",
52
81
  "checks"
53
82
  ];
83
+ const ALL_FEATURES = [
84
+ ...ACTIVE_FEATURES_BEFORE_IGNORE,
85
+ "ignore",
86
+ ...ACTIVE_FEATURES_AFTER_IGNORE
87
+ ];
54
88
  const ALL_FEATURES_WITH_WILDCARD = [...ALL_FEATURES, "*"];
55
- const FeatureSchema = zod_mini.z.enum(ALL_FEATURES);
89
+ const ACTIVE_FEATURES = [...ACTIVE_FEATURES_BEFORE_IGNORE, ...ACTIVE_FEATURES_AFTER_IGNORE];
90
+ const DeprecatedIgnoreFeatureSchema = zod_mini.z.literal("ignore").check((0, zod_mini.meta)({
91
+ deprecated: true,
92
+ description: "Deprecated: use the permissions feature. Ignore remains supported for compatibility throughout Rulesync 14.x."
93
+ }));
94
+ const FeatureSchema = zod_mini.z.union([zod_mini.z.enum(ACTIVE_FEATURES), DeprecatedIgnoreFeatureSchema]);
56
95
  zod_mini.z.array(FeatureSchema);
96
+ const FeatureWithWildcardSchema = zod_mini.z.union([zod_mini.z.enum([...ACTIVE_FEATURES, "*"]), DeprecatedIgnoreFeatureSchema]);
57
97
  const GitignoreDestinationSchema = zod_mini.z.enum(["gitignore", "gitattributes"]);
58
98
  const FlattenedCommandNamingSchema = zod_mini.z.enum(["basename", "path"]);
59
99
  const FeatureOptionsSchema = zod_mini.z.record(zod_mini.z.string(), zod_mini.z.unknown());
@@ -63,8 +103,8 @@ const FeatureValueSchema = zod_mini.z.union([
63
103
  GitignoreDestinationSchema
64
104
  ]);
65
105
  const PerFeatureConfigSchema = zod_mini.z.record(zod_mini.z.string(), FeatureValueSchema);
66
- const PerTargetFeaturesValueSchema = zod_mini.z.union([zod_mini.z.array(zod_mini.z.enum(ALL_FEATURES_WITH_WILDCARD)), PerFeatureConfigSchema]);
67
- const RulesyncFeaturesSchema = zod_mini.z.array(zod_mini.z.enum(ALL_FEATURES_WITH_WILDCARD));
106
+ const PerTargetFeaturesValueSchema = zod_mini.z.union([zod_mini.z.array(FeatureWithWildcardSchema), PerFeatureConfigSchema]);
107
+ const RulesyncFeaturesSchema = zod_mini.z.array(FeatureWithWildcardSchema);
68
108
  /**
69
109
  * Returns true if a per-feature value enables the feature.
70
110
  *
@@ -86,66 +126,36 @@ const isFeatureValueEnabled = (value) => {
86
126
  return false;
87
127
  };
88
128
  //#endregion
89
- //#region src/utils/error.ts
90
- /**
91
- * Convert various error types to a readable error message
92
- * @param error Error instance (ZodError, Error, or unknown)
93
- * @returns Human-readable error message
94
- *
95
- * @example
96
- * // ZodError
97
- * const result = schema.safeParse(data);
98
- * if (!result.success) {
99
- * throw new Error(`Validation failed: ${formatError(result.error)}`);
100
- * }
101
- *
102
- * @example
103
- * // Standard Error
104
- * try {
105
- * // some operation
106
- * } catch (error) {
107
- * console.error(formatError(error));
108
- * }
109
- */
110
- function isZodErrorLike(error) {
111
- return error !== null && typeof error === "object" && "issues" in error && Array.isArray(error.issues) && error.issues.every((issue) => issue !== null && typeof issue === "object" && "path" in issue && Array.isArray(issue.path) && "message" in issue && typeof issue.message === "string");
112
- }
113
- function formatError(error) {
114
- if (error instanceof zod.ZodError || isZodErrorLike(error)) return `Zod raw error: ${JSON.stringify(error.issues)}`;
115
- if (error instanceof Error) return `${error.name}: ${error.message}`;
116
- return String(error);
117
- }
118
- //#endregion
119
129
  //#region src/constants/rulesync-paths.ts
120
- const { join: join$264 } = node_path.posix;
130
+ const { join: join$272 } = node_path.posix;
121
131
  const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
122
132
  const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
123
133
  const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
124
- const RULESYNC_RULES_RELATIVE_DIR_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "rules");
125
- const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$264(RULESYNC_RULES_RELATIVE_DIR_PATH, ".curated");
126
- const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "commands");
127
- const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "subagents");
128
- const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "checks");
129
- const RULESYNC_MCP_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
130
- const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
131
- const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
132
- const RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
133
- const RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
134
- const RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
134
+ const RULESYNC_RULES_RELATIVE_DIR_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "rules");
135
+ const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$272(RULESYNC_RULES_RELATIVE_DIR_PATH, ".curated");
136
+ const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "commands");
137
+ const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "subagents");
138
+ const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "checks");
139
+ const RULESYNC_MCP_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
140
+ const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
141
+ const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
142
+ join$272(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
143
+ const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
144
+ const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
135
145
  const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
136
- const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
146
+ const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
137
147
  const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
138
148
  const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
139
- const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$264(RULESYNC_RELATIVE_DIR_PATH, "skills");
140
- const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$264(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
149
+ const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$272(RULESYNC_RELATIVE_DIR_PATH, "skills");
150
+ const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$272(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
141
151
  const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
142
152
  const RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync-npm.lock.json";
143
- const RULESYNC_MCP_FILE_NAME = "mcp.json";
144
- const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
145
- const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.json";
146
- const RULESYNC_MCP_JSONC_FILE_NAME = "mcp.jsonc";
147
- const RULESYNC_HOOKS_JSONC_FILE_NAME = "hooks.jsonc";
148
- const RULESYNC_PERMISSIONS_JSONC_FILE_NAME = "permissions.jsonc";
153
+ const RULESYNC_MCP_FILE_NAME = "mcp.jsonc";
154
+ const RULESYNC_HOOKS_FILE_NAME = "hooks.jsonc";
155
+ const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.jsonc";
156
+ const RULESYNC_MCP_LEGACY_FILE_NAME = "mcp.json";
157
+ const RULESYNC_HOOKS_LEGACY_FILE_NAME = "hooks.json";
158
+ const RULESYNC_PERMISSIONS_LEGACY_FILE_NAME = "permissions.json";
149
159
  const RULESYNC_CONFIG_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/config-schema.json";
150
160
  const RULESYNC_MCP_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/mcp-schema.json";
151
161
  const RULESYNC_PERMISSIONS_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/permissions-schema.json";
@@ -158,6 +168,7 @@ const rulesProcessorToolTargetTuple = [
158
168
  "amp",
159
169
  "antigravity-cli",
160
170
  "antigravity-ide",
171
+ "antigravity-plugin",
161
172
  "augmentcode",
162
173
  "augmentcode-legacy",
163
174
  "claudecode",
@@ -174,6 +185,7 @@ const rulesProcessorToolTargetTuple = [
174
185
  "hermesagent",
175
186
  "junie",
176
187
  "kilo",
188
+ "kimi-code",
177
189
  "kiro",
178
190
  "kiro-cli",
179
191
  "kiro-ide",
@@ -217,8 +229,10 @@ const mcpProcessorToolTargetTuple = [
217
229
  "amp",
218
230
  "antigravity-cli",
219
231
  "antigravity-ide",
232
+ "antigravity-plugin",
220
233
  "augmentcode",
221
234
  "claudecode",
235
+ "claudecode-plugin",
222
236
  "claudecode-legacy",
223
237
  "cline",
224
238
  "codexcli",
@@ -230,6 +244,7 @@ const mcpProcessorToolTargetTuple = [
230
244
  "goose",
231
245
  "grokcli",
232
246
  "hermesagent",
247
+ "kimi-code",
233
248
  "kilo",
234
249
  "kiro",
235
250
  "kiro-cli",
@@ -252,6 +267,7 @@ const commandsProcessorToolTargetTuple = [
252
267
  "antigravity-ide",
253
268
  "augmentcode",
254
269
  "claudecode",
270
+ "claudecode-plugin",
255
271
  "claudecode-legacy",
256
272
  "cline",
257
273
  "codexcli",
@@ -279,6 +295,7 @@ const subagentsProcessorToolTargetTuple = [
279
295
  "agentsmd",
280
296
  "augmentcode",
281
297
  "claudecode",
298
+ "claudecode-plugin",
282
299
  "claudecode-legacy",
283
300
  "cline",
284
301
  "codexcli",
@@ -291,6 +308,7 @@ const subagentsProcessorToolTargetTuple = [
291
308
  "goose",
292
309
  "grokcli",
293
310
  "hermesagent",
311
+ "kimi-code",
294
312
  "junie",
295
313
  "kiro",
296
314
  "kiro-cli",
@@ -310,8 +328,10 @@ const skillsProcessorToolTargetTuple = [
310
328
  "amp",
311
329
  "antigravity-cli",
312
330
  "antigravity-ide",
331
+ "antigravity-plugin",
313
332
  "augmentcode",
314
333
  "claudecode",
334
+ "claudecode-plugin",
315
335
  "claudecode-legacy",
316
336
  "cline",
317
337
  "codexcli",
@@ -323,6 +343,7 @@ const skillsProcessorToolTargetTuple = [
323
343
  "goose",
324
344
  "grokcli",
325
345
  "hermesagent",
346
+ "kimi-code",
326
347
  "junie",
327
348
  "kilo",
328
349
  "kiro",
@@ -345,9 +366,11 @@ const hooksProcessorToolTargetTuple = [
345
366
  "amp",
346
367
  "antigravity-cli",
347
368
  "antigravity-ide",
369
+ "antigravity-plugin",
348
370
  "kilo",
349
371
  "cursor",
350
372
  "claudecode",
373
+ "claudecode-plugin",
351
374
  "codexcli",
352
375
  "copilot",
353
376
  "copilotcli",
@@ -356,6 +379,7 @@ const hooksProcessorToolTargetTuple = [
356
379
  "factorydroid",
357
380
  "goose",
358
381
  "hermesagent",
382
+ "kimi-code",
359
383
  "deepagents",
360
384
  "kiro",
361
385
  "kiro-cli",
@@ -383,6 +407,7 @@ const permissionsProcessorToolTargetTuple = [
383
407
  "goose",
384
408
  "grokcli",
385
409
  "hermesagent",
410
+ "kimi-code",
386
411
  "junie",
387
412
  "kilo",
388
413
  "kiro",
@@ -413,6 +438,7 @@ const ALL_TOOL_TARGETS = [...new Set([
413
438
  ].flat())];
414
439
  const ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
415
440
  const ToolTargetSchema = zod_mini.z.enum(ALL_TOOL_TARGETS);
441
+ const PACKAGING_TOOL_TARGETS = ["antigravity-plugin", "claudecode-plugin"];
416
442
  zod_mini.z.array(ToolTargetSchema);
417
443
  const RulesyncTargetsSchema = zod_mini.z.array(zod_mini.z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
418
444
  const RulesyncConfigTargetsObjectSchema = zod_mini.z.record(zod_mini.z.string(), PerTargetFeaturesValueSchema);
@@ -568,12 +594,12 @@ async function readFileBuffer(filepath) {
568
594
  return (0, node_fs_promises.readFile)(filepath);
569
595
  }
570
596
  /**
571
- * Adds exactly one trailing newline to content.
597
+ * Normalizes text to LF line endings and adds exactly one trailing newline.
572
598
  * Removes any existing trailing whitespace and appends a single newline.
573
599
  */
574
600
  function addTrailingNewline(content) {
575
601
  if (!content) return "\n";
576
- return content.trimEnd() + "\n";
602
+ return content.replaceAll("\r\n", "\n").replaceAll("\r", "\n").trimEnd() + "\n";
577
603
  }
578
604
  async function writeFileContent(filepath, content) {
579
605
  await ensureDir((0, node_path.dirname)(filepath));
@@ -609,7 +635,7 @@ async function listDirectoryFiles(dir) {
609
635
  }
610
636
  }
611
637
  async function findFilesByGlobs(globs, options = {}) {
612
- const { type = "all" } = options;
638
+ const { type = "all", followSymbolicLinks = true } = options;
613
639
  const globbyOptions = type === "file" ? {
614
640
  onlyFiles: true,
615
641
  onlyDirectories: false
@@ -622,7 +648,7 @@ async function findFilesByGlobs(globs, options = {}) {
622
648
  };
623
649
  const results = (0, globby.globbySync)(Array.isArray(globs) ? globs.map((g) => g.replaceAll("\\", "/")) : globs.replaceAll("\\", "/"), {
624
650
  absolute: true,
625
- followSymbolicLinks: true,
651
+ followSymbolicLinks,
626
652
  ...globbyOptions
627
653
  });
628
654
  const seenRealPaths = /* @__PURE__ */ new Set();
@@ -1035,12 +1061,13 @@ const CONFLICTING_TARGET_PAIRS = [["augmentcode", "augmentcode-legacy"], ["claud
1035
1061
  */
1036
1062
  const LEGACY_TARGETS = ["augmentcode-legacy", "claudecode-legacy"];
1037
1063
  /**
1038
- * Expand the wildcard target (`*`) to every non-legacy tool target. Legacy
1039
- * targets are excluded because they must be requested explicitly. Shared by
1040
- * `Config.getTargets()` and `extractConfigFileTargets()` so the two never drift.
1064
+ * Expand the wildcard target (`*`) to every ordinary non-legacy tool target.
1065
+ * Legacy aliases and package-root targets are excluded because they must be
1066
+ * requested explicitly. Shared by `Config.getTargets()` and
1067
+ * `extractConfigFileTargets()` so the two never drift.
1041
1068
  */
1042
1069
  function expandWildcardTargets() {
1043
- return ALL_TOOL_TARGETS.filter((target) => !LEGACY_TARGETS.includes(target));
1070
+ return ALL_TOOL_TARGETS.filter((target) => !LEGACY_TARGETS.includes(target) && !PACKAGING_TOOL_TARGETS.includes(target));
1044
1071
  }
1045
1072
  /**
1046
1073
  * Validates that the user-authored config does not double-define the
@@ -1190,7 +1217,7 @@ var Config = class Config {
1190
1217
  getTargets() {
1191
1218
  if (this.objectFormTargetKeys !== void 0) return this.objectFormTargetKeys;
1192
1219
  const arrayTargets = Array.isArray(this.targets) ? this.targets : [];
1193
- if (arrayTargets.includes("*")) return expandWildcardTargets();
1220
+ if (arrayTargets.includes("*")) return [.../* @__PURE__ */ new Set([...expandWildcardTargets(), ...arrayTargets.filter((target) => target !== "*")])];
1194
1221
  return arrayTargets.filter((target) => target !== "*");
1195
1222
  }
1196
1223
  getConfigFileTargets() {
@@ -1572,7 +1599,7 @@ function extractConfigFileTargets(targets) {
1572
1599
  if (targets === void 0) return void 0;
1573
1600
  const validTargets = new Set(ALL_TOOL_TARGETS);
1574
1601
  if (isRulesyncConfigTargetsObject(targets)) return Object.keys(targets).filter((key) => validTargets.has(key));
1575
- if (targets.includes("*")) return expandWildcardTargets();
1602
+ if (targets.includes("*")) return [.../* @__PURE__ */ new Set([...expandWildcardTargets(), ...targets.filter((key) => key !== "*" && validTargets.has(key))])];
1576
1603
  return targets.filter((key) => key !== "*" && validTargets.has(key));
1577
1604
  }
1578
1605
  //#endregion
@@ -1968,7 +1995,7 @@ const hasControlChars = (val) => CONTROL_CHARS.some((char) => val.includes(char)
1968
1995
  const safeString = zod_mini.z.pipe(zod_mini.z.string(), zod_mini.z.custom((val) => typeof val === "string" && !hasControlChars(val), "must not contain newline, carriage return, or NUL characters"));
1969
1996
  /**
1970
1997
  * Canonical hook definition.
1971
- * Used in .rulesync/hooks.json and mapped to tool-specific formats.
1998
+ * Used in .rulesync/hooks.jsonc and mapped to tool-specific formats.
1972
1999
  */
1973
2000
  const HookDefinitionSchema = zod_mini.z.looseObject({
1974
2001
  command: zod_mini.z.optional(safeString),
@@ -1982,6 +2009,7 @@ const HookDefinitionSchema = zod_mini.z.looseObject({
1982
2009
  ])),
1983
2010
  url: zod_mini.z.optional(safeString),
1984
2011
  timeout: zod_mini.z.optional(zod_mini.z.number()),
2012
+ cacheTtl: zod_mini.z.optional(zod_mini.z.number().check((0, zod_mini.nonnegative)())),
1985
2013
  matcher: zod_mini.z.optional(safeString),
1986
2014
  prompt: zod_mini.z.optional(safeString),
1987
2015
  loop_limit: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.number())),
@@ -2521,6 +2549,51 @@ const GROKCLI_HOOK_EVENTS = [
2521
2549
  "postCompact"
2522
2550
  ];
2523
2551
  /**
2552
+ * Hook events supported by Kimi Code.
2553
+ *
2554
+ * Kimi Code also exposes `Interrupt`, which has no canonical rulesync event.
2555
+ *
2556
+ * @see https://moonshotai.github.io/kimi-code/en/customization/hooks.html
2557
+ */
2558
+ const KIMI_CODE_HOOK_EVENTS = [
2559
+ "sessionStart",
2560
+ "sessionEnd",
2561
+ "beforeSubmitPrompt",
2562
+ "preToolUse",
2563
+ "postToolUse",
2564
+ "postToolUseFailure",
2565
+ "permissionRequest",
2566
+ "stop",
2567
+ "stopFailure",
2568
+ "notification",
2569
+ "subagentStart",
2570
+ "subagentStop",
2571
+ "preCompact",
2572
+ "postCompact"
2573
+ ];
2574
+ const CANONICAL_TO_KIMI_CODE_EVENT_NAMES = {
2575
+ sessionStart: "SessionStart",
2576
+ sessionEnd: "SessionEnd",
2577
+ beforeSubmitPrompt: "UserPromptSubmit",
2578
+ preToolUse: "PreToolUse",
2579
+ postToolUse: "PostToolUse",
2580
+ postToolUseFailure: "PostToolUseFailure",
2581
+ permissionRequest: "PermissionRequest",
2582
+ stop: "Stop",
2583
+ stopFailure: "StopFailure",
2584
+ notification: "Notification",
2585
+ subagentStart: "SubagentStart",
2586
+ subagentStop: "SubagentStop",
2587
+ preCompact: "PreCompact",
2588
+ postCompact: "PostCompact"
2589
+ };
2590
+ const KIMI_CODE_NATIVE_HOOK_EVENTS = [
2591
+ ...Object.values(CANONICAL_TO_KIMI_CODE_EVENT_NAMES),
2592
+ "PermissionResult",
2593
+ "Interrupt"
2594
+ ];
2595
+ const KIMI_CODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_KIMI_CODE_EVENT_NAMES).map(([canonical, kimiCode]) => [kimiCode, canonical]));
2596
+ /**
2524
2597
  * Hook events supported by Hermes Agent's native Shell Hooks system.
2525
2598
  *
2526
2599
  * Hermes validates hook events against a fixed `VALID_HOOKS` set:
@@ -2611,6 +2684,7 @@ const HooksConfigSchema = zod_mini.z.looseObject({
2611
2684
  vibe: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
2612
2685
  reasonix: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
2613
2686
  grokcli: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
2687
+ "kimi-code": zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
2614
2688
  qwencode: zod_mini.z.optional(zod_mini.z.looseObject({
2615
2689
  hooks: zod_mini.z.optional(hooksRecordSchema),
2616
2690
  disableAllHooks: zod_mini.z.optional(zod_mini.z.boolean())
@@ -3137,6 +3211,28 @@ function parseJsonc$8(content) {
3137
3211
  return deepSanitize(result);
3138
3212
  }
3139
3213
  //#endregion
3214
+ //#region src/utils/rulesync-source-path.ts
3215
+ function getRulesyncSourceCandidates({ paths }) {
3216
+ return [paths.recommended, ...paths.legacy];
3217
+ }
3218
+ async function resolveRulesyncSourceWritePath({ outputRoot, paths }) {
3219
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3220
+ const targetPath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3221
+ if (await fileExists(targetPath)) {
3222
+ await assertWritablePathInsideRoot({
3223
+ rootPath: outputRoot,
3224
+ targetPath
3225
+ });
3226
+ return candidate;
3227
+ }
3228
+ }
3229
+ await assertWritablePathInsideRoot({
3230
+ rootPath: outputRoot,
3231
+ targetPath: (0, node_path.join)(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath)
3232
+ });
3233
+ return paths.recommended;
3234
+ }
3235
+ //#endregion
3140
3236
  //#region src/features/hooks/rulesync-hooks.ts
3141
3237
  var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3142
3238
  json;
@@ -3150,12 +3246,14 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3150
3246
  }
3151
3247
  static getSettablePaths() {
3152
3248
  return {
3153
- relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3154
- relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
3155
- jsonc: {
3249
+ recommended: {
3156
3250
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3157
- relativeFilePath: RULESYNC_HOOKS_JSONC_FILE_NAME
3158
- }
3251
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME
3252
+ },
3253
+ legacy: [{
3254
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3255
+ relativeFilePath: RULESYNC_HOOKS_LEGACY_FILE_NAME
3256
+ }]
3159
3257
  };
3160
3258
  }
3161
3259
  validate() {
@@ -3171,11 +3269,7 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3171
3269
  }
3172
3270
  static async fromFile({ outputRoot = process.cwd(), validate = true }) {
3173
3271
  const paths = RulesyncHooks.getSettablePaths();
3174
- const candidates = [paths.jsonc, {
3175
- relativeDirPath: paths.relativeDirPath,
3176
- relativeFilePath: paths.relativeFilePath
3177
- }];
3178
- for (const candidate of candidates) {
3272
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3179
3273
  const filePath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3180
3274
  if (!await fileExists(filePath)) continue;
3181
3275
  const fileContent = await readFileContent(filePath);
@@ -3187,7 +3281,7 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3187
3281
  validate
3188
3282
  });
3189
3283
  }
3190
- throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} or ${RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH} found.`);
3284
+ throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} or ${RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH} found.`);
3191
3285
  }
3192
3286
  getJson() {
3193
3287
  return this.json;
@@ -3305,8 +3399,8 @@ const RulesyncMcpConfigSchema = zod_mini.z.object({ mcpServers: zod_mini.z.recor
3305
3399
  * Tool-scoped MCP block: servers that apply only to one tool. A named entry
3306
3400
  * replaces/adds the same-named shared server wholesale for that tool; `null`
3307
3401
  * removes the shared server for that tool. Mirrors `{toolname}.hooks` in
3308
- * `.rulesync/hooks.json` and `{toolname}.permission` in
3309
- * `.rulesync/permissions.json`.
3402
+ * `.rulesync/hooks.jsonc` and `{toolname}.permission` in
3403
+ * `.rulesync/permissions.jsonc`.
3310
3404
  */
3311
3405
  const toolScopedMcpSchema = zod_mini.z.looseObject({ mcpServers: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.nullable(RulesyncMcpServerSchema))) });
3312
3406
  const RulesyncMcpFileSchema = zod_mini.z.looseObject({
@@ -3331,6 +3425,7 @@ const RulesyncMcpFileSchema = zod_mini.z.looseObject({
3331
3425
  hermesagent: zod_mini.z.optional(toolScopedMcpSchema),
3332
3426
  junie: zod_mini.z.optional(toolScopedMcpSchema),
3333
3427
  kilo: zod_mini.z.optional(toolScopedMcpSchema),
3428
+ "kimi-code": zod_mini.z.optional(toolScopedMcpSchema),
3334
3429
  kiro: zod_mini.z.optional(toolScopedMcpSchema),
3335
3430
  opencode: zod_mini.z.optional(toolScopedMcpSchema),
3336
3431
  qwencode: zod_mini.z.optional(toolScopedMcpSchema),
@@ -3358,14 +3453,13 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
3358
3453
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3359
3454
  relativeFilePath: RULESYNC_MCP_FILE_NAME
3360
3455
  },
3361
- jsonc: {
3456
+ legacy: [{
3362
3457
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3363
- relativeFilePath: RULESYNC_MCP_JSONC_FILE_NAME
3364
- },
3365
- legacy: {
3458
+ relativeFilePath: RULESYNC_MCP_LEGACY_FILE_NAME
3459
+ }, {
3366
3460
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3367
3461
  relativeFilePath: ".mcp.json"
3368
- }
3462
+ }]
3369
3463
  };
3370
3464
  }
3371
3465
  validate() {
@@ -3381,41 +3475,23 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
3381
3475
  }
3382
3476
  static async fromFile({ outputRoot = process.cwd(), validate = true, logger }) {
3383
3477
  const paths = this.getSettablePaths();
3384
- const recommendedPath = (0, node_path.join)(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
3385
- const jsoncPath = (0, node_path.join)(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);
3386
- const legacyPath = (0, node_path.join)(outputRoot, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
3387
- if (await fileExists(jsoncPath)) {
3388
- const fileContent = await readFileContent(jsoncPath);
3389
- return new RulesyncMcp({
3390
- outputRoot,
3391
- relativeDirPath: paths.jsonc.relativeDirPath,
3392
- relativeFilePath: paths.jsonc.relativeFilePath,
3393
- fileContent,
3394
- validate
3395
- });
3396
- }
3397
- if (await fileExists(recommendedPath)) {
3398
- const fileContent = await readFileContent(recommendedPath);
3399
- return new RulesyncMcp({
3400
- outputRoot,
3401
- relativeDirPath: paths.recommended.relativeDirPath,
3402
- relativeFilePath: paths.recommended.relativeFilePath,
3403
- fileContent,
3404
- validate
3405
- });
3406
- }
3407
- if (await fileExists(legacyPath)) {
3408
- logger?.warn(`⚠️ Using deprecated path "${legacyPath}". Please migrate to "${recommendedPath}"`);
3409
- const fileContent = await readFileContent(legacyPath);
3478
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3479
+ const filePath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3480
+ if (!await fileExists(filePath)) continue;
3481
+ if (candidate.relativeFilePath === ".mcp.json") {
3482
+ const recommendedPath = (0, node_path.join)(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
3483
+ logger?.warn(`⚠️ Using deprecated path "${filePath}". Please migrate to "${recommendedPath}"`);
3484
+ }
3485
+ const fileContent = await readFileContent(filePath);
3410
3486
  return new RulesyncMcp({
3411
3487
  outputRoot,
3412
- relativeDirPath: paths.legacy.relativeDirPath,
3413
- relativeFilePath: paths.legacy.relativeFilePath,
3488
+ relativeDirPath: candidate.relativeDirPath,
3489
+ relativeFilePath: candidate.relativeFilePath,
3414
3490
  fileContent,
3415
3491
  validate
3416
3492
  });
3417
3493
  }
3418
- const fileContent = await readFileContent(recommendedPath);
3494
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath));
3419
3495
  return new RulesyncMcp({
3420
3496
  outputRoot,
3421
3497
  relativeDirPath: paths.recommended.relativeDirPath,
@@ -3616,7 +3692,7 @@ const PermissionRulesSchema = zod_mini.z.record(zod_mini.z.string(), PermissionA
3616
3692
  * key it appears under. During generation the categories placed here are
3617
3693
  * merged over the shared `permission` block per category (the tool-scoped
3618
3694
  * category replaces the shared one wholesale), mirroring how
3619
- * `.rulesync/hooks.json` merges `{toolname}.hooks` per event.
3695
+ * `.rulesync/hooks.jsonc` merges `{toolname}.hooks` per event.
3620
3696
  *
3621
3697
  * @example
3622
3698
  * { "claudecode": { "permission": { "bash": { "git push *": "deny" } } } }
@@ -3629,6 +3705,25 @@ const ToolScopedPermissionSchema = zod_mini.z.record(zod_mini.z.string(), Permis
3629
3705
  * added without a schema break.
3630
3706
  */
3631
3707
  const CanonicalPermissionsOverrideSchema = zod_mini.z.looseObject({ permission: zod_mini.z.optional(ToolScopedPermissionSchema) });
3708
+ const KimiCodePermissionsOverrideSchema = zod_mini.z.looseObject({
3709
+ permission: zod_mini.z.optional(ToolScopedPermissionSchema),
3710
+ defaultPermissionMode: zod_mini.z.optional(zod_mini.z.enum([
3711
+ "manual",
3712
+ "yolo",
3713
+ "auto"
3714
+ ])),
3715
+ rules: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({
3716
+ decision: PermissionActionSchema,
3717
+ pattern: zod_mini.z.string(),
3718
+ scope: zod_mini.z.optional(zod_mini.z.enum([
3719
+ "turn-override",
3720
+ "session-runtime",
3721
+ "project",
3722
+ "user"
3723
+ ])),
3724
+ reason: zod_mini.z.optional(zod_mini.z.string())
3725
+ })))
3726
+ });
3632
3727
  /**
3633
3728
  * OpenCode-specific permission value. Unlike the shared canonical block, which
3634
3729
  * only accepts a pattern-to-action map, OpenCode also allows a bare action
@@ -4220,6 +4315,7 @@ const PermissionsConfigSchema = zod_mini.z.looseObject({
4220
4315
  devin: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
4221
4316
  goose: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
4222
4317
  grokcli: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
4318
+ "kimi-code": zod_mini.z.optional(KimiCodePermissionsOverrideSchema),
4223
4319
  rovodev: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
4224
4320
  zed: zod_mini.z.optional(CanonicalPermissionsOverrideSchema)
4225
4321
  });
@@ -4244,12 +4340,14 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4244
4340
  }
4245
4341
  static getSettablePaths() {
4246
4342
  return {
4247
- relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4248
- relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
4249
- jsonc: {
4343
+ recommended: {
4250
4344
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4251
- relativeFilePath: RULESYNC_PERMISSIONS_JSONC_FILE_NAME
4252
- }
4345
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME
4346
+ },
4347
+ legacy: [{
4348
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4349
+ relativeFilePath: RULESYNC_PERMISSIONS_LEGACY_FILE_NAME
4350
+ }]
4253
4351
  };
4254
4352
  }
4255
4353
  validate() {
@@ -4265,11 +4363,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4265
4363
  }
4266
4364
  static async fromFile({ outputRoot = process.cwd(), validate = true }) {
4267
4365
  const paths = RulesyncPermissions.getSettablePaths();
4268
- const candidates = [paths.jsonc, {
4269
- relativeDirPath: paths.relativeDirPath,
4270
- relativeFilePath: paths.relativeFilePath
4271
- }];
4272
- for (const candidate of candidates) {
4366
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
4273
4367
  const filePath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
4274
4368
  if (!await fileExists(filePath)) continue;
4275
4369
  const fileContent = await readFileContent(filePath);
@@ -4281,7 +4375,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4281
4375
  validate
4282
4376
  });
4283
4377
  }
4284
- throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} or ${RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH} found.`);
4378
+ throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} or ${RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH} found.`);
4285
4379
  }
4286
4380
  getJson() {
4287
4381
  return this.json;
@@ -4291,7 +4385,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4291
4385
  * tool-scoped `{toolname}.permission` block over the shared `permission`
4292
4386
  * block, per category (the tool-scoped category replaces the shared one
4293
4387
  * wholesale — mirroring how `{toolname}.hooks` merges per event in
4294
- * `.rulesync/hooks.json`). The consumed `permission` key is stripped from
4388
+ * `.rulesync/hooks.jsonc`). The consumed `permission` key is stripped from
4295
4389
  * the override block so verbatim-passthrough translators (e.g. the Hermes
4296
4390
  * deep merge or the Codex CLI top-level key whitelist) never see it.
4297
4391
  *
@@ -4656,6 +4750,16 @@ const RulesyncSkillFrontmatterSchema = zod_mini.z.looseObject({
4656
4750
  "disable-model-invocation": zod_mini.z.optional(zod_mini.z.boolean()),
4657
4751
  "user-invocable": zod_mini.z.optional(zod_mini.z.boolean())
4658
4752
  })),
4753
+ "kimi-code": zod_mini.z.optional(zod_mini.z.looseObject({
4754
+ type: zod_mini.z.optional(zod_mini.z.enum([
4755
+ "prompt",
4756
+ "inline",
4757
+ "flow"
4758
+ ])),
4759
+ whenToUse: zod_mini.z.optional(zod_mini.z.string()),
4760
+ disableModelInvocation: zod_mini.z.optional(zod_mini.z.boolean()),
4761
+ arguments: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
4762
+ })),
4659
4763
  agentsskills: zod_mini.z.optional(zod_mini.z.looseObject({
4660
4764
  license: zod_mini.z.optional(zod_mini.z.string()),
4661
4765
  compatibility: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.looseObject({})])),
@@ -6357,6 +6461,28 @@ var ClaudecodeCommand = class ClaudecodeCommand extends ToolCommand {
6357
6461
  }
6358
6462
  };
6359
6463
  //#endregion
6464
+ //#region src/constants/plugin-paths.ts
6465
+ const CLAUDECODE_PLUGIN_COMMANDS_DIR = "commands";
6466
+ const CLAUDECODE_PLUGIN_AGENTS_DIR = "agents";
6467
+ const CLAUDECODE_PLUGIN_SKILLS_DIR = "skills";
6468
+ const CLAUDECODE_PLUGIN_HOOKS_DIR = "hooks";
6469
+ const CLAUDECODE_PLUGIN_HOOKS_FILE_NAME = "hooks.json";
6470
+ const ANTIGRAVITY_PLUGIN_RULES_DIR = "rules";
6471
+ const ANTIGRAVITY_PLUGIN_SKILLS_DIR = "skills";
6472
+ const ANTIGRAVITY_PLUGIN_MCP_FILE_NAME = "mcp_config.json";
6473
+ const ANTIGRAVITY_PLUGIN_HOOKS_FILE_NAME = "hooks.json";
6474
+ //#endregion
6475
+ //#region src/features/commands/claudecode-plugin-command.ts
6476
+ var ClaudecodePluginCommand = class extends ClaudecodeCommand {
6477
+ static isTargetedByRulesyncCommand(rulesyncCommand) {
6478
+ const targets = rulesyncCommand.getFrontmatter().targets;
6479
+ return targets.includes("*") || targets.includes("claudecode-plugin");
6480
+ }
6481
+ static getSettablePaths() {
6482
+ return { relativeDirPath: CLAUDECODE_PLUGIN_COMMANDS_DIR };
6483
+ }
6484
+ };
6485
+ //#endregion
6360
6486
  //#region src/constants/cline-paths.ts
6361
6487
  const CLINE_DIR = ".cline";
6362
6488
  const CLINERULES_DIR = ".clinerules";
@@ -7372,6 +7498,7 @@ const TAKT_CONFIG_SHARED_FILE_KEY = ".takt/config.yaml";
7372
7498
  const CODEXCLI_CONFIG_SHARED_FILE_KEY = ".codex/config.toml";
7373
7499
  const GROKCLI_CONFIG_SHARED_FILE_KEY = ".grok/config.toml";
7374
7500
  const VIBE_CONFIG_SHARED_FILE_KEY = ".vibe/config.toml";
7501
+ const KIMI_CODE_CONFIG_SHARED_FILE_KEY = ".kimi-code/config.toml";
7375
7502
  const REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY = "reasonix.toml";
7376
7503
  const REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY = ".reasonix/config.toml";
7377
7504
  /**
@@ -7716,6 +7843,20 @@ const SHARED_CONFIG_OWNERSHIP = {
7716
7843
  }
7717
7844
  }
7718
7845
  },
7846
+ [KIMI_CODE_CONFIG_SHARED_FILE_KEY]: {
7847
+ format: "toml",
7848
+ invalidRootPolicy: "error",
7849
+ features: {
7850
+ hooks: {
7851
+ kind: "replace-owned-keys",
7852
+ ownedKeys: ["hooks"]
7853
+ },
7854
+ permissions: {
7855
+ kind: "replace-owned-keys",
7856
+ ownedKeys: ["permission", "default_permission_mode"]
7857
+ }
7858
+ }
7859
+ },
7719
7860
  [REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY]: {
7720
7861
  format: "toml",
7721
7862
  features: {
@@ -7850,6 +7991,10 @@ const applyPermissions = (params) => {
7850
7991
  function toolSkillSearchRoots(paths) {
7851
7992
  return [paths.relativeDirPath, ...paths.alternativeSkillRoots ?? []];
7852
7993
  }
7994
+ /** Ordered import roots: managed roots first, followed by read-only discovery roots. */
7995
+ function toolSkillImportRoots(paths) {
7996
+ return [...toolSkillSearchRoots(paths), ...paths.importOnlySkillRoots ?? []];
7997
+ }
7853
7998
  /**
7854
7999
  * Abstract base class for AI development tool-specific skill formats.
7855
8000
  *
@@ -7932,6 +8077,13 @@ var ToolSkill = class extends AiDir {
7932
8077
  throw new Error("Please implement this method in the subclass.");
7933
8078
  }
7934
8079
  /**
8080
+ * Identity used to resolve duplicates across discovery roots during import.
8081
+ * Most tools identify a skill by its directory name.
8082
+ */
8083
+ getImportIdentity() {
8084
+ return this.getDirName();
8085
+ }
8086
+ /**
7935
8087
  * Load and parse skill directory content.
7936
8088
  * This is a helper method that handles the common logic of reading SKILL.md,
7937
8089
  * parsing frontmatter, and collecting other files.
@@ -8683,6 +8835,7 @@ const KIRO_IDE_HOOKS_DIR_PATH = (0, node_path.join)(KIRO_DIR, "hooks");
8683
8835
  const KIRO_IDE_HOOKS_FILE_NAME = "rulesync.json";
8684
8836
  const KIRO_MCP_FILE_NAME = "mcp.json";
8685
8837
  const KIRO_IGNORE_FILE_NAME = ".kiroignore";
8838
+ const KIRO_GLOBAL_IGNORE_FILE_NAME = "kiroignore";
8686
8839
  //#endregion
8687
8840
  //#region src/features/commands/kiro-command.ts
8688
8841
  var KiroCommand = class KiroCommand extends ToolCommand {
@@ -9963,6 +10116,16 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
9963
10116
  supportsSubdirectory: true
9964
10117
  }
9965
10118
  }],
10119
+ ["claudecode-plugin", {
10120
+ class: ClaudecodePluginCommand,
10121
+ meta: {
10122
+ extension: "md",
10123
+ supportsProject: true,
10124
+ supportsGlobal: false,
10125
+ isSimulated: false,
10126
+ supportsSubdirectory: true
10127
+ }
10128
+ }],
9966
10129
  ["claudecode-legacy", {
9967
10130
  class: ClaudecodeCommand,
9968
10131
  meta: {
@@ -10500,7 +10663,7 @@ var ToolHooks = class extends ToolFile {
10500
10663
  return new RulesyncHooks({
10501
10664
  outputRoot: this.outputRoot,
10502
10665
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
10503
- relativeFilePath: "hooks.json",
10666
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
10504
10667
  fileContent: fileContent ?? this.fileContent
10505
10668
  });
10506
10669
  }
@@ -10597,7 +10760,7 @@ function isToolMatcherEntry(x) {
10597
10760
  /**
10598
10761
  * Filter the shared canonical hooks to the supported events and merge tool overrides on top.
10599
10762
  */
10600
- function buildEffectiveHooks$1({ config, toolOverrideHooks, supportedEvents }) {
10763
+ function buildEffectiveHooks$2({ config, toolOverrideHooks, supportedEvents }) {
10601
10764
  const supported = new Set(supportedEvents);
10602
10765
  const sharedHooks = {};
10603
10766
  for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) sharedHooks[event] = defs;
@@ -10727,7 +10890,7 @@ function buildToolHooks({ defs, converterConfig }) {
10727
10890
  * (e.g. beforeSubmitPrompt → UserPromptSubmit).
10728
10891
  */
10729
10892
  function canonicalToToolHooks({ config, toolOverrideHooks, converterConfig, logger }) {
10730
- const effectiveHooks = buildEffectiveHooks$1({
10893
+ const effectiveHooks = buildEffectiveHooks$2({
10731
10894
  config,
10732
10895
  toolOverrideHooks,
10733
10896
  supportedEvents: converterConfig.supportedEvents
@@ -10864,7 +11027,7 @@ function toolMatcherEntryToCanonical({ rawEntry, converterConfig }) {
10864
11027
  }
10865
11028
  /**
10866
11029
  * Assemble the canonical hooks config a tool importer writes to
10867
- * `.rulesync/hooks.json`.
11030
+ * `.rulesync/hooks.jsonc`.
10868
11031
  *
10869
11032
  * The top-level `hooks` record only accepts canonical event names, so any
10870
11033
  * imported native event key without a canonical mapping is moved under the
@@ -11067,6 +11230,16 @@ var AntigravityCliHooks = class extends AntigravityHooks {
11067
11230
  }
11068
11231
  };
11069
11232
  //#endregion
11233
+ //#region src/features/hooks/antigravity-plugin-hooks.ts
11234
+ var AntigravityPluginHooks = class extends AntigravityIdeHooks {
11235
+ static getSettablePaths() {
11236
+ return {
11237
+ relativeDirPath: ".",
11238
+ relativeFilePath: ANTIGRAVITY_PLUGIN_HOOKS_FILE_NAME
11239
+ };
11240
+ }
11241
+ };
11242
+ //#endregion
11070
11243
  //#region src/utils/augmentcode-settings.ts
11071
11244
  /**
11072
11245
  * Top-level keys AugmentCode *replaces* (higher-precedence wins wholesale)
@@ -11292,7 +11465,7 @@ const CLAUDE_CONVERTER_CONFIG = {
11292
11465
  tool: "if"
11293
11466
  }]
11294
11467
  };
11295
- var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11468
+ var ClaudecodeHooks = class extends ToolHooks {
11296
11469
  constructor(params) {
11297
11470
  super({
11298
11471
  ...params,
@@ -11309,9 +11482,9 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11309
11482
  };
11310
11483
  }
11311
11484
  static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
11312
- const paths = ClaudecodeHooks.getSettablePaths({ global });
11485
+ const paths = this.getSettablePaths({ global });
11313
11486
  const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
11314
- return new ClaudecodeHooks({
11487
+ return new this({
11315
11488
  outputRoot,
11316
11489
  relativeDirPath: paths.relativeDirPath,
11317
11490
  relativeFilePath: paths.relativeFilePath,
@@ -11320,7 +11493,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11320
11493
  });
11321
11494
  }
11322
11495
  static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
11323
- const paths = ClaudecodeHooks.getSettablePaths({ global });
11496
+ const paths = this.getSettablePaths({ global });
11324
11497
  const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
11325
11498
  const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
11326
11499
  const config = rulesyncHooks.getJson();
@@ -11336,7 +11509,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11336
11509
  }) },
11337
11510
  filePath
11338
11511
  });
11339
- return new ClaudecodeHooks({
11512
+ return new this({
11340
11513
  outputRoot,
11341
11514
  relativeDirPath: paths.relativeDirPath,
11342
11515
  relativeFilePath: paths.relativeFilePath,
@@ -11367,7 +11540,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11367
11540
  };
11368
11541
  }
11369
11542
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
11370
- return new ClaudecodeHooks({
11543
+ return new this({
11371
11544
  outputRoot,
11372
11545
  relativeDirPath,
11373
11546
  relativeFilePath,
@@ -11377,6 +11550,19 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11377
11550
  }
11378
11551
  };
11379
11552
  //#endregion
11553
+ //#region src/features/hooks/claudecode-plugin-hooks.ts
11554
+ var ClaudecodePluginHooks = class extends ClaudecodeHooks {
11555
+ isDeletable() {
11556
+ return true;
11557
+ }
11558
+ static getSettablePaths() {
11559
+ return {
11560
+ relativeDirPath: CLAUDECODE_PLUGIN_HOOKS_DIR,
11561
+ relativeFilePath: CLAUDECODE_PLUGIN_HOOKS_FILE_NAME
11562
+ };
11563
+ }
11564
+ };
11565
+ //#endregion
11380
11566
  //#region src/features/hooks/codexcli-hooks.ts
11381
11567
  const CODEXCLI_CONVERTER_CONFIG = {
11382
11568
  supportedEvents: CODEXCLI_HOOK_EVENTS,
@@ -12743,7 +12929,7 @@ const HERMESAGENT_MATCHER_EVENTS = /* @__PURE__ */ new Set(["preToolUse", "postT
12743
12929
  * Filter the shared canonical hooks to the events Hermes understands and merge
12744
12930
  * the `hermesagent`-specific override block on top.
12745
12931
  */
12746
- function buildEffectiveHooks(config, toolOverrideHooks) {
12932
+ function buildEffectiveHooks$1(config, toolOverrideHooks) {
12747
12933
  const supported = new Set(HERMESAGENT_HOOK_EVENTS);
12748
12934
  const shared = {};
12749
12935
  for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) shared[event] = defs;
@@ -12765,7 +12951,7 @@ function buildEffectiveHooks(config, toolOverrideHooks) {
12765
12951
  * matcher-less lifecycle events.
12766
12952
  */
12767
12953
  function canonicalToHermesHooks({ config, toolOverrideHooks, logger }) {
12768
- const effectiveHooks = buildEffectiveHooks(config, toolOverrideHooks);
12954
+ const effectiveHooks = buildEffectiveHooks$1(config, toolOverrideHooks);
12769
12955
  const result = {};
12770
12956
  for (const [canonicalEvent, defs] of Object.entries(effectiveHooks)) {
12771
12957
  const nativeEvent = CANONICAL_TO_HERMESAGENT_EVENT_NAMES[canonicalEvent];
@@ -13205,6 +13391,197 @@ var KiloHooks = class KiloHooks extends ToolHooks {
13205
13391
  }
13206
13392
  };
13207
13393
  //#endregion
13394
+ //#region src/constants/kimi-code-paths.ts
13395
+ const KIMI_CODE_DIR = ".kimi-code";
13396
+ const KIMI_CODE_RULE_FILE_NAME = "AGENTS.md";
13397
+ const KIMI_CODE_MCP_FILE_NAME = "mcp.json";
13398
+ const KIMI_CODE_CONFIG_FILE_NAME = "config.toml";
13399
+ const KIMI_CODE_SKILLS_DIR_NAME = "skills";
13400
+ const KIMI_CODE_AGENTS_DIR_NAME = "agents";
13401
+ const KIMI_CODE_SKILLS_DIR_PATH = (0, node_path.join)(KIMI_CODE_DIR, KIMI_CODE_SKILLS_DIR_NAME);
13402
+ (0, node_path.join)(KIMI_CODE_DIR, KIMI_CODE_AGENTS_DIR_NAME);
13403
+ const KIMI_CODE_SHARED_SKILLS_DIR_PATH = (0, node_path.join)(".agents", "skills");
13404
+ const KIMI_CODE_SHARED_AGENTS_DIR_PATH = (0, node_path.join)(".agents", "agents");
13405
+ //#endregion
13406
+ //#region src/utils/kimi-code.ts
13407
+ function getKimiCodeHome() {
13408
+ const configuredHome = process.env.KIMI_CODE_HOME?.trim();
13409
+ return configuredHome ? (0, node_path.resolve)(configuredHome) : void 0;
13410
+ }
13411
+ function resolveToolOutputRoot({ outputRoot, toolTarget, global }) {
13412
+ return toolTarget === "kimi-code" && global ? getKimiCodeHome() ?? outputRoot : outputRoot;
13413
+ }
13414
+ function getKimiCodeRelativeDirPath({ global, relativeDirPath = "." }) {
13415
+ return global && getKimiCodeHome() ? relativeDirPath : (0, node_path.join)(KIMI_CODE_DIR, relativeDirPath);
13416
+ }
13417
+ function getKimiCodeRulesyncOutputRoot({ nativeOutputRoot, global }) {
13418
+ return global && getKimiCodeHome() ? getHomeDirectory() : nativeOutputRoot;
13419
+ }
13420
+ //#endregion
13421
+ //#region src/features/hooks/kimi-code-hooks.ts
13422
+ function runFromTrustedDirectory({ command, trustedDirectory }) {
13423
+ if (process.platform === "win32") return `set "RULESYNC_KIMI_HOOK_CWD=1" && cd /d "${trustedDirectory.replaceAll("%", "%%").replaceAll("\"", "\"\"")}" && ${command}`;
13424
+ return `export RULESYNC_KIMI_HOOK_CWD=1 && cd -- '${trustedDirectory.replaceAll("'", `'"'"'`)}' && ${command}`;
13425
+ }
13426
+ function stripTrustedDirectoryWrapper(command) {
13427
+ const posix = command.match(/^export RULESYNC_KIMI_HOOK_CWD=1 && cd -- '(?:[^']|'"'"')*' && ([\s\S]*)$/);
13428
+ if (posix?.[1]) return posix[1];
13429
+ return command.match(/^set "RULESYNC_KIMI_HOOK_CWD=1" && cd \/d "(?:""|[^"])*" && ([\s\S]*)$/)?.[1] ?? command;
13430
+ }
13431
+ function buildEffectiveHooks(config, toolOverrideHooks) {
13432
+ const supported = new Set(KIMI_CODE_HOOK_EVENTS);
13433
+ const shared = {};
13434
+ for (const [event, definitions] of Object.entries(config.hooks)) if (supported.has(event)) shared[event] = definitions;
13435
+ return {
13436
+ ...shared,
13437
+ ...toolOverrideHooks
13438
+ };
13439
+ }
13440
+ function canonicalToKimiCodeHooks({ config, toolOverrideHooks, trustedDirectory, logger }) {
13441
+ const result = [];
13442
+ const nativeEvents = new Set(KIMI_CODE_NATIVE_HOOK_EVENTS);
13443
+ for (const [event, definitions] of Object.entries(buildEffectiveHooks(config, toolOverrideHooks))) {
13444
+ const nativeEvent = CANONICAL_TO_KIMI_CODE_EVENT_NAMES[event] ?? event;
13445
+ if (!nativeEvents.has(nativeEvent)) {
13446
+ logger?.warn(`Kimi Code hooks: skipping unsupported event "${event}".`);
13447
+ continue;
13448
+ }
13449
+ for (const definition of definitions) {
13450
+ if ((definition.type ?? "command") !== "command" || !definition.command) continue;
13451
+ const timeout = definition.timeout;
13452
+ const validTimeout = timeout === void 0 || Number.isInteger(timeout) && timeout >= 1 && timeout <= 600;
13453
+ if (!validTimeout) logger?.warn(`Kimi Code hooks: omitting invalid timeout for "${event}"; expected an integer from 1 to 600 seconds.`);
13454
+ result.push({
13455
+ event: nativeEvent,
13456
+ command: runFromTrustedDirectory({
13457
+ command: definition.command,
13458
+ trustedDirectory
13459
+ }),
13460
+ ...definition.matcher && { matcher: definition.matcher },
13461
+ ...validTimeout && timeout !== void 0 && { timeout }
13462
+ });
13463
+ }
13464
+ }
13465
+ return result;
13466
+ }
13467
+ function kimiCodeHooksToCanonical(hooks) {
13468
+ const result = {};
13469
+ if (!Array.isArray(hooks)) return result;
13470
+ for (const raw of hooks) {
13471
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
13472
+ const entry = raw;
13473
+ if (typeof entry.event !== "string" || typeof entry.command !== "string") continue;
13474
+ const event = KIMI_CODE_TO_CANONICAL_EVENT_NAMES[entry.event] ?? entry.event;
13475
+ const definition = {
13476
+ type: "command",
13477
+ command: stripTrustedDirectoryWrapper(entry.command),
13478
+ ...typeof entry.matcher === "string" && { matcher: entry.matcher },
13479
+ ...typeof entry.timeout === "number" && { timeout: entry.timeout }
13480
+ };
13481
+ (result[event] ??= []).push(definition);
13482
+ }
13483
+ return result;
13484
+ }
13485
+ /**
13486
+ * Kimi Code lifecycle hooks in the shared user `config.toml`.
13487
+ *
13488
+ * Kimi Code documents hooks only at user scope. The config file also contains
13489
+ * models, providers, permissions, and other settings, so the hooks patch is
13490
+ * merged in place and the file is never deleted.
13491
+ *
13492
+ * @see https://moonshotai.github.io/kimi-code/en/customization/hooks.html
13493
+ */
13494
+ var KimiCodeHooks = class KimiCodeHooks extends ToolHooks {
13495
+ constructor(params) {
13496
+ super({
13497
+ ...params,
13498
+ ...KimiCodeHooks.getSettablePaths({ global: params.global ?? true })
13499
+ });
13500
+ }
13501
+ static getSettablePaths({ global = true } = {}) {
13502
+ return {
13503
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
13504
+ relativeFilePath: KIMI_CODE_CONFIG_FILE_NAME
13505
+ };
13506
+ }
13507
+ validate() {
13508
+ return {
13509
+ success: true,
13510
+ error: null
13511
+ };
13512
+ }
13513
+ isDeletable() {
13514
+ return false;
13515
+ }
13516
+ shouldMergeExistingFileContent() {
13517
+ return true;
13518
+ }
13519
+ setFileContent(fileContent) {
13520
+ const paths = KimiCodeHooks.getSettablePaths({ global: this.global });
13521
+ this.fileContent = applySharedConfigPatch({
13522
+ fileKey: KIMI_CODE_CONFIG_SHARED_FILE_KEY,
13523
+ feature: "hooks",
13524
+ existingContent: fileContent,
13525
+ patch: parseSharedConfig({
13526
+ format: "toml",
13527
+ fileContent: this.fileContent
13528
+ }),
13529
+ filePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
13530
+ });
13531
+ }
13532
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = true }) {
13533
+ const paths = this.getSettablePaths({ global });
13534
+ return new KimiCodeHooks({
13535
+ outputRoot,
13536
+ fileContent: await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)),
13537
+ validate,
13538
+ global
13539
+ });
13540
+ }
13541
+ static fromRulesyncHooks({ outputRoot, rulesyncHooks, logger }) {
13542
+ const config = rulesyncHooks.getJson();
13543
+ return new KimiCodeHooks({
13544
+ outputRoot,
13545
+ fileContent: stringifySharedConfig({
13546
+ format: "toml",
13547
+ document: { hooks: canonicalToKimiCodeHooks({
13548
+ config,
13549
+ toolOverrideHooks: config["kimi-code"]?.hooks,
13550
+ trustedDirectory: (0, node_path.resolve)(rulesyncHooks.getOutputRoot()),
13551
+ logger
13552
+ }) }
13553
+ }),
13554
+ global: true
13555
+ });
13556
+ }
13557
+ toRulesyncHooks() {
13558
+ const config = parseSharedConfig({
13559
+ format: "toml",
13560
+ fileContent: this.getFileContent()
13561
+ });
13562
+ return new RulesyncHooks({
13563
+ outputRoot: getKimiCodeRulesyncOutputRoot({
13564
+ nativeOutputRoot: this.outputRoot,
13565
+ global: this.global
13566
+ }),
13567
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
13568
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
13569
+ fileContent: JSON.stringify(buildImportedHooksConfig({
13570
+ hooks: kimiCodeHooksToCanonical(config.hooks),
13571
+ overrideKey: "kimi-code"
13572
+ }), null, 2)
13573
+ });
13574
+ }
13575
+ static forDeletion({ outputRoot = process.cwd() }) {
13576
+ return new KimiCodeHooks({
13577
+ outputRoot,
13578
+ fileContent: "",
13579
+ validate: false,
13580
+ global: true
13581
+ });
13582
+ }
13583
+ };
13584
+ //#endregion
13208
13585
  //#region src/features/hooks/kiro-hooks.ts
13209
13586
  /**
13210
13587
  * Convert canonical hooks config to Kiro CLI format.
@@ -13220,6 +13597,7 @@ function buildKiroEntriesForEvent(definitions) {
13220
13597
  command: def.command,
13221
13598
  ...def.matcher !== void 0 && def.matcher !== null && def.matcher !== "" && { matcher: def.matcher },
13222
13599
  ...def.timeout !== void 0 && def.timeout !== null && def.timeout > 0 && { timeout_ms: def.timeout },
13600
+ ...def.cacheTtl !== void 0 && { cache_ttl_seconds: def.cacheTtl },
13223
13601
  ...def.name !== void 0 && def.name !== null && { name: def.name },
13224
13602
  ...def.description !== void 0 && def.description !== null && { description: def.description }
13225
13603
  });
@@ -13252,9 +13630,14 @@ const KiroHookEntrySchema = zod_mini.z.looseObject({
13252
13630
  command: zod_mini.z.optional(safeString),
13253
13631
  matcher: zod_mini.z.optional(zod_mini.z.string()),
13254
13632
  timeout_ms: zod_mini.z.optional(zod_mini.z.number()),
13633
+ cache_ttl_seconds: zod_mini.z.optional(zod_mini.z.number().check((0, zod_mini.nonnegative)())),
13255
13634
  name: zod_mini.z.optional(zod_mini.z.string()),
13256
13635
  description: zod_mini.z.optional(zod_mini.z.string())
13257
13636
  });
13637
+ function importCacheTtl(entry) {
13638
+ if (entry.cache_ttl_seconds === void 0) return {};
13639
+ return { cacheTtl: entry.cache_ttl_seconds };
13640
+ }
13258
13641
  /**
13259
13642
  * Extract hooks from Kiro CLI agent config into canonical format.
13260
13643
  */
@@ -13275,6 +13658,7 @@ function kiroHooksToCanonical(kiroHooks) {
13275
13658
  command: entry.command,
13276
13659
  ...entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" && { matcher: entry.matcher },
13277
13660
  ...entry.timeout_ms !== void 0 && entry.timeout_ms !== null && { timeout: entry.timeout_ms },
13661
+ ...importCacheTtl(entry),
13278
13662
  ...entry.name !== void 0 && entry.name !== null && { name: entry.name },
13279
13663
  ...entry.description !== void 0 && entry.description !== null && { description: entry.description }
13280
13664
  });
@@ -14514,6 +14898,17 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14514
14898
  supportedHookTypes: ["command"],
14515
14899
  supportsMatcher: true
14516
14900
  }],
14901
+ ["antigravity-plugin", {
14902
+ class: AntigravityPluginHooks,
14903
+ meta: {
14904
+ supportsProject: true,
14905
+ supportsGlobal: false,
14906
+ supportsImport: true
14907
+ },
14908
+ supportedEvents: ANTIGRAVITY_HOOK_EVENTS,
14909
+ supportedHookTypes: ["command"],
14910
+ supportsMatcher: true
14911
+ }],
14517
14912
  ["cursor", {
14518
14913
  class: CursorHooks,
14519
14914
  meta: {
@@ -14542,6 +14937,23 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14542
14937
  ],
14543
14938
  supportsMatcher: true
14544
14939
  }],
14940
+ ["claudecode-plugin", {
14941
+ class: ClaudecodePluginHooks,
14942
+ meta: {
14943
+ supportsProject: true,
14944
+ supportsGlobal: false,
14945
+ supportsImport: true
14946
+ },
14947
+ supportedEvents: CLAUDE_HOOK_EVENTS,
14948
+ supportedHookTypes: [
14949
+ "command",
14950
+ "prompt",
14951
+ "http",
14952
+ "mcp_tool",
14953
+ "agent"
14954
+ ],
14955
+ supportsMatcher: true
14956
+ }],
14545
14957
  ["codexcli", {
14546
14958
  class: CodexcliHooks,
14547
14959
  meta: {
@@ -14645,6 +15057,18 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14645
15057
  supportedHookTypes: ["command"],
14646
15058
  supportsMatcher: true
14647
15059
  }],
15060
+ ["kimi-code", {
15061
+ class: KimiCodeHooks,
15062
+ meta: {
15063
+ supportsProject: false,
15064
+ supportsGlobal: true,
15065
+ supportsImport: true
15066
+ },
15067
+ supportedEvents: KIMI_CODE_HOOK_EVENTS,
15068
+ supportedHookTypes: ["command"],
15069
+ supportsMatcher: true,
15070
+ passthroughOverrideEvents: true
15071
+ }],
14648
15072
  ["deepagents", {
14649
15073
  class: DeepagentsHooks,
14650
15074
  meta: {
@@ -15820,40 +16244,45 @@ var KiloIgnore = class KiloIgnore extends ToolIgnore {
15820
16244
  //#endregion
15821
16245
  //#region src/features/ignore/kiro-ignore.ts
15822
16246
  var KiroIgnore = class KiroIgnore extends ToolIgnore {
15823
- static getSettablePaths() {
16247
+ static getSettablePaths({ global = false } = {}) {
15824
16248
  return {
15825
- relativeDirPath: ".",
15826
- relativeFilePath: KIRO_IGNORE_FILE_NAME
16249
+ relativeDirPath: global ? KIRO_SETTINGS_DIR_PATH : ".",
16250
+ relativeFilePath: global ? KIRO_GLOBAL_IGNORE_FILE_NAME : KIRO_IGNORE_FILE_NAME
15827
16251
  };
15828
16252
  }
15829
16253
  toRulesyncIgnore() {
15830
16254
  return this.toRulesyncIgnoreDefault();
15831
16255
  }
15832
- static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore }) {
16256
+ static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore, global = false }) {
16257
+ const paths = this.getSettablePaths({ global });
15833
16258
  return new KiroIgnore({
15834
16259
  outputRoot,
15835
- relativeDirPath: this.getSettablePaths().relativeDirPath,
15836
- relativeFilePath: this.getSettablePaths().relativeFilePath,
15837
- fileContent: rulesyncIgnore.getFileContent()
16260
+ relativeDirPath: paths.relativeDirPath,
16261
+ relativeFilePath: paths.relativeFilePath,
16262
+ fileContent: rulesyncIgnore.getFileContent(),
16263
+ global
15838
16264
  });
15839
16265
  }
15840
- static async fromFile({ outputRoot = process.cwd(), validate = true }) {
15841
- const fileContent = await readFileContent((0, node_path.join)(outputRoot, this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath));
16266
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
16267
+ const paths = this.getSettablePaths({ global });
16268
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
15842
16269
  return new KiroIgnore({
15843
16270
  outputRoot,
15844
- relativeDirPath: this.getSettablePaths().relativeDirPath,
15845
- relativeFilePath: this.getSettablePaths().relativeFilePath,
16271
+ relativeDirPath: paths.relativeDirPath,
16272
+ relativeFilePath: paths.relativeFilePath,
15846
16273
  fileContent,
15847
- validate
16274
+ validate,
16275
+ global
15848
16276
  });
15849
16277
  }
15850
- static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
16278
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
15851
16279
  return new KiroIgnore({
15852
16280
  outputRoot,
15853
16281
  relativeDirPath,
15854
16282
  relativeFilePath,
15855
16283
  fileContent: "",
15856
- validate: false
16284
+ validate: false,
16285
+ global
15857
16286
  });
15858
16287
  }
15859
16288
  };
@@ -16160,6 +16589,11 @@ const toolIgnoreFactories = /* @__PURE__ */ new Map([
16160
16589
  ["zed", { class: ZedIgnore }]
16161
16590
  ]);
16162
16591
  const ignoreProcessorToolTargets = [...toolIgnoreFactories.keys()];
16592
+ const ignoreProcessorGlobalToolTargets = [
16593
+ "kiro",
16594
+ "kiro-cli",
16595
+ "kiro-ide"
16596
+ ];
16163
16597
  const defaultGetFactory$4 = (target) => {
16164
16598
  const factory = toolIgnoreFactories.get(target);
16165
16599
  if (!factory) throw new Error(`Unsupported tool target: ${target}`);
@@ -16169,7 +16603,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16169
16603
  toolTarget;
16170
16604
  getFactory;
16171
16605
  featureOptions;
16172
- constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, getFactory = defaultGetFactory$4, dryRun = false, logger, featureOptions }) {
16606
+ global;
16607
+ constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, getFactory = defaultGetFactory$4, global = false, dryRun = false, logger, featureOptions }) {
16173
16608
  super({
16174
16609
  outputRoot,
16175
16610
  inputRoot,
@@ -16181,6 +16616,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
16181
16616
  this.toolTarget = result.data;
16182
16617
  this.getFactory = getFactory;
16183
16618
  this.featureOptions = featureOptions;
16619
+ this.global = global;
16184
16620
  }
16185
16621
  async writeToolIgnoresFromRulesyncIgnores(rulesyncIgnores) {
16186
16622
  const toolIgnores = await this.convertRulesyncFilesToToolFiles(rulesyncIgnores);
@@ -16205,12 +16641,16 @@ var IgnoreProcessor = class extends FeatureProcessor {
16205
16641
  async loadToolFiles({ forDeletion = false } = {}) {
16206
16642
  try {
16207
16643
  const factory = this.getFactory(this.toolTarget);
16208
- const paths = factory.class.getSettablePaths({ options: this.featureOptions });
16644
+ const paths = factory.class.getSettablePaths({
16645
+ options: this.featureOptions,
16646
+ global: this.global
16647
+ });
16209
16648
  if (forDeletion) {
16210
16649
  const toolIgnore = factory.class.forDeletion({
16211
16650
  outputRoot: this.outputRoot,
16212
16651
  relativeDirPath: paths.relativeDirPath,
16213
- relativeFilePath: paths.relativeFilePath
16652
+ relativeFilePath: paths.relativeFilePath,
16653
+ global: this.global
16214
16654
  });
16215
16655
  const hasOwnershipGuard = factory.class.canDeleteAuxiliaryFiles !== void 0;
16216
16656
  if (!(!hasOwnershipGuard || await factory.class.canDeleteAuxiliaryFiles?.({ outputRoot: this.outputRoot }) === true)) return [];
@@ -16230,7 +16670,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16230
16670
  async loadToolIgnores() {
16231
16671
  return [await this.getFactory(this.toolTarget).class.fromFile({
16232
16672
  outputRoot: this.outputRoot,
16233
- options: this.featureOptions
16673
+ options: this.featureOptions,
16674
+ global: this.global
16234
16675
  })];
16235
16676
  }
16236
16677
  /**
@@ -16244,7 +16685,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16244
16685
  const toolIgnore = await factory.class.fromRulesyncIgnore({
16245
16686
  outputRoot: this.outputRoot,
16246
16687
  rulesyncIgnore,
16247
- options: this.featureOptions
16688
+ options: this.featureOptions,
16689
+ global: this.global
16248
16690
  });
16249
16691
  const auxiliaryFiles = await factory.class.getAuxiliaryFiles?.({
16250
16692
  toolIgnore,
@@ -16266,7 +16708,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
16266
16708
  * Return the tool targets that this processor supports
16267
16709
  */
16268
16710
  static getToolTargets({ global = false } = {}) {
16269
- if (global) throw new Error("IgnoreProcessor does not support global mode");
16711
+ if (global) return ignoreProcessorGlobalToolTargets;
16270
16712
  return ignoreProcessorToolTargets;
16271
16713
  }
16272
16714
  };
@@ -16706,6 +17148,16 @@ var AntigravityIdeMcp = class extends AntigravityMcp {
16706
17148
  }
16707
17149
  };
16708
17150
  //#endregion
17151
+ //#region src/features/mcp/antigravity-plugin-mcp.ts
17152
+ var AntigravityPluginMcp = class extends AntigravityIdeMcp {
17153
+ static getSettablePaths() {
17154
+ return {
17155
+ relativeDirPath: ".",
17156
+ relativeFilePath: ANTIGRAVITY_PLUGIN_MCP_FILE_NAME
17157
+ };
17158
+ }
17159
+ };
17160
+ //#endregion
16709
17161
  //#region src/features/mcp/augmentcode-mcp.ts
16710
17162
  function parseAugmentcodeSettings(fileContent, relativeDirPath, relativeFilePath) {
16711
17163
  const configPath = (0, node_path.join)(relativeDirPath, relativeFilePath);
@@ -17125,7 +17577,7 @@ function convertToCodexFormat(mcpServers) {
17125
17577
  for (const [name, config] of Object.entries(mcpServers)) {
17126
17578
  if (!isRecord(config)) continue;
17127
17579
  const { codexName, usedFallback } = normalizeCodexMcpServerName(name);
17128
- if (usedFallback) warnWithFallback(void 0, `MCP server "${name}" cannot be represented as a Codex MCP server name (ASCII [a-zA-Z0-9_-] only), so the stable fallback name "${codexName}" was used. Rename the server in .rulesync/mcp.json to choose a readable Codex name.`);
17580
+ if (usedFallback) warnWithFallback(void 0, `MCP server "${name}" cannot be represented as a Codex MCP server name (ASCII [a-zA-Z0-9_-] only), so the stable fallback name "${codexName}" was used. Rename the server in .rulesync/mcp.jsonc to choose a readable Codex name.`);
17129
17581
  const converted = {};
17130
17582
  for (const [key, value] of Object.entries(config)) {
17131
17583
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
@@ -18934,6 +19386,170 @@ var KiloMcp = class KiloMcp extends ToolMcp {
18934
19386
  }
18935
19387
  };
18936
19388
  //#endregion
19389
+ //#region src/features/mcp/kimi-code-mcp.ts
19390
+ function normalizeKimiCodeTransport({ transport, hasCommand }) {
19391
+ if (transport === "local" || transport === "stdio") return "stdio";
19392
+ if (transport === "sse") return "sse";
19393
+ if (transport === "http" || transport === "streamable-http") return "http";
19394
+ return hasCommand ? "stdio" : "http";
19395
+ }
19396
+ function toKimiCodeServer({ name, server, logger }) {
19397
+ const transport = server.transport ?? server.type;
19398
+ if (transport === "ws") {
19399
+ logger?.warn(`Kimi Code MCP: skipping "${name}" because WebSocket transport is unsupported.`);
19400
+ return null;
19401
+ }
19402
+ const command = server.command;
19403
+ const normalizedCommand = Array.isArray(command) ? command[0] : command;
19404
+ const args = [...Array.isArray(command) ? command.slice(1) : [], ...server.args ?? []];
19405
+ const url = server.httpUrl ?? server.url;
19406
+ const normalizedTransport = normalizeKimiCodeTransport({
19407
+ transport,
19408
+ hasCommand: normalizedCommand !== void 0
19409
+ });
19410
+ if (normalizedTransport === "stdio" && !normalizedCommand || normalizedTransport !== "stdio" && !url) {
19411
+ logger?.warn(`Kimi Code MCP: skipping "${name}" because its ${normalizedTransport} configuration is incomplete.`);
19412
+ return null;
19413
+ }
19414
+ const converted = {
19415
+ transport: normalizedTransport,
19416
+ ...normalizedCommand && { command: normalizedCommand },
19417
+ ...args.length > 0 && { args },
19418
+ ...url && { url }
19419
+ };
19420
+ for (const field of [
19421
+ "env",
19422
+ "cwd",
19423
+ "headers",
19424
+ "bearerTokenEnvVar",
19425
+ "enabled",
19426
+ "startupTimeoutMs",
19427
+ "toolTimeoutMs",
19428
+ "enabledTools",
19429
+ "disabledTools"
19430
+ ]) if (server[field] !== void 0) converted[field] = server[field];
19431
+ if (server.disabled === true) converted.enabled = false;
19432
+ return converted;
19433
+ }
19434
+ function toKimiCodeServers({ servers, logger }) {
19435
+ const result = {};
19436
+ for (const [name, server] of Object.entries(servers)) {
19437
+ const converted = toKimiCodeServer({
19438
+ name,
19439
+ server,
19440
+ logger
19441
+ });
19442
+ if (converted) result[name] = converted;
19443
+ }
19444
+ return result;
19445
+ }
19446
+ function fromKimiCodeServers(servers) {
19447
+ return Object.fromEntries(Object.entries(servers).map(([name, server]) => {
19448
+ const { transport, enabled, ...rest } = server;
19449
+ const type = transport === "stdio" || transport === "sse" || transport === "http" ? transport : void 0;
19450
+ return [name, {
19451
+ ...rest,
19452
+ ...type && { type },
19453
+ ...enabled === false && { disabled: true }
19454
+ }];
19455
+ }));
19456
+ }
19457
+ /**
19458
+ * Kimi Code MCP configuration.
19459
+ *
19460
+ * Both project and user scope use `.kimi-code/mcp.json`, resolved against the
19461
+ * project root or home directory respectively.
19462
+ *
19463
+ * @see https://moonshotai.github.io/kimi-code/en/customization/mcp.html
19464
+ */
19465
+ var KimiCodeMcp = class KimiCodeMcp extends ToolMcp {
19466
+ json;
19467
+ constructor(params) {
19468
+ super(params);
19469
+ try {
19470
+ this.json = this.fileContent ? JSON.parse(this.fileContent) : {};
19471
+ } catch (error) {
19472
+ throw new Error(`Failed to parse Kimi Code MCP config at ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(error)}`, { cause: error });
19473
+ }
19474
+ }
19475
+ isDeletable() {
19476
+ return !this.global;
19477
+ }
19478
+ static getSettablePaths({ global = false } = {}) {
19479
+ return {
19480
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
19481
+ relativeFilePath: KIMI_CODE_MCP_FILE_NAME
19482
+ };
19483
+ }
19484
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
19485
+ const paths = this.getSettablePaths({ global });
19486
+ const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"mcpServers\":{}}";
19487
+ return new KimiCodeMcp({
19488
+ outputRoot,
19489
+ relativeDirPath: paths.relativeDirPath,
19490
+ relativeFilePath: paths.relativeFilePath,
19491
+ fileContent,
19492
+ validate,
19493
+ global
19494
+ });
19495
+ }
19496
+ static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
19497
+ const paths = this.getSettablePaths({ global });
19498
+ const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
19499
+ const existingContent = await readFileContentOrNull(filePath) ?? "{}";
19500
+ let existing;
19501
+ try {
19502
+ existing = JSON.parse(existingContent);
19503
+ } catch (error) {
19504
+ throw new Error(`Failed to parse Kimi Code MCP config at ${filePath}: ${formatError(error)}`, { cause: error });
19505
+ }
19506
+ return new KimiCodeMcp({
19507
+ outputRoot,
19508
+ relativeDirPath: paths.relativeDirPath,
19509
+ relativeFilePath: paths.relativeFilePath,
19510
+ fileContent: JSON.stringify({
19511
+ ...existing,
19512
+ mcpServers: toKimiCodeServers({
19513
+ servers: rulesyncMcp.getMcpServers(),
19514
+ logger
19515
+ })
19516
+ }, null, 2),
19517
+ validate,
19518
+ global
19519
+ });
19520
+ }
19521
+ toRulesyncMcp() {
19522
+ return new RulesyncMcp({
19523
+ outputRoot: getKimiCodeRulesyncOutputRoot({
19524
+ nativeOutputRoot: this.outputRoot,
19525
+ global: this.global
19526
+ }),
19527
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
19528
+ relativeFilePath: RULESYNC_MCP_FILE_NAME,
19529
+ fileContent: JSON.stringify({
19530
+ ...this.json,
19531
+ mcpServers: fromKimiCodeServers(isMcpServers(this.json.mcpServers) ? this.json.mcpServers : {})
19532
+ }, null, 2)
19533
+ });
19534
+ }
19535
+ validate() {
19536
+ return {
19537
+ success: true,
19538
+ error: null
19539
+ };
19540
+ }
19541
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
19542
+ return new KimiCodeMcp({
19543
+ outputRoot,
19544
+ relativeDirPath,
19545
+ relativeFilePath,
19546
+ fileContent: "{}",
19547
+ validate: false,
19548
+ global
19549
+ });
19550
+ }
19551
+ };
19552
+ //#endregion
18937
19553
  //#region src/features/mcp/kiro-mcp.ts
18938
19554
  var KiroMcp = class KiroMcp extends ToolMcp {
18939
19555
  json;
@@ -19742,7 +20358,7 @@ var RovodevMcp = class RovodevMcp extends ToolMcp {
19742
20358
  * `workflow_mcp_servers: { stdio, sse, http }`. Without it, workflow-defined MCP
19743
20359
  * servers are refused regardless of how they are declared. So this adapter emits
19744
20360
  * the transport allowlist derived from the transports present in
19745
- * `.rulesync/mcp.json`, enabling exactly the transports the user's servers need.
20361
+ * `.rulesync/mcp.jsonc`, enabling exactly the transports the user's servers need.
19746
20362
  *
19747
20363
  * Lossiness (documented, intentional): the per-server names, commands, env, URLs
19748
20364
  * and headers are NOT representable in `config.yaml` and are intentionally not
@@ -20262,6 +20878,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20262
20878
  supportsDisabledTools: true
20263
20879
  }
20264
20880
  }],
20881
+ ["antigravity-plugin", {
20882
+ class: AntigravityPluginMcp,
20883
+ meta: {
20884
+ supportsProject: true,
20885
+ supportsGlobal: false,
20886
+ supportsEnabledTools: false,
20887
+ supportsDisabledTools: true
20888
+ }
20889
+ }],
20265
20890
  ["augmentcode", {
20266
20891
  class: AugmentcodeMcp,
20267
20892
  meta: {
@@ -20280,6 +20905,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20280
20905
  supportsDisabledTools: false
20281
20906
  }
20282
20907
  }],
20908
+ ["claudecode-plugin", {
20909
+ class: ClaudecodeMcp,
20910
+ meta: {
20911
+ supportsProject: true,
20912
+ supportsGlobal: false,
20913
+ supportsEnabledTools: false,
20914
+ supportsDisabledTools: false
20915
+ }
20916
+ }],
20283
20917
  ["claudecode-legacy", {
20284
20918
  class: ClaudecodeMcp,
20285
20919
  meta: {
@@ -20379,6 +21013,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20379
21013
  supportsDisabledTools: false
20380
21014
  }
20381
21015
  }],
21016
+ ["kimi-code", {
21017
+ class: KimiCodeMcp,
21018
+ meta: {
21019
+ supportsProject: true,
21020
+ supportsGlobal: true,
21021
+ supportsEnabledTools: true,
21022
+ supportsDisabledTools: true
21023
+ }
21024
+ }],
20382
21025
  ["kilo", {
20383
21026
  class: KiloMcp,
20384
21027
  meta: {
@@ -20394,7 +21037,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20394
21037
  supportsProject: true,
20395
21038
  supportsGlobal: true,
20396
21039
  supportsEnabledTools: false,
20397
- supportsDisabledTools: false
21040
+ supportsDisabledTools: true
20398
21041
  }
20399
21042
  }],
20400
21043
  ["kiro-cli", {
@@ -20403,7 +21046,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20403
21046
  supportsProject: true,
20404
21047
  supportsGlobal: true,
20405
21048
  supportsEnabledTools: false,
20406
- supportsDisabledTools: false
21049
+ supportsDisabledTools: true
20407
21050
  }
20408
21051
  }],
20409
21052
  ["kiro-ide", {
@@ -20412,7 +21055,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20412
21055
  supportsProject: true,
20413
21056
  supportsGlobal: true,
20414
21057
  supportsEnabledTools: false,
20415
- supportsDisabledTools: false
21058
+ supportsDisabledTools: true
20416
21059
  }
20417
21060
  }],
20418
21061
  ["junie", {
@@ -22979,7 +23622,7 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
22979
23622
  function buildCodexBashRulesContent(config) {
22980
23623
  const bashRules = config.permission.bash ?? {};
22981
23624
  const entries = Object.entries(bashRules);
22982
- const header = ["# Generated by Rulesync from .rulesync/permissions.json (permission.bash)", "# https://developers.openai.com/codex/rules"];
23625
+ const header = ["# Generated by Rulesync from .rulesync/permissions.jsonc (permission.bash)", "# https://developers.openai.com/codex/rules"];
22983
23626
  if (entries.length === 0) return [...header, "# No bash permission rules were configured."].join("\n");
22984
23627
  const ruleBlocks = entries.map(([pattern, action]) => {
22985
23628
  const tokens = toCommandPatternTokens(pattern);
@@ -24439,8 +25082,9 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
24439
25082
  });
24440
25083
  const permissions = config.permissions && typeof config.permissions === "object" ? config.permissions.rulesync : {};
24441
25084
  return new RulesyncPermissions({
24442
- relativeDirPath: "",
24443
- relativeFilePath: ".rulesync/permissions.json",
25085
+ outputRoot: this.outputRoot,
25086
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
25087
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
24444
25088
  fileContent: JSON.stringify(permissions ?? {}, null, 2)
24445
25089
  });
24446
25090
  }
@@ -24862,7 +25506,7 @@ var KiloPermissions = class KiloPermissions extends ToolPermissions {
24862
25506
  }
24863
25507
  if (Object.keys(droppedDenyByKey).length > 0) {
24864
25508
  const summary = Object.entries(droppedDenyByKey).map(([key, patterns]) => `${key}: [${patterns.join(", ")}]`).join("; ");
24865
- logger?.warn(`WARNING: Kilo permissions regeneration drops existing 'deny' rule(s) because rulesync output owns these tool keys. Dropped — ${summary}. To preserve these denies, add them to '.rulesync/permissions.json'.`);
25509
+ logger?.warn(`WARNING: Kilo permissions regeneration drops existing 'deny' rule(s) because rulesync output owns these tool keys. Dropped — ${summary}. To preserve these denies, add them to '.rulesync/permissions.jsonc'.`);
24866
25510
  }
24867
25511
  const mergedPermission = {
24868
25512
  ...existingPermission,
@@ -24922,6 +25566,227 @@ var KiloPermissions = class KiloPermissions extends ToolPermissions {
24922
25566
  }
24923
25567
  };
24924
25568
  //#endregion
25569
+ //#region src/features/permissions/kimi-code-permissions.ts
25570
+ const CATEGORY_TO_KIMI_CODE_TOOL = {
25571
+ bash: "Bash",
25572
+ read: "Read",
25573
+ write: "Write",
25574
+ edit: "Edit",
25575
+ grep: "Grep",
25576
+ glob: "Glob",
25577
+ websearch: "WebSearch",
25578
+ webfetch: "FetchURL",
25579
+ agent: "Agent"
25580
+ };
25581
+ function buildKimiCodePattern(category, pattern) {
25582
+ if (category.startsWith("mcp__")) return pattern === "*" || pattern === "" ? category : null;
25583
+ if (category === "mcp") return pattern === "*" || pattern === "" ? "mcp__*" : `mcp__${pattern}`;
25584
+ const tool = CATEGORY_TO_KIMI_CODE_TOOL[category];
25585
+ if (!tool) return null;
25586
+ return pattern === "*" || pattern === "" ? tool : `${tool}(${pattern})`;
25587
+ }
25588
+ function canonicalToKimiCodeRules({ config, logger }) {
25589
+ const canonicalRules = [];
25590
+ const overrideRules = config["kimi-code"]?.rules ?? [];
25591
+ for (const [category, rules] of Object.entries(config.permission)) {
25592
+ if (!(category === "mcp" || category.startsWith("mcp__") || CATEGORY_TO_KIMI_CODE_TOOL[category] !== void 0)) {
25593
+ if (Object.keys(rules).length > 0) logger?.warn(`Kimi Code permissions: skipping unsupported category "${category}".`);
25594
+ continue;
25595
+ }
25596
+ for (const [pattern, decision] of Object.entries(rules)) {
25597
+ if (category.startsWith("mcp__") && pattern !== "*" && pattern !== "") {
25598
+ if (decision === "deny") {
25599
+ logger?.warn(`Kimi Code permissions: broadening argument-specific deny for "${category}" to the whole MCP tool because Kimi does not match MCP tool arguments.`);
25600
+ canonicalRules.push({
25601
+ decision,
25602
+ pattern: category,
25603
+ scope: "user"
25604
+ });
25605
+ } else logger?.warn(`Kimi Code permissions: skipping argument-specific ${decision} for "${category}" because Kimi does not match MCP tool arguments.`);
25606
+ continue;
25607
+ }
25608
+ const kimiCodePattern = buildKimiCodePattern(category, pattern);
25609
+ if (!kimiCodePattern) continue;
25610
+ canonicalRules.push({
25611
+ decision,
25612
+ pattern: kimiCodePattern,
25613
+ scope: "user"
25614
+ });
25615
+ }
25616
+ }
25617
+ return [...overrideRules, ...sortKimiCodeRulesFailClosed(canonicalRules)];
25618
+ }
25619
+ function getKimiCodePatternSpecificity(pattern) {
25620
+ const opening = pattern.indexOf("(");
25621
+ const hasArguments = opening >= 0 && pattern.endsWith(")");
25622
+ const tool = hasArguments ? pattern.slice(0, opening) : pattern;
25623
+ const argument = hasArguments ? pattern.slice(opening + 1, -1) : "";
25624
+ return {
25625
+ tool,
25626
+ toolLiteralLength: tool.replaceAll("*", "").replaceAll("?", "").length,
25627
+ toolWildcardCount: [...tool].filter((character) => "*?".includes(character)).length,
25628
+ literalLength: argument.replaceAll("*", "").replaceAll("?", "").replaceAll("[", "").replaceAll("]", "").length,
25629
+ wildcardCount: [...argument].filter((character) => "*?[]".includes(character)).length,
25630
+ hasArguments
25631
+ };
25632
+ }
25633
+ function sortKimiCodeRulesFailClosed(rules) {
25634
+ const actionPriority = {
25635
+ deny: 0,
25636
+ ask: 1,
25637
+ allow: 2
25638
+ };
25639
+ return rules.map((rule, index) => ({
25640
+ rule,
25641
+ index,
25642
+ specificity: getKimiCodePatternSpecificity(rule.pattern)
25643
+ })).toSorted((left, right) => {
25644
+ const actionOrder = actionPriority[left.rule.decision] - actionPriority[right.rule.decision];
25645
+ if (actionOrder !== 0) return actionOrder;
25646
+ if (left.specificity.tool.startsWith("mcp__") && right.specificity.tool.startsWith("mcp__")) {
25647
+ const toolLiteralOrder = right.specificity.toolLiteralLength - left.specificity.toolLiteralLength;
25648
+ if (toolLiteralOrder !== 0) return toolLiteralOrder;
25649
+ const toolWildcardOrder = left.specificity.toolWildcardCount - right.specificity.toolWildcardCount;
25650
+ if (toolWildcardOrder !== 0) return toolWildcardOrder;
25651
+ }
25652
+ const toolOrder = left.specificity.tool.localeCompare(right.specificity.tool);
25653
+ if (toolOrder !== 0) return toolOrder;
25654
+ if (left.specificity.hasArguments !== right.specificity.hasArguments) return left.specificity.hasArguments ? -1 : 1;
25655
+ const literalOrder = right.specificity.literalLength - left.specificity.literalLength;
25656
+ if (literalOrder !== 0) return literalOrder;
25657
+ const wildcardOrder = left.specificity.wildcardCount - right.specificity.wildcardCount;
25658
+ if (wildcardOrder !== 0) return wildcardOrder;
25659
+ return left.index - right.index;
25660
+ }).map(({ rule }) => rule);
25661
+ }
25662
+ function preserveKimiCodeRules(rules) {
25663
+ const permission = {};
25664
+ const nativeRules = [];
25665
+ if (!Array.isArray(rules)) return {
25666
+ permission,
25667
+ nativeRules
25668
+ };
25669
+ for (const raw of rules) {
25670
+ if (!isRecord(raw)) continue;
25671
+ const decision = raw.decision;
25672
+ const pattern = raw.pattern;
25673
+ if (decision !== "allow" && decision !== "ask" && decision !== "deny" || typeof pattern !== "string") continue;
25674
+ nativeRules.push({
25675
+ decision,
25676
+ pattern,
25677
+ ...typeof raw.scope === "string" && { scope: raw.scope },
25678
+ ...typeof raw.reason === "string" && { reason: raw.reason }
25679
+ });
25680
+ }
25681
+ return {
25682
+ permission,
25683
+ nativeRules
25684
+ };
25685
+ }
25686
+ /**
25687
+ * Kimi Code permission rules in the shared user `config.toml`.
25688
+ *
25689
+ * @see https://moonshotai.github.io/kimi-code/en/configuration/config-files.html
25690
+ */
25691
+ var KimiCodePermissions = class KimiCodePermissions extends ToolPermissions {
25692
+ constructor(params) {
25693
+ super({
25694
+ ...params,
25695
+ ...KimiCodePermissions.getSettablePaths({ global: params.global ?? true })
25696
+ });
25697
+ }
25698
+ static getSettablePaths({ global = true } = {}) {
25699
+ return {
25700
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
25701
+ relativeFilePath: KIMI_CODE_CONFIG_FILE_NAME
25702
+ };
25703
+ }
25704
+ validate() {
25705
+ return {
25706
+ success: true,
25707
+ error: null
25708
+ };
25709
+ }
25710
+ isDeletable() {
25711
+ return false;
25712
+ }
25713
+ shouldMergeExistingFileContent() {
25714
+ return true;
25715
+ }
25716
+ setFileContent(fileContent) {
25717
+ const paths = KimiCodePermissions.getSettablePaths({ global: this.global });
25718
+ this.fileContent = applySharedConfigPatch({
25719
+ fileKey: KIMI_CODE_CONFIG_SHARED_FILE_KEY,
25720
+ feature: "permissions",
25721
+ existingContent: fileContent,
25722
+ patch: parseSharedConfig({
25723
+ format: "toml",
25724
+ fileContent: this.fileContent
25725
+ }),
25726
+ filePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
25727
+ });
25728
+ }
25729
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = true }) {
25730
+ const paths = this.getSettablePaths({ global });
25731
+ return new KimiCodePermissions({
25732
+ outputRoot,
25733
+ fileContent: await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)),
25734
+ validate,
25735
+ global
25736
+ });
25737
+ }
25738
+ static fromRulesyncPermissions({ outputRoot, rulesyncPermissions, logger }) {
25739
+ const config = rulesyncPermissions.getJson();
25740
+ const defaultPermissionMode = config["kimi-code"]?.defaultPermissionMode;
25741
+ return new KimiCodePermissions({
25742
+ outputRoot,
25743
+ fileContent: stringifySharedConfig({
25744
+ format: "toml",
25745
+ document: {
25746
+ ...defaultPermissionMode && { default_permission_mode: defaultPermissionMode },
25747
+ permission: { rules: canonicalToKimiCodeRules({
25748
+ config,
25749
+ logger
25750
+ }) }
25751
+ }
25752
+ }),
25753
+ global: true
25754
+ });
25755
+ }
25756
+ toRulesyncPermissions() {
25757
+ const config = parseSharedConfig({
25758
+ format: "toml",
25759
+ fileContent: this.getFileContent()
25760
+ });
25761
+ const { permission, nativeRules } = preserveKimiCodeRules((isRecord(config.permission) ? config.permission : {}).rules);
25762
+ const defaultPermissionMode = config.default_permission_mode;
25763
+ const toolOverride = {
25764
+ ...defaultPermissionMode === "manual" || defaultPermissionMode === "yolo" || defaultPermissionMode === "auto" ? { defaultPermissionMode } : {},
25765
+ ...nativeRules.length > 0 && { rules: nativeRules }
25766
+ };
25767
+ return new RulesyncPermissions({
25768
+ outputRoot: getKimiCodeRulesyncOutputRoot({
25769
+ nativeOutputRoot: this.outputRoot,
25770
+ global: this.global
25771
+ }),
25772
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
25773
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
25774
+ fileContent: JSON.stringify({
25775
+ permission,
25776
+ ...Object.keys(toolOverride).length > 0 && { "kimi-code": toolOverride }
25777
+ }, null, 2)
25778
+ });
25779
+ }
25780
+ static forDeletion({ outputRoot = process.cwd() }) {
25781
+ return new KimiCodePermissions({
25782
+ outputRoot,
25783
+ fileContent: "",
25784
+ validate: false,
25785
+ global: true
25786
+ });
25787
+ }
25788
+ };
25789
+ //#endregion
24925
25790
  //#region src/features/permissions/kiro-permissions.ts
24926
25791
  const KiroAgentSchema = zod_mini.z.looseObject({
24927
25792
  allowedTools: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
@@ -27137,6 +28002,14 @@ const toolPermissionsFactories = /* @__PURE__ */ new Map([
27137
28002
  supportsImport: true
27138
28003
  }
27139
28004
  }],
28005
+ ["kimi-code", {
28006
+ class: KimiCodePermissions,
28007
+ meta: {
28008
+ supportsProject: false,
28009
+ supportsGlobal: true,
28010
+ supportsImport: true
28011
+ }
28012
+ }],
27140
28013
  ["junie", {
27141
28014
  class: JuniePermissions,
27142
28015
  meta: {
@@ -28230,6 +29103,17 @@ var AntigravityIdeSkill = class extends AntigravitySharedSkill {
28230
29103
  }
28231
29104
  };
28232
29105
  //#endregion
29106
+ //#region src/features/skills/antigravity-plugin-skill.ts
29107
+ var AntigravityPluginSkill = class extends AntigravityIdeSkill {
29108
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
29109
+ const targets = rulesyncSkill.getFrontmatter().targets;
29110
+ return targets.includes("*") || targets.includes("antigravity-plugin");
29111
+ }
29112
+ static getSettablePaths() {
29113
+ return { relativeDirPath: ANTIGRAVITY_PLUGIN_SKILLS_DIR };
29114
+ }
29115
+ };
29116
+ //#endregion
28233
29117
  //#region src/features/skills/augmentcode-skill.ts
28234
29118
  const AugmentcodeSkillFrontmatterSchema = zod_mini.z.looseObject({
28235
29119
  name: zod_mini.z.string(),
@@ -28424,7 +29308,7 @@ function buildClaudecodeSkillFrontmatter({ rulesyncFrontmatter, resolvedDisableM
28424
29308
  * Unlike subagents and commands, skills are directories containing SKILL.md and other files.
28425
29309
  * Extends ToolSkill to inherit directory management and security features from AiDir.
28426
29310
  */
28427
- var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
29311
+ var ClaudecodeSkill = class extends ToolSkill {
28428
29312
  constructor({ outputRoot = process.cwd(), relativeDirPath = CLAUDECODE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
28429
29313
  super({
28430
29314
  outputRoot,
@@ -28519,9 +29403,9 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28519
29403
  section: rulesyncFrontmatter.claudecode
28520
29404
  })
28521
29405
  });
28522
- const settablePaths = ClaudecodeSkill.getSettablePaths({ global });
29406
+ const settablePaths = this.getSettablePaths({ global });
28523
29407
  const relativeDirPath = rulesyncFrontmatter.claudecode?.["scheduled-task"] ? CLAUDECODE_SCHEDULED_TASKS_DIR_PATH : settablePaths.relativeDirPath;
28524
- return new ClaudecodeSkill({
29408
+ return new this({
28525
29409
  outputRoot,
28526
29410
  relativeDirPath,
28527
29411
  dirName: rulesyncSkill.getDirName(),
@@ -28541,14 +29425,14 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28541
29425
  static async fromDir(params) {
28542
29426
  const loaded = await this.loadSkillDirContent({
28543
29427
  ...params,
28544
- getSettablePaths: ClaudecodeSkill.getSettablePaths
29428
+ getSettablePaths: (options) => this.getSettablePaths(options)
28545
29429
  });
28546
29430
  const result = ClaudecodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28547
29431
  if (!result.success) {
28548
29432
  const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28549
29433
  throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28550
29434
  }
28551
- return new ClaudecodeSkill({
29435
+ return new this({
28552
29436
  outputRoot: loaded.outputRoot,
28553
29437
  relativeDirPath: loaded.relativeDirPath,
28554
29438
  dirName: loaded.dirName,
@@ -28560,7 +29444,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28560
29444
  });
28561
29445
  }
28562
29446
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
28563
- return new ClaudecodeSkill({
29447
+ return new this({
28564
29448
  outputRoot,
28565
29449
  relativeDirPath,
28566
29450
  dirName,
@@ -28576,6 +29460,17 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28576
29460
  }
28577
29461
  };
28578
29462
  //#endregion
29463
+ //#region src/features/skills/claudecode-plugin-skill.ts
29464
+ var ClaudecodePluginSkill = class extends ClaudecodeSkill {
29465
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
29466
+ const targets = rulesyncSkill.getFrontmatter().targets;
29467
+ return targets.includes("*") || targets.includes("claudecode-plugin");
29468
+ }
29469
+ static getSettablePaths() {
29470
+ return { relativeDirPath: CLAUDECODE_PLUGIN_SKILLS_DIR };
29471
+ }
29472
+ };
29473
+ //#endregion
28579
29474
  //#region src/features/skills/cline-skill.ts
28580
29475
  const ClineSkillFrontmatterSchema = zod_mini.z.looseObject({
28581
29476
  name: zod_mini.z.string(),
@@ -30365,6 +31260,197 @@ var KiloSkill = class KiloSkill extends ToolSkill {
30365
31260
  }
30366
31261
  };
30367
31262
  //#endregion
31263
+ //#region src/features/skills/kimi-code-skill.ts
31264
+ const KimiCodeSkillFrontmatterSchema = zod_mini.z.looseObject({
31265
+ name: zod_mini.z.string(),
31266
+ description: zod_mini.z.string(),
31267
+ type: zod_mini.z.optional(zod_mini.z.enum([
31268
+ "prompt",
31269
+ "inline",
31270
+ "flow"
31271
+ ])),
31272
+ whenToUse: zod_mini.z.optional(zod_mini.z.string()),
31273
+ disableModelInvocation: zod_mini.z.optional(zod_mini.z.boolean()),
31274
+ arguments: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
31275
+ });
31276
+ const KimiCodeFlatSkillFrontmatterSchema = zod_mini.z.looseObject({
31277
+ name: zod_mini.z.optional(zod_mini.z.string()),
31278
+ description: zod_mini.z.optional(zod_mini.z.string()),
31279
+ type: zod_mini.z.optional(zod_mini.z.enum([
31280
+ "prompt",
31281
+ "inline",
31282
+ "flow"
31283
+ ])),
31284
+ whenToUse: zod_mini.z.optional(zod_mini.z.string()),
31285
+ disableModelInvocation: zod_mini.z.optional(zod_mini.z.boolean()),
31286
+ arguments: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
31287
+ });
31288
+ function logicalSkillDirName(name) {
31289
+ const normalized = name.toLowerCase();
31290
+ return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalized) ? normalized : `kimi-${encodeURIComponent(normalized)}`;
31291
+ }
31292
+ /**
31293
+ * Kimi Code Agent Skill.
31294
+ *
31295
+ * @see https://moonshotai.github.io/kimi-code/en/customization/skills.html
31296
+ */
31297
+ var KimiCodeSkill = class KimiCodeSkill extends ToolSkill {
31298
+ constructor({ outputRoot = process.cwd(), relativeDirPath = KIMI_CODE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
31299
+ super({
31300
+ outputRoot,
31301
+ relativeDirPath,
31302
+ dirName,
31303
+ mainFile: {
31304
+ name: SKILL_FILE_NAME,
31305
+ body,
31306
+ frontmatter: { ...frontmatter }
31307
+ },
31308
+ otherFiles,
31309
+ global
31310
+ });
31311
+ if (validate) {
31312
+ const result = this.validate();
31313
+ if (!result.success) throw result.error;
31314
+ }
31315
+ }
31316
+ static getSettablePaths({ global = false } = {}) {
31317
+ const customHome = global ? getKimiCodeHome() : void 0;
31318
+ return {
31319
+ relativeDirPath: getKimiCodeRelativeDirPath({
31320
+ global,
31321
+ relativeDirPath: KIMI_CODE_SKILLS_DIR_NAME
31322
+ }),
31323
+ importOnlySkillRoots: [customHome ? {
31324
+ outputRoot: getHomeDirectory(),
31325
+ relativeDirPath: KIMI_CODE_SHARED_SKILLS_DIR_PATH
31326
+ } : KIMI_CODE_SHARED_SKILLS_DIR_PATH]
31327
+ };
31328
+ }
31329
+ getFrontmatter() {
31330
+ return KimiCodeSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
31331
+ }
31332
+ getBody() {
31333
+ return this.mainFile?.body ?? "";
31334
+ }
31335
+ getImportIdentity() {
31336
+ return this.getFrontmatter().name.toLowerCase();
31337
+ }
31338
+ validate() {
31339
+ if (!this.mainFile) return {
31340
+ success: false,
31341
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
31342
+ };
31343
+ const result = KimiCodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
31344
+ return result.success ? {
31345
+ success: true,
31346
+ error: null
31347
+ } : {
31348
+ success: false,
31349
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
31350
+ };
31351
+ }
31352
+ toRulesyncSkill() {
31353
+ const { name, description, disableModelInvocation, ...kimiCodeFrontmatter } = this.getFrontmatter();
31354
+ const toolSection = {
31355
+ ...kimiCodeFrontmatter,
31356
+ ...disableModelInvocation !== void 0 && { disableModelInvocation }
31357
+ };
31358
+ const frontmatter = {
31359
+ name,
31360
+ description,
31361
+ targets: ["*"],
31362
+ ...disableModelInvocation !== void 0 && { "disable-model-invocation": disableModelInvocation },
31363
+ ...Object.keys(toolSection).length > 0 && { "kimi-code": toolSection }
31364
+ };
31365
+ return new RulesyncSkill({
31366
+ outputRoot: getKimiCodeRulesyncOutputRoot({
31367
+ nativeOutputRoot: this.outputRoot,
31368
+ global: this.global
31369
+ }),
31370
+ relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
31371
+ dirName: logicalSkillDirName(name),
31372
+ frontmatter,
31373
+ body: this.getBody(),
31374
+ otherFiles: this.getOtherFiles(),
31375
+ validate: true,
31376
+ global: this.global
31377
+ });
31378
+ }
31379
+ static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
31380
+ const frontmatter = rulesyncSkill.getFrontmatter();
31381
+ const kimiCodeSection = frontmatter["kimi-code"] ?? {};
31382
+ const kimiCodeFrontmatter = {
31383
+ name: frontmatter.name,
31384
+ description: frontmatter.description,
31385
+ ...frontmatter["disable-model-invocation"] !== void 0 && { disableModelInvocation: frontmatter["disable-model-invocation"] },
31386
+ ...kimiCodeSection
31387
+ };
31388
+ return new KimiCodeSkill({
31389
+ outputRoot,
31390
+ relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31391
+ dirName: rulesyncSkill.getDirName(),
31392
+ frontmatter: kimiCodeFrontmatter,
31393
+ body: rulesyncSkill.getBody(),
31394
+ otherFiles: rulesyncSkill.getOtherFiles(),
31395
+ validate,
31396
+ global
31397
+ });
31398
+ }
31399
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
31400
+ const targets = rulesyncSkill.getFrontmatter().targets;
31401
+ return targets.includes("*") || targets.includes("kimi-code");
31402
+ }
31403
+ static async fromDir(params) {
31404
+ const loaded = await this.loadSkillDirContent({
31405
+ ...params,
31406
+ getSettablePaths: KimiCodeSkill.getSettablePaths
31407
+ });
31408
+ const result = KimiCodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
31409
+ if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
31410
+ return new KimiCodeSkill({
31411
+ ...loaded,
31412
+ frontmatter: result.data,
31413
+ validate: true
31414
+ });
31415
+ }
31416
+ static async fromFlatFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
31417
+ const filePath = (0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath);
31418
+ const { frontmatter, body } = parseFrontmatter(await readFileContent(filePath), filePath);
31419
+ const result = KimiCodeFlatSkillFrontmatterSchema.safeParse(frontmatter);
31420
+ if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
31421
+ const fileName = (0, node_path.basename)(relativeFilePath, (0, node_path.extname)(relativeFilePath));
31422
+ const firstBodyLine = body.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "");
31423
+ const normalizedFrontmatter = {
31424
+ ...result.data,
31425
+ name: result.data.name ?? fileName,
31426
+ description: result.data.description ?? firstBodyLine?.slice(0, 240) ?? "No description provided."
31427
+ };
31428
+ return new KimiCodeSkill({
31429
+ outputRoot,
31430
+ relativeDirPath,
31431
+ dirName: fileName,
31432
+ frontmatter: normalizedFrontmatter,
31433
+ body: body.trim(),
31434
+ validate: true,
31435
+ global
31436
+ });
31437
+ }
31438
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
31439
+ return new KimiCodeSkill({
31440
+ outputRoot,
31441
+ relativeDirPath: relativeDirPath ?? this.getSettablePaths({ global }).relativeDirPath,
31442
+ dirName,
31443
+ frontmatter: {
31444
+ name: "",
31445
+ description: ""
31446
+ },
31447
+ body: "",
31448
+ validate: false,
31449
+ global
31450
+ });
31451
+ }
31452
+ };
31453
+ //#endregion
30368
31454
  //#region src/features/skills/kiro-skill.ts
30369
31455
  const KiroSkillFrontmatterSchema = zod_mini.z.looseObject({
30370
31456
  name: zod_mini.z.string(),
@@ -32091,6 +33177,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32091
33177
  supportsGlobal: true
32092
33178
  }
32093
33179
  }],
33180
+ ["antigravity-plugin", {
33181
+ class: AntigravityPluginSkill,
33182
+ meta: {
33183
+ supportsProject: true,
33184
+ supportsSimulated: false,
33185
+ supportsGlobal: false
33186
+ }
33187
+ }],
32094
33188
  ["augmentcode", {
32095
33189
  class: AugmentcodeSkill,
32096
33190
  meta: {
@@ -32107,6 +33201,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32107
33201
  supportsGlobal: true
32108
33202
  }
32109
33203
  }],
33204
+ ["claudecode-plugin", {
33205
+ class: ClaudecodePluginSkill,
33206
+ meta: {
33207
+ supportsProject: true,
33208
+ supportsSimulated: false,
33209
+ supportsGlobal: false
33210
+ }
33211
+ }],
32110
33212
  ["claudecode-legacy", {
32111
33213
  class: ClaudecodeSkill,
32112
33214
  meta: {
@@ -32211,6 +33313,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32211
33313
  supportsGlobal: true
32212
33314
  }
32213
33315
  }],
33316
+ ["kimi-code", {
33317
+ class: KimiCodeSkill,
33318
+ meta: {
33319
+ supportsProject: true,
33320
+ supportsSimulated: false,
33321
+ supportsGlobal: true
33322
+ }
33323
+ }],
32214
33324
  ["kiro", {
32215
33325
  class: KiroSkill,
32216
33326
  meta: {
@@ -32432,36 +33542,56 @@ var SkillsProcessor = class extends DirFeatureProcessor {
32432
33542
  */
32433
33543
  async loadToolDirs() {
32434
33544
  const factory = this.getFactory(this.toolTarget);
32435
- const roots = toolSkillSearchRoots(factory.class.getSettablePaths({ global: this.global }));
32436
- const seenDirNames = /* @__PURE__ */ new Set();
32437
- const loadEntries = [];
33545
+ const roots = toolSkillImportRoots(factory.class.getSettablePaths({ global: this.global }));
33546
+ const seenSkillNames = /* @__PURE__ */ new Set();
33547
+ const toolSkills = [];
32438
33548
  for (const root of roots) {
32439
- const skillsDirPath = (0, node_path.join)(this.outputRoot, root);
33549
+ const rootOutputRoot = typeof root === "string" ? this.outputRoot : root.outputRoot;
33550
+ const relativeDirPath = typeof root === "string" ? root : root.relativeDirPath;
33551
+ const skillsDirPath = (0, node_path.join)(rootOutputRoot, relativeDirPath);
32440
33552
  if (!await directoryExists(skillsDirPath)) continue;
32441
33553
  const dirPaths = await findFilesByGlobs((0, node_path.join)(skillsDirPath, "*"), { type: "dir" });
33554
+ const ownedDirNames = [];
32442
33555
  for (const dirPath of dirPaths) {
32443
33556
  const dirName = (0, node_path.basename)(dirPath);
32444
- if (seenDirNames.has(dirName)) continue;
32445
33557
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
32446
- outputRoot: this.outputRoot,
32447
- relativeDirPath: root,
33558
+ outputRoot: rootOutputRoot,
33559
+ relativeDirPath,
32448
33560
  dirName,
32449
33561
  inputRoot: this.inputRoot
32450
33562
  })) continue;
32451
- seenDirNames.add(dirName);
32452
- loadEntries.push({
32453
- root,
32454
- dirName
32455
- });
33563
+ ownedDirNames.push(dirName);
33564
+ }
33565
+ const directorySkills = await Promise.all(ownedDirNames.map((dirName) => factory.class.fromDir({
33566
+ outputRoot: rootOutputRoot,
33567
+ relativeDirPath,
33568
+ dirName,
33569
+ global: this.global
33570
+ })));
33571
+ for (const skill of directorySkills) {
33572
+ const skillName = skill.getImportIdentity();
33573
+ if (seenSkillNames.has(skillName)) continue;
33574
+ seenSkillNames.add(skillName);
33575
+ toolSkills.push(skill);
33576
+ }
33577
+ if (!factory.class.fromFlatFile) continue;
33578
+ const fromFlatFile = factory.class.fromFlatFile;
33579
+ const directoryStems = new Set(ownedDirNames);
33580
+ const flatFilePaths = (await findFilesByGlobs((0, node_path.join)(skillsDirPath, "*.md"), { type: "file" })).filter((filePath) => !directoryStems.has((0, node_path.basename)(filePath, ".md")));
33581
+ const flatSkills = await Promise.all(flatFilePaths.map((filePath) => fromFlatFile({
33582
+ outputRoot: rootOutputRoot,
33583
+ relativeDirPath,
33584
+ relativeFilePath: (0, node_path.basename)(filePath),
33585
+ global: this.global
33586
+ })));
33587
+ for (const skill of flatSkills) {
33588
+ const skillName = skill.getImportIdentity();
33589
+ if (seenSkillNames.has(skillName)) continue;
33590
+ seenSkillNames.add(skillName);
33591
+ toolSkills.push(skill);
32456
33592
  }
32457
33593
  }
32458
- const toolSkills = await Promise.all(loadEntries.map(({ root, dirName }) => factory.class.fromDir({
32459
- outputRoot: this.outputRoot,
32460
- relativeDirPath: root,
32461
- dirName,
32462
- global: this.global
32463
- })));
32464
- this.logger.debug(`Successfully loaded ${toolSkills.length} skills from ${roots.length} root(s): ${roots.join(", ")}`);
33594
+ this.logger.debug(`Successfully loaded ${toolSkills.length} skills from ${roots.length} root(s)`);
32465
33595
  return toolSkills;
32466
33596
  }
32467
33597
  async loadToolDirsToDelete() {
@@ -32471,8 +33601,19 @@ var SkillsProcessor = class extends DirFeatureProcessor {
32471
33601
  for (const root of roots) {
32472
33602
  const skillsDirPath = (0, node_path.join)(this.outputRoot, root);
32473
33603
  if (!await directoryExists(skillsDirPath)) continue;
32474
- const dirPaths = await findFilesByGlobs((0, node_path.join)(skillsDirPath, "*"), { type: "dir" });
33604
+ await assertWritablePathInsideRoot({
33605
+ rootPath: this.outputRoot,
33606
+ targetPath: skillsDirPath
33607
+ });
33608
+ const dirPaths = await findFilesByGlobs((0, node_path.join)(skillsDirPath, "*"), {
33609
+ type: "dir",
33610
+ followSymbolicLinks: false
33611
+ });
32475
33612
  for (const dirPath of dirPaths) {
33613
+ await assertWritablePathInsideRoot({
33614
+ rootPath: skillsDirPath,
33615
+ targetPath: dirPath
33616
+ });
32476
33617
  const dirName = (0, node_path.basename)(dirPath);
32477
33618
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
32478
33619
  outputRoot: this.outputRoot,
@@ -32562,6 +33703,10 @@ var ToolSubagent = class extends ToolFile {
32562
33703
  static fromRulesyncSubagent(_params) {
32563
33704
  throw new Error("Please implement this method in the subclass.");
32564
33705
  }
33706
+ /** Identity used to resolve duplicate imports across discovery roots. */
33707
+ getImportIdentity() {
33708
+ return this.getRelativeFilePath();
33709
+ }
32565
33710
  static isTargetedByRulesyncSubagent(_rulesyncSubagent) {
32566
33711
  throw new Error("Please implement this method in the subclass.");
32567
33712
  }
@@ -33223,6 +34368,17 @@ var ClaudecodeSubagent = class ClaudecodeSubagent extends ToolSubagent {
33223
34368
  }
33224
34369
  };
33225
34370
  //#endregion
34371
+ //#region src/features/subagents/claudecode-plugin-subagent.ts
34372
+ var ClaudecodePluginSubagent = class extends ClaudecodeSubagent {
34373
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
34374
+ const targets = rulesyncSubagent.getFrontmatter().targets;
34375
+ return targets.includes("*") || targets.includes("claudecode-plugin");
34376
+ }
34377
+ static getSettablePaths() {
34378
+ return { relativeDirPath: CLAUDECODE_PLUGIN_AGENTS_DIR };
34379
+ }
34380
+ };
34381
+ //#endregion
33226
34382
  //#region src/features/subagents/cline-subagent.ts
33227
34383
  const ClineSubagentFrontmatterSchema = zod_mini.z.looseObject({
33228
34384
  name: zod_mini.z.string(),
@@ -35210,9 +36366,153 @@ var KiloSubagent = class KiloSubagent extends OpenCodeStyleSubagent {
35210
36366
  }
35211
36367
  };
35212
36368
  //#endregion
36369
+ //#region src/features/subagents/kimi-code-subagent.ts
36370
+ const KimiCodeAgentNameSchema = zod_mini.z.pipe(zod_mini.z.string(), zod_mini.z.custom((value) => typeof value === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value), "must be a kebab-case name"));
36371
+ const KimiCodeSubagentFrontmatterSchema = zod_mini.z.looseObject({
36372
+ name: zod_mini.z.optional(KimiCodeAgentNameSchema),
36373
+ description: zod_mini.z.string(),
36374
+ whenToUse: zod_mini.z.optional(zod_mini.z.string()),
36375
+ override: zod_mini.z.optional(zod_mini.z.boolean()),
36376
+ tools: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())])),
36377
+ disallowedTools: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())])),
36378
+ subagents: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
36379
+ });
36380
+ /**
36381
+ * Kimi Code custom agent.
36382
+ *
36383
+ * @see https://moonshotai.github.io/kimi-code/en/customization/agents.html
36384
+ */
36385
+ var KimiCodeSubagent = class KimiCodeSubagent extends ToolSubagent {
36386
+ frontmatter;
36387
+ body;
36388
+ constructor({ frontmatter, body, fileContent, ...rest }) {
36389
+ if (rest.validate !== false) {
36390
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(frontmatter);
36391
+ if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
36392
+ }
36393
+ super({
36394
+ ...rest,
36395
+ fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
36396
+ });
36397
+ this.frontmatter = frontmatter;
36398
+ this.body = body;
36399
+ }
36400
+ static getSettablePaths({ global = false } = {}) {
36401
+ const customHome = global ? getKimiCodeHome() : void 0;
36402
+ return {
36403
+ relativeDirPath: getKimiCodeRelativeDirPath({
36404
+ global,
36405
+ relativeDirPath: KIMI_CODE_AGENTS_DIR_NAME
36406
+ }),
36407
+ importDirPaths: [customHome ? {
36408
+ outputRoot: getHomeDirectory(),
36409
+ relativeDirPath: KIMI_CODE_SHARED_AGENTS_DIR_PATH
36410
+ } : KIMI_CODE_SHARED_AGENTS_DIR_PATH]
36411
+ };
36412
+ }
36413
+ getFrontmatter() {
36414
+ return this.frontmatter;
36415
+ }
36416
+ getBody() {
36417
+ return this.body;
36418
+ }
36419
+ getImportIdentity() {
36420
+ const fileName = (0, node_path.basename)(this.getRelativeFilePath(), (0, node_path.extname)(this.getRelativeFilePath()));
36421
+ return KimiCodeAgentNameSchema.parse(this.frontmatter.name ?? fileName).toLowerCase();
36422
+ }
36423
+ toRulesyncSubagent() {
36424
+ const { name: _name, description, ...rest } = this.frontmatter;
36425
+ const resolvedName = this.getImportIdentity();
36426
+ const frontmatter = {
36427
+ targets: ["*"],
36428
+ name: resolvedName,
36429
+ description,
36430
+ ...Object.keys(rest).length > 0 && { "kimi-code": rest }
36431
+ };
36432
+ return new RulesyncSubagent({
36433
+ outputRoot: getKimiCodeRulesyncOutputRoot({
36434
+ nativeOutputRoot: this.outputRoot,
36435
+ global: this.global
36436
+ }),
36437
+ relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
36438
+ relativeFilePath: `${resolvedName}.md`,
36439
+ frontmatter,
36440
+ body: this.body,
36441
+ validate: true,
36442
+ global: this.global
36443
+ });
36444
+ }
36445
+ static fromRulesyncSubagent({ outputRoot = process.cwd(), rulesyncSubagent, validate = true, global = false }) {
36446
+ const frontmatter = rulesyncSubagent.getFrontmatter();
36447
+ const toolSection = frontmatter["kimi-code"] ?? {};
36448
+ const kimiCodeFrontmatter = KimiCodeSubagentFrontmatterSchema.parse({
36449
+ name: frontmatter.name,
36450
+ description: frontmatter.description,
36451
+ ...toolSection
36452
+ });
36453
+ const body = rulesyncSubagent.getBody();
36454
+ return new KimiCodeSubagent({
36455
+ outputRoot,
36456
+ relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
36457
+ relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
36458
+ frontmatter: kimiCodeFrontmatter,
36459
+ body,
36460
+ fileContent: stringifyFrontmatter(body, kimiCodeFrontmatter, { avoidBlockScalars: true }),
36461
+ validate,
36462
+ global
36463
+ });
36464
+ }
36465
+ validate() {
36466
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
36467
+ return result.success ? {
36468
+ success: true,
36469
+ error: null
36470
+ } : {
36471
+ success: false,
36472
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
36473
+ };
36474
+ }
36475
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
36476
+ return this.isTargetedByRulesyncSubagentDefault({
36477
+ rulesyncSubagent,
36478
+ toolTarget: "kimi-code"
36479
+ });
36480
+ }
36481
+ static async fromFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, validate = true, global = false }) {
36482
+ const actualRelativeDirPath = relativeDirPath ?? this.getSettablePaths({ global }).relativeDirPath;
36483
+ const filePath = (0, node_path.join)(outputRoot, actualRelativeDirPath, relativeFilePath);
36484
+ const fileContent = await readFileContent(filePath);
36485
+ const { frontmatter, body } = parseFrontmatter(fileContent, filePath);
36486
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(frontmatter);
36487
+ if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
36488
+ return new KimiCodeSubagent({
36489
+ outputRoot,
36490
+ relativeDirPath: actualRelativeDirPath,
36491
+ relativeFilePath,
36492
+ frontmatter: result.data,
36493
+ body: body.trim(),
36494
+ fileContent,
36495
+ validate,
36496
+ global
36497
+ });
36498
+ }
36499
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
36500
+ return new KimiCodeSubagent({
36501
+ outputRoot,
36502
+ relativeDirPath,
36503
+ relativeFilePath,
36504
+ frontmatter: { description: "" },
36505
+ body: "",
36506
+ fileContent: "",
36507
+ validate: false,
36508
+ global
36509
+ });
36510
+ }
36511
+ };
36512
+ //#endregion
35213
36513
  //#region src/features/subagents/kiro-subagent.ts
35214
36514
  const KiroCliSubagentJsonSchema = zod_mini.z.looseObject({
35215
- name: zod_mini.z.string(),
36515
+ name: zod_mini.z.optional(zod_mini.z.string()),
35216
36516
  description: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.string())),
35217
36517
  prompt: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.string())),
35218
36518
  tools: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.array(zod_mini.z.string()))),
@@ -35227,7 +36527,7 @@ const KiroCliSubagentJsonSchema = zod_mini.z.looseObject({
35227
36527
  allowedTools: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.array(zod_mini.z.string()))),
35228
36528
  includeMcpJson: zod_mini.z.optional(zod_mini.z.nullable(zod_mini.z.boolean()))
35229
36529
  });
35230
- var KiroSubagent = class KiroSubagent extends ToolSubagent {
36530
+ var KiroSubagent = class extends ToolSubagent {
35231
36531
  body;
35232
36532
  constructor({ body, ...rest }) {
35233
36533
  if (rest.validate !== false) try {
@@ -35245,6 +36545,9 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35245
36545
  getBody() {
35246
36546
  return this.body;
35247
36547
  }
36548
+ static getToolTarget() {
36549
+ return "kiro";
36550
+ }
35248
36551
  toRulesyncSubagent() {
35249
36552
  let parsed;
35250
36553
  try {
@@ -35253,12 +36556,13 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35253
36556
  throw new Error(`Failed to parse JSON in ${(0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
35254
36557
  }
35255
36558
  const { name, description, prompt, ...restFields } = parsed;
36559
+ const toolTarget = this.constructor.getToolTarget();
35256
36560
  const kiroSection = { ...restFields };
35257
36561
  return new RulesyncSubagent({
35258
36562
  outputRoot: ".",
35259
36563
  frontmatter: {
35260
- targets: ["kiro"],
35261
- name,
36564
+ targets: [toolTarget],
36565
+ name: name ?? (0, node_path.basename)(this.getRelativeFilePath(), ".json"),
35262
36566
  description: description ?? void 0,
35263
36567
  ...Object.keys(kiroSection).length > 0 && { kiro: kiroSection }
35264
36568
  },
@@ -35285,7 +36589,7 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35285
36589
  const body = JSON.stringify(json, null, 2);
35286
36590
  const paths = this.getSettablePaths({ global });
35287
36591
  const relativeFilePath = rulesyncSubagent.getRelativeFilePath().replace(/\.md$/, ".json");
35288
- return new KiroSubagent({
36592
+ return new this({
35289
36593
  outputRoot,
35290
36594
  body,
35291
36595
  relativeDirPath: paths.relativeDirPath,
@@ -35313,14 +36617,14 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35313
36617
  static isTargetedByRulesyncSubagent(rulesyncSubagent) {
35314
36618
  return this.isTargetedByRulesyncSubagentDefault({
35315
36619
  rulesyncSubagent,
35316
- toolTarget: "kiro"
36620
+ toolTarget: this.getToolTarget()
35317
36621
  });
35318
36622
  }
35319
36623
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
35320
36624
  const paths = this.getSettablePaths({ global });
35321
36625
  const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath);
35322
36626
  const fileContent = await readFileContent(filePath);
35323
- const subagent = new KiroSubagent({
36627
+ const subagent = new this({
35324
36628
  outputRoot,
35325
36629
  relativeDirPath: paths.relativeDirPath,
35326
36630
  relativeFilePath,
@@ -35336,7 +36640,7 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35336
36640
  return subagent;
35337
36641
  }
35338
36642
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
35339
- return new KiroSubagent({
36643
+ return new this({
35340
36644
  outputRoot,
35341
36645
  relativeDirPath,
35342
36646
  relativeFilePath,
@@ -35358,11 +36662,8 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35358
36662
  * {@link import("./kiro-ide-subagent.js").KiroIdeSubagent}.)
35359
36663
  */
35360
36664
  var KiroCliSubagent = class extends KiroSubagent {
35361
- static isTargetedByRulesyncSubagent(rulesyncSubagent) {
35362
- return this.isTargetedByRulesyncSubagentDefault({
35363
- rulesyncSubagent,
35364
- toolTarget: "kiro-cli"
35365
- });
36665
+ static getToolTarget() {
36666
+ return "kiro-cli";
35366
36667
  }
35367
36668
  };
35368
36669
  //#endregion
@@ -36349,6 +37650,14 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
36349
37650
  filePattern: "*.md"
36350
37651
  }
36351
37652
  }],
37653
+ ["claudecode-plugin", {
37654
+ class: ClaudecodePluginSubagent,
37655
+ meta: {
37656
+ supportsSimulated: false,
37657
+ supportsGlobal: false,
37658
+ filePattern: "*.md"
37659
+ }
37660
+ }],
36352
37661
  ["claudecode-legacy", {
36353
37662
  class: ClaudecodeSubagent,
36354
37663
  meta: {
@@ -36485,6 +37794,14 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
36485
37794
  filePattern: "*.md"
36486
37795
  }
36487
37796
  }],
37797
+ ["kimi-code", {
37798
+ class: KimiCodeSubagent,
37799
+ meta: {
37800
+ supportsSimulated: false,
37801
+ supportsGlobal: true,
37802
+ filePattern: (0, node_path.join)("**", "*.md")
37803
+ }
37804
+ }],
36488
37805
  ["opencode", {
36489
37806
  class: OpenCodeSubagent,
36490
37807
  meta: {
@@ -36606,7 +37923,18 @@ var SubagentsProcessor = class extends FeatureProcessor {
36606
37923
  }
36607
37924
  rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
36608
37925
  }
36609
- return rulesyncSubagents;
37926
+ const uniqueRulesyncSubagents = [];
37927
+ const seenOutputPaths = /* @__PURE__ */ new Set();
37928
+ for (const rulesyncSubagent of rulesyncSubagents) {
37929
+ const outputPath = (0, node_path.join)(rulesyncSubagent.getRelativeDirPath(), rulesyncSubagent.getRelativeFilePath());
37930
+ if (seenOutputPaths.has(outputPath)) {
37931
+ this.logger.warn(`Multiple ${this.toolTarget} subagents resolve to "${outputPath}"; keeping the first and ignoring this copy.`);
37932
+ continue;
37933
+ }
37934
+ seenOutputPaths.add(outputPath);
37935
+ uniqueRulesyncSubagents.push(rulesyncSubagent);
37936
+ }
37937
+ return uniqueRulesyncSubagents;
36610
37938
  }
36611
37939
  /**
36612
37940
  * Implementation of abstract method from Processor
@@ -36654,25 +37982,35 @@ var SubagentsProcessor = class extends FeatureProcessor {
36654
37982
  async loadToolFiles({ forDeletion = false } = {}) {
36655
37983
  const factory = this.getFactory(this.toolTarget);
36656
37984
  const paths = factory.class.getSettablePaths({ global: this.global });
36657
- const dirPaths = forDeletion ? [paths.relativeDirPath] : [paths.relativeDirPath, ...paths.importDirPaths ?? []];
37985
+ const roots = forDeletion ? [paths.relativeDirPath] : [paths.relativeDirPath, ...paths.importDirPaths ?? []];
36658
37986
  const toolSubagents = [];
36659
37987
  const seenRelativeFilePaths = /* @__PURE__ */ new Set();
36660
- for (const dirPath of dirPaths) {
36661
- const baseDir = (0, node_path.join)(this.outputRoot, dirPath);
36662
- const subagentFilePaths = await findFilesByGlobs((0, node_path.join)(baseDir, factory.meta.filePattern));
37988
+ for (const root of roots) {
37989
+ const rootOutputRoot = typeof root === "string" ? this.outputRoot : root.outputRoot;
37990
+ const dirPath = typeof root === "string" ? root : root.relativeDirPath;
37991
+ const baseDir = (0, node_path.join)(rootOutputRoot, dirPath);
37992
+ if (forDeletion && await directoryExists(baseDir)) await assertWritablePathInsideRoot({
37993
+ rootPath: rootOutputRoot,
37994
+ targetPath: baseDir
37995
+ });
37996
+ const subagentFilePaths = await findFilesByGlobs((0, node_path.join)(baseDir, factory.meta.filePattern), { followSymbolicLinks: !forDeletion });
36663
37997
  const toRelativeFilePath = (path) => (0, node_path.relative)(baseDir, path);
36664
37998
  let ownedFilePaths = subagentFilePaths;
36665
37999
  if (factory.class.isFileOwned) {
36666
38000
  const ownership = await Promise.all(subagentFilePaths.map((path) => factory.class.isFileOwned({
36667
- outputRoot: this.outputRoot,
38001
+ outputRoot: rootOutputRoot,
36668
38002
  relativeDirPath: dirPath,
36669
38003
  relativeFilePath: toRelativeFilePath(path)
36670
38004
  })));
36671
38005
  ownedFilePaths = subagentFilePaths.filter((_, index) => ownership[index]);
36672
38006
  }
36673
38007
  if (forDeletion) {
38008
+ await Promise.all(ownedFilePaths.map((path) => assertWritablePathInsideRoot({
38009
+ rootPath: baseDir,
38010
+ targetPath: path
38011
+ })));
36674
38012
  toolSubagents.push(...ownedFilePaths.map((path) => factory.class.forDeletion({
36675
- outputRoot: this.outputRoot,
38013
+ outputRoot: rootOutputRoot,
36676
38014
  relativeDirPath: dirPath,
36677
38015
  relativeFilePath: toRelativeFilePath(path),
36678
38016
  global: this.global
@@ -36680,14 +38018,14 @@ var SubagentsProcessor = class extends FeatureProcessor {
36680
38018
  continue;
36681
38019
  }
36682
38020
  const loaded = await Promise.all(ownedFilePaths.map((path) => factory.class.fromFile({
36683
- outputRoot: this.outputRoot,
38021
+ outputRoot: rootOutputRoot,
36684
38022
  relativeDirPath: dirPath,
36685
38023
  relativeFilePath: toRelativeFilePath(path),
36686
38024
  global: this.global
36687
38025
  })));
36688
38026
  const deduped = [];
36689
38027
  for (const subagent of loaded) {
36690
- const key = subagent.getRelativeFilePath();
38028
+ const key = subagent.getImportIdentity();
36691
38029
  if (seenRelativeFilePaths.has(key)) {
36692
38030
  this.logger.warn(`Duplicate ${this.toolTarget} subagent "${key}" found in ${dirPath}; keeping the one from a higher-precedence directory and ignoring this copy.`);
36693
38031
  continue;
@@ -36703,7 +38041,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
36703
38041
  global: this.global
36704
38042
  });
36705
38043
  for (const subagent of additionalSubagents) {
36706
- const key = subagent.getRelativeFilePath();
38044
+ const key = subagent.getImportIdentity();
36707
38045
  if (seenRelativeFilePaths.has(key)) {
36708
38046
  this.logger.warn(`Duplicate ${this.toolTarget} subagent "${key}" defined inline; keeping the standalone file and ignoring the inline copy.`);
36709
38047
  continue;
@@ -36712,7 +38050,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
36712
38050
  toolSubagents.push(subagent);
36713
38051
  }
36714
38052
  }
36715
- this.logger.debug(`Successfully loaded ${toolSubagents.length} ${this.toolTarget} subagents from ${dirPaths.join(", ")}`);
38053
+ this.logger.debug(`Successfully loaded ${toolSubagents.length} ${this.toolTarget} subagents from ${roots.length} root(s)`);
36716
38054
  return toolSubagents;
36717
38055
  }
36718
38056
  /**
@@ -37376,17 +38714,18 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37376
38714
  };
37377
38715
  }
37378
38716
  static getSettablePaths({ global = false, excludeToolDir } = {}) {
37379
- if (global) return { root: AntigravityIdeRule.getGlobalRootPath(excludeToolDir) };
38717
+ if (global) return { root: this.getGlobalRootPath(excludeToolDir) };
37380
38718
  return {
37381
- root: AntigravityIdeRule.getProjectRootPath(),
38719
+ root: this.getProjectRootPath(),
37382
38720
  nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules", excludeToolDir) }
37383
38721
  };
37384
38722
  }
37385
38723
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
38724
+ const paths = this.getSettablePaths({ global });
37386
38725
  if (global) {
37387
- const rootPath = AntigravityIdeRule.getGlobalRootPath();
38726
+ const rootPath = paths.root;
37388
38727
  const fileContent = await readFileContent((0, node_path.join)(outputRoot, rootPath.relativeDirPath, rootPath.relativeFilePath));
37389
- return new AntigravityIdeRule({
38728
+ return new this({
37390
38729
  outputRoot,
37391
38730
  relativeDirPath: rootPath.relativeDirPath,
37392
38731
  relativeFilePath: rootPath.relativeFilePath,
@@ -37396,10 +38735,10 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37396
38735
  root: true
37397
38736
  });
37398
38737
  }
37399
- if (relativeFilePath === "AGENTS.md") {
37400
- const rootPath = AntigravityIdeRule.getProjectRootPath();
38738
+ if (relativeFilePath === paths.root.relativeFilePath) {
38739
+ const rootPath = paths.root;
37401
38740
  const rootContent = await readFileContent((0, node_path.join)(outputRoot, rootPath.relativeDirPath, rootPath.relativeFilePath));
37402
- return new AntigravityIdeRule({
38741
+ return new this({
37403
38742
  outputRoot,
37404
38743
  relativeDirPath: rootPath.relativeDirPath,
37405
38744
  relativeFilePath: rootPath.relativeFilePath,
@@ -37409,7 +38748,8 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37409
38748
  root: true
37410
38749
  });
37411
38750
  }
37412
- const nonRootDirPath = buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules");
38751
+ if (!("nonRoot" in paths) || !paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
38752
+ const nonRootDirPath = paths.nonRoot.relativeDirPath;
37413
38753
  const filePath = (0, node_path.join)(outputRoot, nonRootDirPath, relativeFilePath);
37414
38754
  const { frontmatter, body } = parseFrontmatter(await readFileContent(filePath), filePath);
37415
38755
  let parsedFrontmatter;
@@ -37418,7 +38758,7 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37418
38758
  if (result.success) parsedFrontmatter = result.data;
37419
38759
  else throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
37420
38760
  } else parsedFrontmatter = frontmatter;
37421
- return new AntigravityIdeRule({
38761
+ return new this({
37422
38762
  outputRoot,
37423
38763
  relativeDirPath: nonRootDirPath,
37424
38764
  relativeFilePath,
@@ -37429,9 +38769,10 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37429
38769
  });
37430
38770
  }
37431
38771
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
38772
+ const paths = this.getSettablePaths({ global });
37432
38773
  if (global) {
37433
- const rootPath = AntigravityIdeRule.getGlobalRootPath();
37434
- return new AntigravityIdeRule({
38774
+ const rootPath = paths.root;
38775
+ return new this({
37435
38776
  outputRoot,
37436
38777
  relativeDirPath: rootPath.relativeDirPath,
37437
38778
  relativeFilePath: rootPath.relativeFilePath,
@@ -37442,8 +38783,8 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37442
38783
  });
37443
38784
  }
37444
38785
  if (rulesyncRule.getFrontmatter().root) {
37445
- const rootPath = AntigravityIdeRule.getProjectRootPath();
37446
- return new AntigravityIdeRule({
38786
+ const rootPath = paths.root;
38787
+ return new this({
37447
38788
  outputRoot,
37448
38789
  relativeDirPath: rootPath.relativeDirPath,
37449
38790
  relativeFilePath: rootPath.relativeFilePath,
@@ -37460,10 +38801,11 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37460
38801
  const strategy = STRATEGIES$1.find((s) => s.canHandle(storedTrigger));
37461
38802
  if (!strategy) throw new Error(`No strategy found for trigger: ${storedTrigger}`);
37462
38803
  const frontmatter = strategy.generateFrontmatter(normalized, rulesyncFrontmatter);
38804
+ if (!("nonRoot" in paths) || !paths.nonRoot) throw new Error(`nonRoot path is not set for ${rulesyncRule.getRelativeFilePath()}`);
37463
38805
  const kebabCaseFilename = toKebabCaseFilename(rulesyncRule.getRelativeFilePath());
37464
- return new AntigravityIdeRule({
38806
+ return new this({
37465
38807
  outputRoot,
37466
- relativeDirPath: buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules"),
38808
+ relativeDirPath: paths.nonRoot.relativeDirPath,
37467
38809
  relativeFilePath: kebabCaseFilename,
37468
38810
  frontmatter,
37469
38811
  body: rulesyncRule.getBody(),
@@ -37532,6 +38874,23 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37532
38874
  }
37533
38875
  };
37534
38876
  //#endregion
38877
+ //#region src/features/rules/antigravity-plugin-rule.ts
38878
+ var AntigravityPluginRule = class extends AntigravityIdeRule {
38879
+ static isTargetedByRulesyncRule(rulesyncRule) {
38880
+ const targets = rulesyncRule.getFrontmatter().targets;
38881
+ return targets.includes("*") || targets.includes("antigravity-plugin");
38882
+ }
38883
+ static getSettablePaths() {
38884
+ return {
38885
+ root: {
38886
+ relativeDirPath: ANTIGRAVITY_PLUGIN_RULES_DIR,
38887
+ relativeFilePath: "AGENTS.md"
38888
+ },
38889
+ nonRoot: { relativeDirPath: ANTIGRAVITY_PLUGIN_RULES_DIR }
38890
+ };
38891
+ }
38892
+ };
38893
+ //#endregion
37535
38894
  //#region src/features/rules/augmentcode-legacy-rule.ts
37536
38895
  var AugmentcodeLegacyRule = class AugmentcodeLegacyRule extends ToolRule {
37537
38896
  toRulesyncRule() {
@@ -39481,13 +40840,17 @@ var JunieRule = class JunieRule extends ToolRule {
39481
40840
  if (global) {
39482
40841
  const paths = this.getSettablePaths({ global: true });
39483
40842
  if (!("root" in paths) || !paths.root) throw new Error("JunieRule global settable paths must include a root path");
39484
- if (!rulesyncRule.getFrontmatter().root) throw new Error(`JunieRule does not support non-root rules in global mode; expected a root rule but got '${rulesyncRule.getRelativeFilePath()}'`);
39485
- return new JunieRule(this.buildToolRuleParamsDefault({
40843
+ const frontmatter = rulesyncRule.getFrontmatter();
40844
+ return new JunieRule({
39486
40845
  outputRoot,
39487
- rulesyncRule,
40846
+ relativeDirPath: paths.root.relativeDirPath,
40847
+ relativeFilePath: paths.root.relativeFilePath,
40848
+ fileContent: rulesyncRule.getBody(),
39488
40849
  validate,
39489
- rootPath: paths.root
39490
- }));
40850
+ root: frontmatter.root ?? false,
40851
+ description: frontmatter.description,
40852
+ globs: frontmatter.globs
40853
+ });
39491
40854
  }
39492
40855
  const { root } = this.getSettablePaths();
39493
40856
  return new JunieRule({
@@ -39608,6 +40971,97 @@ var KiloRule = class KiloRule extends ToolRule {
39608
40971
  }
39609
40972
  };
39610
40973
  //#endregion
40974
+ //#region src/features/rules/kimi-code-rule.ts
40975
+ /**
40976
+ * Kimi Code instruction file.
40977
+ *
40978
+ * Kimi Code discovers `.kimi-code/AGENTS.md` at project scope and
40979
+ * `~/.kimi-code/AGENTS.md` at user scope. Rulesync's topic rules have no
40980
+ * dedicated Kimi rule directory, so the processor folds them into this root
40981
+ * instruction file.
40982
+ *
40983
+ * @see https://moonshotai.github.io/kimi-code/en/customization/agents.html
40984
+ */
40985
+ var KimiCodeRule = class KimiCodeRule extends ToolRule {
40986
+ constructor({ fileContent, root, ...rest }) {
40987
+ super({
40988
+ ...rest,
40989
+ fileContent,
40990
+ root: root ?? false
40991
+ });
40992
+ }
40993
+ static getSettablePaths({ global = false } = {}) {
40994
+ return { root: {
40995
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
40996
+ relativeFilePath: KIMI_CODE_RULE_FILE_NAME
40997
+ } };
40998
+ }
40999
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
41000
+ const { root } = this.getSettablePaths({ global });
41001
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, root.relativeDirPath, root.relativeFilePath));
41002
+ return new KimiCodeRule({
41003
+ outputRoot,
41004
+ relativeDirPath: root.relativeDirPath,
41005
+ relativeFilePath: root.relativeFilePath,
41006
+ fileContent,
41007
+ validate,
41008
+ global,
41009
+ root: true
41010
+ });
41011
+ }
41012
+ static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
41013
+ const { root } = this.getSettablePaths({ global });
41014
+ return new KimiCodeRule({
41015
+ outputRoot,
41016
+ relativeDirPath: root.relativeDirPath,
41017
+ relativeFilePath: root.relativeFilePath,
41018
+ fileContent: rulesyncRule.getBody(),
41019
+ validate,
41020
+ global,
41021
+ root: rulesyncRule.getFrontmatter().root ?? false
41022
+ });
41023
+ }
41024
+ toRulesyncRule() {
41025
+ return new RulesyncRule({
41026
+ outputRoot: getKimiCodeRulesyncOutputRoot({
41027
+ nativeOutputRoot: this.outputRoot,
41028
+ global: this.global
41029
+ }),
41030
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
41031
+ relativeFilePath: RULESYNC_OVERVIEW_FILE_NAME,
41032
+ frontmatter: {
41033
+ root: true,
41034
+ targets: ["*"],
41035
+ globs: ["**/*"]
41036
+ },
41037
+ body: this.getFileContent()
41038
+ });
41039
+ }
41040
+ validate() {
41041
+ return {
41042
+ success: true,
41043
+ error: null
41044
+ };
41045
+ }
41046
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
41047
+ return new KimiCodeRule({
41048
+ outputRoot,
41049
+ relativeDirPath,
41050
+ relativeFilePath,
41051
+ fileContent: "",
41052
+ validate: false,
41053
+ global,
41054
+ root: relativeDirPath === getKimiCodeRelativeDirPath({ global }) && relativeFilePath === "AGENTS.md"
41055
+ });
41056
+ }
41057
+ static isTargetedByRulesyncRule(rulesyncRule) {
41058
+ return this.isTargetedByRulesyncRuleDefault({
41059
+ rulesyncRule,
41060
+ toolTarget: "kimi-code"
41061
+ });
41062
+ }
41063
+ };
41064
+ //#endregion
39611
41065
  //#region src/features/rules/kiro-rule.ts
39612
41066
  const WILDCARD_GLOBS = /* @__PURE__ */ new Set([
39613
41067
  "**/*",
@@ -41058,6 +42512,14 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
41058
42512
  ruleDiscoveryMode: "auto"
41059
42513
  }
41060
42514
  }],
42515
+ ["antigravity-plugin", {
42516
+ class: AntigravityPluginRule,
42517
+ meta: {
42518
+ extension: "md",
42519
+ supportsGlobal: false,
42520
+ ruleDiscoveryMode: "auto"
42521
+ }
42522
+ }],
41061
42523
  ["augmentcode", {
41062
42524
  class: AugmentcodeRule,
41063
42525
  meta: {
@@ -41197,6 +42659,15 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
41197
42659
  mcpInstructionsRegistrar: KiloMcp
41198
42660
  }
41199
42661
  }],
42662
+ ["kimi-code", {
42663
+ class: KimiCodeRule,
42664
+ meta: {
42665
+ extension: "md",
42666
+ supportsGlobal: true,
42667
+ ruleDiscoveryMode: "auto",
42668
+ foldsNonRootIntoRoot: true
42669
+ }
42670
+ }],
41200
42671
  ["kiro", {
41201
42672
  class: KiroRule,
41202
42673
  meta: {
@@ -41670,7 +43141,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
41670
43141
  if (targetedLocalRootRules.length > 0 && targetedRootRules.length === 0) throw new Error(`localRoot: true requires a root: true rule to exist for target '${this.toolTarget}' (found in ${formatRulePaths(targetedLocalRootRules)})`);
41671
43142
  if (this.global) {
41672
43143
  const globalPaths = factory.class.getSettablePaths({ global: true });
41673
- const supportsGlobalNonRoot = "nonRoot" in globalPaths && globalPaths.nonRoot !== null;
43144
+ const supportsGlobalNonRoot = "nonRoot" in globalPaths && globalPaths.nonRoot !== null || factory.meta.supportsGlobal && factory.meta.foldsNonRootIntoRoot === true;
41674
43145
  const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root && !rule.getFrontmatter().localRoot && factory.class.isTargetedByRulesyncRule(rule));
41675
43146
  if (nonRootRules.length > 0 && !supportsGlobalNonRoot) this.logger.warn(`${nonRootRules.length} non-root rulesync rules found, but it's in global mode, so ignoring them: ${formatRulePaths(nonRootRules)}`);
41676
43147
  if (targetedLocalRootRules.length > 0) this.logger.warn(`${targetedLocalRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them: ${formatRulePaths(targetedLocalRootRules)}`);
@@ -41873,12 +43344,25 @@ As this project's AI coding tool, you must follow the additional conventions bel
41873
43344
  }
41874
43345
  };
41875
43346
  //#endregion
43347
+ //#region src/utils/plugin-root.ts
43348
+ function isPackagingToolTarget(toolTarget) {
43349
+ return PACKAGING_TOOL_TARGETS.includes(toolTarget);
43350
+ }
43351
+ async function assertPluginRootSafe(params) {
43352
+ if (!isPackagingToolTarget(params.toolTarget)) return;
43353
+ await assertDirectoryIfExists(params.outputRoot);
43354
+ if (!await directoryExists(params.outputRoot)) throw new Error(`Plugin output root must be an existing directory: ${params.outputRoot}.`);
43355
+ await assertTreeContainsNoSymlinks(params.outputRoot);
43356
+ }
43357
+ //#endregion
41876
43358
  //#region src/lib/convert.ts
41877
43359
  /**
41878
43360
  * Convert configuration files between AI tools without writing intermediate
41879
43361
  * `.rulesync/` files to disk. Rulesync file instances live in memory only.
41880
43362
  */
41881
43363
  async function convertFromTool(params) {
43364
+ const packagingTarget = [params.fromTool, ...params.toTools].find(isPackagingToolTarget);
43365
+ if (packagingTarget) throw new Error(`Plugin packaging target '${packagingTarget}' is not supported by convert. Use import and generate with explicit plugin directories.`);
41882
43366
  const ctx = params;
41883
43367
  const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount, checksCount] = [
41884
43368
  await runFeatureConvert(ctx, buildRulesStrategy(ctx)),
@@ -41957,7 +43441,11 @@ function buildRulesStrategy(ctx) {
41957
43441
  itemLabel: "rule file(s)",
41958
43442
  allTargets: RulesProcessor.getToolTargets({ global }),
41959
43443
  createProcessor: ({ toolTarget, dryRun }) => new RulesProcessor({
41960
- outputRoot,
43444
+ outputRoot: resolveToolOutputRoot({
43445
+ outputRoot,
43446
+ toolTarget,
43447
+ global
43448
+ }),
41961
43449
  toolTarget,
41962
43450
  global,
41963
43451
  dryRun,
@@ -41971,18 +43459,20 @@ function buildRulesStrategy(ctx) {
41971
43459
  }
41972
43460
  function buildIgnoreStrategy(ctx) {
41973
43461
  const { config, logger } = ctx;
41974
- if (config.getGlobal()) {
41975
- logger.debug("Skipping ignore conversion (not supported in global mode)");
41976
- return null;
41977
- }
43462
+ const global = config.getGlobal();
41978
43463
  const outputRoot = getOutputRoot(config);
41979
43464
  return {
41980
43465
  feature: "ignore",
41981
43466
  itemLabel: "ignore file(s)",
41982
- allTargets: IgnoreProcessor.getToolTargets(),
43467
+ allTargets: IgnoreProcessor.getToolTargets({ global }),
41983
43468
  createProcessor: ({ toolTarget, dryRun }) => new IgnoreProcessor({
41984
- outputRoot,
43469
+ outputRoot: resolveToolOutputRoot({
43470
+ outputRoot,
43471
+ toolTarget,
43472
+ global
43473
+ }),
41985
43474
  toolTarget,
43475
+ global,
41986
43476
  dryRun,
41987
43477
  logger,
41988
43478
  featureOptions: config.getFeatureOptions(toolTarget, "ignore")
@@ -42002,7 +43492,11 @@ function buildMcpStrategy(ctx) {
42002
43492
  itemLabel: "MCP file(s)",
42003
43493
  allTargets: McpProcessor.getToolTargets({ global }),
42004
43494
  createProcessor: ({ toolTarget, dryRun }) => new McpProcessor({
42005
- outputRoot,
43495
+ outputRoot: resolveToolOutputRoot({
43496
+ outputRoot,
43497
+ toolTarget,
43498
+ global
43499
+ }),
42006
43500
  toolTarget,
42007
43501
  global,
42008
43502
  dryRun,
@@ -42051,7 +43545,11 @@ function buildSubagentsStrategy(ctx) {
42051
43545
  includeSimulated: false
42052
43546
  }),
42053
43547
  createProcessor: ({ toolTarget, dryRun }) => new SubagentsProcessor({
42054
- outputRoot,
43548
+ outputRoot: resolveToolOutputRoot({
43549
+ outputRoot,
43550
+ toolTarget,
43551
+ global
43552
+ }),
42055
43553
  toolTarget,
42056
43554
  global,
42057
43555
  dryRun,
@@ -42072,7 +43570,11 @@ function buildSkillsStrategy(ctx) {
42072
43570
  itemLabel: "skill(s)",
42073
43571
  allTargets: SkillsProcessor.getToolTargets({ global }),
42074
43572
  createProcessor: ({ toolTarget, dryRun }) => new SkillsProcessor({
42075
- outputRoot,
43573
+ outputRoot: resolveToolOutputRoot({
43574
+ outputRoot,
43575
+ toolTarget,
43576
+ global
43577
+ }),
42076
43578
  toolTarget,
42077
43579
  global,
42078
43580
  dryRun,
@@ -42097,7 +43599,11 @@ function buildHooksStrategy(ctx) {
42097
43599
  importOnly: true
42098
43600
  }),
42099
43601
  createProcessor: ({ toolTarget, dryRun }) => new HooksProcessor({
42100
- outputRoot,
43602
+ outputRoot: resolveToolOutputRoot({
43603
+ outputRoot,
43604
+ toolTarget,
43605
+ global
43606
+ }),
42101
43607
  toolTarget,
42102
43608
  global,
42103
43609
  dryRun,
@@ -42122,7 +43628,11 @@ function buildPermissionsStrategy(ctx) {
42122
43628
  importOnly: true
42123
43629
  }),
42124
43630
  createProcessor: ({ toolTarget, dryRun }) => new PermissionsProcessor({
42125
- outputRoot,
43631
+ outputRoot: resolveToolOutputRoot({
43632
+ outputRoot,
43633
+ toolTarget,
43634
+ global
43635
+ }),
42126
43636
  toolTarget,
42127
43637
  global,
42128
43638
  dryRun,
@@ -42623,6 +44133,10 @@ async function warnSkillSubagentNameCollisions(params) {
42623
44133
  */
42624
44134
  async function generate(params) {
42625
44135
  const { config, logger } = params;
44136
+ for (const toolTarget of config.getTargets()) for (const outputRoot of config.getOutputRoots(toolTarget)) await assertPluginRootSafe({
44137
+ toolTarget,
44138
+ outputRoot
44139
+ });
42626
44140
  await warnSkillSubagentNameCollisions({
42627
44141
  config,
42628
44142
  logger
@@ -42742,7 +44256,11 @@ async function generateRulesCore(params) {
42742
44256
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42743
44257
  if (!config.getFeatures(toolTarget).includes("rules")) continue;
42744
44258
  const processor = new RulesProcessor({
42745
- outputRoot,
44259
+ outputRoot: resolveToolOutputRoot({
44260
+ outputRoot,
44261
+ toolTarget,
44262
+ global: config.getGlobal()
44263
+ }),
42746
44264
  inputRoot: config.getInputRoot(),
42747
44265
  toolTarget,
42748
44266
  global: config.getGlobal(),
@@ -42777,18 +44295,14 @@ async function generateRulesCore(params) {
42777
44295
  }
42778
44296
  async function generateIgnoreCore(params) {
42779
44297
  const { config, logger } = params;
42780
- const supportedIgnoreTargets = config.getGlobal() ? [] : IgnoreProcessor.getToolTargets();
44298
+ const global = config.getGlobal();
44299
+ const supportedIgnoreTargets = IgnoreProcessor.getToolTargets({ global });
42781
44300
  warnUnsupportedTargets({
42782
44301
  config,
42783
44302
  supportedTargets: supportedIgnoreTargets,
42784
44303
  featureName: "ignore",
42785
44304
  logger
42786
44305
  });
42787
- if (config.getGlobal()) return {
42788
- count: 0,
42789
- paths: [],
42790
- hasDiff: false
42791
- };
42792
44306
  let totalCount = 0;
42793
44307
  const allPaths = [];
42794
44308
  let hasDiff = false;
@@ -42799,6 +44313,7 @@ async function generateIgnoreCore(params) {
42799
44313
  outputRoot,
42800
44314
  inputRoot: config.getInputRoot(),
42801
44315
  toolTarget,
44316
+ global,
42802
44317
  dryRun: config.isPreviewMode(),
42803
44318
  logger,
42804
44319
  featureOptions: config.getFeatureOptions(toolTarget, "ignore")
@@ -42838,7 +44353,11 @@ async function generateMcpCore(params) {
42838
44353
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42839
44354
  if (!config.getFeatures(toolTarget).includes("mcp")) continue;
42840
44355
  const processor = new McpProcessor({
42841
- outputRoot,
44356
+ outputRoot: resolveToolOutputRoot({
44357
+ outputRoot,
44358
+ toolTarget,
44359
+ global: config.getGlobal()
44360
+ }),
42842
44361
  inputRoot: config.getInputRoot(),
42843
44362
  toolTarget,
42844
44363
  global: config.getGlobal(),
@@ -42923,7 +44442,11 @@ async function generateSubagentsCore(params) {
42923
44442
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42924
44443
  if (!config.getFeatures(toolTarget).includes("subagents")) continue;
42925
44444
  const processor = new SubagentsProcessor({
42926
- outputRoot,
44445
+ outputRoot: resolveToolOutputRoot({
44446
+ outputRoot,
44447
+ toolTarget,
44448
+ global: config.getGlobal()
44449
+ }),
42927
44450
  inputRoot: config.getInputRoot(),
42928
44451
  toolTarget,
42929
44452
  global: config.getGlobal(),
@@ -42966,7 +44489,11 @@ async function generateSkillsCore(params) {
42966
44489
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42967
44490
  if (!config.getFeatures(toolTarget).includes("skills")) continue;
42968
44491
  const processor = new SkillsProcessor({
42969
- outputRoot,
44492
+ outputRoot: resolveToolOutputRoot({
44493
+ outputRoot,
44494
+ toolTarget,
44495
+ global: config.getGlobal()
44496
+ }),
42970
44497
  inputRoot: config.getInputRoot(),
42971
44498
  toolTarget,
42972
44499
  global: config.getGlobal(),
@@ -43007,7 +44534,11 @@ async function generateHooksCore(params) {
43007
44534
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
43008
44535
  if (!config.getFeatures(toolTarget).includes("hooks")) continue;
43009
44536
  const processor = new HooksProcessor({
43010
- outputRoot,
44537
+ outputRoot: resolveToolOutputRoot({
44538
+ outputRoot,
44539
+ toolTarget,
44540
+ global: config.getGlobal()
44541
+ }),
43011
44542
  inputRoot: config.getInputRoot(),
43012
44543
  toolTarget,
43013
44544
  global: config.getGlobal(),
@@ -43045,7 +44576,11 @@ async function generatePermissionsCore(params) {
43045
44576
  if (!config.getFeatures(toolTarget).includes("permissions")) continue;
43046
44577
  try {
43047
44578
  const processor = new PermissionsProcessor({
43048
- outputRoot,
44579
+ outputRoot: resolveToolOutputRoot({
44580
+ outputRoot,
44581
+ toolTarget,
44582
+ global: config.getGlobal()
44583
+ }),
43049
44584
  inputRoot: config.getInputRoot(),
43050
44585
  toolTarget,
43051
44586
  global: config.getGlobal(),
@@ -43111,21 +44646,41 @@ async function generateChecksCore(params) {
43111
44646
  }
43112
44647
  //#endregion
43113
44648
  //#region src/lib/import.ts
43114
- /**
43115
- * Import always writes the `.json` variant of a fixed-path source file, but a
43116
- * sibling `.jsonc` variant takes precedence at read time — so an import into a
43117
- * project that authors the `.jsonc` variant would be silently shadowed. Warn
43118
- * so the user merges (or removes) one of the two by hand.
43119
- */
43120
- async function warnIfShadowedByJsonc(params) {
43121
- const { outputRoot, jsonRelativePath, jsoncRelativePath, logger } = params;
43122
- if (await fileExists((0, node_path.join)(outputRoot, jsoncRelativePath))) logger.warn(`${jsoncRelativePath} exists and takes precedence over the imported ${jsonRelativePath}. Merge the imported content into ${jsoncRelativePath} (or remove it) so the import takes effect.`);
44649
+ async function applyRulesyncSourcePath({ files, paths, sourceClass, outputRoot }) {
44650
+ const first = files[0];
44651
+ if (!first) return files;
44652
+ const destinationOutputRoot = outputRoot ?? first.getOutputRoot();
44653
+ const destination = await resolveRulesyncSourceWritePath({
44654
+ outputRoot: destinationOutputRoot,
44655
+ paths
44656
+ });
44657
+ return files.map((file) => new sourceClass({
44658
+ outputRoot: destinationOutputRoot,
44659
+ relativeDirPath: destination.relativeDirPath,
44660
+ relativeFilePath: destination.relativeFilePath,
44661
+ fileContent: file.getFileContent(),
44662
+ validate: true
44663
+ }));
44664
+ }
44665
+ function getToolOutputRoot({ config, tool }) {
44666
+ return resolveToolOutputRoot({
44667
+ outputRoot: config.getOutputRoots(tool)[0] ?? ".",
44668
+ toolTarget: tool,
44669
+ global: config.getGlobal()
44670
+ });
43123
44671
  }
43124
44672
  /**
43125
44673
  * Import configuration files from AI tools.
43126
44674
  */
43127
44675
  async function importFromTool(params) {
43128
44676
  const { config, tool, logger } = params;
44677
+ await assertPluginRootSafe({
44678
+ toolTarget: tool,
44679
+ outputRoot: getToolOutputRoot({
44680
+ config,
44681
+ tool
44682
+ })
44683
+ });
43129
44684
  return {
43130
44685
  rulesCount: await importRulesCore({
43131
44686
  config,
@@ -43180,7 +44735,10 @@ async function importRulesCore(params) {
43180
44735
  const global = config.getGlobal();
43181
44736
  if (!RulesProcessor.getToolTargets({ global }).includes(tool)) return 0;
43182
44737
  const rulesProcessor = new RulesProcessor({
43183
- outputRoot: config.getOutputRoots()[0] ?? ".",
44738
+ outputRoot: getToolOutputRoot({
44739
+ config,
44740
+ tool
44741
+ }),
43184
44742
  toolTarget: tool,
43185
44743
  global,
43186
44744
  logger
@@ -43198,14 +44756,15 @@ async function importRulesCore(params) {
43198
44756
  async function importIgnoreCore(params) {
43199
44757
  const { config, tool, logger } = params;
43200
44758
  if (!config.getFeatures(tool).includes("ignore")) return 0;
43201
- if (config.getGlobal()) {
43202
- logger.debug("Skipping ignore file import (not supported in global mode)");
43203
- return 0;
43204
- }
43205
- if (!IgnoreProcessor.getToolTargets().includes(tool)) return 0;
44759
+ const global = config.getGlobal();
44760
+ if (!IgnoreProcessor.getToolTargets({ global }).includes(tool)) return 0;
43206
44761
  const ignoreProcessor = new IgnoreProcessor({
43207
- outputRoot: config.getOutputRoots()[0] ?? ".",
44762
+ outputRoot: getToolOutputRoot({
44763
+ config,
44764
+ tool
44765
+ }),
43208
44766
  toolTarget: tool,
44767
+ global,
43209
44768
  logger,
43210
44769
  featureOptions: config.getFeatureOptions(tool, "ignore")
43211
44770
  });
@@ -43226,7 +44785,10 @@ async function importMcpCore(params) {
43226
44785
  const global = config.getGlobal();
43227
44786
  if (!McpProcessor.getToolTargets({ global }).includes(tool)) return 0;
43228
44787
  const mcpProcessor = new McpProcessor({
43229
- outputRoot: config.getOutputRoots()[0] ?? ".",
44788
+ outputRoot: getToolOutputRoot({
44789
+ config,
44790
+ tool
44791
+ }),
43230
44792
  toolTarget: tool,
43231
44793
  global,
43232
44794
  logger
@@ -43236,14 +44798,13 @@ async function importMcpCore(params) {
43236
44798
  logger.warn(`No MCP files found for ${tool}. Skipping import.`);
43237
44799
  return 0;
43238
44800
  }
43239
- const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43240
- const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
43241
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43242
- outputRoot: config.getOutputRoots()[0] ?? ".",
43243
- jsonRelativePath: RULESYNC_MCP_RELATIVE_FILE_PATH,
43244
- jsoncRelativePath: RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH,
43245
- logger
44801
+ const rulesyncFiles = await applyRulesyncSourcePath({
44802
+ files: await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44803
+ paths: RulesyncMcp.getSettablePaths(),
44804
+ sourceClass: RulesyncMcp,
44805
+ outputRoot: isPackagingToolTarget(tool) ? process.cwd() : void 0
43246
44806
  });
44807
+ const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
43247
44808
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} MCP files`);
43248
44809
  return writtenCount;
43249
44810
  }
@@ -43256,7 +44817,10 @@ async function importCommandsCore(params) {
43256
44817
  includeSimulated: false
43257
44818
  }).includes(tool)) return 0;
43258
44819
  const commandsProcessor = new CommandsProcessor({
43259
- outputRoot: config.getOutputRoots()[0] ?? ".",
44820
+ outputRoot: getToolOutputRoot({
44821
+ config,
44822
+ tool
44823
+ }),
43260
44824
  toolTarget: tool,
43261
44825
  global,
43262
44826
  logger
@@ -43280,7 +44844,10 @@ async function importSubagentsCore(params) {
43280
44844
  includeSimulated: false
43281
44845
  }).includes(tool)) return 0;
43282
44846
  const subagentsProcessor = new SubagentsProcessor({
43283
- outputRoot: config.getOutputRoots()[0] ?? ".",
44847
+ outputRoot: getToolOutputRoot({
44848
+ config,
44849
+ tool
44850
+ }),
43284
44851
  toolTarget: tool,
43285
44852
  global: config.getGlobal(),
43286
44853
  logger
@@ -43301,7 +44868,10 @@ async function importSkillsCore(params) {
43301
44868
  const global = config.getGlobal();
43302
44869
  if (!SkillsProcessor.getToolTargets({ global }).includes(tool)) return 0;
43303
44870
  const skillsProcessor = new SkillsProcessor({
43304
- outputRoot: config.getOutputRoots()[0] ?? ".",
44871
+ outputRoot: getToolOutputRoot({
44872
+ config,
44873
+ tool
44874
+ }),
43305
44875
  toolTarget: tool,
43306
44876
  global,
43307
44877
  logger
@@ -43311,8 +44881,21 @@ async function importSkillsCore(params) {
43311
44881
  logger.warn(`No skill directories found for ${tool}. Skipping import.`);
43312
44882
  return 0;
43313
44883
  }
43314
- const rulesyncDirs = await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs);
43315
- const { count: writtenCount } = await skillsProcessor.writeAiDirs(rulesyncDirs);
44884
+ const rebasedRulesyncDirs = (await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs)).map((dir) => {
44885
+ if (!isPackagingToolTarget(tool)) return dir;
44886
+ if (!(dir instanceof RulesyncSkill)) return dir;
44887
+ return new RulesyncSkill({
44888
+ outputRoot: process.cwd(),
44889
+ relativeDirPath: dir.getRelativeDirPath(),
44890
+ dirName: dir.getDirName(),
44891
+ frontmatter: dir.getFrontmatter(),
44892
+ body: dir.getBody(),
44893
+ otherFiles: dir.getOtherFiles(),
44894
+ validate: true,
44895
+ global: false
44896
+ });
44897
+ });
44898
+ const { count: writtenCount } = await skillsProcessor.writeAiDirs(rebasedRulesyncDirs);
43316
44899
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} skill directories`);
43317
44900
  return writtenCount;
43318
44901
  }
@@ -43331,7 +44914,10 @@ async function importHooksCore(params) {
43331
44914
  return 0;
43332
44915
  }
43333
44916
  const hooksProcessor = new HooksProcessor({
43334
- outputRoot: config.getOutputRoots()[0] ?? ".",
44917
+ outputRoot: getToolOutputRoot({
44918
+ config,
44919
+ tool
44920
+ }),
43335
44921
  toolTarget: tool,
43336
44922
  global,
43337
44923
  logger
@@ -43341,14 +44927,13 @@ async function importHooksCore(params) {
43341
44927
  logger.warn(`No hooks files found for ${tool}. Skipping import.`);
43342
44928
  return 0;
43343
44929
  }
43344
- const rulesyncFiles = await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43345
- const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
43346
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43347
- outputRoot: config.getOutputRoots()[0] ?? ".",
43348
- jsonRelativePath: RULESYNC_HOOKS_RELATIVE_FILE_PATH,
43349
- jsoncRelativePath: RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH,
43350
- logger
44930
+ const rulesyncFiles = await applyRulesyncSourcePath({
44931
+ files: await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44932
+ paths: RulesyncHooks.getSettablePaths(),
44933
+ sourceClass: RulesyncHooks,
44934
+ outputRoot: isPackagingToolTarget(tool) ? process.cwd() : void 0
43351
44935
  });
44936
+ const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
43352
44937
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} hooks file(s)`);
43353
44938
  return writtenCount;
43354
44939
  }
@@ -43366,7 +44951,10 @@ async function importPermissionsCore(params) {
43366
44951
  return 0;
43367
44952
  }
43368
44953
  const permissionsProcessor = new PermissionsProcessor({
43369
- outputRoot: config.getOutputRoots()[0] ?? ".",
44954
+ outputRoot: getToolOutputRoot({
44955
+ config,
44956
+ tool
44957
+ }),
43370
44958
  toolTarget: tool,
43371
44959
  global: config.getGlobal(),
43372
44960
  logger
@@ -43376,14 +44964,12 @@ async function importPermissionsCore(params) {
43376
44964
  logger.warn(`No permissions files found for ${tool}. Skipping import.`);
43377
44965
  return 0;
43378
44966
  }
43379
- const rulesyncFiles = await permissionsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43380
- const { count: writtenCount } = await permissionsProcessor.writeAiFiles(rulesyncFiles);
43381
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43382
- outputRoot: config.getOutputRoots()[0] ?? ".",
43383
- jsonRelativePath: RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH,
43384
- jsoncRelativePath: RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH,
43385
- logger
44967
+ const rulesyncFiles = await applyRulesyncSourcePath({
44968
+ files: await permissionsProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44969
+ paths: RulesyncPermissions.getSettablePaths(),
44970
+ sourceClass: RulesyncPermissions
43386
44971
  });
44972
+ const { count: writtenCount } = await permissionsProcessor.writeAiFiles(rulesyncFiles);
43387
44973
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} permissions file(s)`);
43388
44974
  return writtenCount;
43389
44975
  }
@@ -43547,6 +45133,12 @@ Object.defineProperty(exports, "McpProcessor", {
43547
45133
  return McpProcessor;
43548
45134
  }
43549
45135
  });
45136
+ Object.defineProperty(exports, "PACKAGING_TOOL_TARGETS", {
45137
+ enumerable: true,
45138
+ get: function() {
45139
+ return PACKAGING_TOOL_TARGETS;
45140
+ }
45141
+ });
43550
45142
  Object.defineProperty(exports, "RULESYNC_AIIGNORE_FILE_NAME", {
43551
45143
  enumerable: true,
43552
45144
  get: function() {
@@ -43601,10 +45193,10 @@ Object.defineProperty(exports, "RULESYNC_HOOKS_FILE_NAME", {
43601
45193
  return RULESYNC_HOOKS_FILE_NAME;
43602
45194
  }
43603
45195
  });
43604
- Object.defineProperty(exports, "RULESYNC_HOOKS_JSONC_FILE_NAME", {
45196
+ Object.defineProperty(exports, "RULESYNC_HOOKS_LEGACY_FILE_NAME", {
43605
45197
  enumerable: true,
43606
45198
  get: function() {
43607
- return RULESYNC_HOOKS_JSONC_FILE_NAME;
45199
+ return RULESYNC_HOOKS_LEGACY_FILE_NAME;
43608
45200
  }
43609
45201
  });
43610
45202
  Object.defineProperty(exports, "RULESYNC_HOOKS_RELATIVE_FILE_PATH", {
@@ -43631,10 +45223,10 @@ Object.defineProperty(exports, "RULESYNC_MCP_FILE_NAME", {
43631
45223
  return RULESYNC_MCP_FILE_NAME;
43632
45224
  }
43633
45225
  });
43634
- Object.defineProperty(exports, "RULESYNC_MCP_JSONC_FILE_NAME", {
45226
+ Object.defineProperty(exports, "RULESYNC_MCP_LEGACY_FILE_NAME", {
43635
45227
  enumerable: true,
43636
45228
  get: function() {
43637
- return RULESYNC_MCP_JSONC_FILE_NAME;
45229
+ return RULESYNC_MCP_LEGACY_FILE_NAME;
43638
45230
  }
43639
45231
  });
43640
45232
  Object.defineProperty(exports, "RULESYNC_MCP_RELATIVE_FILE_PATH", {
@@ -43661,10 +45253,10 @@ Object.defineProperty(exports, "RULESYNC_PERMISSIONS_FILE_NAME", {
43661
45253
  return RULESYNC_PERMISSIONS_FILE_NAME;
43662
45254
  }
43663
45255
  });
43664
- Object.defineProperty(exports, "RULESYNC_PERMISSIONS_JSONC_FILE_NAME", {
45256
+ Object.defineProperty(exports, "RULESYNC_PERMISSIONS_LEGACY_FILE_NAME", {
43665
45257
  enumerable: true,
43666
45258
  get: function() {
43667
- return RULESYNC_PERMISSIONS_JSONC_FILE_NAME;
45259
+ return RULESYNC_PERMISSIONS_LEGACY_FILE_NAME;
43668
45260
  }
43669
45261
  });
43670
45262
  Object.defineProperty(exports, "RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH", {
@@ -43949,12 +45541,24 @@ Object.defineProperty(exports, "getProcessorRegistryEntry", {
43949
45541
  return getProcessorRegistryEntry;
43950
45542
  }
43951
45543
  });
45544
+ Object.defineProperty(exports, "getRulesyncSourceCandidates", {
45545
+ enumerable: true,
45546
+ get: function() {
45547
+ return getRulesyncSourceCandidates;
45548
+ }
45549
+ });
43952
45550
  Object.defineProperty(exports, "importFromTool", {
43953
45551
  enumerable: true,
43954
45552
  get: function() {
43955
45553
  return importFromTool;
43956
45554
  }
43957
45555
  });
45556
+ Object.defineProperty(exports, "isPackagingToolTarget", {
45557
+ enumerable: true,
45558
+ get: function() {
45559
+ return isPackagingToolTarget;
45560
+ }
45561
+ });
43958
45562
  Object.defineProperty(exports, "isSymlink", {
43959
45563
  enumerable: true,
43960
45564
  get: function() {
@@ -43973,6 +45577,12 @@ Object.defineProperty(exports, "loadYaml", {
43973
45577
  return loadYaml;
43974
45578
  }
43975
45579
  });
45580
+ Object.defineProperty(exports, "parseJsonc", {
45581
+ enumerable: true,
45582
+ get: function() {
45583
+ return parseJsonc$8;
45584
+ }
45585
+ });
43976
45586
  Object.defineProperty(exports, "readFileContent", {
43977
45587
  enumerable: true,
43978
45588
  get: function() {
@@ -44021,6 +45631,12 @@ Object.defineProperty(exports, "resolvePath", {
44021
45631
  return resolvePath;
44022
45632
  }
44023
45633
  });
45634
+ Object.defineProperty(exports, "resolveRulesyncSourceWritePath", {
45635
+ enumerable: true,
45636
+ get: function() {
45637
+ return resolveRulesyncSourceWritePath;
45638
+ }
45639
+ });
44024
45640
  Object.defineProperty(exports, "runWithDirectoryRollback", {
44025
45641
  enumerable: true,
44026
45642
  get: function() {