rulesync 14.2.0 → 15.0.1

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.
@@ -1,5 +1,5 @@
1
- import { minLength, optional, refine, z } from "zod/mini";
2
1
  import { ZodError } from "zod";
2
+ import { meta, minLength, nonnegative, optional, refine, z } from "zod/mini";
3
3
  import { cp, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
4
4
  import path, { basename, dirname, extname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
5
5
  import { parse, printParseErrorCode } from "jsonc-parser";
@@ -14,10 +14,39 @@ import { isDeepStrictEqual } from "node:util";
14
14
  import * as smolToml from "smol-toml";
15
15
  import { parse as parse$1, stringify } from "smol-toml";
16
16
  import { encode } from "@toon-format/toon";
17
+ //#region src/utils/error.ts
18
+ /**
19
+ * Convert various error types to a readable error message
20
+ * @param error Error instance (ZodError, Error, or unknown)
21
+ * @returns Human-readable error message
22
+ *
23
+ * @example
24
+ * // ZodError
25
+ * const result = schema.safeParse(data);
26
+ * if (!result.success) {
27
+ * throw new Error(`Validation failed: ${formatError(result.error)}`);
28
+ * }
29
+ *
30
+ * @example
31
+ * // Standard Error
32
+ * try {
33
+ * // some operation
34
+ * } catch (error) {
35
+ * console.error(formatError(error));
36
+ * }
37
+ */
38
+ function isZodErrorLike(error) {
39
+ 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");
40
+ }
41
+ function formatError(error) {
42
+ if (error instanceof ZodError || isZodErrorLike(error)) return `Zod raw error: ${JSON.stringify(error.issues)}`;
43
+ if (error instanceof Error) return `${error.name}: ${error.message}`;
44
+ return String(error);
45
+ }
46
+ //#endregion
17
47
  //#region src/types/features.ts
18
- const ALL_FEATURES = [
19
- "rules",
20
- "ignore",
48
+ const ACTIVE_FEATURES_BEFORE_IGNORE = ["rules"];
49
+ const ACTIVE_FEATURES_AFTER_IGNORE = [
21
50
  "mcp",
22
51
  "subagents",
23
52
  "commands",
@@ -26,9 +55,20 @@ const ALL_FEATURES = [
26
55
  "permissions",
27
56
  "checks"
28
57
  ];
58
+ const ALL_FEATURES = [
59
+ ...ACTIVE_FEATURES_BEFORE_IGNORE,
60
+ "ignore",
61
+ ...ACTIVE_FEATURES_AFTER_IGNORE
62
+ ];
29
63
  const ALL_FEATURES_WITH_WILDCARD = [...ALL_FEATURES, "*"];
30
- const FeatureSchema = z.enum(ALL_FEATURES);
64
+ const ACTIVE_FEATURES = [...ACTIVE_FEATURES_BEFORE_IGNORE, ...ACTIVE_FEATURES_AFTER_IGNORE];
65
+ const DeprecatedIgnoreFeatureSchema = z.literal("ignore").check(meta({
66
+ deprecated: true,
67
+ description: "Deprecated: use the permissions feature. Ignore remains supported for compatibility throughout Rulesync 14.x."
68
+ }));
69
+ const FeatureSchema = z.union([z.enum(ACTIVE_FEATURES), DeprecatedIgnoreFeatureSchema]);
31
70
  z.array(FeatureSchema);
71
+ const FeatureWithWildcardSchema = z.union([z.enum([...ACTIVE_FEATURES, "*"]), DeprecatedIgnoreFeatureSchema]);
32
72
  const GitignoreDestinationSchema = z.enum(["gitignore", "gitattributes"]);
33
73
  const FlattenedCommandNamingSchema = z.enum(["basename", "path"]);
34
74
  const FeatureOptionsSchema = z.record(z.string(), z.unknown());
@@ -38,8 +78,8 @@ const FeatureValueSchema = z.union([
38
78
  GitignoreDestinationSchema
39
79
  ]);
40
80
  const PerFeatureConfigSchema = z.record(z.string(), FeatureValueSchema);
41
- const PerTargetFeaturesValueSchema = z.union([z.array(z.enum(ALL_FEATURES_WITH_WILDCARD)), PerFeatureConfigSchema]);
42
- const RulesyncFeaturesSchema = z.array(z.enum(ALL_FEATURES_WITH_WILDCARD));
81
+ const PerTargetFeaturesValueSchema = z.union([z.array(FeatureWithWildcardSchema), PerFeatureConfigSchema]);
82
+ const RulesyncFeaturesSchema = z.array(FeatureWithWildcardSchema);
43
83
  /**
44
84
  * Returns true if a per-feature value enables the feature.
45
85
  *
@@ -61,36 +101,6 @@ const isFeatureValueEnabled = (value) => {
61
101
  return false;
62
102
  };
63
103
  //#endregion
64
- //#region src/utils/error.ts
65
- /**
66
- * Convert various error types to a readable error message
67
- * @param error Error instance (ZodError, Error, or unknown)
68
- * @returns Human-readable error message
69
- *
70
- * @example
71
- * // ZodError
72
- * const result = schema.safeParse(data);
73
- * if (!result.success) {
74
- * throw new Error(`Validation failed: ${formatError(result.error)}`);
75
- * }
76
- *
77
- * @example
78
- * // Standard Error
79
- * try {
80
- * // some operation
81
- * } catch (error) {
82
- * console.error(formatError(error));
83
- * }
84
- */
85
- function isZodErrorLike(error) {
86
- 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");
87
- }
88
- function formatError(error) {
89
- if (error instanceof ZodError || isZodErrorLike(error)) return `Zod raw error: ${JSON.stringify(error.issues)}`;
90
- if (error instanceof Error) return `${error.name}: ${error.message}`;
91
- return String(error);
92
- }
93
- //#endregion
94
104
  //#region src/constants/rulesync-paths.ts
95
105
  const { join: join$1 } = posix;
96
106
  const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
@@ -101,12 +111,12 @@ const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$1(RULESYNC_RULES_RELATIVE_
101
111
  const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "commands");
102
112
  const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "subagents");
103
113
  const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "checks");
104
- const RULESYNC_MCP_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
105
- const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
106
- const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
107
- const RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
108
- const RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
109
- const RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
114
+ const RULESYNC_MCP_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
115
+ const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
116
+ const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
117
+ join$1(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
118
+ const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
119
+ const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
110
120
  const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
111
121
  const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
112
122
  const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
@@ -115,12 +125,12 @@ const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "sk
115
125
  const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$1(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
116
126
  const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
117
127
  const RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync-npm.lock.json";
118
- const RULESYNC_MCP_FILE_NAME = "mcp.json";
119
- const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
120
- const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.json";
121
- const RULESYNC_MCP_JSONC_FILE_NAME = "mcp.jsonc";
122
- const RULESYNC_HOOKS_JSONC_FILE_NAME = "hooks.jsonc";
123
- const RULESYNC_PERMISSIONS_JSONC_FILE_NAME = "permissions.jsonc";
128
+ const RULESYNC_MCP_FILE_NAME = "mcp.jsonc";
129
+ const RULESYNC_HOOKS_FILE_NAME = "hooks.jsonc";
130
+ const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.jsonc";
131
+ const RULESYNC_MCP_LEGACY_FILE_NAME = "mcp.json";
132
+ const RULESYNC_HOOKS_LEGACY_FILE_NAME = "hooks.json";
133
+ const RULESYNC_PERMISSIONS_LEGACY_FILE_NAME = "permissions.json";
124
134
  const RULESYNC_CONFIG_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/config-schema.json";
125
135
  const RULESYNC_MCP_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/mcp-schema.json";
126
136
  const RULESYNC_PERMISSIONS_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/permissions-schema.json";
@@ -133,6 +143,7 @@ const rulesProcessorToolTargetTuple = [
133
143
  "amp",
134
144
  "antigravity-cli",
135
145
  "antigravity-ide",
146
+ "antigravity-plugin",
136
147
  "augmentcode",
137
148
  "augmentcode-legacy",
138
149
  "claudecode",
@@ -149,6 +160,7 @@ const rulesProcessorToolTargetTuple = [
149
160
  "hermesagent",
150
161
  "junie",
151
162
  "kilo",
163
+ "kimi-code",
152
164
  "kiro",
153
165
  "kiro-cli",
154
166
  "kiro-ide",
@@ -192,8 +204,10 @@ const mcpProcessorToolTargetTuple = [
192
204
  "amp",
193
205
  "antigravity-cli",
194
206
  "antigravity-ide",
207
+ "antigravity-plugin",
195
208
  "augmentcode",
196
209
  "claudecode",
210
+ "claudecode-plugin",
197
211
  "claudecode-legacy",
198
212
  "cline",
199
213
  "codexcli",
@@ -205,6 +219,7 @@ const mcpProcessorToolTargetTuple = [
205
219
  "goose",
206
220
  "grokcli",
207
221
  "hermesagent",
222
+ "kimi-code",
208
223
  "kilo",
209
224
  "kiro",
210
225
  "kiro-cli",
@@ -227,6 +242,7 @@ const commandsProcessorToolTargetTuple = [
227
242
  "antigravity-ide",
228
243
  "augmentcode",
229
244
  "claudecode",
245
+ "claudecode-plugin",
230
246
  "claudecode-legacy",
231
247
  "cline",
232
248
  "codexcli",
@@ -254,6 +270,7 @@ const subagentsProcessorToolTargetTuple = [
254
270
  "agentsmd",
255
271
  "augmentcode",
256
272
  "claudecode",
273
+ "claudecode-plugin",
257
274
  "claudecode-legacy",
258
275
  "cline",
259
276
  "codexcli",
@@ -266,6 +283,7 @@ const subagentsProcessorToolTargetTuple = [
266
283
  "goose",
267
284
  "grokcli",
268
285
  "hermesagent",
286
+ "kimi-code",
269
287
  "junie",
270
288
  "kiro",
271
289
  "kiro-cli",
@@ -285,8 +303,10 @@ const skillsProcessorToolTargetTuple = [
285
303
  "amp",
286
304
  "antigravity-cli",
287
305
  "antigravity-ide",
306
+ "antigravity-plugin",
288
307
  "augmentcode",
289
308
  "claudecode",
309
+ "claudecode-plugin",
290
310
  "claudecode-legacy",
291
311
  "cline",
292
312
  "codexcli",
@@ -298,6 +318,7 @@ const skillsProcessorToolTargetTuple = [
298
318
  "goose",
299
319
  "grokcli",
300
320
  "hermesagent",
321
+ "kimi-code",
301
322
  "junie",
302
323
  "kilo",
303
324
  "kiro",
@@ -320,9 +341,11 @@ const hooksProcessorToolTargetTuple = [
320
341
  "amp",
321
342
  "antigravity-cli",
322
343
  "antigravity-ide",
344
+ "antigravity-plugin",
323
345
  "kilo",
324
346
  "cursor",
325
347
  "claudecode",
348
+ "claudecode-plugin",
326
349
  "codexcli",
327
350
  "copilot",
328
351
  "copilotcli",
@@ -331,6 +354,7 @@ const hooksProcessorToolTargetTuple = [
331
354
  "factorydroid",
332
355
  "goose",
333
356
  "hermesagent",
357
+ "kimi-code",
334
358
  "deepagents",
335
359
  "kiro",
336
360
  "kiro-cli",
@@ -358,6 +382,7 @@ const permissionsProcessorToolTargetTuple = [
358
382
  "goose",
359
383
  "grokcli",
360
384
  "hermesagent",
385
+ "kimi-code",
361
386
  "junie",
362
387
  "kilo",
363
388
  "kiro",
@@ -388,6 +413,7 @@ const ALL_TOOL_TARGETS = [...new Set([
388
413
  ].flat())];
389
414
  const ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
390
415
  const ToolTargetSchema = z.enum(ALL_TOOL_TARGETS);
416
+ const PACKAGING_TOOL_TARGETS = ["antigravity-plugin", "claudecode-plugin"];
391
417
  z.array(ToolTargetSchema);
392
418
  const RulesyncTargetsSchema = z.array(z.enum(ALL_TOOL_TARGETS_WITH_WILDCARD));
393
419
  const RulesyncConfigTargetsObjectSchema = z.record(z.string(), PerTargetFeaturesValueSchema);
@@ -543,12 +569,12 @@ async function readFileBuffer(filepath) {
543
569
  return readFile(filepath);
544
570
  }
545
571
  /**
546
- * Adds exactly one trailing newline to content.
572
+ * Normalizes text to LF line endings and adds exactly one trailing newline.
547
573
  * Removes any existing trailing whitespace and appends a single newline.
548
574
  */
549
575
  function addTrailingNewline(content) {
550
576
  if (!content) return "\n";
551
- return content.trimEnd() + "\n";
577
+ return content.replaceAll("\r\n", "\n").replaceAll("\r", "\n").trimEnd() + "\n";
552
578
  }
553
579
  async function writeFileContent(filepath, content) {
554
580
  await ensureDir(dirname(filepath));
@@ -584,7 +610,7 @@ async function listDirectoryFiles(dir) {
584
610
  }
585
611
  }
586
612
  async function findFilesByGlobs(globs, options = {}) {
587
- const { type = "all" } = options;
613
+ const { type = "all", followSymbolicLinks = true } = options;
588
614
  const globbyOptions = type === "file" ? {
589
615
  onlyFiles: true,
590
616
  onlyDirectories: false
@@ -597,7 +623,7 @@ async function findFilesByGlobs(globs, options = {}) {
597
623
  };
598
624
  const results = globbySync(Array.isArray(globs) ? globs.map((g) => g.replaceAll("\\", "/")) : globs.replaceAll("\\", "/"), {
599
625
  absolute: true,
600
- followSymbolicLinks: true,
626
+ followSymbolicLinks,
601
627
  ...globbyOptions
602
628
  });
603
629
  const seenRealPaths = /* @__PURE__ */ new Set();
@@ -1010,12 +1036,13 @@ const CONFLICTING_TARGET_PAIRS = [["augmentcode", "augmentcode-legacy"], ["claud
1010
1036
  */
1011
1037
  const LEGACY_TARGETS = ["augmentcode-legacy", "claudecode-legacy"];
1012
1038
  /**
1013
- * Expand the wildcard target (`*`) to every non-legacy tool target. Legacy
1014
- * targets are excluded because they must be requested explicitly. Shared by
1015
- * `Config.getTargets()` and `extractConfigFileTargets()` so the two never drift.
1039
+ * Expand the wildcard target (`*`) to every ordinary non-legacy tool target.
1040
+ * Legacy aliases and package-root targets are excluded because they must be
1041
+ * requested explicitly. Shared by `Config.getTargets()` and
1042
+ * `extractConfigFileTargets()` so the two never drift.
1016
1043
  */
1017
1044
  function expandWildcardTargets() {
1018
- return ALL_TOOL_TARGETS.filter((target) => !LEGACY_TARGETS.includes(target));
1045
+ return ALL_TOOL_TARGETS.filter((target) => !LEGACY_TARGETS.includes(target) && !PACKAGING_TOOL_TARGETS.includes(target));
1019
1046
  }
1020
1047
  /**
1021
1048
  * Validates that the user-authored config does not double-define the
@@ -1165,7 +1192,7 @@ var Config = class Config {
1165
1192
  getTargets() {
1166
1193
  if (this.objectFormTargetKeys !== void 0) return this.objectFormTargetKeys;
1167
1194
  const arrayTargets = Array.isArray(this.targets) ? this.targets : [];
1168
- if (arrayTargets.includes("*")) return expandWildcardTargets();
1195
+ if (arrayTargets.includes("*")) return [.../* @__PURE__ */ new Set([...expandWildcardTargets(), ...arrayTargets.filter((target) => target !== "*")])];
1169
1196
  return arrayTargets.filter((target) => target !== "*");
1170
1197
  }
1171
1198
  getConfigFileTargets() {
@@ -1547,7 +1574,7 @@ function extractConfigFileTargets(targets) {
1547
1574
  if (targets === void 0) return void 0;
1548
1575
  const validTargets = new Set(ALL_TOOL_TARGETS);
1549
1576
  if (isRulesyncConfigTargetsObject(targets)) return Object.keys(targets).filter((key) => validTargets.has(key));
1550
- if (targets.includes("*")) return expandWildcardTargets();
1577
+ if (targets.includes("*")) return [.../* @__PURE__ */ new Set([...expandWildcardTargets(), ...targets.filter((key) => key !== "*" && validTargets.has(key))])];
1551
1578
  return targets.filter((key) => key !== "*" && validTargets.has(key));
1552
1579
  }
1553
1580
  //#endregion
@@ -1943,7 +1970,7 @@ const hasControlChars = (val) => CONTROL_CHARS.some((char) => val.includes(char)
1943
1970
  const safeString = z.pipe(z.string(), z.custom((val) => typeof val === "string" && !hasControlChars(val), "must not contain newline, carriage return, or NUL characters"));
1944
1971
  /**
1945
1972
  * Canonical hook definition.
1946
- * Used in .rulesync/hooks.json and mapped to tool-specific formats.
1973
+ * Used in .rulesync/hooks.jsonc and mapped to tool-specific formats.
1947
1974
  */
1948
1975
  const HookDefinitionSchema = z.looseObject({
1949
1976
  command: z.optional(safeString),
@@ -1957,6 +1984,7 @@ const HookDefinitionSchema = z.looseObject({
1957
1984
  ])),
1958
1985
  url: z.optional(safeString),
1959
1986
  timeout: z.optional(z.number()),
1987
+ cacheTtl: z.optional(z.number().check(nonnegative())),
1960
1988
  matcher: z.optional(safeString),
1961
1989
  prompt: z.optional(safeString),
1962
1990
  loop_limit: z.optional(z.nullable(z.number())),
@@ -2496,6 +2524,51 @@ const GROKCLI_HOOK_EVENTS = [
2496
2524
  "postCompact"
2497
2525
  ];
2498
2526
  /**
2527
+ * Hook events supported by Kimi Code.
2528
+ *
2529
+ * Kimi Code also exposes `Interrupt`, which has no canonical rulesync event.
2530
+ *
2531
+ * @see https://moonshotai.github.io/kimi-code/en/customization/hooks.html
2532
+ */
2533
+ const KIMI_CODE_HOOK_EVENTS = [
2534
+ "sessionStart",
2535
+ "sessionEnd",
2536
+ "beforeSubmitPrompt",
2537
+ "preToolUse",
2538
+ "postToolUse",
2539
+ "postToolUseFailure",
2540
+ "permissionRequest",
2541
+ "stop",
2542
+ "stopFailure",
2543
+ "notification",
2544
+ "subagentStart",
2545
+ "subagentStop",
2546
+ "preCompact",
2547
+ "postCompact"
2548
+ ];
2549
+ const CANONICAL_TO_KIMI_CODE_EVENT_NAMES = {
2550
+ sessionStart: "SessionStart",
2551
+ sessionEnd: "SessionEnd",
2552
+ beforeSubmitPrompt: "UserPromptSubmit",
2553
+ preToolUse: "PreToolUse",
2554
+ postToolUse: "PostToolUse",
2555
+ postToolUseFailure: "PostToolUseFailure",
2556
+ permissionRequest: "PermissionRequest",
2557
+ stop: "Stop",
2558
+ stopFailure: "StopFailure",
2559
+ notification: "Notification",
2560
+ subagentStart: "SubagentStart",
2561
+ subagentStop: "SubagentStop",
2562
+ preCompact: "PreCompact",
2563
+ postCompact: "PostCompact"
2564
+ };
2565
+ const KIMI_CODE_NATIVE_HOOK_EVENTS = [
2566
+ ...Object.values(CANONICAL_TO_KIMI_CODE_EVENT_NAMES),
2567
+ "PermissionResult",
2568
+ "Interrupt"
2569
+ ];
2570
+ const KIMI_CODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_KIMI_CODE_EVENT_NAMES).map(([canonical, kimiCode]) => [kimiCode, canonical]));
2571
+ /**
2499
2572
  * Hook events supported by Hermes Agent's native Shell Hooks system.
2500
2573
  *
2501
2574
  * Hermes validates hook events against a fixed `VALID_HOOKS` set:
@@ -2586,6 +2659,7 @@ const HooksConfigSchema = z.looseObject({
2586
2659
  vibe: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
2587
2660
  reasonix: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
2588
2661
  grokcli: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
2662
+ "kimi-code": z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
2589
2663
  qwencode: z.optional(z.looseObject({
2590
2664
  hooks: z.optional(hooksRecordSchema),
2591
2665
  disableAllHooks: z.optional(z.boolean())
@@ -3112,6 +3186,28 @@ function parseJsonc(content) {
3112
3186
  return deepSanitize(result);
3113
3187
  }
3114
3188
  //#endregion
3189
+ //#region src/utils/rulesync-source-path.ts
3190
+ function getRulesyncSourceCandidates({ paths }) {
3191
+ return [paths.recommended, ...paths.legacy];
3192
+ }
3193
+ async function resolveRulesyncSourceWritePath({ outputRoot, paths }) {
3194
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3195
+ const targetPath = join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3196
+ if (await fileExists(targetPath)) {
3197
+ await assertWritablePathInsideRoot({
3198
+ rootPath: outputRoot,
3199
+ targetPath
3200
+ });
3201
+ return candidate;
3202
+ }
3203
+ }
3204
+ await assertWritablePathInsideRoot({
3205
+ rootPath: outputRoot,
3206
+ targetPath: join(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath)
3207
+ });
3208
+ return paths.recommended;
3209
+ }
3210
+ //#endregion
3115
3211
  //#region src/features/hooks/rulesync-hooks.ts
3116
3212
  var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3117
3213
  json;
@@ -3125,12 +3221,14 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3125
3221
  }
3126
3222
  static getSettablePaths() {
3127
3223
  return {
3128
- relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3129
- relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
3130
- jsonc: {
3224
+ recommended: {
3131
3225
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3132
- relativeFilePath: RULESYNC_HOOKS_JSONC_FILE_NAME
3133
- }
3226
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME
3227
+ },
3228
+ legacy: [{
3229
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3230
+ relativeFilePath: RULESYNC_HOOKS_LEGACY_FILE_NAME
3231
+ }]
3134
3232
  };
3135
3233
  }
3136
3234
  validate() {
@@ -3146,11 +3244,7 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3146
3244
  }
3147
3245
  static async fromFile({ outputRoot = process.cwd(), validate = true }) {
3148
3246
  const paths = RulesyncHooks.getSettablePaths();
3149
- const candidates = [paths.jsonc, {
3150
- relativeDirPath: paths.relativeDirPath,
3151
- relativeFilePath: paths.relativeFilePath
3152
- }];
3153
- for (const candidate of candidates) {
3247
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3154
3248
  const filePath = join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3155
3249
  if (!await fileExists(filePath)) continue;
3156
3250
  const fileContent = await readFileContent(filePath);
@@ -3162,7 +3256,7 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
3162
3256
  validate
3163
3257
  });
3164
3258
  }
3165
- throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} or ${RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH} found.`);
3259
+ throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} or ${RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH} found.`);
3166
3260
  }
3167
3261
  getJson() {
3168
3262
  return this.json;
@@ -3280,8 +3374,8 @@ const RulesyncMcpConfigSchema = z.object({ mcpServers: z.record(z.string(), Rule
3280
3374
  * Tool-scoped MCP block: servers that apply only to one tool. A named entry
3281
3375
  * replaces/adds the same-named shared server wholesale for that tool; `null`
3282
3376
  * removes the shared server for that tool. Mirrors `{toolname}.hooks` in
3283
- * `.rulesync/hooks.json` and `{toolname}.permission` in
3284
- * `.rulesync/permissions.json`.
3377
+ * `.rulesync/hooks.jsonc` and `{toolname}.permission` in
3378
+ * `.rulesync/permissions.jsonc`.
3285
3379
  */
3286
3380
  const toolScopedMcpSchema = z.looseObject({ mcpServers: z.optional(z.record(z.string(), z.nullable(RulesyncMcpServerSchema))) });
3287
3381
  const RulesyncMcpFileSchema = z.looseObject({
@@ -3306,6 +3400,7 @@ const RulesyncMcpFileSchema = z.looseObject({
3306
3400
  hermesagent: z.optional(toolScopedMcpSchema),
3307
3401
  junie: z.optional(toolScopedMcpSchema),
3308
3402
  kilo: z.optional(toolScopedMcpSchema),
3403
+ "kimi-code": z.optional(toolScopedMcpSchema),
3309
3404
  kiro: z.optional(toolScopedMcpSchema),
3310
3405
  opencode: z.optional(toolScopedMcpSchema),
3311
3406
  qwencode: z.optional(toolScopedMcpSchema),
@@ -3333,14 +3428,13 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
3333
3428
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3334
3429
  relativeFilePath: RULESYNC_MCP_FILE_NAME
3335
3430
  },
3336
- jsonc: {
3431
+ legacy: [{
3337
3432
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3338
- relativeFilePath: RULESYNC_MCP_JSONC_FILE_NAME
3339
- },
3340
- legacy: {
3433
+ relativeFilePath: RULESYNC_MCP_LEGACY_FILE_NAME
3434
+ }, {
3341
3435
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
3342
3436
  relativeFilePath: ".mcp.json"
3343
- }
3437
+ }]
3344
3438
  };
3345
3439
  }
3346
3440
  validate() {
@@ -3356,41 +3450,23 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
3356
3450
  }
3357
3451
  static async fromFile({ outputRoot = process.cwd(), validate = true, logger }) {
3358
3452
  const paths = this.getSettablePaths();
3359
- const recommendedPath = join(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
3360
- const jsoncPath = join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);
3361
- const legacyPath = join(outputRoot, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
3362
- if (await fileExists(jsoncPath)) {
3363
- const fileContent = await readFileContent(jsoncPath);
3364
- return new RulesyncMcp({
3365
- outputRoot,
3366
- relativeDirPath: paths.jsonc.relativeDirPath,
3367
- relativeFilePath: paths.jsonc.relativeFilePath,
3368
- fileContent,
3369
- validate
3370
- });
3371
- }
3372
- if (await fileExists(recommendedPath)) {
3373
- const fileContent = await readFileContent(recommendedPath);
3374
- return new RulesyncMcp({
3375
- outputRoot,
3376
- relativeDirPath: paths.recommended.relativeDirPath,
3377
- relativeFilePath: paths.recommended.relativeFilePath,
3378
- fileContent,
3379
- validate
3380
- });
3381
- }
3382
- if (await fileExists(legacyPath)) {
3383
- logger?.warn(`⚠️ Using deprecated path "${legacyPath}". Please migrate to "${recommendedPath}"`);
3384
- const fileContent = await readFileContent(legacyPath);
3453
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
3454
+ const filePath = join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
3455
+ if (!await fileExists(filePath)) continue;
3456
+ if (candidate.relativeFilePath === ".mcp.json") {
3457
+ const recommendedPath = join(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
3458
+ logger?.warn(`⚠️ Using deprecated path "${filePath}". Please migrate to "${recommendedPath}"`);
3459
+ }
3460
+ const fileContent = await readFileContent(filePath);
3385
3461
  return new RulesyncMcp({
3386
3462
  outputRoot,
3387
- relativeDirPath: paths.legacy.relativeDirPath,
3388
- relativeFilePath: paths.legacy.relativeFilePath,
3463
+ relativeDirPath: candidate.relativeDirPath,
3464
+ relativeFilePath: candidate.relativeFilePath,
3389
3465
  fileContent,
3390
3466
  validate
3391
3467
  });
3392
3468
  }
3393
- const fileContent = await readFileContent(recommendedPath);
3469
+ const fileContent = await readFileContent(join(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath));
3394
3470
  return new RulesyncMcp({
3395
3471
  outputRoot,
3396
3472
  relativeDirPath: paths.recommended.relativeDirPath,
@@ -3591,7 +3667,7 @@ const PermissionRulesSchema = z.record(z.string(), PermissionActionSchema);
3591
3667
  * key it appears under. During generation the categories placed here are
3592
3668
  * merged over the shared `permission` block per category (the tool-scoped
3593
3669
  * category replaces the shared one wholesale), mirroring how
3594
- * `.rulesync/hooks.json` merges `{toolname}.hooks` per event.
3670
+ * `.rulesync/hooks.jsonc` merges `{toolname}.hooks` per event.
3595
3671
  *
3596
3672
  * @example
3597
3673
  * { "claudecode": { "permission": { "bash": { "git push *": "deny" } } } }
@@ -3604,6 +3680,25 @@ const ToolScopedPermissionSchema = z.record(z.string(), PermissionRulesSchema);
3604
3680
  * added without a schema break.
3605
3681
  */
3606
3682
  const CanonicalPermissionsOverrideSchema = z.looseObject({ permission: z.optional(ToolScopedPermissionSchema) });
3683
+ const KimiCodePermissionsOverrideSchema = z.looseObject({
3684
+ permission: z.optional(ToolScopedPermissionSchema),
3685
+ defaultPermissionMode: z.optional(z.enum([
3686
+ "manual",
3687
+ "yolo",
3688
+ "auto"
3689
+ ])),
3690
+ rules: z.optional(z.array(z.looseObject({
3691
+ decision: PermissionActionSchema,
3692
+ pattern: z.string(),
3693
+ scope: z.optional(z.enum([
3694
+ "turn-override",
3695
+ "session-runtime",
3696
+ "project",
3697
+ "user"
3698
+ ])),
3699
+ reason: z.optional(z.string())
3700
+ })))
3701
+ });
3607
3702
  /**
3608
3703
  * OpenCode-specific permission value. Unlike the shared canonical block, which
3609
3704
  * only accepts a pattern-to-action map, OpenCode also allows a bare action
@@ -4195,6 +4290,7 @@ const PermissionsConfigSchema = z.looseObject({
4195
4290
  devin: z.optional(CanonicalPermissionsOverrideSchema),
4196
4291
  goose: z.optional(CanonicalPermissionsOverrideSchema),
4197
4292
  grokcli: z.optional(CanonicalPermissionsOverrideSchema),
4293
+ "kimi-code": z.optional(KimiCodePermissionsOverrideSchema),
4198
4294
  rovodev: z.optional(CanonicalPermissionsOverrideSchema),
4199
4295
  zed: z.optional(CanonicalPermissionsOverrideSchema)
4200
4296
  });
@@ -4219,12 +4315,14 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4219
4315
  }
4220
4316
  static getSettablePaths() {
4221
4317
  return {
4222
- relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4223
- relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
4224
- jsonc: {
4318
+ recommended: {
4225
4319
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4226
- relativeFilePath: RULESYNC_PERMISSIONS_JSONC_FILE_NAME
4227
- }
4320
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME
4321
+ },
4322
+ legacy: [{
4323
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
4324
+ relativeFilePath: RULESYNC_PERMISSIONS_LEGACY_FILE_NAME
4325
+ }]
4228
4326
  };
4229
4327
  }
4230
4328
  validate() {
@@ -4240,11 +4338,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4240
4338
  }
4241
4339
  static async fromFile({ outputRoot = process.cwd(), validate = true }) {
4242
4340
  const paths = RulesyncPermissions.getSettablePaths();
4243
- const candidates = [paths.jsonc, {
4244
- relativeDirPath: paths.relativeDirPath,
4245
- relativeFilePath: paths.relativeFilePath
4246
- }];
4247
- for (const candidate of candidates) {
4341
+ for (const candidate of getRulesyncSourceCandidates({ paths })) {
4248
4342
  const filePath = join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
4249
4343
  if (!await fileExists(filePath)) continue;
4250
4344
  const fileContent = await readFileContent(filePath);
@@ -4256,7 +4350,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4256
4350
  validate
4257
4351
  });
4258
4352
  }
4259
- throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} or ${RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH} found.`);
4353
+ throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} or ${RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH} found.`);
4260
4354
  }
4261
4355
  getJson() {
4262
4356
  return this.json;
@@ -4266,7 +4360,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
4266
4360
  * tool-scoped `{toolname}.permission` block over the shared `permission`
4267
4361
  * block, per category (the tool-scoped category replaces the shared one
4268
4362
  * wholesale — mirroring how `{toolname}.hooks` merges per event in
4269
- * `.rulesync/hooks.json`). The consumed `permission` key is stripped from
4363
+ * `.rulesync/hooks.jsonc`). The consumed `permission` key is stripped from
4270
4364
  * the override block so verbatim-passthrough translators (e.g. the Hermes
4271
4365
  * deep merge or the Codex CLI top-level key whitelist) never see it.
4272
4366
  *
@@ -4631,6 +4725,16 @@ const RulesyncSkillFrontmatterSchema = z.looseObject({
4631
4725
  "disable-model-invocation": z.optional(z.boolean()),
4632
4726
  "user-invocable": z.optional(z.boolean())
4633
4727
  })),
4728
+ "kimi-code": z.optional(z.looseObject({
4729
+ type: z.optional(z.enum([
4730
+ "prompt",
4731
+ "inline",
4732
+ "flow"
4733
+ ])),
4734
+ whenToUse: z.optional(z.string()),
4735
+ disableModelInvocation: z.optional(z.boolean()),
4736
+ arguments: z.optional(z.union([z.string(), z.array(z.string())]))
4737
+ })),
4634
4738
  agentsskills: z.optional(z.looseObject({
4635
4739
  license: z.optional(z.string()),
4636
4740
  compatibility: z.optional(z.union([z.string(), z.looseObject({})])),
@@ -6332,6 +6436,28 @@ var ClaudecodeCommand = class ClaudecodeCommand extends ToolCommand {
6332
6436
  }
6333
6437
  };
6334
6438
  //#endregion
6439
+ //#region src/constants/plugin-paths.ts
6440
+ const CLAUDECODE_PLUGIN_COMMANDS_DIR = "commands";
6441
+ const CLAUDECODE_PLUGIN_AGENTS_DIR = "agents";
6442
+ const CLAUDECODE_PLUGIN_SKILLS_DIR = "skills";
6443
+ const CLAUDECODE_PLUGIN_HOOKS_DIR = "hooks";
6444
+ const CLAUDECODE_PLUGIN_HOOKS_FILE_NAME = "hooks.json";
6445
+ const ANTIGRAVITY_PLUGIN_RULES_DIR = "rules";
6446
+ const ANTIGRAVITY_PLUGIN_SKILLS_DIR = "skills";
6447
+ const ANTIGRAVITY_PLUGIN_MCP_FILE_NAME = "mcp_config.json";
6448
+ const ANTIGRAVITY_PLUGIN_HOOKS_FILE_NAME = "hooks.json";
6449
+ //#endregion
6450
+ //#region src/features/commands/claudecode-plugin-command.ts
6451
+ var ClaudecodePluginCommand = class extends ClaudecodeCommand {
6452
+ static isTargetedByRulesyncCommand(rulesyncCommand) {
6453
+ const targets = rulesyncCommand.getFrontmatter().targets;
6454
+ return targets.includes("*") || targets.includes("claudecode-plugin");
6455
+ }
6456
+ static getSettablePaths() {
6457
+ return { relativeDirPath: CLAUDECODE_PLUGIN_COMMANDS_DIR };
6458
+ }
6459
+ };
6460
+ //#endregion
6335
6461
  //#region src/constants/cline-paths.ts
6336
6462
  const CLINE_DIR = ".cline";
6337
6463
  const CLINERULES_DIR = ".clinerules";
@@ -7347,6 +7473,7 @@ const TAKT_CONFIG_SHARED_FILE_KEY = ".takt/config.yaml";
7347
7473
  const CODEXCLI_CONFIG_SHARED_FILE_KEY = ".codex/config.toml";
7348
7474
  const GROKCLI_CONFIG_SHARED_FILE_KEY = ".grok/config.toml";
7349
7475
  const VIBE_CONFIG_SHARED_FILE_KEY = ".vibe/config.toml";
7476
+ const KIMI_CODE_CONFIG_SHARED_FILE_KEY = ".kimi-code/config.toml";
7350
7477
  const REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY = "reasonix.toml";
7351
7478
  const REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY = ".reasonix/config.toml";
7352
7479
  /**
@@ -7691,6 +7818,20 @@ const SHARED_CONFIG_OWNERSHIP = {
7691
7818
  }
7692
7819
  }
7693
7820
  },
7821
+ [KIMI_CODE_CONFIG_SHARED_FILE_KEY]: {
7822
+ format: "toml",
7823
+ invalidRootPolicy: "error",
7824
+ features: {
7825
+ hooks: {
7826
+ kind: "replace-owned-keys",
7827
+ ownedKeys: ["hooks"]
7828
+ },
7829
+ permissions: {
7830
+ kind: "replace-owned-keys",
7831
+ ownedKeys: ["permission", "default_permission_mode"]
7832
+ }
7833
+ }
7834
+ },
7694
7835
  [REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY]: {
7695
7836
  format: "toml",
7696
7837
  features: {
@@ -7825,6 +7966,10 @@ const applyPermissions = (params) => {
7825
7966
  function toolSkillSearchRoots(paths) {
7826
7967
  return [paths.relativeDirPath, ...paths.alternativeSkillRoots ?? []];
7827
7968
  }
7969
+ /** Ordered import roots: managed roots first, followed by read-only discovery roots. */
7970
+ function toolSkillImportRoots(paths) {
7971
+ return [...toolSkillSearchRoots(paths), ...paths.importOnlySkillRoots ?? []];
7972
+ }
7828
7973
  /**
7829
7974
  * Abstract base class for AI development tool-specific skill formats.
7830
7975
  *
@@ -7907,6 +8052,13 @@ var ToolSkill = class extends AiDir {
7907
8052
  throw new Error("Please implement this method in the subclass.");
7908
8053
  }
7909
8054
  /**
8055
+ * Identity used to resolve duplicates across discovery roots during import.
8056
+ * Most tools identify a skill by its directory name.
8057
+ */
8058
+ getImportIdentity() {
8059
+ return this.getDirName();
8060
+ }
8061
+ /**
7910
8062
  * Load and parse skill directory content.
7911
8063
  * This is a helper method that handles the common logic of reading SKILL.md,
7912
8064
  * parsing frontmatter, and collecting other files.
@@ -8658,6 +8810,7 @@ const KIRO_IDE_HOOKS_DIR_PATH = join(KIRO_DIR, "hooks");
8658
8810
  const KIRO_IDE_HOOKS_FILE_NAME = "rulesync.json";
8659
8811
  const KIRO_MCP_FILE_NAME = "mcp.json";
8660
8812
  const KIRO_IGNORE_FILE_NAME = ".kiroignore";
8813
+ const KIRO_GLOBAL_IGNORE_FILE_NAME = "kiroignore";
8661
8814
  //#endregion
8662
8815
  //#region src/features/commands/kiro-command.ts
8663
8816
  var KiroCommand = class KiroCommand extends ToolCommand {
@@ -9938,6 +10091,16 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
9938
10091
  supportsSubdirectory: true
9939
10092
  }
9940
10093
  }],
10094
+ ["claudecode-plugin", {
10095
+ class: ClaudecodePluginCommand,
10096
+ meta: {
10097
+ extension: "md",
10098
+ supportsProject: true,
10099
+ supportsGlobal: false,
10100
+ isSimulated: false,
10101
+ supportsSubdirectory: true
10102
+ }
10103
+ }],
9941
10104
  ["claudecode-legacy", {
9942
10105
  class: ClaudecodeCommand,
9943
10106
  meta: {
@@ -10475,7 +10638,7 @@ var ToolHooks = class extends ToolFile {
10475
10638
  return new RulesyncHooks({
10476
10639
  outputRoot: this.outputRoot,
10477
10640
  relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
10478
- relativeFilePath: "hooks.json",
10641
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
10479
10642
  fileContent: fileContent ?? this.fileContent
10480
10643
  });
10481
10644
  }
@@ -10572,7 +10735,7 @@ function isToolMatcherEntry(x) {
10572
10735
  /**
10573
10736
  * Filter the shared canonical hooks to the supported events and merge tool overrides on top.
10574
10737
  */
10575
- function buildEffectiveHooks$1({ config, toolOverrideHooks, supportedEvents }) {
10738
+ function buildEffectiveHooks$2({ config, toolOverrideHooks, supportedEvents }) {
10576
10739
  const supported = new Set(supportedEvents);
10577
10740
  const sharedHooks = {};
10578
10741
  for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) sharedHooks[event] = defs;
@@ -10702,7 +10865,7 @@ function buildToolHooks({ defs, converterConfig }) {
10702
10865
  * (e.g. beforeSubmitPrompt → UserPromptSubmit).
10703
10866
  */
10704
10867
  function canonicalToToolHooks({ config, toolOverrideHooks, converterConfig, logger }) {
10705
- const effectiveHooks = buildEffectiveHooks$1({
10868
+ const effectiveHooks = buildEffectiveHooks$2({
10706
10869
  config,
10707
10870
  toolOverrideHooks,
10708
10871
  supportedEvents: converterConfig.supportedEvents
@@ -10839,7 +11002,7 @@ function toolMatcherEntryToCanonical({ rawEntry, converterConfig }) {
10839
11002
  }
10840
11003
  /**
10841
11004
  * Assemble the canonical hooks config a tool importer writes to
10842
- * `.rulesync/hooks.json`.
11005
+ * `.rulesync/hooks.jsonc`.
10843
11006
  *
10844
11007
  * The top-level `hooks` record only accepts canonical event names, so any
10845
11008
  * imported native event key without a canonical mapping is moved under the
@@ -11042,6 +11205,16 @@ var AntigravityCliHooks = class extends AntigravityHooks {
11042
11205
  }
11043
11206
  };
11044
11207
  //#endregion
11208
+ //#region src/features/hooks/antigravity-plugin-hooks.ts
11209
+ var AntigravityPluginHooks = class extends AntigravityIdeHooks {
11210
+ static getSettablePaths() {
11211
+ return {
11212
+ relativeDirPath: ".",
11213
+ relativeFilePath: ANTIGRAVITY_PLUGIN_HOOKS_FILE_NAME
11214
+ };
11215
+ }
11216
+ };
11217
+ //#endregion
11045
11218
  //#region src/utils/augmentcode-settings.ts
11046
11219
  /**
11047
11220
  * Top-level keys AugmentCode *replaces* (higher-precedence wins wholesale)
@@ -11267,7 +11440,7 @@ const CLAUDE_CONVERTER_CONFIG = {
11267
11440
  tool: "if"
11268
11441
  }]
11269
11442
  };
11270
- var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11443
+ var ClaudecodeHooks = class extends ToolHooks {
11271
11444
  constructor(params) {
11272
11445
  super({
11273
11446
  ...params,
@@ -11284,9 +11457,9 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11284
11457
  };
11285
11458
  }
11286
11459
  static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
11287
- const paths = ClaudecodeHooks.getSettablePaths({ global });
11460
+ const paths = this.getSettablePaths({ global });
11288
11461
  const fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
11289
- return new ClaudecodeHooks({
11462
+ return new this({
11290
11463
  outputRoot,
11291
11464
  relativeDirPath: paths.relativeDirPath,
11292
11465
  relativeFilePath: paths.relativeFilePath,
@@ -11295,7 +11468,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11295
11468
  });
11296
11469
  }
11297
11470
  static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
11298
- const paths = ClaudecodeHooks.getSettablePaths({ global });
11471
+ const paths = this.getSettablePaths({ global });
11299
11472
  const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
11300
11473
  const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
11301
11474
  const config = rulesyncHooks.getJson();
@@ -11311,7 +11484,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11311
11484
  }) },
11312
11485
  filePath
11313
11486
  });
11314
- return new ClaudecodeHooks({
11487
+ return new this({
11315
11488
  outputRoot,
11316
11489
  relativeDirPath: paths.relativeDirPath,
11317
11490
  relativeFilePath: paths.relativeFilePath,
@@ -11342,7 +11515,7 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11342
11515
  };
11343
11516
  }
11344
11517
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
11345
- return new ClaudecodeHooks({
11518
+ return new this({
11346
11519
  outputRoot,
11347
11520
  relativeDirPath,
11348
11521
  relativeFilePath,
@@ -11352,6 +11525,19 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
11352
11525
  }
11353
11526
  };
11354
11527
  //#endregion
11528
+ //#region src/features/hooks/claudecode-plugin-hooks.ts
11529
+ var ClaudecodePluginHooks = class extends ClaudecodeHooks {
11530
+ isDeletable() {
11531
+ return true;
11532
+ }
11533
+ static getSettablePaths() {
11534
+ return {
11535
+ relativeDirPath: CLAUDECODE_PLUGIN_HOOKS_DIR,
11536
+ relativeFilePath: CLAUDECODE_PLUGIN_HOOKS_FILE_NAME
11537
+ };
11538
+ }
11539
+ };
11540
+ //#endregion
11355
11541
  //#region src/features/hooks/codexcli-hooks.ts
11356
11542
  const CODEXCLI_CONVERTER_CONFIG = {
11357
11543
  supportedEvents: CODEXCLI_HOOK_EVENTS,
@@ -12718,7 +12904,7 @@ const HERMESAGENT_MATCHER_EVENTS = /* @__PURE__ */ new Set(["preToolUse", "postT
12718
12904
  * Filter the shared canonical hooks to the events Hermes understands and merge
12719
12905
  * the `hermesagent`-specific override block on top.
12720
12906
  */
12721
- function buildEffectiveHooks(config, toolOverrideHooks) {
12907
+ function buildEffectiveHooks$1(config, toolOverrideHooks) {
12722
12908
  const supported = new Set(HERMESAGENT_HOOK_EVENTS);
12723
12909
  const shared = {};
12724
12910
  for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) shared[event] = defs;
@@ -12740,7 +12926,7 @@ function buildEffectiveHooks(config, toolOverrideHooks) {
12740
12926
  * matcher-less lifecycle events.
12741
12927
  */
12742
12928
  function canonicalToHermesHooks({ config, toolOverrideHooks, logger }) {
12743
- const effectiveHooks = buildEffectiveHooks(config, toolOverrideHooks);
12929
+ const effectiveHooks = buildEffectiveHooks$1(config, toolOverrideHooks);
12744
12930
  const result = {};
12745
12931
  for (const [canonicalEvent, defs] of Object.entries(effectiveHooks)) {
12746
12932
  const nativeEvent = CANONICAL_TO_HERMESAGENT_EVENT_NAMES[canonicalEvent];
@@ -13180,6 +13366,197 @@ var KiloHooks = class KiloHooks extends ToolHooks {
13180
13366
  }
13181
13367
  };
13182
13368
  //#endregion
13369
+ //#region src/constants/kimi-code-paths.ts
13370
+ const KIMI_CODE_DIR = ".kimi-code";
13371
+ const KIMI_CODE_RULE_FILE_NAME = "AGENTS.md";
13372
+ const KIMI_CODE_MCP_FILE_NAME = "mcp.json";
13373
+ const KIMI_CODE_CONFIG_FILE_NAME = "config.toml";
13374
+ const KIMI_CODE_SKILLS_DIR_NAME = "skills";
13375
+ const KIMI_CODE_AGENTS_DIR_NAME = "agents";
13376
+ const KIMI_CODE_SKILLS_DIR_PATH = join(KIMI_CODE_DIR, KIMI_CODE_SKILLS_DIR_NAME);
13377
+ join(KIMI_CODE_DIR, KIMI_CODE_AGENTS_DIR_NAME);
13378
+ const KIMI_CODE_SHARED_SKILLS_DIR_PATH = join(".agents", "skills");
13379
+ const KIMI_CODE_SHARED_AGENTS_DIR_PATH = join(".agents", "agents");
13380
+ //#endregion
13381
+ //#region src/utils/kimi-code.ts
13382
+ function getKimiCodeHome() {
13383
+ const configuredHome = process.env.KIMI_CODE_HOME?.trim();
13384
+ return configuredHome ? resolve(configuredHome) : void 0;
13385
+ }
13386
+ function resolveToolOutputRoot({ outputRoot, toolTarget, global }) {
13387
+ return toolTarget === "kimi-code" && global ? getKimiCodeHome() ?? outputRoot : outputRoot;
13388
+ }
13389
+ function getKimiCodeRelativeDirPath({ global, relativeDirPath = "." }) {
13390
+ return global && getKimiCodeHome() ? relativeDirPath : join(KIMI_CODE_DIR, relativeDirPath);
13391
+ }
13392
+ function getKimiCodeRulesyncOutputRoot({ nativeOutputRoot, global }) {
13393
+ return global && getKimiCodeHome() ? getHomeDirectory() : nativeOutputRoot;
13394
+ }
13395
+ //#endregion
13396
+ //#region src/features/hooks/kimi-code-hooks.ts
13397
+ function runFromTrustedDirectory({ command, trustedDirectory }) {
13398
+ if (process.platform === "win32") return `set "RULESYNC_KIMI_HOOK_CWD=1" && cd /d "${trustedDirectory.replaceAll("%", "%%").replaceAll("\"", "\"\"")}" && ${command}`;
13399
+ return `export RULESYNC_KIMI_HOOK_CWD=1 && cd -- '${trustedDirectory.replaceAll("'", `'"'"'`)}' && ${command}`;
13400
+ }
13401
+ function stripTrustedDirectoryWrapper(command) {
13402
+ const posix = command.match(/^export RULESYNC_KIMI_HOOK_CWD=1 && cd -- '(?:[^']|'"'"')*' && ([\s\S]*)$/);
13403
+ if (posix?.[1]) return posix[1];
13404
+ return command.match(/^set "RULESYNC_KIMI_HOOK_CWD=1" && cd \/d "(?:""|[^"])*" && ([\s\S]*)$/)?.[1] ?? command;
13405
+ }
13406
+ function buildEffectiveHooks(config, toolOverrideHooks) {
13407
+ const supported = new Set(KIMI_CODE_HOOK_EVENTS);
13408
+ const shared = {};
13409
+ for (const [event, definitions] of Object.entries(config.hooks)) if (supported.has(event)) shared[event] = definitions;
13410
+ return {
13411
+ ...shared,
13412
+ ...toolOverrideHooks
13413
+ };
13414
+ }
13415
+ function canonicalToKimiCodeHooks({ config, toolOverrideHooks, trustedDirectory, logger }) {
13416
+ const result = [];
13417
+ const nativeEvents = new Set(KIMI_CODE_NATIVE_HOOK_EVENTS);
13418
+ for (const [event, definitions] of Object.entries(buildEffectiveHooks(config, toolOverrideHooks))) {
13419
+ const nativeEvent = CANONICAL_TO_KIMI_CODE_EVENT_NAMES[event] ?? event;
13420
+ if (!nativeEvents.has(nativeEvent)) {
13421
+ logger?.warn(`Kimi Code hooks: skipping unsupported event "${event}".`);
13422
+ continue;
13423
+ }
13424
+ for (const definition of definitions) {
13425
+ if ((definition.type ?? "command") !== "command" || !definition.command) continue;
13426
+ const timeout = definition.timeout;
13427
+ const validTimeout = timeout === void 0 || Number.isInteger(timeout) && timeout >= 1 && timeout <= 600;
13428
+ if (!validTimeout) logger?.warn(`Kimi Code hooks: omitting invalid timeout for "${event}"; expected an integer from 1 to 600 seconds.`);
13429
+ result.push({
13430
+ event: nativeEvent,
13431
+ command: runFromTrustedDirectory({
13432
+ command: definition.command,
13433
+ trustedDirectory
13434
+ }),
13435
+ ...definition.matcher && { matcher: definition.matcher },
13436
+ ...validTimeout && timeout !== void 0 && { timeout }
13437
+ });
13438
+ }
13439
+ }
13440
+ return result;
13441
+ }
13442
+ function kimiCodeHooksToCanonical(hooks) {
13443
+ const result = {};
13444
+ if (!Array.isArray(hooks)) return result;
13445
+ for (const raw of hooks) {
13446
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
13447
+ const entry = raw;
13448
+ if (typeof entry.event !== "string" || typeof entry.command !== "string") continue;
13449
+ const event = KIMI_CODE_TO_CANONICAL_EVENT_NAMES[entry.event] ?? entry.event;
13450
+ const definition = {
13451
+ type: "command",
13452
+ command: stripTrustedDirectoryWrapper(entry.command),
13453
+ ...typeof entry.matcher === "string" && { matcher: entry.matcher },
13454
+ ...typeof entry.timeout === "number" && { timeout: entry.timeout }
13455
+ };
13456
+ (result[event] ??= []).push(definition);
13457
+ }
13458
+ return result;
13459
+ }
13460
+ /**
13461
+ * Kimi Code lifecycle hooks in the shared user `config.toml`.
13462
+ *
13463
+ * Kimi Code documents hooks only at user scope. The config file also contains
13464
+ * models, providers, permissions, and other settings, so the hooks patch is
13465
+ * merged in place and the file is never deleted.
13466
+ *
13467
+ * @see https://moonshotai.github.io/kimi-code/en/customization/hooks.html
13468
+ */
13469
+ var KimiCodeHooks = class KimiCodeHooks extends ToolHooks {
13470
+ constructor(params) {
13471
+ super({
13472
+ ...params,
13473
+ ...KimiCodeHooks.getSettablePaths({ global: params.global ?? true })
13474
+ });
13475
+ }
13476
+ static getSettablePaths({ global = true } = {}) {
13477
+ return {
13478
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
13479
+ relativeFilePath: KIMI_CODE_CONFIG_FILE_NAME
13480
+ };
13481
+ }
13482
+ validate() {
13483
+ return {
13484
+ success: true,
13485
+ error: null
13486
+ };
13487
+ }
13488
+ isDeletable() {
13489
+ return false;
13490
+ }
13491
+ shouldMergeExistingFileContent() {
13492
+ return true;
13493
+ }
13494
+ setFileContent(fileContent) {
13495
+ const paths = KimiCodeHooks.getSettablePaths({ global: this.global });
13496
+ this.fileContent = applySharedConfigPatch({
13497
+ fileKey: KIMI_CODE_CONFIG_SHARED_FILE_KEY,
13498
+ feature: "hooks",
13499
+ existingContent: fileContent,
13500
+ patch: parseSharedConfig({
13501
+ format: "toml",
13502
+ fileContent: this.fileContent
13503
+ }),
13504
+ filePath: join(paths.relativeDirPath, paths.relativeFilePath)
13505
+ });
13506
+ }
13507
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = true }) {
13508
+ const paths = this.getSettablePaths({ global });
13509
+ return new KimiCodeHooks({
13510
+ outputRoot,
13511
+ fileContent: await readFileContent(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)),
13512
+ validate,
13513
+ global
13514
+ });
13515
+ }
13516
+ static fromRulesyncHooks({ outputRoot, rulesyncHooks, logger }) {
13517
+ const config = rulesyncHooks.getJson();
13518
+ return new KimiCodeHooks({
13519
+ outputRoot,
13520
+ fileContent: stringifySharedConfig({
13521
+ format: "toml",
13522
+ document: { hooks: canonicalToKimiCodeHooks({
13523
+ config,
13524
+ toolOverrideHooks: config["kimi-code"]?.hooks,
13525
+ trustedDirectory: resolve(rulesyncHooks.getOutputRoot()),
13526
+ logger
13527
+ }) }
13528
+ }),
13529
+ global: true
13530
+ });
13531
+ }
13532
+ toRulesyncHooks() {
13533
+ const config = parseSharedConfig({
13534
+ format: "toml",
13535
+ fileContent: this.getFileContent()
13536
+ });
13537
+ return new RulesyncHooks({
13538
+ outputRoot: getKimiCodeRulesyncOutputRoot({
13539
+ nativeOutputRoot: this.outputRoot,
13540
+ global: this.global
13541
+ }),
13542
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
13543
+ relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
13544
+ fileContent: JSON.stringify(buildImportedHooksConfig({
13545
+ hooks: kimiCodeHooksToCanonical(config.hooks),
13546
+ overrideKey: "kimi-code"
13547
+ }), null, 2)
13548
+ });
13549
+ }
13550
+ static forDeletion({ outputRoot = process.cwd() }) {
13551
+ return new KimiCodeHooks({
13552
+ outputRoot,
13553
+ fileContent: "",
13554
+ validate: false,
13555
+ global: true
13556
+ });
13557
+ }
13558
+ };
13559
+ //#endregion
13183
13560
  //#region src/features/hooks/kiro-hooks.ts
13184
13561
  /**
13185
13562
  * Convert canonical hooks config to Kiro CLI format.
@@ -13195,6 +13572,7 @@ function buildKiroEntriesForEvent(definitions) {
13195
13572
  command: def.command,
13196
13573
  ...def.matcher !== void 0 && def.matcher !== null && def.matcher !== "" && { matcher: def.matcher },
13197
13574
  ...def.timeout !== void 0 && def.timeout !== null && def.timeout > 0 && { timeout_ms: def.timeout },
13575
+ ...def.cacheTtl !== void 0 && { cache_ttl_seconds: def.cacheTtl },
13198
13576
  ...def.name !== void 0 && def.name !== null && { name: def.name },
13199
13577
  ...def.description !== void 0 && def.description !== null && { description: def.description }
13200
13578
  });
@@ -13227,9 +13605,14 @@ const KiroHookEntrySchema = z.looseObject({
13227
13605
  command: z.optional(safeString),
13228
13606
  matcher: z.optional(z.string()),
13229
13607
  timeout_ms: z.optional(z.number()),
13608
+ cache_ttl_seconds: z.optional(z.number().check(nonnegative())),
13230
13609
  name: z.optional(z.string()),
13231
13610
  description: z.optional(z.string())
13232
13611
  });
13612
+ function importCacheTtl(entry) {
13613
+ if (entry.cache_ttl_seconds === void 0) return {};
13614
+ return { cacheTtl: entry.cache_ttl_seconds };
13615
+ }
13233
13616
  /**
13234
13617
  * Extract hooks from Kiro CLI agent config into canonical format.
13235
13618
  */
@@ -13250,6 +13633,7 @@ function kiroHooksToCanonical(kiroHooks) {
13250
13633
  command: entry.command,
13251
13634
  ...entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" && { matcher: entry.matcher },
13252
13635
  ...entry.timeout_ms !== void 0 && entry.timeout_ms !== null && { timeout: entry.timeout_ms },
13636
+ ...importCacheTtl(entry),
13253
13637
  ...entry.name !== void 0 && entry.name !== null && { name: entry.name },
13254
13638
  ...entry.description !== void 0 && entry.description !== null && { description: entry.description }
13255
13639
  });
@@ -14489,6 +14873,17 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14489
14873
  supportedHookTypes: ["command"],
14490
14874
  supportsMatcher: true
14491
14875
  }],
14876
+ ["antigravity-plugin", {
14877
+ class: AntigravityPluginHooks,
14878
+ meta: {
14879
+ supportsProject: true,
14880
+ supportsGlobal: false,
14881
+ supportsImport: true
14882
+ },
14883
+ supportedEvents: ANTIGRAVITY_HOOK_EVENTS,
14884
+ supportedHookTypes: ["command"],
14885
+ supportsMatcher: true
14886
+ }],
14492
14887
  ["cursor", {
14493
14888
  class: CursorHooks,
14494
14889
  meta: {
@@ -14517,6 +14912,23 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14517
14912
  ],
14518
14913
  supportsMatcher: true
14519
14914
  }],
14915
+ ["claudecode-plugin", {
14916
+ class: ClaudecodePluginHooks,
14917
+ meta: {
14918
+ supportsProject: true,
14919
+ supportsGlobal: false,
14920
+ supportsImport: true
14921
+ },
14922
+ supportedEvents: CLAUDE_HOOK_EVENTS,
14923
+ supportedHookTypes: [
14924
+ "command",
14925
+ "prompt",
14926
+ "http",
14927
+ "mcp_tool",
14928
+ "agent"
14929
+ ],
14930
+ supportsMatcher: true
14931
+ }],
14520
14932
  ["codexcli", {
14521
14933
  class: CodexcliHooks,
14522
14934
  meta: {
@@ -14620,6 +15032,18 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
14620
15032
  supportedHookTypes: ["command"],
14621
15033
  supportsMatcher: true
14622
15034
  }],
15035
+ ["kimi-code", {
15036
+ class: KimiCodeHooks,
15037
+ meta: {
15038
+ supportsProject: false,
15039
+ supportsGlobal: true,
15040
+ supportsImport: true
15041
+ },
15042
+ supportedEvents: KIMI_CODE_HOOK_EVENTS,
15043
+ supportedHookTypes: ["command"],
15044
+ supportsMatcher: true,
15045
+ passthroughOverrideEvents: true
15046
+ }],
14623
15047
  ["deepagents", {
14624
15048
  class: DeepagentsHooks,
14625
15049
  meta: {
@@ -15795,40 +16219,45 @@ var KiloIgnore = class KiloIgnore extends ToolIgnore {
15795
16219
  //#endregion
15796
16220
  //#region src/features/ignore/kiro-ignore.ts
15797
16221
  var KiroIgnore = class KiroIgnore extends ToolIgnore {
15798
- static getSettablePaths() {
16222
+ static getSettablePaths({ global = false } = {}) {
15799
16223
  return {
15800
- relativeDirPath: ".",
15801
- relativeFilePath: KIRO_IGNORE_FILE_NAME
16224
+ relativeDirPath: global ? KIRO_SETTINGS_DIR_PATH : ".",
16225
+ relativeFilePath: global ? KIRO_GLOBAL_IGNORE_FILE_NAME : KIRO_IGNORE_FILE_NAME
15802
16226
  };
15803
16227
  }
15804
16228
  toRulesyncIgnore() {
15805
16229
  return this.toRulesyncIgnoreDefault();
15806
16230
  }
15807
- static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore }) {
16231
+ static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore, global = false }) {
16232
+ const paths = this.getSettablePaths({ global });
15808
16233
  return new KiroIgnore({
15809
16234
  outputRoot,
15810
- relativeDirPath: this.getSettablePaths().relativeDirPath,
15811
- relativeFilePath: this.getSettablePaths().relativeFilePath,
15812
- fileContent: rulesyncIgnore.getFileContent()
16235
+ relativeDirPath: paths.relativeDirPath,
16236
+ relativeFilePath: paths.relativeFilePath,
16237
+ fileContent: rulesyncIgnore.getFileContent(),
16238
+ global
15813
16239
  });
15814
16240
  }
15815
- static async fromFile({ outputRoot = process.cwd(), validate = true }) {
15816
- const fileContent = await readFileContent(join(outputRoot, this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath));
16241
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
16242
+ const paths = this.getSettablePaths({ global });
16243
+ const fileContent = await readFileContent(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
15817
16244
  return new KiroIgnore({
15818
16245
  outputRoot,
15819
- relativeDirPath: this.getSettablePaths().relativeDirPath,
15820
- relativeFilePath: this.getSettablePaths().relativeFilePath,
16246
+ relativeDirPath: paths.relativeDirPath,
16247
+ relativeFilePath: paths.relativeFilePath,
15821
16248
  fileContent,
15822
- validate
16249
+ validate,
16250
+ global
15823
16251
  });
15824
16252
  }
15825
- static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
16253
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
15826
16254
  return new KiroIgnore({
15827
16255
  outputRoot,
15828
16256
  relativeDirPath,
15829
16257
  relativeFilePath,
15830
16258
  fileContent: "",
15831
- validate: false
16259
+ validate: false,
16260
+ global
15832
16261
  });
15833
16262
  }
15834
16263
  };
@@ -16135,6 +16564,11 @@ const toolIgnoreFactories = /* @__PURE__ */ new Map([
16135
16564
  ["zed", { class: ZedIgnore }]
16136
16565
  ]);
16137
16566
  const ignoreProcessorToolTargets = [...toolIgnoreFactories.keys()];
16567
+ const ignoreProcessorGlobalToolTargets = [
16568
+ "kiro",
16569
+ "kiro-cli",
16570
+ "kiro-ide"
16571
+ ];
16138
16572
  const defaultGetFactory$4 = (target) => {
16139
16573
  const factory = toolIgnoreFactories.get(target);
16140
16574
  if (!factory) throw new Error(`Unsupported tool target: ${target}`);
@@ -16144,7 +16578,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16144
16578
  toolTarget;
16145
16579
  getFactory;
16146
16580
  featureOptions;
16147
- constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, getFactory = defaultGetFactory$4, dryRun = false, logger, featureOptions }) {
16581
+ global;
16582
+ constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, getFactory = defaultGetFactory$4, global = false, dryRun = false, logger, featureOptions }) {
16148
16583
  super({
16149
16584
  outputRoot,
16150
16585
  inputRoot,
@@ -16156,6 +16591,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
16156
16591
  this.toolTarget = result.data;
16157
16592
  this.getFactory = getFactory;
16158
16593
  this.featureOptions = featureOptions;
16594
+ this.global = global;
16159
16595
  }
16160
16596
  async writeToolIgnoresFromRulesyncIgnores(rulesyncIgnores) {
16161
16597
  const toolIgnores = await this.convertRulesyncFilesToToolFiles(rulesyncIgnores);
@@ -16180,12 +16616,16 @@ var IgnoreProcessor = class extends FeatureProcessor {
16180
16616
  async loadToolFiles({ forDeletion = false } = {}) {
16181
16617
  try {
16182
16618
  const factory = this.getFactory(this.toolTarget);
16183
- const paths = factory.class.getSettablePaths({ options: this.featureOptions });
16619
+ const paths = factory.class.getSettablePaths({
16620
+ options: this.featureOptions,
16621
+ global: this.global
16622
+ });
16184
16623
  if (forDeletion) {
16185
16624
  const toolIgnore = factory.class.forDeletion({
16186
16625
  outputRoot: this.outputRoot,
16187
16626
  relativeDirPath: paths.relativeDirPath,
16188
- relativeFilePath: paths.relativeFilePath
16627
+ relativeFilePath: paths.relativeFilePath,
16628
+ global: this.global
16189
16629
  });
16190
16630
  const hasOwnershipGuard = factory.class.canDeleteAuxiliaryFiles !== void 0;
16191
16631
  if (!(!hasOwnershipGuard || await factory.class.canDeleteAuxiliaryFiles?.({ outputRoot: this.outputRoot }) === true)) return [];
@@ -16205,7 +16645,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16205
16645
  async loadToolIgnores() {
16206
16646
  return [await this.getFactory(this.toolTarget).class.fromFile({
16207
16647
  outputRoot: this.outputRoot,
16208
- options: this.featureOptions
16648
+ options: this.featureOptions,
16649
+ global: this.global
16209
16650
  })];
16210
16651
  }
16211
16652
  /**
@@ -16219,7 +16660,8 @@ var IgnoreProcessor = class extends FeatureProcessor {
16219
16660
  const toolIgnore = await factory.class.fromRulesyncIgnore({
16220
16661
  outputRoot: this.outputRoot,
16221
16662
  rulesyncIgnore,
16222
- options: this.featureOptions
16663
+ options: this.featureOptions,
16664
+ global: this.global
16223
16665
  });
16224
16666
  const auxiliaryFiles = await factory.class.getAuxiliaryFiles?.({
16225
16667
  toolIgnore,
@@ -16241,7 +16683,7 @@ var IgnoreProcessor = class extends FeatureProcessor {
16241
16683
  * Return the tool targets that this processor supports
16242
16684
  */
16243
16685
  static getToolTargets({ global = false } = {}) {
16244
- if (global) throw new Error("IgnoreProcessor does not support global mode");
16686
+ if (global) return ignoreProcessorGlobalToolTargets;
16245
16687
  return ignoreProcessorToolTargets;
16246
16688
  }
16247
16689
  };
@@ -16681,6 +17123,16 @@ var AntigravityIdeMcp = class extends AntigravityMcp {
16681
17123
  }
16682
17124
  };
16683
17125
  //#endregion
17126
+ //#region src/features/mcp/antigravity-plugin-mcp.ts
17127
+ var AntigravityPluginMcp = class extends AntigravityIdeMcp {
17128
+ static getSettablePaths() {
17129
+ return {
17130
+ relativeDirPath: ".",
17131
+ relativeFilePath: ANTIGRAVITY_PLUGIN_MCP_FILE_NAME
17132
+ };
17133
+ }
17134
+ };
17135
+ //#endregion
16684
17136
  //#region src/features/mcp/augmentcode-mcp.ts
16685
17137
  function parseAugmentcodeSettings(fileContent, relativeDirPath, relativeFilePath) {
16686
17138
  const configPath = join(relativeDirPath, relativeFilePath);
@@ -17100,7 +17552,7 @@ function convertToCodexFormat(mcpServers) {
17100
17552
  for (const [name, config] of Object.entries(mcpServers)) {
17101
17553
  if (!isRecord(config)) continue;
17102
17554
  const { codexName, usedFallback } = normalizeCodexMcpServerName(name);
17103
- 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.`);
17555
+ 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.`);
17104
17556
  const converted = {};
17105
17557
  for (const [key, value] of Object.entries(config)) {
17106
17558
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
@@ -18909,6 +19361,170 @@ var KiloMcp = class KiloMcp extends ToolMcp {
18909
19361
  }
18910
19362
  };
18911
19363
  //#endregion
19364
+ //#region src/features/mcp/kimi-code-mcp.ts
19365
+ function normalizeKimiCodeTransport({ transport, hasCommand }) {
19366
+ if (transport === "local" || transport === "stdio") return "stdio";
19367
+ if (transport === "sse") return "sse";
19368
+ if (transport === "http" || transport === "streamable-http") return "http";
19369
+ return hasCommand ? "stdio" : "http";
19370
+ }
19371
+ function toKimiCodeServer({ name, server, logger }) {
19372
+ const transport = server.transport ?? server.type;
19373
+ if (transport === "ws") {
19374
+ logger?.warn(`Kimi Code MCP: skipping "${name}" because WebSocket transport is unsupported.`);
19375
+ return null;
19376
+ }
19377
+ const command = server.command;
19378
+ const normalizedCommand = Array.isArray(command) ? command[0] : command;
19379
+ const args = [...Array.isArray(command) ? command.slice(1) : [], ...server.args ?? []];
19380
+ const url = server.httpUrl ?? server.url;
19381
+ const normalizedTransport = normalizeKimiCodeTransport({
19382
+ transport,
19383
+ hasCommand: normalizedCommand !== void 0
19384
+ });
19385
+ if (normalizedTransport === "stdio" && !normalizedCommand || normalizedTransport !== "stdio" && !url) {
19386
+ logger?.warn(`Kimi Code MCP: skipping "${name}" because its ${normalizedTransport} configuration is incomplete.`);
19387
+ return null;
19388
+ }
19389
+ const converted = {
19390
+ transport: normalizedTransport,
19391
+ ...normalizedCommand && { command: normalizedCommand },
19392
+ ...args.length > 0 && { args },
19393
+ ...url && { url }
19394
+ };
19395
+ for (const field of [
19396
+ "env",
19397
+ "cwd",
19398
+ "headers",
19399
+ "bearerTokenEnvVar",
19400
+ "enabled",
19401
+ "startupTimeoutMs",
19402
+ "toolTimeoutMs",
19403
+ "enabledTools",
19404
+ "disabledTools"
19405
+ ]) if (server[field] !== void 0) converted[field] = server[field];
19406
+ if (server.disabled === true) converted.enabled = false;
19407
+ return converted;
19408
+ }
19409
+ function toKimiCodeServers({ servers, logger }) {
19410
+ const result = {};
19411
+ for (const [name, server] of Object.entries(servers)) {
19412
+ const converted = toKimiCodeServer({
19413
+ name,
19414
+ server,
19415
+ logger
19416
+ });
19417
+ if (converted) result[name] = converted;
19418
+ }
19419
+ return result;
19420
+ }
19421
+ function fromKimiCodeServers(servers) {
19422
+ return Object.fromEntries(Object.entries(servers).map(([name, server]) => {
19423
+ const { transport, enabled, ...rest } = server;
19424
+ const type = transport === "stdio" || transport === "sse" || transport === "http" ? transport : void 0;
19425
+ return [name, {
19426
+ ...rest,
19427
+ ...type && { type },
19428
+ ...enabled === false && { disabled: true }
19429
+ }];
19430
+ }));
19431
+ }
19432
+ /**
19433
+ * Kimi Code MCP configuration.
19434
+ *
19435
+ * Both project and user scope use `.kimi-code/mcp.json`, resolved against the
19436
+ * project root or home directory respectively.
19437
+ *
19438
+ * @see https://moonshotai.github.io/kimi-code/en/customization/mcp.html
19439
+ */
19440
+ var KimiCodeMcp = class KimiCodeMcp extends ToolMcp {
19441
+ json;
19442
+ constructor(params) {
19443
+ super(params);
19444
+ try {
19445
+ this.json = this.fileContent ? JSON.parse(this.fileContent) : {};
19446
+ } catch (error) {
19447
+ throw new Error(`Failed to parse Kimi Code MCP config at ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(error)}`, { cause: error });
19448
+ }
19449
+ }
19450
+ isDeletable() {
19451
+ return !this.global;
19452
+ }
19453
+ static getSettablePaths({ global = false } = {}) {
19454
+ return {
19455
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
19456
+ relativeFilePath: KIMI_CODE_MCP_FILE_NAME
19457
+ };
19458
+ }
19459
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
19460
+ const paths = this.getSettablePaths({ global });
19461
+ const fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"mcpServers\":{}}";
19462
+ return new KimiCodeMcp({
19463
+ outputRoot,
19464
+ relativeDirPath: paths.relativeDirPath,
19465
+ relativeFilePath: paths.relativeFilePath,
19466
+ fileContent,
19467
+ validate,
19468
+ global
19469
+ });
19470
+ }
19471
+ static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
19472
+ const paths = this.getSettablePaths({ global });
19473
+ const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
19474
+ const existingContent = await readFileContentOrNull(filePath) ?? "{}";
19475
+ let existing;
19476
+ try {
19477
+ existing = JSON.parse(existingContent);
19478
+ } catch (error) {
19479
+ throw new Error(`Failed to parse Kimi Code MCP config at ${filePath}: ${formatError(error)}`, { cause: error });
19480
+ }
19481
+ return new KimiCodeMcp({
19482
+ outputRoot,
19483
+ relativeDirPath: paths.relativeDirPath,
19484
+ relativeFilePath: paths.relativeFilePath,
19485
+ fileContent: JSON.stringify({
19486
+ ...existing,
19487
+ mcpServers: toKimiCodeServers({
19488
+ servers: rulesyncMcp.getMcpServers(),
19489
+ logger
19490
+ })
19491
+ }, null, 2),
19492
+ validate,
19493
+ global
19494
+ });
19495
+ }
19496
+ toRulesyncMcp() {
19497
+ return new RulesyncMcp({
19498
+ outputRoot: getKimiCodeRulesyncOutputRoot({
19499
+ nativeOutputRoot: this.outputRoot,
19500
+ global: this.global
19501
+ }),
19502
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
19503
+ relativeFilePath: RULESYNC_MCP_FILE_NAME,
19504
+ fileContent: JSON.stringify({
19505
+ ...this.json,
19506
+ mcpServers: fromKimiCodeServers(isMcpServers(this.json.mcpServers) ? this.json.mcpServers : {})
19507
+ }, null, 2)
19508
+ });
19509
+ }
19510
+ validate() {
19511
+ return {
19512
+ success: true,
19513
+ error: null
19514
+ };
19515
+ }
19516
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
19517
+ return new KimiCodeMcp({
19518
+ outputRoot,
19519
+ relativeDirPath,
19520
+ relativeFilePath,
19521
+ fileContent: "{}",
19522
+ validate: false,
19523
+ global
19524
+ });
19525
+ }
19526
+ };
19527
+ //#endregion
18912
19528
  //#region src/features/mcp/kiro-mcp.ts
18913
19529
  var KiroMcp = class KiroMcp extends ToolMcp {
18914
19530
  json;
@@ -19717,7 +20333,7 @@ var RovodevMcp = class RovodevMcp extends ToolMcp {
19717
20333
  * `workflow_mcp_servers: { stdio, sse, http }`. Without it, workflow-defined MCP
19718
20334
  * servers are refused regardless of how they are declared. So this adapter emits
19719
20335
  * the transport allowlist derived from the transports present in
19720
- * `.rulesync/mcp.json`, enabling exactly the transports the user's servers need.
20336
+ * `.rulesync/mcp.jsonc`, enabling exactly the transports the user's servers need.
19721
20337
  *
19722
20338
  * Lossiness (documented, intentional): the per-server names, commands, env, URLs
19723
20339
  * and headers are NOT representable in `config.yaml` and are intentionally not
@@ -20237,6 +20853,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20237
20853
  supportsDisabledTools: true
20238
20854
  }
20239
20855
  }],
20856
+ ["antigravity-plugin", {
20857
+ class: AntigravityPluginMcp,
20858
+ meta: {
20859
+ supportsProject: true,
20860
+ supportsGlobal: false,
20861
+ supportsEnabledTools: false,
20862
+ supportsDisabledTools: true
20863
+ }
20864
+ }],
20240
20865
  ["augmentcode", {
20241
20866
  class: AugmentcodeMcp,
20242
20867
  meta: {
@@ -20255,6 +20880,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20255
20880
  supportsDisabledTools: false
20256
20881
  }
20257
20882
  }],
20883
+ ["claudecode-plugin", {
20884
+ class: ClaudecodeMcp,
20885
+ meta: {
20886
+ supportsProject: true,
20887
+ supportsGlobal: false,
20888
+ supportsEnabledTools: false,
20889
+ supportsDisabledTools: false
20890
+ }
20891
+ }],
20258
20892
  ["claudecode-legacy", {
20259
20893
  class: ClaudecodeMcp,
20260
20894
  meta: {
@@ -20354,6 +20988,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20354
20988
  supportsDisabledTools: false
20355
20989
  }
20356
20990
  }],
20991
+ ["kimi-code", {
20992
+ class: KimiCodeMcp,
20993
+ meta: {
20994
+ supportsProject: true,
20995
+ supportsGlobal: true,
20996
+ supportsEnabledTools: true,
20997
+ supportsDisabledTools: true
20998
+ }
20999
+ }],
20357
21000
  ["kilo", {
20358
21001
  class: KiloMcp,
20359
21002
  meta: {
@@ -20369,7 +21012,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20369
21012
  supportsProject: true,
20370
21013
  supportsGlobal: true,
20371
21014
  supportsEnabledTools: false,
20372
- supportsDisabledTools: false
21015
+ supportsDisabledTools: true
20373
21016
  }
20374
21017
  }],
20375
21018
  ["kiro-cli", {
@@ -20378,7 +21021,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20378
21021
  supportsProject: true,
20379
21022
  supportsGlobal: true,
20380
21023
  supportsEnabledTools: false,
20381
- supportsDisabledTools: false
21024
+ supportsDisabledTools: true
20382
21025
  }
20383
21026
  }],
20384
21027
  ["kiro-ide", {
@@ -20387,7 +21030,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
20387
21030
  supportsProject: true,
20388
21031
  supportsGlobal: true,
20389
21032
  supportsEnabledTools: false,
20390
- supportsDisabledTools: false
21033
+ supportsDisabledTools: true
20391
21034
  }
20392
21035
  }],
20393
21036
  ["junie", {
@@ -22954,7 +23597,7 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
22954
23597
  function buildCodexBashRulesContent(config) {
22955
23598
  const bashRules = config.permission.bash ?? {};
22956
23599
  const entries = Object.entries(bashRules);
22957
- const header = ["# Generated by Rulesync from .rulesync/permissions.json (permission.bash)", "# https://developers.openai.com/codex/rules"];
23600
+ const header = ["# Generated by Rulesync from .rulesync/permissions.jsonc (permission.bash)", "# https://developers.openai.com/codex/rules"];
22958
23601
  if (entries.length === 0) return [...header, "# No bash permission rules were configured."].join("\n");
22959
23602
  const ruleBlocks = entries.map(([pattern, action]) => {
22960
23603
  const tokens = toCommandPatternTokens(pattern);
@@ -24414,8 +25057,9 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
24414
25057
  });
24415
25058
  const permissions = config.permissions && typeof config.permissions === "object" ? config.permissions.rulesync : {};
24416
25059
  return new RulesyncPermissions({
24417
- relativeDirPath: "",
24418
- relativeFilePath: ".rulesync/permissions.json",
25060
+ outputRoot: this.outputRoot,
25061
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
25062
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
24419
25063
  fileContent: JSON.stringify(permissions ?? {}, null, 2)
24420
25064
  });
24421
25065
  }
@@ -24837,7 +25481,7 @@ var KiloPermissions = class KiloPermissions extends ToolPermissions {
24837
25481
  }
24838
25482
  if (Object.keys(droppedDenyByKey).length > 0) {
24839
25483
  const summary = Object.entries(droppedDenyByKey).map(([key, patterns]) => `${key}: [${patterns.join(", ")}]`).join("; ");
24840
- 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'.`);
25484
+ 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'.`);
24841
25485
  }
24842
25486
  const mergedPermission = {
24843
25487
  ...existingPermission,
@@ -24897,6 +25541,227 @@ var KiloPermissions = class KiloPermissions extends ToolPermissions {
24897
25541
  }
24898
25542
  };
24899
25543
  //#endregion
25544
+ //#region src/features/permissions/kimi-code-permissions.ts
25545
+ const CATEGORY_TO_KIMI_CODE_TOOL = {
25546
+ bash: "Bash",
25547
+ read: "Read",
25548
+ write: "Write",
25549
+ edit: "Edit",
25550
+ grep: "Grep",
25551
+ glob: "Glob",
25552
+ websearch: "WebSearch",
25553
+ webfetch: "FetchURL",
25554
+ agent: "Agent"
25555
+ };
25556
+ function buildKimiCodePattern(category, pattern) {
25557
+ if (category.startsWith("mcp__")) return pattern === "*" || pattern === "" ? category : null;
25558
+ if (category === "mcp") return pattern === "*" || pattern === "" ? "mcp__*" : `mcp__${pattern}`;
25559
+ const tool = CATEGORY_TO_KIMI_CODE_TOOL[category];
25560
+ if (!tool) return null;
25561
+ return pattern === "*" || pattern === "" ? tool : `${tool}(${pattern})`;
25562
+ }
25563
+ function canonicalToKimiCodeRules({ config, logger }) {
25564
+ const canonicalRules = [];
25565
+ const overrideRules = config["kimi-code"]?.rules ?? [];
25566
+ for (const [category, rules] of Object.entries(config.permission)) {
25567
+ if (!(category === "mcp" || category.startsWith("mcp__") || CATEGORY_TO_KIMI_CODE_TOOL[category] !== void 0)) {
25568
+ if (Object.keys(rules).length > 0) logger?.warn(`Kimi Code permissions: skipping unsupported category "${category}".`);
25569
+ continue;
25570
+ }
25571
+ for (const [pattern, decision] of Object.entries(rules)) {
25572
+ if (category.startsWith("mcp__") && pattern !== "*" && pattern !== "") {
25573
+ if (decision === "deny") {
25574
+ logger?.warn(`Kimi Code permissions: broadening argument-specific deny for "${category}" to the whole MCP tool because Kimi does not match MCP tool arguments.`);
25575
+ canonicalRules.push({
25576
+ decision,
25577
+ pattern: category,
25578
+ scope: "user"
25579
+ });
25580
+ } else logger?.warn(`Kimi Code permissions: skipping argument-specific ${decision} for "${category}" because Kimi does not match MCP tool arguments.`);
25581
+ continue;
25582
+ }
25583
+ const kimiCodePattern = buildKimiCodePattern(category, pattern);
25584
+ if (!kimiCodePattern) continue;
25585
+ canonicalRules.push({
25586
+ decision,
25587
+ pattern: kimiCodePattern,
25588
+ scope: "user"
25589
+ });
25590
+ }
25591
+ }
25592
+ return [...overrideRules, ...sortKimiCodeRulesFailClosed(canonicalRules)];
25593
+ }
25594
+ function getKimiCodePatternSpecificity(pattern) {
25595
+ const opening = pattern.indexOf("(");
25596
+ const hasArguments = opening >= 0 && pattern.endsWith(")");
25597
+ const tool = hasArguments ? pattern.slice(0, opening) : pattern;
25598
+ const argument = hasArguments ? pattern.slice(opening + 1, -1) : "";
25599
+ return {
25600
+ tool,
25601
+ toolLiteralLength: tool.replaceAll("*", "").replaceAll("?", "").length,
25602
+ toolWildcardCount: [...tool].filter((character) => "*?".includes(character)).length,
25603
+ literalLength: argument.replaceAll("*", "").replaceAll("?", "").replaceAll("[", "").replaceAll("]", "").length,
25604
+ wildcardCount: [...argument].filter((character) => "*?[]".includes(character)).length,
25605
+ hasArguments
25606
+ };
25607
+ }
25608
+ function sortKimiCodeRulesFailClosed(rules) {
25609
+ const actionPriority = {
25610
+ deny: 0,
25611
+ ask: 1,
25612
+ allow: 2
25613
+ };
25614
+ return rules.map((rule, index) => ({
25615
+ rule,
25616
+ index,
25617
+ specificity: getKimiCodePatternSpecificity(rule.pattern)
25618
+ })).toSorted((left, right) => {
25619
+ const actionOrder = actionPriority[left.rule.decision] - actionPriority[right.rule.decision];
25620
+ if (actionOrder !== 0) return actionOrder;
25621
+ if (left.specificity.tool.startsWith("mcp__") && right.specificity.tool.startsWith("mcp__")) {
25622
+ const toolLiteralOrder = right.specificity.toolLiteralLength - left.specificity.toolLiteralLength;
25623
+ if (toolLiteralOrder !== 0) return toolLiteralOrder;
25624
+ const toolWildcardOrder = left.specificity.toolWildcardCount - right.specificity.toolWildcardCount;
25625
+ if (toolWildcardOrder !== 0) return toolWildcardOrder;
25626
+ }
25627
+ const toolOrder = left.specificity.tool.localeCompare(right.specificity.tool);
25628
+ if (toolOrder !== 0) return toolOrder;
25629
+ if (left.specificity.hasArguments !== right.specificity.hasArguments) return left.specificity.hasArguments ? -1 : 1;
25630
+ const literalOrder = right.specificity.literalLength - left.specificity.literalLength;
25631
+ if (literalOrder !== 0) return literalOrder;
25632
+ const wildcardOrder = left.specificity.wildcardCount - right.specificity.wildcardCount;
25633
+ if (wildcardOrder !== 0) return wildcardOrder;
25634
+ return left.index - right.index;
25635
+ }).map(({ rule }) => rule);
25636
+ }
25637
+ function preserveKimiCodeRules(rules) {
25638
+ const permission = {};
25639
+ const nativeRules = [];
25640
+ if (!Array.isArray(rules)) return {
25641
+ permission,
25642
+ nativeRules
25643
+ };
25644
+ for (const raw of rules) {
25645
+ if (!isRecord(raw)) continue;
25646
+ const decision = raw.decision;
25647
+ const pattern = raw.pattern;
25648
+ if (decision !== "allow" && decision !== "ask" && decision !== "deny" || typeof pattern !== "string") continue;
25649
+ nativeRules.push({
25650
+ decision,
25651
+ pattern,
25652
+ ...typeof raw.scope === "string" && { scope: raw.scope },
25653
+ ...typeof raw.reason === "string" && { reason: raw.reason }
25654
+ });
25655
+ }
25656
+ return {
25657
+ permission,
25658
+ nativeRules
25659
+ };
25660
+ }
25661
+ /**
25662
+ * Kimi Code permission rules in the shared user `config.toml`.
25663
+ *
25664
+ * @see https://moonshotai.github.io/kimi-code/en/configuration/config-files.html
25665
+ */
25666
+ var KimiCodePermissions = class KimiCodePermissions extends ToolPermissions {
25667
+ constructor(params) {
25668
+ super({
25669
+ ...params,
25670
+ ...KimiCodePermissions.getSettablePaths({ global: params.global ?? true })
25671
+ });
25672
+ }
25673
+ static getSettablePaths({ global = true } = {}) {
25674
+ return {
25675
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
25676
+ relativeFilePath: KIMI_CODE_CONFIG_FILE_NAME
25677
+ };
25678
+ }
25679
+ validate() {
25680
+ return {
25681
+ success: true,
25682
+ error: null
25683
+ };
25684
+ }
25685
+ isDeletable() {
25686
+ return false;
25687
+ }
25688
+ shouldMergeExistingFileContent() {
25689
+ return true;
25690
+ }
25691
+ setFileContent(fileContent) {
25692
+ const paths = KimiCodePermissions.getSettablePaths({ global: this.global });
25693
+ this.fileContent = applySharedConfigPatch({
25694
+ fileKey: KIMI_CODE_CONFIG_SHARED_FILE_KEY,
25695
+ feature: "permissions",
25696
+ existingContent: fileContent,
25697
+ patch: parseSharedConfig({
25698
+ format: "toml",
25699
+ fileContent: this.fileContent
25700
+ }),
25701
+ filePath: join(paths.relativeDirPath, paths.relativeFilePath)
25702
+ });
25703
+ }
25704
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = true }) {
25705
+ const paths = this.getSettablePaths({ global });
25706
+ return new KimiCodePermissions({
25707
+ outputRoot,
25708
+ fileContent: await readFileContent(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)),
25709
+ validate,
25710
+ global
25711
+ });
25712
+ }
25713
+ static fromRulesyncPermissions({ outputRoot, rulesyncPermissions, logger }) {
25714
+ const config = rulesyncPermissions.getJson();
25715
+ const defaultPermissionMode = config["kimi-code"]?.defaultPermissionMode;
25716
+ return new KimiCodePermissions({
25717
+ outputRoot,
25718
+ fileContent: stringifySharedConfig({
25719
+ format: "toml",
25720
+ document: {
25721
+ ...defaultPermissionMode && { default_permission_mode: defaultPermissionMode },
25722
+ permission: { rules: canonicalToKimiCodeRules({
25723
+ config,
25724
+ logger
25725
+ }) }
25726
+ }
25727
+ }),
25728
+ global: true
25729
+ });
25730
+ }
25731
+ toRulesyncPermissions() {
25732
+ const config = parseSharedConfig({
25733
+ format: "toml",
25734
+ fileContent: this.getFileContent()
25735
+ });
25736
+ const { permission, nativeRules } = preserveKimiCodeRules((isRecord(config.permission) ? config.permission : {}).rules);
25737
+ const defaultPermissionMode = config.default_permission_mode;
25738
+ const toolOverride = {
25739
+ ...defaultPermissionMode === "manual" || defaultPermissionMode === "yolo" || defaultPermissionMode === "auto" ? { defaultPermissionMode } : {},
25740
+ ...nativeRules.length > 0 && { rules: nativeRules }
25741
+ };
25742
+ return new RulesyncPermissions({
25743
+ outputRoot: getKimiCodeRulesyncOutputRoot({
25744
+ nativeOutputRoot: this.outputRoot,
25745
+ global: this.global
25746
+ }),
25747
+ relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
25748
+ relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
25749
+ fileContent: JSON.stringify({
25750
+ permission,
25751
+ ...Object.keys(toolOverride).length > 0 && { "kimi-code": toolOverride }
25752
+ }, null, 2)
25753
+ });
25754
+ }
25755
+ static forDeletion({ outputRoot = process.cwd() }) {
25756
+ return new KimiCodePermissions({
25757
+ outputRoot,
25758
+ fileContent: "",
25759
+ validate: false,
25760
+ global: true
25761
+ });
25762
+ }
25763
+ };
25764
+ //#endregion
24900
25765
  //#region src/features/permissions/kiro-permissions.ts
24901
25766
  const KiroAgentSchema = z.looseObject({
24902
25767
  allowedTools: z.optional(z.array(z.string())),
@@ -27112,6 +27977,14 @@ const toolPermissionsFactories = /* @__PURE__ */ new Map([
27112
27977
  supportsImport: true
27113
27978
  }
27114
27979
  }],
27980
+ ["kimi-code", {
27981
+ class: KimiCodePermissions,
27982
+ meta: {
27983
+ supportsProject: false,
27984
+ supportsGlobal: true,
27985
+ supportsImport: true
27986
+ }
27987
+ }],
27115
27988
  ["junie", {
27116
27989
  class: JuniePermissions,
27117
27990
  meta: {
@@ -28205,6 +29078,17 @@ var AntigravityIdeSkill = class extends AntigravitySharedSkill {
28205
29078
  }
28206
29079
  };
28207
29080
  //#endregion
29081
+ //#region src/features/skills/antigravity-plugin-skill.ts
29082
+ var AntigravityPluginSkill = class extends AntigravityIdeSkill {
29083
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
29084
+ const targets = rulesyncSkill.getFrontmatter().targets;
29085
+ return targets.includes("*") || targets.includes("antigravity-plugin");
29086
+ }
29087
+ static getSettablePaths() {
29088
+ return { relativeDirPath: ANTIGRAVITY_PLUGIN_SKILLS_DIR };
29089
+ }
29090
+ };
29091
+ //#endregion
28208
29092
  //#region src/features/skills/augmentcode-skill.ts
28209
29093
  const AugmentcodeSkillFrontmatterSchema = z.looseObject({
28210
29094
  name: z.string(),
@@ -28399,7 +29283,7 @@ function buildClaudecodeSkillFrontmatter({ rulesyncFrontmatter, resolvedDisableM
28399
29283
  * Unlike subagents and commands, skills are directories containing SKILL.md and other files.
28400
29284
  * Extends ToolSkill to inherit directory management and security features from AiDir.
28401
29285
  */
28402
- var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
29286
+ var ClaudecodeSkill = class extends ToolSkill {
28403
29287
  constructor({ outputRoot = process.cwd(), relativeDirPath = CLAUDECODE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
28404
29288
  super({
28405
29289
  outputRoot,
@@ -28494,9 +29378,9 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28494
29378
  section: rulesyncFrontmatter.claudecode
28495
29379
  })
28496
29380
  });
28497
- const settablePaths = ClaudecodeSkill.getSettablePaths({ global });
29381
+ const settablePaths = this.getSettablePaths({ global });
28498
29382
  const relativeDirPath = rulesyncFrontmatter.claudecode?.["scheduled-task"] ? CLAUDECODE_SCHEDULED_TASKS_DIR_PATH : settablePaths.relativeDirPath;
28499
- return new ClaudecodeSkill({
29383
+ return new this({
28500
29384
  outputRoot,
28501
29385
  relativeDirPath,
28502
29386
  dirName: rulesyncSkill.getDirName(),
@@ -28516,14 +29400,14 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28516
29400
  static async fromDir(params) {
28517
29401
  const loaded = await this.loadSkillDirContent({
28518
29402
  ...params,
28519
- getSettablePaths: ClaudecodeSkill.getSettablePaths
29403
+ getSettablePaths: (options) => this.getSettablePaths(options)
28520
29404
  });
28521
29405
  const result = ClaudecodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28522
29406
  if (!result.success) {
28523
29407
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28524
29408
  throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28525
29409
  }
28526
- return new ClaudecodeSkill({
29410
+ return new this({
28527
29411
  outputRoot: loaded.outputRoot,
28528
29412
  relativeDirPath: loaded.relativeDirPath,
28529
29413
  dirName: loaded.dirName,
@@ -28535,7 +29419,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28535
29419
  });
28536
29420
  }
28537
29421
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
28538
- return new ClaudecodeSkill({
29422
+ return new this({
28539
29423
  outputRoot,
28540
29424
  relativeDirPath,
28541
29425
  dirName,
@@ -28551,6 +29435,17 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
28551
29435
  }
28552
29436
  };
28553
29437
  //#endregion
29438
+ //#region src/features/skills/claudecode-plugin-skill.ts
29439
+ var ClaudecodePluginSkill = class extends ClaudecodeSkill {
29440
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
29441
+ const targets = rulesyncSkill.getFrontmatter().targets;
29442
+ return targets.includes("*") || targets.includes("claudecode-plugin");
29443
+ }
29444
+ static getSettablePaths() {
29445
+ return { relativeDirPath: CLAUDECODE_PLUGIN_SKILLS_DIR };
29446
+ }
29447
+ };
29448
+ //#endregion
28554
29449
  //#region src/features/skills/cline-skill.ts
28555
29450
  const ClineSkillFrontmatterSchema = z.looseObject({
28556
29451
  name: z.string(),
@@ -30340,6 +31235,197 @@ var KiloSkill = class KiloSkill extends ToolSkill {
30340
31235
  }
30341
31236
  };
30342
31237
  //#endregion
31238
+ //#region src/features/skills/kimi-code-skill.ts
31239
+ const KimiCodeSkillFrontmatterSchema = z.looseObject({
31240
+ name: z.string(),
31241
+ description: z.string(),
31242
+ type: z.optional(z.enum([
31243
+ "prompt",
31244
+ "inline",
31245
+ "flow"
31246
+ ])),
31247
+ whenToUse: z.optional(z.string()),
31248
+ disableModelInvocation: z.optional(z.boolean()),
31249
+ arguments: z.optional(z.union([z.string(), z.array(z.string())]))
31250
+ });
31251
+ const KimiCodeFlatSkillFrontmatterSchema = z.looseObject({
31252
+ name: z.optional(z.string()),
31253
+ description: z.optional(z.string()),
31254
+ type: z.optional(z.enum([
31255
+ "prompt",
31256
+ "inline",
31257
+ "flow"
31258
+ ])),
31259
+ whenToUse: z.optional(z.string()),
31260
+ disableModelInvocation: z.optional(z.boolean()),
31261
+ arguments: z.optional(z.union([z.string(), z.array(z.string())]))
31262
+ });
31263
+ function logicalSkillDirName(name) {
31264
+ const normalized = name.toLowerCase();
31265
+ return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalized) ? normalized : `kimi-${encodeURIComponent(normalized)}`;
31266
+ }
31267
+ /**
31268
+ * Kimi Code Agent Skill.
31269
+ *
31270
+ * @see https://moonshotai.github.io/kimi-code/en/customization/skills.html
31271
+ */
31272
+ var KimiCodeSkill = class KimiCodeSkill extends ToolSkill {
31273
+ constructor({ outputRoot = process.cwd(), relativeDirPath = KIMI_CODE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
31274
+ super({
31275
+ outputRoot,
31276
+ relativeDirPath,
31277
+ dirName,
31278
+ mainFile: {
31279
+ name: SKILL_FILE_NAME,
31280
+ body,
31281
+ frontmatter: { ...frontmatter }
31282
+ },
31283
+ otherFiles,
31284
+ global
31285
+ });
31286
+ if (validate) {
31287
+ const result = this.validate();
31288
+ if (!result.success) throw result.error;
31289
+ }
31290
+ }
31291
+ static getSettablePaths({ global = false } = {}) {
31292
+ const customHome = global ? getKimiCodeHome() : void 0;
31293
+ return {
31294
+ relativeDirPath: getKimiCodeRelativeDirPath({
31295
+ global,
31296
+ relativeDirPath: KIMI_CODE_SKILLS_DIR_NAME
31297
+ }),
31298
+ importOnlySkillRoots: [customHome ? {
31299
+ outputRoot: getHomeDirectory(),
31300
+ relativeDirPath: KIMI_CODE_SHARED_SKILLS_DIR_PATH
31301
+ } : KIMI_CODE_SHARED_SKILLS_DIR_PATH]
31302
+ };
31303
+ }
31304
+ getFrontmatter() {
31305
+ return KimiCodeSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
31306
+ }
31307
+ getBody() {
31308
+ return this.mainFile?.body ?? "";
31309
+ }
31310
+ getImportIdentity() {
31311
+ return this.getFrontmatter().name.toLowerCase();
31312
+ }
31313
+ validate() {
31314
+ if (!this.mainFile) return {
31315
+ success: false,
31316
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
31317
+ };
31318
+ const result = KimiCodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
31319
+ return result.success ? {
31320
+ success: true,
31321
+ error: null
31322
+ } : {
31323
+ success: false,
31324
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
31325
+ };
31326
+ }
31327
+ toRulesyncSkill() {
31328
+ const { name, description, disableModelInvocation, ...kimiCodeFrontmatter } = this.getFrontmatter();
31329
+ const toolSection = {
31330
+ ...kimiCodeFrontmatter,
31331
+ ...disableModelInvocation !== void 0 && { disableModelInvocation }
31332
+ };
31333
+ const frontmatter = {
31334
+ name,
31335
+ description,
31336
+ targets: ["*"],
31337
+ ...disableModelInvocation !== void 0 && { "disable-model-invocation": disableModelInvocation },
31338
+ ...Object.keys(toolSection).length > 0 && { "kimi-code": toolSection }
31339
+ };
31340
+ return new RulesyncSkill({
31341
+ outputRoot: getKimiCodeRulesyncOutputRoot({
31342
+ nativeOutputRoot: this.outputRoot,
31343
+ global: this.global
31344
+ }),
31345
+ relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
31346
+ dirName: logicalSkillDirName(name),
31347
+ frontmatter,
31348
+ body: this.getBody(),
31349
+ otherFiles: this.getOtherFiles(),
31350
+ validate: true,
31351
+ global: this.global
31352
+ });
31353
+ }
31354
+ static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
31355
+ const frontmatter = rulesyncSkill.getFrontmatter();
31356
+ const kimiCodeSection = frontmatter["kimi-code"] ?? {};
31357
+ const kimiCodeFrontmatter = {
31358
+ name: frontmatter.name,
31359
+ description: frontmatter.description,
31360
+ ...frontmatter["disable-model-invocation"] !== void 0 && { disableModelInvocation: frontmatter["disable-model-invocation"] },
31361
+ ...kimiCodeSection
31362
+ };
31363
+ return new KimiCodeSkill({
31364
+ outputRoot,
31365
+ relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31366
+ dirName: rulesyncSkill.getDirName(),
31367
+ frontmatter: kimiCodeFrontmatter,
31368
+ body: rulesyncSkill.getBody(),
31369
+ otherFiles: rulesyncSkill.getOtherFiles(),
31370
+ validate,
31371
+ global
31372
+ });
31373
+ }
31374
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
31375
+ const targets = rulesyncSkill.getFrontmatter().targets;
31376
+ return targets.includes("*") || targets.includes("kimi-code");
31377
+ }
31378
+ static async fromDir(params) {
31379
+ const loaded = await this.loadSkillDirContent({
31380
+ ...params,
31381
+ getSettablePaths: KimiCodeSkill.getSettablePaths
31382
+ });
31383
+ const result = KimiCodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
31384
+ if (!result.success) throw new Error(`Invalid frontmatter in ${join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
31385
+ return new KimiCodeSkill({
31386
+ ...loaded,
31387
+ frontmatter: result.data,
31388
+ validate: true
31389
+ });
31390
+ }
31391
+ static async fromFlatFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
31392
+ const filePath = join(outputRoot, relativeDirPath, relativeFilePath);
31393
+ const { frontmatter, body } = parseFrontmatter(await readFileContent(filePath), filePath);
31394
+ const result = KimiCodeFlatSkillFrontmatterSchema.safeParse(frontmatter);
31395
+ if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
31396
+ const fileName = basename(relativeFilePath, extname(relativeFilePath));
31397
+ const firstBodyLine = body.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "");
31398
+ const normalizedFrontmatter = {
31399
+ ...result.data,
31400
+ name: result.data.name ?? fileName,
31401
+ description: result.data.description ?? firstBodyLine?.slice(0, 240) ?? "No description provided."
31402
+ };
31403
+ return new KimiCodeSkill({
31404
+ outputRoot,
31405
+ relativeDirPath,
31406
+ dirName: fileName,
31407
+ frontmatter: normalizedFrontmatter,
31408
+ body: body.trim(),
31409
+ validate: true,
31410
+ global
31411
+ });
31412
+ }
31413
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
31414
+ return new KimiCodeSkill({
31415
+ outputRoot,
31416
+ relativeDirPath: relativeDirPath ?? this.getSettablePaths({ global }).relativeDirPath,
31417
+ dirName,
31418
+ frontmatter: {
31419
+ name: "",
31420
+ description: ""
31421
+ },
31422
+ body: "",
31423
+ validate: false,
31424
+ global
31425
+ });
31426
+ }
31427
+ };
31428
+ //#endregion
30343
31429
  //#region src/features/skills/kiro-skill.ts
30344
31430
  const KiroSkillFrontmatterSchema = z.looseObject({
30345
31431
  name: z.string(),
@@ -32066,6 +33152,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32066
33152
  supportsGlobal: true
32067
33153
  }
32068
33154
  }],
33155
+ ["antigravity-plugin", {
33156
+ class: AntigravityPluginSkill,
33157
+ meta: {
33158
+ supportsProject: true,
33159
+ supportsSimulated: false,
33160
+ supportsGlobal: false
33161
+ }
33162
+ }],
32069
33163
  ["augmentcode", {
32070
33164
  class: AugmentcodeSkill,
32071
33165
  meta: {
@@ -32082,6 +33176,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32082
33176
  supportsGlobal: true
32083
33177
  }
32084
33178
  }],
33179
+ ["claudecode-plugin", {
33180
+ class: ClaudecodePluginSkill,
33181
+ meta: {
33182
+ supportsProject: true,
33183
+ supportsSimulated: false,
33184
+ supportsGlobal: false
33185
+ }
33186
+ }],
32085
33187
  ["claudecode-legacy", {
32086
33188
  class: ClaudecodeSkill,
32087
33189
  meta: {
@@ -32186,6 +33288,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
32186
33288
  supportsGlobal: true
32187
33289
  }
32188
33290
  }],
33291
+ ["kimi-code", {
33292
+ class: KimiCodeSkill,
33293
+ meta: {
33294
+ supportsProject: true,
33295
+ supportsSimulated: false,
33296
+ supportsGlobal: true
33297
+ }
33298
+ }],
32189
33299
  ["kiro", {
32190
33300
  class: KiroSkill,
32191
33301
  meta: {
@@ -32407,36 +33517,56 @@ var SkillsProcessor = class extends DirFeatureProcessor {
32407
33517
  */
32408
33518
  async loadToolDirs() {
32409
33519
  const factory = this.getFactory(this.toolTarget);
32410
- const roots = toolSkillSearchRoots(factory.class.getSettablePaths({ global: this.global }));
32411
- const seenDirNames = /* @__PURE__ */ new Set();
32412
- const loadEntries = [];
33520
+ const roots = toolSkillImportRoots(factory.class.getSettablePaths({ global: this.global }));
33521
+ const seenSkillNames = /* @__PURE__ */ new Set();
33522
+ const toolSkills = [];
32413
33523
  for (const root of roots) {
32414
- const skillsDirPath = join(this.outputRoot, root);
33524
+ const rootOutputRoot = typeof root === "string" ? this.outputRoot : root.outputRoot;
33525
+ const relativeDirPath = typeof root === "string" ? root : root.relativeDirPath;
33526
+ const skillsDirPath = join(rootOutputRoot, relativeDirPath);
32415
33527
  if (!await directoryExists(skillsDirPath)) continue;
32416
33528
  const dirPaths = await findFilesByGlobs(join(skillsDirPath, "*"), { type: "dir" });
33529
+ const ownedDirNames = [];
32417
33530
  for (const dirPath of dirPaths) {
32418
33531
  const dirName = basename(dirPath);
32419
- if (seenDirNames.has(dirName)) continue;
32420
33532
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
32421
- outputRoot: this.outputRoot,
32422
- relativeDirPath: root,
33533
+ outputRoot: rootOutputRoot,
33534
+ relativeDirPath,
32423
33535
  dirName,
32424
33536
  inputRoot: this.inputRoot
32425
33537
  })) continue;
32426
- seenDirNames.add(dirName);
32427
- loadEntries.push({
32428
- root,
32429
- dirName
32430
- });
33538
+ ownedDirNames.push(dirName);
33539
+ }
33540
+ const directorySkills = await Promise.all(ownedDirNames.map((dirName) => factory.class.fromDir({
33541
+ outputRoot: rootOutputRoot,
33542
+ relativeDirPath,
33543
+ dirName,
33544
+ global: this.global
33545
+ })));
33546
+ for (const skill of directorySkills) {
33547
+ const skillName = skill.getImportIdentity();
33548
+ if (seenSkillNames.has(skillName)) continue;
33549
+ seenSkillNames.add(skillName);
33550
+ toolSkills.push(skill);
33551
+ }
33552
+ if (!factory.class.fromFlatFile) continue;
33553
+ const fromFlatFile = factory.class.fromFlatFile;
33554
+ const directoryStems = new Set(ownedDirNames);
33555
+ const flatFilePaths = (await findFilesByGlobs(join(skillsDirPath, "*.md"), { type: "file" })).filter((filePath) => !directoryStems.has(basename(filePath, ".md")));
33556
+ const flatSkills = await Promise.all(flatFilePaths.map((filePath) => fromFlatFile({
33557
+ outputRoot: rootOutputRoot,
33558
+ relativeDirPath,
33559
+ relativeFilePath: basename(filePath),
33560
+ global: this.global
33561
+ })));
33562
+ for (const skill of flatSkills) {
33563
+ const skillName = skill.getImportIdentity();
33564
+ if (seenSkillNames.has(skillName)) continue;
33565
+ seenSkillNames.add(skillName);
33566
+ toolSkills.push(skill);
32431
33567
  }
32432
33568
  }
32433
- const toolSkills = await Promise.all(loadEntries.map(({ root, dirName }) => factory.class.fromDir({
32434
- outputRoot: this.outputRoot,
32435
- relativeDirPath: root,
32436
- dirName,
32437
- global: this.global
32438
- })));
32439
- this.logger.debug(`Successfully loaded ${toolSkills.length} skills from ${roots.length} root(s): ${roots.join(", ")}`);
33569
+ this.logger.debug(`Successfully loaded ${toolSkills.length} skills from ${roots.length} root(s)`);
32440
33570
  return toolSkills;
32441
33571
  }
32442
33572
  async loadToolDirsToDelete() {
@@ -32446,8 +33576,19 @@ var SkillsProcessor = class extends DirFeatureProcessor {
32446
33576
  for (const root of roots) {
32447
33577
  const skillsDirPath = join(this.outputRoot, root);
32448
33578
  if (!await directoryExists(skillsDirPath)) continue;
32449
- const dirPaths = await findFilesByGlobs(join(skillsDirPath, "*"), { type: "dir" });
33579
+ await assertWritablePathInsideRoot({
33580
+ rootPath: this.outputRoot,
33581
+ targetPath: skillsDirPath
33582
+ });
33583
+ const dirPaths = await findFilesByGlobs(join(skillsDirPath, "*"), {
33584
+ type: "dir",
33585
+ followSymbolicLinks: false
33586
+ });
32450
33587
  for (const dirPath of dirPaths) {
33588
+ await assertWritablePathInsideRoot({
33589
+ rootPath: skillsDirPath,
33590
+ targetPath: dirPath
33591
+ });
32451
33592
  const dirName = basename(dirPath);
32452
33593
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
32453
33594
  outputRoot: this.outputRoot,
@@ -32537,6 +33678,10 @@ var ToolSubagent = class extends ToolFile {
32537
33678
  static fromRulesyncSubagent(_params) {
32538
33679
  throw new Error("Please implement this method in the subclass.");
32539
33680
  }
33681
+ /** Identity used to resolve duplicate imports across discovery roots. */
33682
+ getImportIdentity() {
33683
+ return this.getRelativeFilePath();
33684
+ }
32540
33685
  static isTargetedByRulesyncSubagent(_rulesyncSubagent) {
32541
33686
  throw new Error("Please implement this method in the subclass.");
32542
33687
  }
@@ -33198,6 +34343,17 @@ var ClaudecodeSubagent = class ClaudecodeSubagent extends ToolSubagent {
33198
34343
  }
33199
34344
  };
33200
34345
  //#endregion
34346
+ //#region src/features/subagents/claudecode-plugin-subagent.ts
34347
+ var ClaudecodePluginSubagent = class extends ClaudecodeSubagent {
34348
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
34349
+ const targets = rulesyncSubagent.getFrontmatter().targets;
34350
+ return targets.includes("*") || targets.includes("claudecode-plugin");
34351
+ }
34352
+ static getSettablePaths() {
34353
+ return { relativeDirPath: CLAUDECODE_PLUGIN_AGENTS_DIR };
34354
+ }
34355
+ };
34356
+ //#endregion
33201
34357
  //#region src/features/subagents/cline-subagent.ts
33202
34358
  const ClineSubagentFrontmatterSchema = z.looseObject({
33203
34359
  name: z.string(),
@@ -35185,9 +36341,153 @@ var KiloSubagent = class KiloSubagent extends OpenCodeStyleSubagent {
35185
36341
  }
35186
36342
  };
35187
36343
  //#endregion
36344
+ //#region src/features/subagents/kimi-code-subagent.ts
36345
+ const KimiCodeAgentNameSchema = z.pipe(z.string(), z.custom((value) => typeof value === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value), "must be a kebab-case name"));
36346
+ const KimiCodeSubagentFrontmatterSchema = z.looseObject({
36347
+ name: z.optional(KimiCodeAgentNameSchema),
36348
+ description: z.string(),
36349
+ whenToUse: z.optional(z.string()),
36350
+ override: z.optional(z.boolean()),
36351
+ tools: z.optional(z.union([z.string(), z.array(z.string())])),
36352
+ disallowedTools: z.optional(z.union([z.string(), z.array(z.string())])),
36353
+ subagents: z.optional(z.union([z.string(), z.array(z.string())]))
36354
+ });
36355
+ /**
36356
+ * Kimi Code custom agent.
36357
+ *
36358
+ * @see https://moonshotai.github.io/kimi-code/en/customization/agents.html
36359
+ */
36360
+ var KimiCodeSubagent = class KimiCodeSubagent extends ToolSubagent {
36361
+ frontmatter;
36362
+ body;
36363
+ constructor({ frontmatter, body, fileContent, ...rest }) {
36364
+ if (rest.validate !== false) {
36365
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(frontmatter);
36366
+ if (!result.success) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
36367
+ }
36368
+ super({
36369
+ ...rest,
36370
+ fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
36371
+ });
36372
+ this.frontmatter = frontmatter;
36373
+ this.body = body;
36374
+ }
36375
+ static getSettablePaths({ global = false } = {}) {
36376
+ const customHome = global ? getKimiCodeHome() : void 0;
36377
+ return {
36378
+ relativeDirPath: getKimiCodeRelativeDirPath({
36379
+ global,
36380
+ relativeDirPath: KIMI_CODE_AGENTS_DIR_NAME
36381
+ }),
36382
+ importDirPaths: [customHome ? {
36383
+ outputRoot: getHomeDirectory(),
36384
+ relativeDirPath: KIMI_CODE_SHARED_AGENTS_DIR_PATH
36385
+ } : KIMI_CODE_SHARED_AGENTS_DIR_PATH]
36386
+ };
36387
+ }
36388
+ getFrontmatter() {
36389
+ return this.frontmatter;
36390
+ }
36391
+ getBody() {
36392
+ return this.body;
36393
+ }
36394
+ getImportIdentity() {
36395
+ const fileName = basename(this.getRelativeFilePath(), extname(this.getRelativeFilePath()));
36396
+ return KimiCodeAgentNameSchema.parse(this.frontmatter.name ?? fileName).toLowerCase();
36397
+ }
36398
+ toRulesyncSubagent() {
36399
+ const { name: _name, description, ...rest } = this.frontmatter;
36400
+ const resolvedName = this.getImportIdentity();
36401
+ const frontmatter = {
36402
+ targets: ["*"],
36403
+ name: resolvedName,
36404
+ description,
36405
+ ...Object.keys(rest).length > 0 && { "kimi-code": rest }
36406
+ };
36407
+ return new RulesyncSubagent({
36408
+ outputRoot: getKimiCodeRulesyncOutputRoot({
36409
+ nativeOutputRoot: this.outputRoot,
36410
+ global: this.global
36411
+ }),
36412
+ relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
36413
+ relativeFilePath: `${resolvedName}.md`,
36414
+ frontmatter,
36415
+ body: this.body,
36416
+ validate: true,
36417
+ global: this.global
36418
+ });
36419
+ }
36420
+ static fromRulesyncSubagent({ outputRoot = process.cwd(), rulesyncSubagent, validate = true, global = false }) {
36421
+ const frontmatter = rulesyncSubagent.getFrontmatter();
36422
+ const toolSection = frontmatter["kimi-code"] ?? {};
36423
+ const kimiCodeFrontmatter = KimiCodeSubagentFrontmatterSchema.parse({
36424
+ name: frontmatter.name,
36425
+ description: frontmatter.description,
36426
+ ...toolSection
36427
+ });
36428
+ const body = rulesyncSubagent.getBody();
36429
+ return new KimiCodeSubagent({
36430
+ outputRoot,
36431
+ relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
36432
+ relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
36433
+ frontmatter: kimiCodeFrontmatter,
36434
+ body,
36435
+ fileContent: stringifyFrontmatter(body, kimiCodeFrontmatter, { avoidBlockScalars: true }),
36436
+ validate,
36437
+ global
36438
+ });
36439
+ }
36440
+ validate() {
36441
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
36442
+ return result.success ? {
36443
+ success: true,
36444
+ error: null
36445
+ } : {
36446
+ success: false,
36447
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
36448
+ };
36449
+ }
36450
+ static isTargetedByRulesyncSubagent(rulesyncSubagent) {
36451
+ return this.isTargetedByRulesyncSubagentDefault({
36452
+ rulesyncSubagent,
36453
+ toolTarget: "kimi-code"
36454
+ });
36455
+ }
36456
+ static async fromFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, validate = true, global = false }) {
36457
+ const actualRelativeDirPath = relativeDirPath ?? this.getSettablePaths({ global }).relativeDirPath;
36458
+ const filePath = join(outputRoot, actualRelativeDirPath, relativeFilePath);
36459
+ const fileContent = await readFileContent(filePath);
36460
+ const { frontmatter, body } = parseFrontmatter(fileContent, filePath);
36461
+ const result = KimiCodeSubagentFrontmatterSchema.safeParse(frontmatter);
36462
+ if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
36463
+ return new KimiCodeSubagent({
36464
+ outputRoot,
36465
+ relativeDirPath: actualRelativeDirPath,
36466
+ relativeFilePath,
36467
+ frontmatter: result.data,
36468
+ body: body.trim(),
36469
+ fileContent,
36470
+ validate,
36471
+ global
36472
+ });
36473
+ }
36474
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
36475
+ return new KimiCodeSubagent({
36476
+ outputRoot,
36477
+ relativeDirPath,
36478
+ relativeFilePath,
36479
+ frontmatter: { description: "" },
36480
+ body: "",
36481
+ fileContent: "",
36482
+ validate: false,
36483
+ global
36484
+ });
36485
+ }
36486
+ };
36487
+ //#endregion
35188
36488
  //#region src/features/subagents/kiro-subagent.ts
35189
36489
  const KiroCliSubagentJsonSchema = z.looseObject({
35190
- name: z.string(),
36490
+ name: z.optional(z.string()),
35191
36491
  description: z.optional(z.nullable(z.string())),
35192
36492
  prompt: z.optional(z.nullable(z.string())),
35193
36493
  tools: z.optional(z.nullable(z.array(z.string()))),
@@ -35202,7 +36502,7 @@ const KiroCliSubagentJsonSchema = z.looseObject({
35202
36502
  allowedTools: z.optional(z.nullable(z.array(z.string()))),
35203
36503
  includeMcpJson: z.optional(z.nullable(z.boolean()))
35204
36504
  });
35205
- var KiroSubagent = class KiroSubagent extends ToolSubagent {
36505
+ var KiroSubagent = class extends ToolSubagent {
35206
36506
  body;
35207
36507
  constructor({ body, ...rest }) {
35208
36508
  if (rest.validate !== false) try {
@@ -35220,6 +36520,9 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35220
36520
  getBody() {
35221
36521
  return this.body;
35222
36522
  }
36523
+ static getToolTarget() {
36524
+ return "kiro";
36525
+ }
35223
36526
  toRulesyncSubagent() {
35224
36527
  let parsed;
35225
36528
  try {
@@ -35228,12 +36531,13 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35228
36531
  throw new Error(`Failed to parse JSON in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
35229
36532
  }
35230
36533
  const { name, description, prompt, ...restFields } = parsed;
36534
+ const toolTarget = this.constructor.getToolTarget();
35231
36535
  const kiroSection = { ...restFields };
35232
36536
  return new RulesyncSubagent({
35233
36537
  outputRoot: ".",
35234
36538
  frontmatter: {
35235
- targets: ["kiro"],
35236
- name,
36539
+ targets: [toolTarget],
36540
+ name: name ?? basename(this.getRelativeFilePath(), ".json"),
35237
36541
  description: description ?? void 0,
35238
36542
  ...Object.keys(kiroSection).length > 0 && { kiro: kiroSection }
35239
36543
  },
@@ -35260,7 +36564,7 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35260
36564
  const body = JSON.stringify(json, null, 2);
35261
36565
  const paths = this.getSettablePaths({ global });
35262
36566
  const relativeFilePath = rulesyncSubagent.getRelativeFilePath().replace(/\.md$/, ".json");
35263
- return new KiroSubagent({
36567
+ return new this({
35264
36568
  outputRoot,
35265
36569
  body,
35266
36570
  relativeDirPath: paths.relativeDirPath,
@@ -35288,14 +36592,14 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35288
36592
  static isTargetedByRulesyncSubagent(rulesyncSubagent) {
35289
36593
  return this.isTargetedByRulesyncSubagentDefault({
35290
36594
  rulesyncSubagent,
35291
- toolTarget: "kiro"
36595
+ toolTarget: this.getToolTarget()
35292
36596
  });
35293
36597
  }
35294
36598
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
35295
36599
  const paths = this.getSettablePaths({ global });
35296
36600
  const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
35297
36601
  const fileContent = await readFileContent(filePath);
35298
- const subagent = new KiroSubagent({
36602
+ const subagent = new this({
35299
36603
  outputRoot,
35300
36604
  relativeDirPath: paths.relativeDirPath,
35301
36605
  relativeFilePath,
@@ -35311,7 +36615,7 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35311
36615
  return subagent;
35312
36616
  }
35313
36617
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
35314
- return new KiroSubagent({
36618
+ return new this({
35315
36619
  outputRoot,
35316
36620
  relativeDirPath,
35317
36621
  relativeFilePath,
@@ -35333,11 +36637,8 @@ var KiroSubagent = class KiroSubagent extends ToolSubagent {
35333
36637
  * {@link import("./kiro-ide-subagent.js").KiroIdeSubagent}.)
35334
36638
  */
35335
36639
  var KiroCliSubagent = class extends KiroSubagent {
35336
- static isTargetedByRulesyncSubagent(rulesyncSubagent) {
35337
- return this.isTargetedByRulesyncSubagentDefault({
35338
- rulesyncSubagent,
35339
- toolTarget: "kiro-cli"
35340
- });
36640
+ static getToolTarget() {
36641
+ return "kiro-cli";
35341
36642
  }
35342
36643
  };
35343
36644
  //#endregion
@@ -36324,6 +37625,14 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
36324
37625
  filePattern: "*.md"
36325
37626
  }
36326
37627
  }],
37628
+ ["claudecode-plugin", {
37629
+ class: ClaudecodePluginSubagent,
37630
+ meta: {
37631
+ supportsSimulated: false,
37632
+ supportsGlobal: false,
37633
+ filePattern: "*.md"
37634
+ }
37635
+ }],
36327
37636
  ["claudecode-legacy", {
36328
37637
  class: ClaudecodeSubagent,
36329
37638
  meta: {
@@ -36460,6 +37769,14 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
36460
37769
  filePattern: "*.md"
36461
37770
  }
36462
37771
  }],
37772
+ ["kimi-code", {
37773
+ class: KimiCodeSubagent,
37774
+ meta: {
37775
+ supportsSimulated: false,
37776
+ supportsGlobal: true,
37777
+ filePattern: join("**", "*.md")
37778
+ }
37779
+ }],
36463
37780
  ["opencode", {
36464
37781
  class: OpenCodeSubagent,
36465
37782
  meta: {
@@ -36581,7 +37898,18 @@ var SubagentsProcessor = class extends FeatureProcessor {
36581
37898
  }
36582
37899
  rulesyncSubagents.push(toolSubagent.toRulesyncSubagent());
36583
37900
  }
36584
- return rulesyncSubagents;
37901
+ const uniqueRulesyncSubagents = [];
37902
+ const seenOutputPaths = /* @__PURE__ */ new Set();
37903
+ for (const rulesyncSubagent of rulesyncSubagents) {
37904
+ const outputPath = join(rulesyncSubagent.getRelativeDirPath(), rulesyncSubagent.getRelativeFilePath());
37905
+ if (seenOutputPaths.has(outputPath)) {
37906
+ this.logger.warn(`Multiple ${this.toolTarget} subagents resolve to "${outputPath}"; keeping the first and ignoring this copy.`);
37907
+ continue;
37908
+ }
37909
+ seenOutputPaths.add(outputPath);
37910
+ uniqueRulesyncSubagents.push(rulesyncSubagent);
37911
+ }
37912
+ return uniqueRulesyncSubagents;
36585
37913
  }
36586
37914
  /**
36587
37915
  * Implementation of abstract method from Processor
@@ -36629,25 +37957,35 @@ var SubagentsProcessor = class extends FeatureProcessor {
36629
37957
  async loadToolFiles({ forDeletion = false } = {}) {
36630
37958
  const factory = this.getFactory(this.toolTarget);
36631
37959
  const paths = factory.class.getSettablePaths({ global: this.global });
36632
- const dirPaths = forDeletion ? [paths.relativeDirPath] : [paths.relativeDirPath, ...paths.importDirPaths ?? []];
37960
+ const roots = forDeletion ? [paths.relativeDirPath] : [paths.relativeDirPath, ...paths.importDirPaths ?? []];
36633
37961
  const toolSubagents = [];
36634
37962
  const seenRelativeFilePaths = /* @__PURE__ */ new Set();
36635
- for (const dirPath of dirPaths) {
36636
- const baseDir = join(this.outputRoot, dirPath);
36637
- const subagentFilePaths = await findFilesByGlobs(join(baseDir, factory.meta.filePattern));
37963
+ for (const root of roots) {
37964
+ const rootOutputRoot = typeof root === "string" ? this.outputRoot : root.outputRoot;
37965
+ const dirPath = typeof root === "string" ? root : root.relativeDirPath;
37966
+ const baseDir = join(rootOutputRoot, dirPath);
37967
+ if (forDeletion && await directoryExists(baseDir)) await assertWritablePathInsideRoot({
37968
+ rootPath: rootOutputRoot,
37969
+ targetPath: baseDir
37970
+ });
37971
+ const subagentFilePaths = await findFilesByGlobs(join(baseDir, factory.meta.filePattern), { followSymbolicLinks: !forDeletion });
36638
37972
  const toRelativeFilePath = (path) => relative(baseDir, path);
36639
37973
  let ownedFilePaths = subagentFilePaths;
36640
37974
  if (factory.class.isFileOwned) {
36641
37975
  const ownership = await Promise.all(subagentFilePaths.map((path) => factory.class.isFileOwned({
36642
- outputRoot: this.outputRoot,
37976
+ outputRoot: rootOutputRoot,
36643
37977
  relativeDirPath: dirPath,
36644
37978
  relativeFilePath: toRelativeFilePath(path)
36645
37979
  })));
36646
37980
  ownedFilePaths = subagentFilePaths.filter((_, index) => ownership[index]);
36647
37981
  }
36648
37982
  if (forDeletion) {
37983
+ await Promise.all(ownedFilePaths.map((path) => assertWritablePathInsideRoot({
37984
+ rootPath: baseDir,
37985
+ targetPath: path
37986
+ })));
36649
37987
  toolSubagents.push(...ownedFilePaths.map((path) => factory.class.forDeletion({
36650
- outputRoot: this.outputRoot,
37988
+ outputRoot: rootOutputRoot,
36651
37989
  relativeDirPath: dirPath,
36652
37990
  relativeFilePath: toRelativeFilePath(path),
36653
37991
  global: this.global
@@ -36655,14 +37993,14 @@ var SubagentsProcessor = class extends FeatureProcessor {
36655
37993
  continue;
36656
37994
  }
36657
37995
  const loaded = await Promise.all(ownedFilePaths.map((path) => factory.class.fromFile({
36658
- outputRoot: this.outputRoot,
37996
+ outputRoot: rootOutputRoot,
36659
37997
  relativeDirPath: dirPath,
36660
37998
  relativeFilePath: toRelativeFilePath(path),
36661
37999
  global: this.global
36662
38000
  })));
36663
38001
  const deduped = [];
36664
38002
  for (const subagent of loaded) {
36665
- const key = subagent.getRelativeFilePath();
38003
+ const key = subagent.getImportIdentity();
36666
38004
  if (seenRelativeFilePaths.has(key)) {
36667
38005
  this.logger.warn(`Duplicate ${this.toolTarget} subagent "${key}" found in ${dirPath}; keeping the one from a higher-precedence directory and ignoring this copy.`);
36668
38006
  continue;
@@ -36678,7 +38016,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
36678
38016
  global: this.global
36679
38017
  });
36680
38018
  for (const subagent of additionalSubagents) {
36681
- const key = subagent.getRelativeFilePath();
38019
+ const key = subagent.getImportIdentity();
36682
38020
  if (seenRelativeFilePaths.has(key)) {
36683
38021
  this.logger.warn(`Duplicate ${this.toolTarget} subagent "${key}" defined inline; keeping the standalone file and ignoring the inline copy.`);
36684
38022
  continue;
@@ -36687,7 +38025,7 @@ var SubagentsProcessor = class extends FeatureProcessor {
36687
38025
  toolSubagents.push(subagent);
36688
38026
  }
36689
38027
  }
36690
- this.logger.debug(`Successfully loaded ${toolSubagents.length} ${this.toolTarget} subagents from ${dirPaths.join(", ")}`);
38028
+ this.logger.debug(`Successfully loaded ${toolSubagents.length} ${this.toolTarget} subagents from ${roots.length} root(s)`);
36691
38029
  return toolSubagents;
36692
38030
  }
36693
38031
  /**
@@ -37351,17 +38689,18 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37351
38689
  };
37352
38690
  }
37353
38691
  static getSettablePaths({ global = false, excludeToolDir } = {}) {
37354
- if (global) return { root: AntigravityIdeRule.getGlobalRootPath(excludeToolDir) };
38692
+ if (global) return { root: this.getGlobalRootPath(excludeToolDir) };
37355
38693
  return {
37356
- root: AntigravityIdeRule.getProjectRootPath(),
38694
+ root: this.getProjectRootPath(),
37357
38695
  nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules", excludeToolDir) }
37358
38696
  };
37359
38697
  }
37360
38698
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
38699
+ const paths = this.getSettablePaths({ global });
37361
38700
  if (global) {
37362
- const rootPath = AntigravityIdeRule.getGlobalRootPath();
38701
+ const rootPath = paths.root;
37363
38702
  const fileContent = await readFileContent(join(outputRoot, rootPath.relativeDirPath, rootPath.relativeFilePath));
37364
- return new AntigravityIdeRule({
38703
+ return new this({
37365
38704
  outputRoot,
37366
38705
  relativeDirPath: rootPath.relativeDirPath,
37367
38706
  relativeFilePath: rootPath.relativeFilePath,
@@ -37371,10 +38710,10 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37371
38710
  root: true
37372
38711
  });
37373
38712
  }
37374
- if (relativeFilePath === "AGENTS.md") {
37375
- const rootPath = AntigravityIdeRule.getProjectRootPath();
38713
+ if (relativeFilePath === paths.root.relativeFilePath) {
38714
+ const rootPath = paths.root;
37376
38715
  const rootContent = await readFileContent(join(outputRoot, rootPath.relativeDirPath, rootPath.relativeFilePath));
37377
- return new AntigravityIdeRule({
38716
+ return new this({
37378
38717
  outputRoot,
37379
38718
  relativeDirPath: rootPath.relativeDirPath,
37380
38719
  relativeFilePath: rootPath.relativeFilePath,
@@ -37384,7 +38723,8 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37384
38723
  root: true
37385
38724
  });
37386
38725
  }
37387
- const nonRootDirPath = buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules");
38726
+ if (!("nonRoot" in paths) || !paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
38727
+ const nonRootDirPath = paths.nonRoot.relativeDirPath;
37388
38728
  const filePath = join(outputRoot, nonRootDirPath, relativeFilePath);
37389
38729
  const { frontmatter, body } = parseFrontmatter(await readFileContent(filePath), filePath);
37390
38730
  let parsedFrontmatter;
@@ -37393,7 +38733,7 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37393
38733
  if (result.success) parsedFrontmatter = result.data;
37394
38734
  else throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
37395
38735
  } else parsedFrontmatter = frontmatter;
37396
- return new AntigravityIdeRule({
38736
+ return new this({
37397
38737
  outputRoot,
37398
38738
  relativeDirPath: nonRootDirPath,
37399
38739
  relativeFilePath,
@@ -37404,9 +38744,10 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37404
38744
  });
37405
38745
  }
37406
38746
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
38747
+ const paths = this.getSettablePaths({ global });
37407
38748
  if (global) {
37408
- const rootPath = AntigravityIdeRule.getGlobalRootPath();
37409
- return new AntigravityIdeRule({
38749
+ const rootPath = paths.root;
38750
+ return new this({
37410
38751
  outputRoot,
37411
38752
  relativeDirPath: rootPath.relativeDirPath,
37412
38753
  relativeFilePath: rootPath.relativeFilePath,
@@ -37417,8 +38758,8 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37417
38758
  });
37418
38759
  }
37419
38760
  if (rulesyncRule.getFrontmatter().root) {
37420
- const rootPath = AntigravityIdeRule.getProjectRootPath();
37421
- return new AntigravityIdeRule({
38761
+ const rootPath = paths.root;
38762
+ return new this({
37422
38763
  outputRoot,
37423
38764
  relativeDirPath: rootPath.relativeDirPath,
37424
38765
  relativeFilePath: rootPath.relativeFilePath,
@@ -37435,10 +38776,11 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37435
38776
  const strategy = STRATEGIES$1.find((s) => s.canHandle(storedTrigger));
37436
38777
  if (!strategy) throw new Error(`No strategy found for trigger: ${storedTrigger}`);
37437
38778
  const frontmatter = strategy.generateFrontmatter(normalized, rulesyncFrontmatter);
38779
+ if (!("nonRoot" in paths) || !paths.nonRoot) throw new Error(`nonRoot path is not set for ${rulesyncRule.getRelativeFilePath()}`);
37438
38780
  const kebabCaseFilename = toKebabCaseFilename(rulesyncRule.getRelativeFilePath());
37439
- return new AntigravityIdeRule({
38781
+ return new this({
37440
38782
  outputRoot,
37441
- relativeDirPath: buildToolPath(ANTIGRAVITY_IDE_AGENTS_DIR, "rules"),
38783
+ relativeDirPath: paths.nonRoot.relativeDirPath,
37442
38784
  relativeFilePath: kebabCaseFilename,
37443
38785
  frontmatter,
37444
38786
  body: rulesyncRule.getBody(),
@@ -37507,6 +38849,23 @@ var AntigravityIdeRule = class AntigravityIdeRule extends ToolRule {
37507
38849
  }
37508
38850
  };
37509
38851
  //#endregion
38852
+ //#region src/features/rules/antigravity-plugin-rule.ts
38853
+ var AntigravityPluginRule = class extends AntigravityIdeRule {
38854
+ static isTargetedByRulesyncRule(rulesyncRule) {
38855
+ const targets = rulesyncRule.getFrontmatter().targets;
38856
+ return targets.includes("*") || targets.includes("antigravity-plugin");
38857
+ }
38858
+ static getSettablePaths() {
38859
+ return {
38860
+ root: {
38861
+ relativeDirPath: ANTIGRAVITY_PLUGIN_RULES_DIR,
38862
+ relativeFilePath: "AGENTS.md"
38863
+ },
38864
+ nonRoot: { relativeDirPath: ANTIGRAVITY_PLUGIN_RULES_DIR }
38865
+ };
38866
+ }
38867
+ };
38868
+ //#endregion
37510
38869
  //#region src/features/rules/augmentcode-legacy-rule.ts
37511
38870
  var AugmentcodeLegacyRule = class AugmentcodeLegacyRule extends ToolRule {
37512
38871
  toRulesyncRule() {
@@ -39456,13 +40815,17 @@ var JunieRule = class JunieRule extends ToolRule {
39456
40815
  if (global) {
39457
40816
  const paths = this.getSettablePaths({ global: true });
39458
40817
  if (!("root" in paths) || !paths.root) throw new Error("JunieRule global settable paths must include a root path");
39459
- 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()}'`);
39460
- return new JunieRule(this.buildToolRuleParamsDefault({
40818
+ const frontmatter = rulesyncRule.getFrontmatter();
40819
+ return new JunieRule({
39461
40820
  outputRoot,
39462
- rulesyncRule,
40821
+ relativeDirPath: paths.root.relativeDirPath,
40822
+ relativeFilePath: paths.root.relativeFilePath,
40823
+ fileContent: rulesyncRule.getBody(),
39463
40824
  validate,
39464
- rootPath: paths.root
39465
- }));
40825
+ root: frontmatter.root ?? false,
40826
+ description: frontmatter.description,
40827
+ globs: frontmatter.globs
40828
+ });
39466
40829
  }
39467
40830
  const { root } = this.getSettablePaths();
39468
40831
  return new JunieRule({
@@ -39583,6 +40946,97 @@ var KiloRule = class KiloRule extends ToolRule {
39583
40946
  }
39584
40947
  };
39585
40948
  //#endregion
40949
+ //#region src/features/rules/kimi-code-rule.ts
40950
+ /**
40951
+ * Kimi Code instruction file.
40952
+ *
40953
+ * Kimi Code discovers `.kimi-code/AGENTS.md` at project scope and
40954
+ * `~/.kimi-code/AGENTS.md` at user scope. Rulesync's topic rules have no
40955
+ * dedicated Kimi rule directory, so the processor folds them into this root
40956
+ * instruction file.
40957
+ *
40958
+ * @see https://moonshotai.github.io/kimi-code/en/customization/agents.html
40959
+ */
40960
+ var KimiCodeRule = class KimiCodeRule extends ToolRule {
40961
+ constructor({ fileContent, root, ...rest }) {
40962
+ super({
40963
+ ...rest,
40964
+ fileContent,
40965
+ root: root ?? false
40966
+ });
40967
+ }
40968
+ static getSettablePaths({ global = false } = {}) {
40969
+ return { root: {
40970
+ relativeDirPath: getKimiCodeRelativeDirPath({ global }),
40971
+ relativeFilePath: KIMI_CODE_RULE_FILE_NAME
40972
+ } };
40973
+ }
40974
+ static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
40975
+ const { root } = this.getSettablePaths({ global });
40976
+ const fileContent = await readFileContent(join(outputRoot, root.relativeDirPath, root.relativeFilePath));
40977
+ return new KimiCodeRule({
40978
+ outputRoot,
40979
+ relativeDirPath: root.relativeDirPath,
40980
+ relativeFilePath: root.relativeFilePath,
40981
+ fileContent,
40982
+ validate,
40983
+ global,
40984
+ root: true
40985
+ });
40986
+ }
40987
+ static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
40988
+ const { root } = this.getSettablePaths({ global });
40989
+ return new KimiCodeRule({
40990
+ outputRoot,
40991
+ relativeDirPath: root.relativeDirPath,
40992
+ relativeFilePath: root.relativeFilePath,
40993
+ fileContent: rulesyncRule.getBody(),
40994
+ validate,
40995
+ global,
40996
+ root: rulesyncRule.getFrontmatter().root ?? false
40997
+ });
40998
+ }
40999
+ toRulesyncRule() {
41000
+ return new RulesyncRule({
41001
+ outputRoot: getKimiCodeRulesyncOutputRoot({
41002
+ nativeOutputRoot: this.outputRoot,
41003
+ global: this.global
41004
+ }),
41005
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
41006
+ relativeFilePath: RULESYNC_OVERVIEW_FILE_NAME,
41007
+ frontmatter: {
41008
+ root: true,
41009
+ targets: ["*"],
41010
+ globs: ["**/*"]
41011
+ },
41012
+ body: this.getFileContent()
41013
+ });
41014
+ }
41015
+ validate() {
41016
+ return {
41017
+ success: true,
41018
+ error: null
41019
+ };
41020
+ }
41021
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
41022
+ return new KimiCodeRule({
41023
+ outputRoot,
41024
+ relativeDirPath,
41025
+ relativeFilePath,
41026
+ fileContent: "",
41027
+ validate: false,
41028
+ global,
41029
+ root: relativeDirPath === getKimiCodeRelativeDirPath({ global }) && relativeFilePath === "AGENTS.md"
41030
+ });
41031
+ }
41032
+ static isTargetedByRulesyncRule(rulesyncRule) {
41033
+ return this.isTargetedByRulesyncRuleDefault({
41034
+ rulesyncRule,
41035
+ toolTarget: "kimi-code"
41036
+ });
41037
+ }
41038
+ };
41039
+ //#endregion
39586
41040
  //#region src/features/rules/kiro-rule.ts
39587
41041
  const WILDCARD_GLOBS = /* @__PURE__ */ new Set([
39588
41042
  "**/*",
@@ -41033,6 +42487,14 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
41033
42487
  ruleDiscoveryMode: "auto"
41034
42488
  }
41035
42489
  }],
42490
+ ["antigravity-plugin", {
42491
+ class: AntigravityPluginRule,
42492
+ meta: {
42493
+ extension: "md",
42494
+ supportsGlobal: false,
42495
+ ruleDiscoveryMode: "auto"
42496
+ }
42497
+ }],
41036
42498
  ["augmentcode", {
41037
42499
  class: AugmentcodeRule,
41038
42500
  meta: {
@@ -41172,6 +42634,15 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
41172
42634
  mcpInstructionsRegistrar: KiloMcp
41173
42635
  }
41174
42636
  }],
42637
+ ["kimi-code", {
42638
+ class: KimiCodeRule,
42639
+ meta: {
42640
+ extension: "md",
42641
+ supportsGlobal: true,
42642
+ ruleDiscoveryMode: "auto",
42643
+ foldsNonRootIntoRoot: true
42644
+ }
42645
+ }],
41175
42646
  ["kiro", {
41176
42647
  class: KiroRule,
41177
42648
  meta: {
@@ -41645,7 +43116,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
41645
43116
  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)})`);
41646
43117
  if (this.global) {
41647
43118
  const globalPaths = factory.class.getSettablePaths({ global: true });
41648
- const supportsGlobalNonRoot = "nonRoot" in globalPaths && globalPaths.nonRoot !== null;
43119
+ const supportsGlobalNonRoot = "nonRoot" in globalPaths && globalPaths.nonRoot !== null || factory.meta.supportsGlobal && factory.meta.foldsNonRootIntoRoot === true;
41649
43120
  const nonRootRules = rulesyncRules.filter((rule) => !rule.getFrontmatter().root && !rule.getFrontmatter().localRoot && factory.class.isTargetedByRulesyncRule(rule));
41650
43121
  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)}`);
41651
43122
  if (targetedLocalRootRules.length > 0) this.logger.warn(`${targetedLocalRootRules.length} localRoot rules found, but localRoot is not supported in global mode, ignoring them: ${formatRulePaths(targetedLocalRootRules)}`);
@@ -41848,12 +43319,25 @@ As this project's AI coding tool, you must follow the additional conventions bel
41848
43319
  }
41849
43320
  };
41850
43321
  //#endregion
43322
+ //#region src/utils/plugin-root.ts
43323
+ function isPackagingToolTarget(toolTarget) {
43324
+ return PACKAGING_TOOL_TARGETS.includes(toolTarget);
43325
+ }
43326
+ async function assertPluginRootSafe(params) {
43327
+ if (!isPackagingToolTarget(params.toolTarget)) return;
43328
+ await assertDirectoryIfExists(params.outputRoot);
43329
+ if (!await directoryExists(params.outputRoot)) throw new Error(`Plugin output root must be an existing directory: ${params.outputRoot}.`);
43330
+ await assertTreeContainsNoSymlinks(params.outputRoot);
43331
+ }
43332
+ //#endregion
41851
43333
  //#region src/lib/convert.ts
41852
43334
  /**
41853
43335
  * Convert configuration files between AI tools without writing intermediate
41854
43336
  * `.rulesync/` files to disk. Rulesync file instances live in memory only.
41855
43337
  */
41856
43338
  async function convertFromTool(params) {
43339
+ const packagingTarget = [params.fromTool, ...params.toTools].find(isPackagingToolTarget);
43340
+ if (packagingTarget) throw new Error(`Plugin packaging target '${packagingTarget}' is not supported by convert. Use import and generate with explicit plugin directories.`);
41857
43341
  const ctx = params;
41858
43342
  const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount, checksCount] = [
41859
43343
  await runFeatureConvert(ctx, buildRulesStrategy(ctx)),
@@ -41932,7 +43416,11 @@ function buildRulesStrategy(ctx) {
41932
43416
  itemLabel: "rule file(s)",
41933
43417
  allTargets: RulesProcessor.getToolTargets({ global }),
41934
43418
  createProcessor: ({ toolTarget, dryRun }) => new RulesProcessor({
41935
- outputRoot,
43419
+ outputRoot: resolveToolOutputRoot({
43420
+ outputRoot,
43421
+ toolTarget,
43422
+ global
43423
+ }),
41936
43424
  toolTarget,
41937
43425
  global,
41938
43426
  dryRun,
@@ -41946,18 +43434,20 @@ function buildRulesStrategy(ctx) {
41946
43434
  }
41947
43435
  function buildIgnoreStrategy(ctx) {
41948
43436
  const { config, logger } = ctx;
41949
- if (config.getGlobal()) {
41950
- logger.debug("Skipping ignore conversion (not supported in global mode)");
41951
- return null;
41952
- }
43437
+ const global = config.getGlobal();
41953
43438
  const outputRoot = getOutputRoot(config);
41954
43439
  return {
41955
43440
  feature: "ignore",
41956
43441
  itemLabel: "ignore file(s)",
41957
- allTargets: IgnoreProcessor.getToolTargets(),
43442
+ allTargets: IgnoreProcessor.getToolTargets({ global }),
41958
43443
  createProcessor: ({ toolTarget, dryRun }) => new IgnoreProcessor({
41959
- outputRoot,
43444
+ outputRoot: resolveToolOutputRoot({
43445
+ outputRoot,
43446
+ toolTarget,
43447
+ global
43448
+ }),
41960
43449
  toolTarget,
43450
+ global,
41961
43451
  dryRun,
41962
43452
  logger,
41963
43453
  featureOptions: config.getFeatureOptions(toolTarget, "ignore")
@@ -41977,7 +43467,11 @@ function buildMcpStrategy(ctx) {
41977
43467
  itemLabel: "MCP file(s)",
41978
43468
  allTargets: McpProcessor.getToolTargets({ global }),
41979
43469
  createProcessor: ({ toolTarget, dryRun }) => new McpProcessor({
41980
- outputRoot,
43470
+ outputRoot: resolveToolOutputRoot({
43471
+ outputRoot,
43472
+ toolTarget,
43473
+ global
43474
+ }),
41981
43475
  toolTarget,
41982
43476
  global,
41983
43477
  dryRun,
@@ -42026,7 +43520,11 @@ function buildSubagentsStrategy(ctx) {
42026
43520
  includeSimulated: false
42027
43521
  }),
42028
43522
  createProcessor: ({ toolTarget, dryRun }) => new SubagentsProcessor({
42029
- outputRoot,
43523
+ outputRoot: resolveToolOutputRoot({
43524
+ outputRoot,
43525
+ toolTarget,
43526
+ global
43527
+ }),
42030
43528
  toolTarget,
42031
43529
  global,
42032
43530
  dryRun,
@@ -42047,7 +43545,11 @@ function buildSkillsStrategy(ctx) {
42047
43545
  itemLabel: "skill(s)",
42048
43546
  allTargets: SkillsProcessor.getToolTargets({ global }),
42049
43547
  createProcessor: ({ toolTarget, dryRun }) => new SkillsProcessor({
42050
- outputRoot,
43548
+ outputRoot: resolveToolOutputRoot({
43549
+ outputRoot,
43550
+ toolTarget,
43551
+ global
43552
+ }),
42051
43553
  toolTarget,
42052
43554
  global,
42053
43555
  dryRun,
@@ -42072,7 +43574,11 @@ function buildHooksStrategy(ctx) {
42072
43574
  importOnly: true
42073
43575
  }),
42074
43576
  createProcessor: ({ toolTarget, dryRun }) => new HooksProcessor({
42075
- outputRoot,
43577
+ outputRoot: resolveToolOutputRoot({
43578
+ outputRoot,
43579
+ toolTarget,
43580
+ global
43581
+ }),
42076
43582
  toolTarget,
42077
43583
  global,
42078
43584
  dryRun,
@@ -42097,7 +43603,11 @@ function buildPermissionsStrategy(ctx) {
42097
43603
  importOnly: true
42098
43604
  }),
42099
43605
  createProcessor: ({ toolTarget, dryRun }) => new PermissionsProcessor({
42100
- outputRoot,
43606
+ outputRoot: resolveToolOutputRoot({
43607
+ outputRoot,
43608
+ toolTarget,
43609
+ global
43610
+ }),
42101
43611
  toolTarget,
42102
43612
  global,
42103
43613
  dryRun,
@@ -42598,6 +44108,10 @@ async function warnSkillSubagentNameCollisions(params) {
42598
44108
  */
42599
44109
  async function generate(params) {
42600
44110
  const { config, logger } = params;
44111
+ for (const toolTarget of config.getTargets()) for (const outputRoot of config.getOutputRoots(toolTarget)) await assertPluginRootSafe({
44112
+ toolTarget,
44113
+ outputRoot
44114
+ });
42601
44115
  await warnSkillSubagentNameCollisions({
42602
44116
  config,
42603
44117
  logger
@@ -42717,7 +44231,11 @@ async function generateRulesCore(params) {
42717
44231
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42718
44232
  if (!config.getFeatures(toolTarget).includes("rules")) continue;
42719
44233
  const processor = new RulesProcessor({
42720
- outputRoot,
44234
+ outputRoot: resolveToolOutputRoot({
44235
+ outputRoot,
44236
+ toolTarget,
44237
+ global: config.getGlobal()
44238
+ }),
42721
44239
  inputRoot: config.getInputRoot(),
42722
44240
  toolTarget,
42723
44241
  global: config.getGlobal(),
@@ -42752,18 +44270,14 @@ async function generateRulesCore(params) {
42752
44270
  }
42753
44271
  async function generateIgnoreCore(params) {
42754
44272
  const { config, logger } = params;
42755
- const supportedIgnoreTargets = config.getGlobal() ? [] : IgnoreProcessor.getToolTargets();
44273
+ const global = config.getGlobal();
44274
+ const supportedIgnoreTargets = IgnoreProcessor.getToolTargets({ global });
42756
44275
  warnUnsupportedTargets({
42757
44276
  config,
42758
44277
  supportedTargets: supportedIgnoreTargets,
42759
44278
  featureName: "ignore",
42760
44279
  logger
42761
44280
  });
42762
- if (config.getGlobal()) return {
42763
- count: 0,
42764
- paths: [],
42765
- hasDiff: false
42766
- };
42767
44281
  let totalCount = 0;
42768
44282
  const allPaths = [];
42769
44283
  let hasDiff = false;
@@ -42774,6 +44288,7 @@ async function generateIgnoreCore(params) {
42774
44288
  outputRoot,
42775
44289
  inputRoot: config.getInputRoot(),
42776
44290
  toolTarget,
44291
+ global,
42777
44292
  dryRun: config.isPreviewMode(),
42778
44293
  logger,
42779
44294
  featureOptions: config.getFeatureOptions(toolTarget, "ignore")
@@ -42813,7 +44328,11 @@ async function generateMcpCore(params) {
42813
44328
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42814
44329
  if (!config.getFeatures(toolTarget).includes("mcp")) continue;
42815
44330
  const processor = new McpProcessor({
42816
- outputRoot,
44331
+ outputRoot: resolveToolOutputRoot({
44332
+ outputRoot,
44333
+ toolTarget,
44334
+ global: config.getGlobal()
44335
+ }),
42817
44336
  inputRoot: config.getInputRoot(),
42818
44337
  toolTarget,
42819
44338
  global: config.getGlobal(),
@@ -42898,7 +44417,11 @@ async function generateSubagentsCore(params) {
42898
44417
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42899
44418
  if (!config.getFeatures(toolTarget).includes("subagents")) continue;
42900
44419
  const processor = new SubagentsProcessor({
42901
- outputRoot,
44420
+ outputRoot: resolveToolOutputRoot({
44421
+ outputRoot,
44422
+ toolTarget,
44423
+ global: config.getGlobal()
44424
+ }),
42902
44425
  inputRoot: config.getInputRoot(),
42903
44426
  toolTarget,
42904
44427
  global: config.getGlobal(),
@@ -42941,7 +44464,11 @@ async function generateSkillsCore(params) {
42941
44464
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42942
44465
  if (!config.getFeatures(toolTarget).includes("skills")) continue;
42943
44466
  const processor = new SkillsProcessor({
42944
- outputRoot,
44467
+ outputRoot: resolveToolOutputRoot({
44468
+ outputRoot,
44469
+ toolTarget,
44470
+ global: config.getGlobal()
44471
+ }),
42945
44472
  inputRoot: config.getInputRoot(),
42946
44473
  toolTarget,
42947
44474
  global: config.getGlobal(),
@@ -42982,7 +44509,11 @@ async function generateHooksCore(params) {
42982
44509
  for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
42983
44510
  if (!config.getFeatures(toolTarget).includes("hooks")) continue;
42984
44511
  const processor = new HooksProcessor({
42985
- outputRoot,
44512
+ outputRoot: resolveToolOutputRoot({
44513
+ outputRoot,
44514
+ toolTarget,
44515
+ global: config.getGlobal()
44516
+ }),
42986
44517
  inputRoot: config.getInputRoot(),
42987
44518
  toolTarget,
42988
44519
  global: config.getGlobal(),
@@ -43020,7 +44551,11 @@ async function generatePermissionsCore(params) {
43020
44551
  if (!config.getFeatures(toolTarget).includes("permissions")) continue;
43021
44552
  try {
43022
44553
  const processor = new PermissionsProcessor({
43023
- outputRoot,
44554
+ outputRoot: resolveToolOutputRoot({
44555
+ outputRoot,
44556
+ toolTarget,
44557
+ global: config.getGlobal()
44558
+ }),
43024
44559
  inputRoot: config.getInputRoot(),
43025
44560
  toolTarget,
43026
44561
  global: config.getGlobal(),
@@ -43086,21 +44621,41 @@ async function generateChecksCore(params) {
43086
44621
  }
43087
44622
  //#endregion
43088
44623
  //#region src/lib/import.ts
43089
- /**
43090
- * Import always writes the `.json` variant of a fixed-path source file, but a
43091
- * sibling `.jsonc` variant takes precedence at read time — so an import into a
43092
- * project that authors the `.jsonc` variant would be silently shadowed. Warn
43093
- * so the user merges (or removes) one of the two by hand.
43094
- */
43095
- async function warnIfShadowedByJsonc(params) {
43096
- const { outputRoot, jsonRelativePath, jsoncRelativePath, logger } = params;
43097
- if (await fileExists(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.`);
44624
+ async function applyRulesyncSourcePath({ files, paths, sourceClass, outputRoot }) {
44625
+ const first = files[0];
44626
+ if (!first) return files;
44627
+ const destinationOutputRoot = outputRoot ?? first.getOutputRoot();
44628
+ const destination = await resolveRulesyncSourceWritePath({
44629
+ outputRoot: destinationOutputRoot,
44630
+ paths
44631
+ });
44632
+ return files.map((file) => new sourceClass({
44633
+ outputRoot: destinationOutputRoot,
44634
+ relativeDirPath: destination.relativeDirPath,
44635
+ relativeFilePath: destination.relativeFilePath,
44636
+ fileContent: file.getFileContent(),
44637
+ validate: true
44638
+ }));
44639
+ }
44640
+ function getToolOutputRoot({ config, tool }) {
44641
+ return resolveToolOutputRoot({
44642
+ outputRoot: config.getOutputRoots(tool)[0] ?? ".",
44643
+ toolTarget: tool,
44644
+ global: config.getGlobal()
44645
+ });
43098
44646
  }
43099
44647
  /**
43100
44648
  * Import configuration files from AI tools.
43101
44649
  */
43102
44650
  async function importFromTool(params) {
43103
44651
  const { config, tool, logger } = params;
44652
+ await assertPluginRootSafe({
44653
+ toolTarget: tool,
44654
+ outputRoot: getToolOutputRoot({
44655
+ config,
44656
+ tool
44657
+ })
44658
+ });
43104
44659
  return {
43105
44660
  rulesCount: await importRulesCore({
43106
44661
  config,
@@ -43155,7 +44710,10 @@ async function importRulesCore(params) {
43155
44710
  const global = config.getGlobal();
43156
44711
  if (!RulesProcessor.getToolTargets({ global }).includes(tool)) return 0;
43157
44712
  const rulesProcessor = new RulesProcessor({
43158
- outputRoot: config.getOutputRoots()[0] ?? ".",
44713
+ outputRoot: getToolOutputRoot({
44714
+ config,
44715
+ tool
44716
+ }),
43159
44717
  toolTarget: tool,
43160
44718
  global,
43161
44719
  logger
@@ -43173,14 +44731,15 @@ async function importRulesCore(params) {
43173
44731
  async function importIgnoreCore(params) {
43174
44732
  const { config, tool, logger } = params;
43175
44733
  if (!config.getFeatures(tool).includes("ignore")) return 0;
43176
- if (config.getGlobal()) {
43177
- logger.debug("Skipping ignore file import (not supported in global mode)");
43178
- return 0;
43179
- }
43180
- if (!IgnoreProcessor.getToolTargets().includes(tool)) return 0;
44734
+ const global = config.getGlobal();
44735
+ if (!IgnoreProcessor.getToolTargets({ global }).includes(tool)) return 0;
43181
44736
  const ignoreProcessor = new IgnoreProcessor({
43182
- outputRoot: config.getOutputRoots()[0] ?? ".",
44737
+ outputRoot: getToolOutputRoot({
44738
+ config,
44739
+ tool
44740
+ }),
43183
44741
  toolTarget: tool,
44742
+ global,
43184
44743
  logger,
43185
44744
  featureOptions: config.getFeatureOptions(tool, "ignore")
43186
44745
  });
@@ -43201,7 +44760,10 @@ async function importMcpCore(params) {
43201
44760
  const global = config.getGlobal();
43202
44761
  if (!McpProcessor.getToolTargets({ global }).includes(tool)) return 0;
43203
44762
  const mcpProcessor = new McpProcessor({
43204
- outputRoot: config.getOutputRoots()[0] ?? ".",
44763
+ outputRoot: getToolOutputRoot({
44764
+ config,
44765
+ tool
44766
+ }),
43205
44767
  toolTarget: tool,
43206
44768
  global,
43207
44769
  logger
@@ -43211,14 +44773,13 @@ async function importMcpCore(params) {
43211
44773
  logger.warn(`No MCP files found for ${tool}. Skipping import.`);
43212
44774
  return 0;
43213
44775
  }
43214
- const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43215
- const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
43216
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43217
- outputRoot: config.getOutputRoots()[0] ?? ".",
43218
- jsonRelativePath: RULESYNC_MCP_RELATIVE_FILE_PATH,
43219
- jsoncRelativePath: RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH,
43220
- logger
44776
+ const rulesyncFiles = await applyRulesyncSourcePath({
44777
+ files: await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44778
+ paths: RulesyncMcp.getSettablePaths(),
44779
+ sourceClass: RulesyncMcp,
44780
+ outputRoot: isPackagingToolTarget(tool) ? process.cwd() : void 0
43221
44781
  });
44782
+ const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
43222
44783
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} MCP files`);
43223
44784
  return writtenCount;
43224
44785
  }
@@ -43231,7 +44792,10 @@ async function importCommandsCore(params) {
43231
44792
  includeSimulated: false
43232
44793
  }).includes(tool)) return 0;
43233
44794
  const commandsProcessor = new CommandsProcessor({
43234
- outputRoot: config.getOutputRoots()[0] ?? ".",
44795
+ outputRoot: getToolOutputRoot({
44796
+ config,
44797
+ tool
44798
+ }),
43235
44799
  toolTarget: tool,
43236
44800
  global,
43237
44801
  logger
@@ -43255,7 +44819,10 @@ async function importSubagentsCore(params) {
43255
44819
  includeSimulated: false
43256
44820
  }).includes(tool)) return 0;
43257
44821
  const subagentsProcessor = new SubagentsProcessor({
43258
- outputRoot: config.getOutputRoots()[0] ?? ".",
44822
+ outputRoot: getToolOutputRoot({
44823
+ config,
44824
+ tool
44825
+ }),
43259
44826
  toolTarget: tool,
43260
44827
  global: config.getGlobal(),
43261
44828
  logger
@@ -43276,7 +44843,10 @@ async function importSkillsCore(params) {
43276
44843
  const global = config.getGlobal();
43277
44844
  if (!SkillsProcessor.getToolTargets({ global }).includes(tool)) return 0;
43278
44845
  const skillsProcessor = new SkillsProcessor({
43279
- outputRoot: config.getOutputRoots()[0] ?? ".",
44846
+ outputRoot: getToolOutputRoot({
44847
+ config,
44848
+ tool
44849
+ }),
43280
44850
  toolTarget: tool,
43281
44851
  global,
43282
44852
  logger
@@ -43286,8 +44856,21 @@ async function importSkillsCore(params) {
43286
44856
  logger.warn(`No skill directories found for ${tool}. Skipping import.`);
43287
44857
  return 0;
43288
44858
  }
43289
- const rulesyncDirs = await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs);
43290
- const { count: writtenCount } = await skillsProcessor.writeAiDirs(rulesyncDirs);
44859
+ const rebasedRulesyncDirs = (await skillsProcessor.convertToolDirsToRulesyncDirs(toolDirs)).map((dir) => {
44860
+ if (!isPackagingToolTarget(tool)) return dir;
44861
+ if (!(dir instanceof RulesyncSkill)) return dir;
44862
+ return new RulesyncSkill({
44863
+ outputRoot: process.cwd(),
44864
+ relativeDirPath: dir.getRelativeDirPath(),
44865
+ dirName: dir.getDirName(),
44866
+ frontmatter: dir.getFrontmatter(),
44867
+ body: dir.getBody(),
44868
+ otherFiles: dir.getOtherFiles(),
44869
+ validate: true,
44870
+ global: false
44871
+ });
44872
+ });
44873
+ const { count: writtenCount } = await skillsProcessor.writeAiDirs(rebasedRulesyncDirs);
43291
44874
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} skill directories`);
43292
44875
  return writtenCount;
43293
44876
  }
@@ -43306,7 +44889,10 @@ async function importHooksCore(params) {
43306
44889
  return 0;
43307
44890
  }
43308
44891
  const hooksProcessor = new HooksProcessor({
43309
- outputRoot: config.getOutputRoots()[0] ?? ".",
44892
+ outputRoot: getToolOutputRoot({
44893
+ config,
44894
+ tool
44895
+ }),
43310
44896
  toolTarget: tool,
43311
44897
  global,
43312
44898
  logger
@@ -43316,14 +44902,13 @@ async function importHooksCore(params) {
43316
44902
  logger.warn(`No hooks files found for ${tool}. Skipping import.`);
43317
44903
  return 0;
43318
44904
  }
43319
- const rulesyncFiles = await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43320
- const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
43321
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43322
- outputRoot: config.getOutputRoots()[0] ?? ".",
43323
- jsonRelativePath: RULESYNC_HOOKS_RELATIVE_FILE_PATH,
43324
- jsoncRelativePath: RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH,
43325
- logger
44905
+ const rulesyncFiles = await applyRulesyncSourcePath({
44906
+ files: await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44907
+ paths: RulesyncHooks.getSettablePaths(),
44908
+ sourceClass: RulesyncHooks,
44909
+ outputRoot: isPackagingToolTarget(tool) ? process.cwd() : void 0
43326
44910
  });
44911
+ const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
43327
44912
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} hooks file(s)`);
43328
44913
  return writtenCount;
43329
44914
  }
@@ -43341,7 +44926,10 @@ async function importPermissionsCore(params) {
43341
44926
  return 0;
43342
44927
  }
43343
44928
  const permissionsProcessor = new PermissionsProcessor({
43344
- outputRoot: config.getOutputRoots()[0] ?? ".",
44929
+ outputRoot: getToolOutputRoot({
44930
+ config,
44931
+ tool
44932
+ }),
43345
44933
  toolTarget: tool,
43346
44934
  global: config.getGlobal(),
43347
44935
  logger
@@ -43351,14 +44939,12 @@ async function importPermissionsCore(params) {
43351
44939
  logger.warn(`No permissions files found for ${tool}. Skipping import.`);
43352
44940
  return 0;
43353
44941
  }
43354
- const rulesyncFiles = await permissionsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
43355
- const { count: writtenCount } = await permissionsProcessor.writeAiFiles(rulesyncFiles);
43356
- if (writtenCount > 0) await warnIfShadowedByJsonc({
43357
- outputRoot: config.getOutputRoots()[0] ?? ".",
43358
- jsonRelativePath: RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH,
43359
- jsoncRelativePath: RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH,
43360
- logger
44942
+ const rulesyncFiles = await applyRulesyncSourcePath({
44943
+ files: await permissionsProcessor.convertToolFilesToRulesyncFiles(toolFiles),
44944
+ paths: RulesyncPermissions.getSettablePaths(),
44945
+ sourceClass: RulesyncPermissions
43361
44946
  });
44947
+ const { count: writtenCount } = await permissionsProcessor.writeAiFiles(rulesyncFiles);
43362
44948
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} permissions file(s)`);
43363
44949
  return writtenCount;
43364
44950
  }
@@ -43384,6 +44970,6 @@ async function importChecksCore(params) {
43384
44970
  return writtenCount;
43385
44971
  }
43386
44972
  //#endregion
43387
- export { createTempDirectory as $, RulesyncIgnore as A, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as At, ConfigFileSchema as B, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Bt, RulesyncSubagentFrontmatterSchema as C, RULESYNC_AIIGNORE_FILE_NAME as Ct, RulesyncRuleFrontmatterSchema as D, RULESYNC_CONFIG_RELATIVE_FILE_PATH as Dt, RulesyncRule as E, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as Et, RulesyncCheckFrontmatterSchema as F, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as Ft, fallbackLogger as G, RULESYNC_RELATIVE_DIR_PATH as Gt, findControlCharacter as H, RULESYNC_PERMISSIONS_JSONC_FILE_NAME as Ht, stringifyFrontmatter as I, RULESYNC_MCP_FILE_NAME as It, ErrorCodes as J, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Jt, warnOnConflictingFlags as K, RULESYNC_RULES_RELATIVE_DIR_PATH as Kt, loadYaml as L, RULESYNC_MCP_JSONC_FILE_NAME as Lt, RulesyncCommand as M, RULESYNC_HOOKS_JSONC_FILE_NAME as Mt, RulesyncCommandFrontmatterSchema as N, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Nt, RulesyncPermissions as O, RULESYNC_CONFIG_SCHEMA_URL as Ot, RulesyncCheck as P, RULESYNC_IGNORE_RELATIVE_FILE_PATH as Pt, checkPathTraversal as Q, ALL_FEATURES_WITH_WILDCARD as Qt, SKILL_FILE_NAME as R, RULESYNC_MCP_RELATIVE_FILE_PATH as Rt, RulesyncSubagent as S, MAX_FILE_SIZE as St, RulesyncSkillFrontmatterSchema as T, RULESYNC_CHECKS_RELATIVE_DIR_PATH as Tt, ConsoleLogger as U, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Ut, SourceEntrySchema as V, RULESYNC_PERMISSIONS_FILE_NAME as Vt, JsonLogger as W, RULESYNC_PERMISSIONS_SCHEMA_URL as Wt, assertTreeContainsNoSymlinks as X, formatError as Xt, assertDirectoryIfExists as Y, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Yt, assertWritablePathInsideRoot as Z, ALL_FEATURES as Zt, CLAUDECODE_MEMORIES_DIR_NAME as _, toPosixPath as _t, convertFromTool as a, getHomeDirectory as at, ChecksProcessor as b, ALL_TOOL_TARGETS_WITH_WILDCARD as bt, SkillsProcessor as c, readFileContent as ct, HooksProcessor as d, removeDirectoryStrict as dt, directoryExists as et, CommandsProcessor as f, removeFile as ft, CLAUDECODE_LOCAL_RULE_FILE_NAME as g, runWithDirectoryRollback as gt, CLAUDECODE_DIR as h, resolvePath as ht, getProcessorRegistryEntry as i, getFileSize as it, RulesyncHooks as j, RULESYNC_HOOKS_FILE_NAME as jt, RulesyncMcp as k, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as kt, McpProcessor as l, readFileContentOrNull as lt, CODEXCLI_DIR as m, removeTempDirectory as mt, checkRulesyncDirExists as n, fileExists as nt, RulesProcessor as o, isSymlink as ot, CODEXCLI_BASH_RULES_FILE_NAME as p, removeFileStrict as pt, CLIError as q, RULESYNC_SKILLS_RELATIVE_DIR_PATH as qt, generate as r, findFilesByGlobs as rt, SubagentsProcessor as s, listDirectoryFiles as st, importFromTool as t, ensureDir as tt, IgnoreProcessor as u, removeDirectory as ut, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as v, writeFileContent as vt, RulesyncSkill as w, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as wt, getLocalSkillDirNames as x, ToolTargetSchema as xt, CLAUDECODE_SKILLS_DIR_PATH as y, ALL_TOOL_TARGETS as yt, ConfigResolver as z, RULESYNC_MCP_SCHEMA_URL as zt };
44973
+ export { assertDirectoryIfExists as $, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as $t, RulesyncMcp as A, RULESYNC_CHECKS_RELATIVE_DIR_PATH as At, stringifyFrontmatter as B, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as Bt, RulesyncSubagent as C, ALL_TOOL_TARGETS as Ct, RulesyncRule as D, MAX_FILE_SIZE as Dt, RulesyncSkillFrontmatterSchema as E, ToolTargetSchema as Et, parseJsonc as F, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as Ft, SourceEntrySchema as G, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Gt, SKILL_FILE_NAME as H, RULESYNC_MCP_LEGACY_FILE_NAME as Ht, RulesyncCommand as I, RULESYNC_HOOKS_FILE_NAME as It, JsonLogger as J, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Jt, findControlCharacter as K, RULESYNC_PERMISSIONS_FILE_NAME as Kt, RulesyncCommandFrontmatterSchema as L, RULESYNC_HOOKS_LEGACY_FILE_NAME as Lt, RulesyncHooks as M, RULESYNC_CONFIG_RELATIVE_FILE_PATH as Mt, getRulesyncSourceCandidates as N, RULESYNC_CONFIG_SCHEMA_URL as Nt, RulesyncRuleFrontmatterSchema as O, RULESYNC_AIIGNORE_FILE_NAME as Ot, resolveRulesyncSourceWritePath as P, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as Pt, ErrorCodes as Q, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Qt, RulesyncCheck as R, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Rt, getLocalSkillDirNames as S, writeFileContent as St, RulesyncSkill as T, PACKAGING_TOOL_TARGETS as Tt, ConfigResolver as U, RULESYNC_MCP_RELATIVE_FILE_PATH as Ut, loadYaml as V, RULESYNC_MCP_FILE_NAME as Vt, ConfigFileSchema as W, RULESYNC_MCP_SCHEMA_URL as Wt, warnOnConflictingFlags as X, RULESYNC_RELATIVE_DIR_PATH as Xt, fallbackLogger as Y, RULESYNC_PERMISSIONS_SCHEMA_URL as Yt, CLIError as Z, RULESYNC_RULES_RELATIVE_DIR_PATH as Zt, CLAUDECODE_LOCAL_RULE_FILE_NAME as _, removeFileStrict as _t, convertFromTool as a, ensureDir as at, CLAUDECODE_SKILLS_DIR_PATH as b, runWithDirectoryRollback as bt, SubagentsProcessor as c, getFileSize as ct, IgnoreProcessor as d, listDirectoryFiles as dt, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as en, assertTreeContainsNoSymlinks as et, HooksProcessor as f, readFileContent as ft, CLAUDECODE_DIR as g, removeFile as gt, CODEXCLI_DIR as h, removeDirectoryStrict as ht, getProcessorRegistryEntry as i, directoryExists as it, RulesyncIgnore as j, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as jt, RulesyncPermissions as k, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as kt, SkillsProcessor as l, getHomeDirectory as lt, CODEXCLI_BASH_RULES_FILE_NAME as m, removeDirectory as mt, checkRulesyncDirExists as n, ALL_FEATURES_WITH_WILDCARD as nn, checkPathTraversal as nt, isPackagingToolTarget as o, fileExists as ot, CommandsProcessor as p, readFileContentOrNull as pt, ConsoleLogger as q, RULESYNC_PERMISSIONS_LEGACY_FILE_NAME as qt, generate as r, formatError as rn, createTempDirectory as rt, RulesProcessor as s, findFilesByGlobs as st, importFromTool as t, ALL_FEATURES as tn, assertWritablePathInsideRoot as tt, McpProcessor as u, isSymlink as ut, CLAUDECODE_MEMORIES_DIR_NAME as v, removeTempDirectory as vt, RulesyncSubagentFrontmatterSchema as w, ALL_TOOL_TARGETS_WITH_WILDCARD as wt, ChecksProcessor as x, toPosixPath as xt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as y, resolvePath as yt, RulesyncCheckFrontmatterSchema as z, RULESYNC_IGNORE_RELATIVE_FILE_PATH as zt };
43388
44974
 
43389
- //# sourceMappingURL=import-CMCy95RI.js.map
44975
+ //# sourceMappingURL=import-BuxzyDyH.js.map