rulesync 9.5.0 → 9.6.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.
@@ -31,11 +31,11 @@ node_os = __toESM(node_os, 1);
31
31
  let es_toolkit = require("es-toolkit");
32
32
  let globby = require("globby");
33
33
  let node_util = require("node:util");
34
- let js_yaml = require("js-yaml");
35
34
  let smol_toml = require("smol-toml");
36
35
  smol_toml = __toESM(smol_toml, 1);
37
36
  let gray_matter = require("gray-matter");
38
37
  gray_matter = __toESM(gray_matter, 1);
38
+ let js_yaml = require("js-yaml");
39
39
  let es_toolkit_object = require("es-toolkit/object");
40
40
  let _toon_format_toon = require("@toon-format/toon");
41
41
  //#region src/types/features.ts
@@ -114,22 +114,22 @@ function formatError(error) {
114
114
  }
115
115
  //#endregion
116
116
  //#region src/constants/rulesync-paths.ts
117
- const { join: join$247 } = node_path.posix;
117
+ const { join: join$249 } = node_path.posix;
118
118
  const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
119
119
  const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
120
120
  const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
121
- const RULESYNC_RULES_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "rules");
122
- const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "commands");
123
- const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "subagents");
124
- const RULESYNC_MCP_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
125
- const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
126
- const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
121
+ const RULESYNC_RULES_RELATIVE_DIR_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "rules");
122
+ const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "commands");
123
+ const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "subagents");
124
+ const RULESYNC_MCP_RELATIVE_FILE_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
125
+ const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
126
+ const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
127
127
  const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
128
- const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
128
+ const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
129
129
  const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
130
130
  const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
131
- const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "skills");
132
- const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$247(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
131
+ const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$249(RULESYNC_RELATIVE_DIR_PATH, "skills");
132
+ const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$249(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
133
133
  const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
134
134
  const RULESYNC_MCP_FILE_NAME = "mcp.json";
135
135
  const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
@@ -167,6 +167,7 @@ const rulesProcessorToolTargetTuple = [
167
167
  "opencode",
168
168
  "pi",
169
169
  "qwencode",
170
+ "reasonix",
170
171
  "replit",
171
172
  "roo",
172
173
  "rovodev",
@@ -314,6 +315,7 @@ const skillsProcessorToolTargetTuple = [
314
315
  "opencode",
315
316
  "pi",
316
317
  "qwencode",
318
+ "reasonix",
317
319
  "replit",
318
320
  "roo",
319
321
  "rovodev",
@@ -1317,7 +1319,8 @@ var ConfigResolver = class {
1317
1319
  const validatedConfigPath = resolvePath(configPath, (0, node_path.resolve)(inputRoot ?? cwd));
1318
1320
  const baseConfig = await loadConfigFromFile(validatedConfigPath);
1319
1321
  const localConfigPath = (0, node_path.join)((0, node_path.dirname)(validatedConfigPath), RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH);
1320
- const configByFile = mergeConfigs(baseConfig, await loadConfigFromFile(localConfigPath));
1322
+ const localConfig = await loadConfigFromFile(localConfigPath);
1323
+ const configByFile = mergeConfigs(baseConfig, localConfig);
1321
1324
  if (inputRoot === void 0 && configByFile.inputRoot !== void 0) validateOutputRoot(configByFile.inputRoot);
1322
1325
  assertMergedTargetsFeaturesExclusive({
1323
1326
  configByFile,
@@ -1450,7 +1453,7 @@ function isRecord(value) {
1450
1453
  * conversion, etc.) should reject inputs whose prototype could carry
1451
1454
  * malicious accessor descriptors.
1452
1455
  */
1453
- function isPlainObject(value) {
1456
+ function isPlainObject$1(value) {
1454
1457
  if (!isRecord(value)) return false;
1455
1458
  const proto = Object.getPrototypeOf(value);
1456
1459
  return proto === null || proto === Object.prototype;
@@ -1462,11 +1465,43 @@ function isStringArray(value) {
1462
1465
  return Array.isArray(value) && value.every((item) => typeof item === "string");
1463
1466
  }
1464
1467
  //#endregion
1468
+ //#region src/utils/yaml.ts
1469
+ /**
1470
+ * js-yaml v5's `reason` for an empty document. `load("")` — and any
1471
+ * whitespace/comment-only input — throws a `YAMLException` with this reason
1472
+ * instead of returning `undefined` the way v4 did.
1473
+ */
1474
+ const EMPTY_INPUT_REASON = "expected a document, but the input is empty";
1475
+ /**
1476
+ * Load YAML content while preserving js-yaml v4's behavior of returning
1477
+ * `undefined` for empty documents (empty, whitespace-only, or comment-only
1478
+ * input).
1479
+ *
1480
+ * js-yaml v5 changed `load("")` to **throw** ("expected a document, but the
1481
+ * input is empty") instead of returning `undefined`. Many call sites here parse
1482
+ * config/lock/frontmatter files that can legitimately be empty and rely on the
1483
+ * old `undefined` sentinel (`load(input) ?? {}`, `if (loaded === undefined)`,
1484
+ * "an empty file parses to undefined/null"). Routing every load through this
1485
+ * wrapper keeps that contract in one place so a future js-yaml bump cannot
1486
+ * reintroduce the empty-input regression. Genuine parse errors still propagate.
1487
+ *
1488
+ * @see https://github.com/nodeca/js-yaml/blob/master/docs/migrate_v4_to_v5.md#empty-input-throws
1489
+ */
1490
+ function loadYaml(content) {
1491
+ if (content.trim() === "") return;
1492
+ try {
1493
+ return (0, js_yaml.load)(content);
1494
+ } catch (error) {
1495
+ if (error instanceof js_yaml.YAMLException && error.reason === EMPTY_INPUT_REASON) return;
1496
+ throw error;
1497
+ }
1498
+ }
1499
+ //#endregion
1465
1500
  //#region src/utils/frontmatter.ts
1466
1501
  function deepRemoveNullishValue(value) {
1467
1502
  if (value === null || value === void 0) return;
1468
1503
  if (Array.isArray(value)) return value.map((item) => deepRemoveNullishValue(item)).filter((item) => item !== void 0);
1469
- if (isPlainObject(value)) {
1504
+ if (isPlainObject$1(value)) {
1470
1505
  const result = {};
1471
1506
  for (const [key, val] of Object.entries(value)) {
1472
1507
  const cleaned = deepRemoveNullishValue(val);
@@ -1489,7 +1524,7 @@ function deepFlattenStringsValue(value) {
1489
1524
  if (value === null || value === void 0) return;
1490
1525
  if (typeof value === "string") return value.replace(/\n+/g, " ").trim();
1491
1526
  if (Array.isArray(value)) return value.map((item) => deepFlattenStringsValue(item)).filter((item) => item !== void 0);
1492
- if (isPlainObject(value)) {
1527
+ if (isPlainObject$1(value)) {
1493
1528
  const result = {};
1494
1529
  for (const [key, val] of Object.entries(value)) {
1495
1530
  const cleaned = deepFlattenStringsValue(val);
@@ -1512,7 +1547,7 @@ function stringifyFrontmatter(body, frontmatter, options) {
1512
1547
  const { avoidBlockScalars = false } = options ?? {};
1513
1548
  const cleanFrontmatter = avoidBlockScalars ? deepFlattenStringsObject(frontmatter) : deepRemoveNullishObject(frontmatter);
1514
1549
  if (avoidBlockScalars) return gray_matter.default.stringify(body, cleanFrontmatter, { engines: { yaml: {
1515
- parse: (input) => (0, js_yaml.load)(input) ?? {},
1550
+ parse: (input) => loadYaml(input) ?? {},
1516
1551
  stringify: (data) => (0, js_yaml.dump)(data, { lineWidth: -1 })
1517
1552
  } } });
1518
1553
  return gray_matter.default.stringify(body, cleanFrontmatter);
@@ -1551,7 +1586,7 @@ function tryJsonEquivalent(a, b) {
1551
1586
  }
1552
1587
  function tryYamlEquivalent(a, b) {
1553
1588
  try {
1554
- return (0, node_util.isDeepStrictEqual)((0, js_yaml.load)(a), (0, js_yaml.load)(b));
1589
+ return (0, node_util.isDeepStrictEqual)(loadYaml(a), loadYaml(b));
1555
1590
  } catch {
1556
1591
  return;
1557
1592
  }
@@ -2373,14 +2408,17 @@ var AugmentcodeCommand = class AugmentcodeCommand extends ToolCommand {
2373
2408
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
2374
2409
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
2375
2410
  const augmentcodeFields = rulesyncFrontmatter.augmentcode ?? {};
2411
+ const augmentcodeFrontmatter = {
2412
+ description: rulesyncFrontmatter.description,
2413
+ ...augmentcodeFields
2414
+ };
2415
+ const body = rulesyncCommand.getBody();
2416
+ const paths = this.getSettablePaths({ global });
2376
2417
  return new AugmentcodeCommand({
2377
2418
  outputRoot,
2378
- frontmatter: {
2379
- description: rulesyncFrontmatter.description,
2380
- ...augmentcodeFields
2381
- },
2382
- body: rulesyncCommand.getBody(),
2383
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
2419
+ frontmatter: augmentcodeFrontmatter,
2420
+ body,
2421
+ relativeDirPath: paths.relativeDirPath,
2384
2422
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
2385
2423
  validate
2386
2424
  });
@@ -2514,14 +2552,17 @@ var ClaudecodeCommand = class ClaudecodeCommand extends ToolCommand {
2514
2552
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
2515
2553
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
2516
2554
  const claudecodeFields = rulesyncFrontmatter.claudecode ?? {};
2555
+ const claudecodeFrontmatter = {
2556
+ description: rulesyncFrontmatter.description,
2557
+ ...claudecodeFields
2558
+ };
2559
+ const body = rulesyncCommand.getBody();
2560
+ const paths = this.getSettablePaths({ global });
2517
2561
  return new ClaudecodeCommand({
2518
2562
  outputRoot,
2519
- frontmatter: {
2520
- description: rulesyncFrontmatter.description,
2521
- ...claudecodeFields
2522
- },
2523
- body: rulesyncCommand.getBody(),
2524
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
2563
+ frontmatter: claudecodeFrontmatter,
2564
+ body,
2565
+ relativeDirPath: paths.relativeDirPath,
2525
2566
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
2526
2567
  validate
2527
2568
  });
@@ -2722,12 +2763,13 @@ var CodexcliCommand = class CodexcliCommand extends ToolCommand {
2722
2763
  const paths = this.getSettablePaths({ global });
2723
2764
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
2724
2765
  const codexcliFields = rulesyncFrontmatter.codexcli ?? {};
2766
+ const codexcliFrontmatter = {
2767
+ ...rulesyncFrontmatter.description !== void 0 && { description: rulesyncFrontmatter.description },
2768
+ ...codexcliFields
2769
+ };
2725
2770
  return new CodexcliCommand({
2726
2771
  outputRoot,
2727
- frontmatter: {
2728
- ...rulesyncFrontmatter.description !== void 0 && { description: rulesyncFrontmatter.description },
2729
- ...codexcliFields
2730
- },
2772
+ frontmatter: codexcliFrontmatter,
2731
2773
  body: rulesyncCommand.getBody(),
2732
2774
  relativeDirPath: paths.relativeDirPath,
2733
2775
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
@@ -2989,14 +3031,17 @@ var CursorCommand = class CursorCommand extends ToolCommand {
2989
3031
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
2990
3032
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
2991
3033
  const cursorFields = rulesyncFrontmatter.cursor ?? {};
3034
+ const cursorFrontmatter = {
3035
+ ...rulesyncFrontmatter.description && { description: rulesyncFrontmatter.description },
3036
+ ...cursorFields
3037
+ };
3038
+ const body = rulesyncCommand.getBody();
3039
+ const paths = this.getSettablePaths({ global });
2992
3040
  return new CursorCommand({
2993
3041
  outputRoot,
2994
- frontmatter: {
2995
- ...rulesyncFrontmatter.description && { description: rulesyncFrontmatter.description },
2996
- ...cursorFields
2997
- },
2998
- body: rulesyncCommand.getBody(),
2999
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3042
+ frontmatter: cursorFrontmatter,
3043
+ body,
3044
+ relativeDirPath: paths.relativeDirPath,
3000
3045
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3001
3046
  validate
3002
3047
  });
@@ -3120,14 +3165,17 @@ var DevinCommand = class DevinCommand extends ToolCommand {
3120
3165
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
3121
3166
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
3122
3167
  const devinFields = rulesyncFrontmatter.devin ?? {};
3168
+ const devinFrontmatter = {
3169
+ description: rulesyncFrontmatter.description,
3170
+ ...devinFields
3171
+ };
3172
+ const body = rulesyncCommand.getBody();
3173
+ const paths = this.getSettablePaths({ global });
3123
3174
  return new DevinCommand({
3124
3175
  outputRoot,
3125
- frontmatter: {
3126
- description: rulesyncFrontmatter.description,
3127
- ...devinFields
3128
- },
3129
- body: rulesyncCommand.getBody(),
3130
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3176
+ frontmatter: devinFrontmatter,
3177
+ body,
3178
+ relativeDirPath: paths.relativeDirPath,
3131
3179
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3132
3180
  validate
3133
3181
  });
@@ -3241,14 +3289,17 @@ var FactorydroidCommand = class FactorydroidCommand extends ToolCommand {
3241
3289
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
3242
3290
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
3243
3291
  const factorydroidFields = rulesyncFrontmatter.factorydroid ?? {};
3292
+ const factorydroidFrontmatter = {
3293
+ description: rulesyncFrontmatter.description,
3294
+ ...factorydroidFields
3295
+ };
3296
+ const body = rulesyncCommand.getBody();
3297
+ const paths = this.getSettablePaths({ global });
3244
3298
  return new FactorydroidCommand({
3245
3299
  outputRoot,
3246
- frontmatter: {
3247
- description: rulesyncFrontmatter.description,
3248
- ...factorydroidFields
3249
- },
3250
- body: rulesyncCommand.getBody(),
3251
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3300
+ frontmatter: factorydroidFrontmatter,
3301
+ body,
3302
+ relativeDirPath: paths.relativeDirPath,
3252
3303
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3253
3304
  validate
3254
3305
  });
@@ -3358,7 +3409,7 @@ var GooseCommand = class GooseCommand extends ToolCommand {
3358
3409
  const where = (0, node_path.join)(this.relativeDirPath, this.relativeFilePath);
3359
3410
  let parsed;
3360
3411
  try {
3361
- parsed = (0, js_yaml.load)(content);
3412
+ parsed = loadYaml(content);
3362
3413
  } catch (error) {
3363
3414
  throw new Error(`Failed to parse Goose recipe (${where}): ${formatError(error)}`, { cause: error });
3364
3415
  }
@@ -3409,9 +3460,10 @@ var GooseCommand = class GooseCommand extends ToolCommand {
3409
3460
  prompt,
3410
3461
  ...extraFields
3411
3462
  };
3463
+ const paths = this.getSettablePaths({ global });
3412
3464
  return new GooseCommand({
3413
3465
  outputRoot,
3414
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3466
+ relativeDirPath: paths.relativeDirPath,
3415
3467
  relativeFilePath,
3416
3468
  fileContent: (0, js_yaml.dump)(recipe, {
3417
3469
  lineWidth: -1,
@@ -3452,19 +3504,20 @@ var GooseCommand = class GooseCommand extends ToolCommand {
3452
3504
  });
3453
3505
  }
3454
3506
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
3507
+ const placeholder = (0, js_yaml.dump)({
3508
+ version: RECIPE_VERSION$1,
3509
+ title: "",
3510
+ description: "",
3511
+ prompt: ""
3512
+ }, {
3513
+ lineWidth: -1,
3514
+ noRefs: true
3515
+ });
3455
3516
  return new GooseCommand({
3456
3517
  outputRoot,
3457
3518
  relativeDirPath,
3458
3519
  relativeFilePath,
3459
- fileContent: (0, js_yaml.dump)({
3460
- version: RECIPE_VERSION$1,
3461
- title: "",
3462
- description: "",
3463
- prompt: ""
3464
- }, {
3465
- lineWidth: -1,
3466
- noRefs: true
3467
- }),
3520
+ fileContent: placeholder,
3468
3521
  validate: false
3469
3522
  });
3470
3523
  }
@@ -3622,14 +3675,17 @@ var JunieCommand = class JunieCommand extends ToolCommand {
3622
3675
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
3623
3676
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
3624
3677
  const junieFields = rulesyncFrontmatter.junie ?? {};
3678
+ const junieFrontmatter = {
3679
+ description: rulesyncFrontmatter.description,
3680
+ ...junieFields
3681
+ };
3682
+ const body = rulesyncCommand.getBody();
3683
+ const paths = this.getSettablePaths({ global });
3625
3684
  return new JunieCommand({
3626
3685
  outputRoot,
3627
- frontmatter: {
3628
- description: rulesyncFrontmatter.description,
3629
- ...junieFields
3630
- },
3631
- body: rulesyncCommand.getBody(),
3632
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3686
+ frontmatter: junieFrontmatter,
3687
+ body,
3688
+ relativeDirPath: paths.relativeDirPath,
3633
3689
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3634
3690
  validate
3635
3691
  });
@@ -3753,14 +3809,17 @@ var KiloCommand = class KiloCommand extends ToolCommand {
3753
3809
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
3754
3810
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
3755
3811
  const kiloFields = rulesyncFrontmatter.kilo ?? {};
3812
+ const kiloFrontmatter = {
3813
+ description: rulesyncFrontmatter.description,
3814
+ ...kiloFields
3815
+ };
3816
+ const body = rulesyncCommand.getBody();
3817
+ const paths = this.getSettablePaths({ global });
3756
3818
  return new KiloCommand({
3757
3819
  outputRoot,
3758
- frontmatter: {
3759
- description: rulesyncFrontmatter.description,
3760
- ...kiloFields
3761
- },
3762
- body: rulesyncCommand.getBody(),
3763
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
3820
+ frontmatter: kiloFrontmatter,
3821
+ body,
3822
+ relativeDirPath: paths.relativeDirPath,
3764
3823
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3765
3824
  validate
3766
3825
  });
@@ -4012,7 +4071,7 @@ function omitPrototypePollutionKeys(record) {
4012
4071
  //#region src/features/shared/shared-config-gateway.ts
4013
4072
  function sanitizeSharedConfigValue(value) {
4014
4073
  if (Array.isArray(value)) return value.map(sanitizeSharedConfigValue);
4015
- if (!isPlainObject(value)) return value;
4074
+ if (!isPlainObject$1(value)) return value;
4016
4075
  const result = {};
4017
4076
  for (const [key, nested] of Object.entries(omitPrototypePollutionKeys(value))) result[key] = sanitizeSharedConfigValue(nested);
4018
4077
  return result;
@@ -4028,14 +4087,14 @@ function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy =
4028
4087
  const at = filePath === void 0 ? "" : ` at ${filePath}`;
4029
4088
  let parsed;
4030
4089
  try {
4031
- if (format === "yaml") parsed = (0, js_yaml.load)(fileContent);
4090
+ if (format === "yaml") parsed = loadYaml(fileContent);
4032
4091
  else if (format === "json") parsed = JSON.parse(fileContent);
4033
4092
  else parsed = (0, jsonc_parser.parse)(fileContent);
4034
4093
  } catch (error) {
4035
4094
  throw new Error(`Failed to parse shared config${at}: ${formatError(error)}`, { cause: error });
4036
4095
  }
4037
4096
  if (parsed === void 0 || parsed === null) return {};
4038
- if (!isPlainObject(parsed)) {
4097
+ if (!isPlainObject$1(parsed)) {
4039
4098
  if (invalidRootPolicy === "error") throw new Error(`Failed to parse shared config${at}: expected a mapping at the root`);
4040
4099
  return {};
4041
4100
  }
@@ -4078,7 +4137,7 @@ function mergeSharedConfigDeep({ base, patch }) {
4078
4137
  for (const [key, patchValue] of Object.entries(patch)) {
4079
4138
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
4080
4139
  const baseValue = result[key];
4081
- if (isPlainObject(baseValue) && isPlainObject(patchValue)) result[key] = mergeSharedConfigDeep({
4140
+ if (isPlainObject$1(baseValue) && isPlainObject$1(patchValue)) result[key] = mergeSharedConfigDeep({
4082
4141
  base: baseValue,
4083
4142
  patch: patchValue
4084
4143
  });
@@ -4348,14 +4407,17 @@ var OpenCodeCommand = class OpenCodeCommand extends ToolCommand {
4348
4407
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
4349
4408
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
4350
4409
  const opencodeFields = rulesyncFrontmatter.opencode ?? {};
4410
+ const opencodeFrontmatter = {
4411
+ description: rulesyncFrontmatter.description,
4412
+ ...opencodeFields
4413
+ };
4414
+ const body = rulesyncCommand.getBody();
4415
+ const paths = this.getSettablePaths({ global });
4351
4416
  return new OpenCodeCommand({
4352
4417
  outputRoot,
4353
- frontmatter: {
4354
- description: rulesyncFrontmatter.description,
4355
- ...opencodeFields
4356
- },
4357
- body: rulesyncCommand.getBody(),
4358
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
4418
+ frontmatter: opencodeFrontmatter,
4419
+ body,
4420
+ relativeDirPath: paths.relativeDirPath,
4359
4421
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
4360
4422
  validate
4361
4423
  });
@@ -4643,14 +4705,17 @@ var QwencodeCommand = class QwencodeCommand extends ToolCommand {
4643
4705
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
4644
4706
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
4645
4707
  const qwencodeFields = rulesyncFrontmatter.qwencode ?? {};
4708
+ const qwencodeFrontmatter = {
4709
+ description: rulesyncFrontmatter.description,
4710
+ ...qwencodeFields
4711
+ };
4712
+ const body = rulesyncCommand.getBody();
4713
+ const paths = this.getSettablePaths({ global });
4646
4714
  return new QwencodeCommand({
4647
4715
  outputRoot,
4648
- frontmatter: {
4649
- description: rulesyncFrontmatter.description,
4650
- ...qwencodeFields
4651
- },
4652
- body: rulesyncCommand.getBody(),
4653
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
4716
+ frontmatter: qwencodeFrontmatter,
4717
+ body,
4718
+ relativeDirPath: paths.relativeDirPath,
4654
4719
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
4655
4720
  validate
4656
4721
  });
@@ -4712,6 +4777,8 @@ const REASONIX_GLOBAL_PERMISSIONS_FILE_NAME = REASONIX_GLOBAL_MCP_FILE_NAME;
4712
4777
  const REASONIX_DIR = REASONIX_GLOBAL_DIR;
4713
4778
  const REASONIX_SETTINGS_FILE_NAME = "settings.json";
4714
4779
  const REASONIX_COMMANDS_DIR_PATH = (0, node_path.join)(REASONIX_DIR, "commands");
4780
+ const REASONIX_RULE_FILE_NAME = "REASONIX.md";
4781
+ const REASONIX_SKILLS_DIR_PATH = (0, node_path.join)(REASONIX_DIR, "skills");
4715
4782
  //#endregion
4716
4783
  //#region src/features/commands/reasonix-command.ts
4717
4784
  /**
@@ -4772,14 +4839,17 @@ var ReasonixCommand = class ReasonixCommand extends ToolCommand {
4772
4839
  static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
4773
4840
  const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
4774
4841
  const reasonixFields = rulesyncFrontmatter.reasonix ?? {};
4842
+ const reasonixFrontmatter = {
4843
+ description: rulesyncFrontmatter.description,
4844
+ ...reasonixFields
4845
+ };
4846
+ const body = rulesyncCommand.getBody();
4847
+ const paths = this.getSettablePaths({ global });
4775
4848
  return new ReasonixCommand({
4776
4849
  outputRoot,
4777
- frontmatter: {
4778
- description: rulesyncFrontmatter.description,
4779
- ...reasonixFields
4780
- },
4781
- body: rulesyncCommand.getBody(),
4782
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
4850
+ frontmatter: reasonixFrontmatter,
4851
+ body,
4852
+ relativeDirPath: paths.relativeDirPath,
4783
4853
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
4784
4854
  validate
4785
4855
  });
@@ -5077,14 +5147,15 @@ var RovodevCommand = class RovodevCommand extends ToolCommand {
5077
5147
  const paths = this.getSettablePaths({ global });
5078
5148
  const body = (await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath))).trim();
5079
5149
  const name = (0, node_path.basename)(relativeFilePath, ".md");
5150
+ const description = await lookupPromptDescription({
5151
+ outputRoot,
5152
+ relativeFilePath,
5153
+ name
5154
+ });
5080
5155
  return new RovodevCommand({
5081
5156
  outputRoot,
5082
5157
  name,
5083
- description: await lookupPromptDescription({
5084
- outputRoot,
5085
- relativeFilePath,
5086
- name
5087
- }),
5158
+ description,
5088
5159
  body,
5089
5160
  relativeDirPath: paths.relativeDirPath,
5090
5161
  relativeFilePath,
@@ -5117,8 +5188,8 @@ var RovodevCommand = class RovodevCommand extends ToolCommand {
5117
5188
  const existingContent = await readFileContentOrNull((0, node_path.join)(outputRoot, ROVODEV_DIR, ROVODEV_PROMPTS_FILE_NAME));
5118
5189
  let existing = {};
5119
5190
  if (existingContent) try {
5120
- const parsed = (0, js_yaml.load)(existingContent);
5121
- if (isPlainObject(parsed)) existing = parsed;
5191
+ const parsed = loadYaml(existingContent);
5192
+ if (isPlainObject$1(parsed)) existing = parsed;
5122
5193
  } catch {}
5123
5194
  const prompts = rovodevCommands.map((command) => ({
5124
5195
  name: command.getName(),
@@ -5148,11 +5219,11 @@ async function lookupPromptDescription({ outputRoot, relativeFilePath, name }) {
5148
5219
  if (!manifestContent) return "";
5149
5220
  let parsed;
5150
5221
  try {
5151
- parsed = (0, js_yaml.load)(manifestContent);
5222
+ parsed = loadYaml(manifestContent);
5152
5223
  } catch {
5153
5224
  return "";
5154
5225
  }
5155
- if (!isPlainObject(parsed) || !Array.isArray(parsed.prompts)) return "";
5226
+ if (!isPlainObject$1(parsed) || !Array.isArray(parsed.prompts)) return "";
5156
5227
  const expectedContentFile = toPosixPath((0, node_path.join)("prompts", relativeFilePath));
5157
5228
  const entry = parsed.prompts.find((candidate) => isRecord(candidate) && (candidate.content_file === expectedContentFile || candidate.name === name));
5158
5229
  return isRecord(entry) && typeof entry.description === "string" ? entry.description : "";
@@ -5283,14 +5354,15 @@ var TaktCommand = class TaktCommand extends ToolCommand {
5283
5354
  });
5284
5355
  const relativeFilePath = `${stem}.md`;
5285
5356
  const paths = this.getSettablePaths({ global });
5357
+ const body = prependTaktExtends({
5358
+ extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
5359
+ body: rulesyncCommand.getBody(),
5360
+ featureLabel: "command",
5361
+ sourceLabel
5362
+ });
5286
5363
  return new TaktCommand({
5287
5364
  outputRoot,
5288
- body: prependTaktExtends({
5289
- extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
5290
- body: rulesyncCommand.getBody(),
5291
- featureLabel: "command",
5292
- sourceLabel
5293
- }),
5365
+ body,
5294
5366
  relativeDirPath: paths.relativeDirPath,
5295
5367
  relativeFilePath,
5296
5368
  validate
@@ -6190,18 +6262,25 @@ const QWENCODE_HOOK_EVENTS = [
6190
6262
  * Reasonix's `.reasonix/settings.json` (project) / `~/.reasonix/settings.json`
6191
6263
  * (global) documents a ten-event surface (`PreToolUse`, `PostToolUse`,
6192
6264
  * `UserPromptSubmit`, `Stop`, `PostLLMCall`, `SessionStart`, `SessionEnd`,
6193
- * `SubagentStop`, `Notification`, `PreCompact`), but only the four events the
6194
- * upstream issue scoped in are mapped here: `PreToolUse`, `PostToolUse`,
6195
- * `UserPromptSubmit` ← `beforeSubmitPrompt`, and `Stop`. `match` (Reasonix's
6196
- * matcher field name) is honored only on `PreToolUse`/`PostToolUse`, matching
6197
- * the canonical `matcher` field's tool-event scoping used by other adapters.
6265
+ * `SubagentStop`, `Notification`, `PreCompact`). The eight events with a clean
6266
+ * canonical equivalent are mapped: `PreToolUse`, `PostToolUse`,
6267
+ * `UserPromptSubmit` ← `beforeSubmitPrompt`, `Stop`, `SessionStart`,
6268
+ * `SessionEnd`, `SubagentStop`, and `PostLLMCall` `postModelInvocation`.
6269
+ * (`Notification` and `PreCompact` have no canonical event and are left out.)
6270
+ * `match` (Reasonix's matcher field name) is honored only on
6271
+ * `PreToolUse`/`PostToolUse`, matching the canonical `matcher` field's
6272
+ * tool-event scoping used by other adapters.
6198
6273
  * @see https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/DESKTOP_HOOKS.zh-CN.md
6199
6274
  */
6200
6275
  const REASONIX_HOOK_EVENTS = [
6201
6276
  "preToolUse",
6202
6277
  "postToolUse",
6203
6278
  "beforeSubmitPrompt",
6204
- "stop"
6279
+ "stop",
6280
+ "sessionStart",
6281
+ "sessionEnd",
6282
+ "subagentStop",
6283
+ "postModelInvocation"
6205
6284
  ];
6206
6285
  /**
6207
6286
  * Hook events supported by Hermes Agent's native Shell Hooks system.
@@ -6637,14 +6716,18 @@ const QWENCODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANO
6637
6716
  /**
6638
6717
  * Map canonical camelCase event names to Reasonix PascalCase.
6639
6718
  * Reasonix explicitly mirrors Claude Code's hooks model, so it reuses the same
6640
- * PascalCase names for the four events rulesync maps.
6719
+ * PascalCase names for the events rulesync maps.
6641
6720
  * @see https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/DESKTOP_HOOKS.zh-CN.md
6642
6721
  */
6643
6722
  const CANONICAL_TO_REASONIX_EVENT_NAMES = {
6644
6723
  preToolUse: "PreToolUse",
6645
6724
  postToolUse: "PostToolUse",
6646
6725
  beforeSubmitPrompt: "UserPromptSubmit",
6647
- stop: "Stop"
6726
+ stop: "Stop",
6727
+ sessionStart: "SessionStart",
6728
+ sessionEnd: "SessionEnd",
6729
+ subagentStop: "SubagentStop",
6730
+ postModelInvocation: "PostLLMCall"
6648
6731
  };
6649
6732
  /**
6650
6733
  * Map Reasonix PascalCase event names to canonical camelCase.
@@ -6693,6 +6776,21 @@ function applyCommandPrefix({ def, converterConfig }) {
6693
6776
  return converterConfig.projectDirVar !== "" && typeof trimmedCommand === "string" && !trimmedCommand.startsWith("$") && (!converterConfig.prefixDotRelativeCommandsOnly || trimmedCommand.startsWith(".")) && typeof trimmedCommand === "string" ? `"${converterConfig.projectDirVar}"/${trimmedCommand.replace(/^\.\//, "")}` : def.command;
6694
6777
  }
6695
6778
  /**
6779
+ * Emit the configured boolean passthrough fields on the tool side, mapping each
6780
+ * canonical field name to its (possibly renamed) tool field name. Only boolean
6781
+ * values are carried through.
6782
+ */
6783
+ function emitBooleanPassthroughFields({ def, converterConfig }) {
6784
+ return Object.fromEntries((converterConfig.booleanPassthroughFields ?? []).filter(({ canonical }) => typeof def[canonical] === "boolean").map(({ canonical, tool }) => [tool, def[canonical]]));
6785
+ }
6786
+ /**
6787
+ * Import the configured boolean passthrough fields back into canonical fields,
6788
+ * reversing {@link emitBooleanPassthroughFields}. Only boolean values are read.
6789
+ */
6790
+ function importBooleanPassthroughFields({ h, converterConfig }) {
6791
+ return Object.fromEntries((converterConfig.booleanPassthroughFields ?? []).filter(({ tool }) => typeof h[tool] === "boolean").map(({ canonical, tool }) => [canonical, h[tool]]));
6792
+ }
6793
+ /**
6696
6794
  * Convert the definitions of a single matcher group into tool hook entries,
6697
6795
  * honoring supported hook types and passthrough fields.
6698
6796
  */
@@ -6706,6 +6804,10 @@ function buildToolHooks({ defs, converterConfig }) {
6706
6804
  converterConfig
6707
6805
  });
6708
6806
  hooks.push({
6807
+ ...emitBooleanPassthroughFields({
6808
+ def,
6809
+ converterConfig
6810
+ }),
6709
6811
  type: hookType,
6710
6812
  ...command !== void 0 && command !== null && { command },
6711
6813
  ...def.timeout !== void 0 && def.timeout !== null && { timeout: def.timeout },
@@ -6793,6 +6895,10 @@ function toolHookToCanonical({ h, rawEntry, converterConfig }) {
6793
6895
  ...prompt !== void 0 && prompt !== null && { prompt },
6794
6896
  ...converterConfig.passthroughFields?.includes("name") && typeof h.name === "string" && { name: h.name },
6795
6897
  ...converterConfig.passthroughFields?.includes("description") && typeof h.description === "string" && { description: h.description },
6898
+ ...importBooleanPassthroughFields({
6899
+ h,
6900
+ converterConfig
6901
+ }),
6796
6902
  ...rawEntry.matcher !== void 0 && rawEntry.matcher !== null && rawEntry.matcher !== "" && { matcher: rawEntry.matcher }
6797
6903
  };
6798
6904
  }
@@ -7087,7 +7193,7 @@ function combineAugmentSettings(base, local) {
7087
7193
  const baseValue = result[key];
7088
7194
  if (AUGMENTCODE_REPLACE_KEYS.has(key)) result[key] = localValue;
7089
7195
  else if (Array.isArray(localValue) && Array.isArray(baseValue)) result[key] = [...localValue, ...baseValue];
7090
- else if (isPlainObject(localValue) && isPlainObject(baseValue)) result[key] = combineAugmentSettings(baseValue, localValue);
7196
+ else if (isPlainObject$1(localValue) && isPlainObject$1(baseValue)) result[key] = combineAugmentSettings(baseValue, localValue);
7091
7197
  else result[key] = localValue;
7092
7198
  }
7093
7199
  return result;
@@ -7131,14 +7237,14 @@ async function readAugmentcodeSettingsWithLocalOverlay({ outputRoot, relativeDir
7131
7237
  } catch (error) {
7132
7238
  throw new Error(`Failed to parse AugmentCode settings at ${configPath}: ${formatError(error)}`, { cause: error });
7133
7239
  }
7134
- if (!isPlainObject(localParsed)) throw new Error(`Failed to parse AugmentCode settings at ${configPath}: expected a JSON object`);
7240
+ if (!isPlainObject$1(localParsed)) throw new Error(`Failed to parse AugmentCode settings at ${configPath}: expected a JSON object`);
7135
7241
  let baseParsed;
7136
7242
  try {
7137
7243
  baseParsed = JSON.parse(baseContent);
7138
7244
  } catch {
7139
7245
  return baseContent;
7140
7246
  }
7141
- const merged = combineAugmentSettings(isPlainObject(baseParsed) ? baseParsed : {}, localParsed);
7247
+ const merged = combineAugmentSettings(isPlainObject$1(baseParsed) ? baseParsed : {}, localParsed);
7142
7248
  return JSON.stringify(merged, null, 2);
7143
7249
  }
7144
7250
  //#endregion
@@ -7407,11 +7513,12 @@ var CodexcliConfigToml = class CodexcliConfigToml extends ToolFile {
7407
7513
  };
7408
7514
  }
7409
7515
  static async fromOutputRoot({ outputRoot }) {
7516
+ const fileContent = await buildCodexConfigTomlContent({ outputRoot });
7410
7517
  return new CodexcliConfigToml({
7411
7518
  outputRoot,
7412
7519
  relativeDirPath: CODEXCLI_DIR,
7413
7520
  relativeFilePath: CODEXCLI_MCP_FILE_NAME,
7414
- fileContent: await buildCodexConfigTomlContent({ outputRoot })
7521
+ fileContent
7415
7522
  });
7416
7523
  }
7417
7524
  };
@@ -8702,15 +8809,16 @@ var HermesagentHooks = class HermesagentHooks extends ToolHooks {
8702
8809
  }
8703
8810
  static fromRulesyncHooks({ outputRoot, rulesyncHooks, logger }) {
8704
8811
  const config = rulesyncHooks.getJson();
8812
+ const hermesHooks = canonicalToHermesHooks({
8813
+ config,
8814
+ toolOverrideHooks: config.hermesagent?.hooks,
8815
+ logger
8816
+ });
8705
8817
  return new HermesagentHooks({
8706
8818
  outputRoot,
8707
8819
  fileContent: stringifySharedConfig({
8708
8820
  format: "yaml",
8709
- document: { hooks: canonicalToHermesHooks({
8710
- config,
8711
- toolOverrideHooks: config.hermesagent?.hooks,
8712
- logger
8713
- }) }
8821
+ document: { hooks: hermesHooks }
8714
8822
  })
8715
8823
  });
8716
8824
  }
@@ -8723,7 +8831,14 @@ const JUNIE_CONVERTER_CONFIG = {
8723
8831
  toolToCanonicalEventNames: JUNIE_TO_CANONICAL_EVENT_NAMES,
8724
8832
  projectDirVar: "",
8725
8833
  supportedHookTypes: /* @__PURE__ */ new Set(["command"]),
8726
- noMatcherEvents: /* @__PURE__ */ new Set(["beforeSubmitPrompt", "stop"])
8834
+ noMatcherEvents: /* @__PURE__ */ new Set(["beforeSubmitPrompt", "stop"]),
8835
+ booleanPassthroughFields: [{
8836
+ canonical: "failClosed",
8837
+ tool: "blockOnError"
8838
+ }, {
8839
+ canonical: "async",
8840
+ tool: "async"
8841
+ }]
8727
8842
  };
8728
8843
  var JunieHooks = class JunieHooks extends ToolHooks {
8729
8844
  constructor(params) {
@@ -9759,8 +9874,9 @@ function reasonixHooksToCanonical(hooks) {
9759
9874
  * Reasonix hooks live in a Claude-Code-style but standalone JSON file —
9760
9875
  * `.reasonix/settings.json` (project) or `~/.reasonix/settings.json`
9761
9876
  * (global) — separate from the `[permissions]`/`[[plugins]]` TOML config.
9762
- * Only the four events documented in the upstream issue are mapped:
9763
- * PreToolUse/PostToolUse/UserPromptSubmit/Stop (see REASONIX_HOOK_EVENTS).
9877
+ * The eight upstream events with a clean canonical equivalent are mapped:
9878
+ * PreToolUse/PostToolUse/UserPromptSubmit/Stop plus SessionStart/SessionEnd/
9879
+ * SubagentStop/PostLLMCall (see REASONIX_HOOK_EVENTS).
9764
9880
  * @see https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/DESKTOP_HOOKS.zh-CN.md
9765
9881
  */
9766
9882
  var ReasonixHooks = class ReasonixHooks extends ToolHooks {
@@ -9977,11 +10093,12 @@ var VibeConfigToml = class VibeConfigToml extends ToolFile {
9977
10093
  };
9978
10094
  }
9979
10095
  static async fromOutputRoot({ outputRoot }) {
10096
+ const fileContent = await buildVibeConfigTomlContent({ outputRoot });
9980
10097
  return new VibeConfigToml({
9981
10098
  outputRoot,
9982
10099
  relativeDirPath: VIBE_DIR,
9983
10100
  relativeFilePath: VIBE_CONFIG_FILE_NAME,
9984
- fileContent: await buildVibeConfigTomlContent({ outputRoot })
10101
+ fileContent
9985
10102
  });
9986
10103
  }
9987
10104
  };
@@ -10758,9 +10875,10 @@ var ClaudecodeIgnore = class ClaudecodeIgnore extends ToolIgnore {
10758
10875
  this.patterns = jsonValue.permissions?.deny ?? [];
10759
10876
  }
10760
10877
  static getSettablePaths(params) {
10878
+ const fileMode = resolveFileMode(params?.options);
10761
10879
  return {
10762
10880
  relativeDirPath: CLAUDECODE_DIR,
10763
- relativeFilePath: fileNameForMode(resolveFileMode(params?.options))
10881
+ relativeFilePath: fileNameForMode(fileMode)
10764
10882
  };
10765
10883
  }
10766
10884
  /**
@@ -10993,11 +11111,12 @@ var DevinIgnore = class DevinIgnore extends ToolIgnore {
10993
11111
  const primaryPath = (0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath);
10994
11112
  const legacyPath = (0, node_path.join)(outputRoot, relativeDirPath, DEVIN_LEGACY_IGNORE_FILE_NAME);
10995
11113
  const resolvedFilePath = !await fileExists(primaryPath) && await fileExists(legacyPath) ? DEVIN_LEGACY_IGNORE_FILE_NAME : relativeFilePath;
11114
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, resolvedFilePath));
10996
11115
  return new DevinIgnore({
10997
11116
  outputRoot,
10998
11117
  relativeDirPath,
10999
11118
  relativeFilePath: resolvedFilePath,
11000
- fileContent: await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, resolvedFilePath)),
11119
+ fileContent,
11001
11120
  validate
11002
11121
  });
11003
11122
  }
@@ -11839,7 +11958,7 @@ function parseAmpSettingsJsonc(fileContent) {
11839
11958
  const details = errors.map((error) => `${(0, jsonc_parser.printParseErrorCode)(error.error)} at offset ${error.offset}`).join(", ");
11840
11959
  throw new Error(`Failed to parse Amp settings: ${details}`);
11841
11960
  }
11842
- if (!isPlainObject(parsed)) throw new Error("Amp settings must be a JSON object");
11961
+ if (!isPlainObject$1(parsed)) throw new Error("Amp settings must be a JSON object");
11843
11962
  return parsed;
11844
11963
  }
11845
11964
  function filterMcpServers(mcpServers) {
@@ -12161,7 +12280,7 @@ function parseAugmentcodeSettings(fileContent, relativeDirPath, relativeFilePath
12161
12280
  } catch (error) {
12162
12281
  throw new Error(`Failed to parse AugmentCode settings at ${configPath}: ${formatError(error)}`, { cause: error });
12163
12282
  }
12164
- if (!isPlainObject(parsed)) throw new Error(`Failed to parse AugmentCode settings at ${configPath}: expected a JSON object`);
12283
+ if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse AugmentCode settings at ${configPath}: expected a JSON object`);
12165
12284
  return parsed;
12166
12285
  }
12167
12286
  /**
@@ -12387,7 +12506,7 @@ function parseClineSettings(fileContent, relativeDirPath, relativeFilePath) {
12387
12506
  } catch (error) {
12388
12507
  throw new Error(`Failed to parse Cline MCP settings at ${configPath}: ${formatError(error)}`, { cause: error });
12389
12508
  }
12390
- if (!isPlainObject(parsed)) throw new Error(`Failed to parse Cline MCP settings at ${configPath}: expected a JSON object`);
12509
+ if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse Cline MCP settings at ${configPath}: expected a JSON object`);
12391
12510
  return parsed;
12392
12511
  }
12393
12512
  /**
@@ -12658,7 +12777,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
12658
12777
  for (const [key, value] of Object.entries(obj)) {
12659
12778
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
12660
12779
  if (value === null) continue;
12661
- if (isPlainObject(value)) {
12780
+ if (isPlainObject$1(value)) {
12662
12781
  const cleaned = this.removeEmptyEntries(value, depth + 1);
12663
12782
  if (Object.keys(cleaned).length === 0) continue;
12664
12783
  filtered[key] = cleaned;
@@ -13299,12 +13418,12 @@ function parseGooseConfig(fileContent, relativeDirPath, relativeFilePath) {
13299
13418
  const configPath = (0, node_path.join)(relativeDirPath, relativeFilePath);
13300
13419
  let parsed;
13301
13420
  try {
13302
- parsed = (0, js_yaml.load)(fileContent);
13421
+ parsed = loadYaml(fileContent);
13303
13422
  } catch (error) {
13304
13423
  throw new Error(`Failed to parse Goose config at ${configPath}: ${formatError(error)}`, { cause: error });
13305
13424
  }
13306
13425
  if (parsed === void 0 || parsed === null) return {};
13307
- if (!isPlainObject(parsed)) throw new Error(`Failed to parse Goose config at ${configPath}: expected a YAML mapping`);
13426
+ if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse Goose config at ${configPath}: expected a YAML mapping`);
13308
13427
  return parsed;
13309
13428
  }
13310
13429
  /**
@@ -13349,7 +13468,7 @@ function applyGooseStdioFields(ext, config) {
13349
13468
  ext.cmd = command;
13350
13469
  if (isStringArray(config.args)) ext.args = config.args;
13351
13470
  }
13352
- if (isPlainObject(config.env)) ext.envs = omitPrototypePollutionKeys(config.env);
13471
+ if (isPlainObject$1(config.env)) ext.envs = omitPrototypePollutionKeys(config.env);
13353
13472
  }
13354
13473
  /**
13355
13474
  * Converts a single rulesync canonical MCP server into a Goose `extensions:` entry.
@@ -13364,7 +13483,7 @@ function convertServerToGooseExtension(name, config) {
13364
13483
  if (gooseType === "stdio") applyGooseStdioFields(ext, config);
13365
13484
  else if (gooseType === "sse" || gooseType === "streamable_http") {
13366
13485
  if (url !== void 0) ext.uri = url;
13367
- if (isPlainObject(config.headers)) ext.headers = omitPrototypePollutionKeys(config.headers);
13486
+ if (isPlainObject$1(config.headers)) ext.headers = omitPrototypePollutionKeys(config.headers);
13368
13487
  }
13369
13488
  ext.enabled = config.disabled !== true;
13370
13489
  const timeout = resolveGooseTimeout(config);
@@ -13406,9 +13525,9 @@ function convertFromGooseFormat(extensions) {
13406
13525
  else if (type === "stdio") server.type = "stdio";
13407
13526
  if (typeof ext.cmd === "string") server.command = ext.cmd;
13408
13527
  if (isStringArray(ext.args)) server.args = ext.args;
13409
- if (isPlainObject(ext.envs)) server.env = omitPrototypePollutionKeys(ext.envs);
13528
+ if (isPlainObject$1(ext.envs)) server.env = omitPrototypePollutionKeys(ext.envs);
13410
13529
  if (typeof ext.uri === "string") server.url = ext.uri;
13411
- if (isPlainObject(ext.headers)) server.headers = omitPrototypePollutionKeys(ext.headers);
13530
+ if (isPlainObject$1(ext.headers)) server.headers = omitPrototypePollutionKeys(ext.headers);
13412
13531
  if (ext.enabled === false) server.disabled = true;
13413
13532
  if (typeof ext.timeout === "number") server.timeout = ext.timeout;
13414
13533
  result[name] = server;
@@ -13431,7 +13550,7 @@ function buildGoosePluginStdioServer(config) {
13431
13550
  server.command = command;
13432
13551
  if (isStringArray(config.args)) server.args = config.args;
13433
13552
  }
13434
- if (isPlainObject(config.env)) server.env = omitPrototypePollutionKeys(config.env);
13553
+ if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
13435
13554
  if (typeof config.cwd === "string") server.cwd = config.cwd;
13436
13555
  return server;
13437
13556
  }
@@ -13731,7 +13850,7 @@ var GrokcliMcp = class GrokcliMcp extends ToolMcp {
13731
13850
  for (const [key, value] of Object.entries(obj)) {
13732
13851
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
13733
13852
  if (value === null) continue;
13734
- if (isPlainObject(value)) {
13853
+ if (isPlainObject$1(value)) {
13735
13854
  const cleaned = this.removeEmptyEntries(value, depth + 1);
13736
13855
  if (Object.keys(cleaned).length === 0) continue;
13737
13856
  filtered[key] = cleaned;
@@ -13793,10 +13912,10 @@ function convertServerToHermes(config) {
13793
13912
  out.command = command;
13794
13913
  if (isStringArray(config.args)) out.args = config.args;
13795
13914
  }
13796
- if (isPlainObject(config.env)) out.env = omitPrototypePollutionKeys(config.env);
13915
+ if (isPlainObject$1(config.env)) out.env = omitPrototypePollutionKeys(config.env);
13797
13916
  } else if (url !== void 0) {
13798
13917
  out.url = url;
13799
- if (isPlainObject(config.headers)) out.headers = omitPrototypePollutionKeys(config.headers);
13918
+ if (isPlainObject$1(config.headers)) out.headers = omitPrototypePollutionKeys(config.headers);
13800
13919
  }
13801
13920
  if (config.disabled === true) out.enabled = false;
13802
13921
  const timeout = resolveHermesTimeout(config);
@@ -13841,9 +13960,9 @@ function convertFromHermesFormat(mcpServers) {
13841
13960
  const server = {};
13842
13961
  if (typeof config.command === "string") server.command = config.command;
13843
13962
  if (isStringArray(config.args)) server.args = config.args;
13844
- if (isPlainObject(config.env)) server.env = omitPrototypePollutionKeys(config.env);
13963
+ if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
13845
13964
  if (typeof config.url === "string") server.url = config.url;
13846
- if (isPlainObject(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
13965
+ if (isPlainObject$1(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
13847
13966
  if (config.enabled === false) server.disabled = true;
13848
13967
  if (typeof config.timeout === "number") server.networkTimeout = config.timeout;
13849
13968
  if (isRecord(config.tools)) {
@@ -14780,7 +14899,9 @@ const REASONIX_PLUGIN_FIELDS = [
14780
14899
  "env",
14781
14900
  "url",
14782
14901
  "headers",
14783
- "trusted_read_only_tools"
14902
+ "trusted_read_only_tools",
14903
+ "call_timeout_seconds",
14904
+ "tool_timeout_seconds"
14784
14905
  ];
14785
14906
  var ReasonixMcp = class ReasonixMcp extends ToolMcp {
14786
14907
  toml;
@@ -15012,7 +15133,7 @@ function parseRovodevMcpJson(fileContent, relativeDirPath, relativeFilePath) {
15012
15133
  } catch (error) {
15013
15134
  throw new Error(`Failed to parse Rovodev MCP config at ${configPath}: ${formatError(error)}`, { cause: error });
15014
15135
  }
15015
- if (!isPlainObject(parsed)) throw new Error(`Failed to parse Rovodev MCP config at ${configPath}: expected a JSON object`);
15136
+ if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse Rovodev MCP config at ${configPath}: expected a JSON object`);
15016
15137
  return parsed;
15017
15138
  }
15018
15139
  /**
@@ -16283,15 +16404,123 @@ const AntigravityCliPermissionsOverrideSchema = zod_mini.z.looseObject({
16283
16404
  enableTerminalSandbox: zod_mini.z.optional(zod_mini.z.boolean())
16284
16405
  });
16285
16406
  /**
16407
+ * Tool-scoped override block for AugmentCode. AugmentCode's `toolPermissions[]`
16408
+ * array supports "custom policy" entries the canonical allow/ask/deny model
16409
+ * cannot express: `permission.type` of `webhook-policy` / `script-policy`
16410
+ * (delegating the decision to a `webhookUrl` / `script`) and an `eventType` of
16411
+ * `tool-response` (a post-execution check rather than the default pre-execution
16412
+ * `tool-call`). These are authored here as verbatim `toolPermissions` entries
16413
+ * and prepended — ahead of the canonical-generated basic rules — into the shared
16414
+ * `.augment/settings.json`, so a webhook/script gate or tool-response check is
16415
+ * never shadowed by a regenerated allow/deny/ask entry under AugmentCode's
16416
+ * first-match-wins evaluation. The shared `permission` block continues to drive
16417
+ * the basic `allow` / `deny` / `ask-user` entries. Kept `looseObject` (verbatim
16418
+ * passthrough) so `shellInputRegex`, `eventType`, `webhookUrl`, `script`, and
16419
+ * any future policy field survive untouched. Both project and global scope are
16420
+ * supported.
16421
+ *
16422
+ * @example
16423
+ * { "toolPermissions": [
16424
+ * { "toolName": "github-api",
16425
+ * "permission": { "type": "webhook-policy", "webhookUrl": "https://api.example.com/validate" } },
16426
+ * { "toolName": "view", "eventType": "tool-response", "permission": { "type": "allow" } } ] }
16427
+ */
16428
+ const AugmentcodePermissionsOverrideSchema = zod_mini.z.looseObject({ toolPermissions: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({
16429
+ toolName: zod_mini.z.string(),
16430
+ permission: zod_mini.z.looseObject({ type: zod_mini.z.string() })
16431
+ }))) });
16432
+ /**
16433
+ * Tool-scoped override block for Kiro. Kiro's agent config (`.kiro/agents/<name>.json`)
16434
+ * exposes per-tool `toolsSettings` knobs with no canonical allow/ask/deny
16435
+ * category: the shell auto-trust flags `shell.autoAllowReadonly` /
16436
+ * `shell.denyByDefault`, the `aws` built-in tool's `allowedServices` /
16437
+ * `deniedServices` (+ `autoAllowReadonly`), and the `web_fetch` domain trust
16438
+ * arrays `trusted` / `blocked` (regex host patterns; documented for `web_fetch`
16439
+ * only — `web_search` has no such surface). Fields placed here are deep-merged
16440
+ * (per `toolsSettings` key, override wins at the leaf) into the shared agent
16441
+ * config, while the canonical `permission` block continues to drive
16442
+ * `shell.{allowed,denied}Commands`, `read`/`write`/`grep`/`glob` paths, and the
16443
+ * `web_fetch`/`web_search` `allowedTools` toggles. Kept `looseObject` at every
16444
+ * level (verbatim passthrough) so future Kiro `toolsSettings` fields survive.
16445
+ *
16446
+ * Kiro's MCP `autoApprove` / `disabledTools` lists are intentionally NOT modeled
16447
+ * here: they live in a SEPARATE file (`.kiro/settings/mcp.json`, under
16448
+ * `mcpServers.<name>`), not the agent config this permissions translator writes,
16449
+ * and reconciling them with the canonical `mcp__*` model is a distinct design
16450
+ * question left out of scope.
16451
+ *
16452
+ * @example
16453
+ * { "toolsSettings": { "shell": { "autoAllowReadonly": true },
16454
+ * "aws": { "allowedServices": ["s3"], "deniedServices": ["eks"] },
16455
+ * "web_fetch": { "trusted": [".*github\\.com.*"] } } }
16456
+ */
16457
+ const KiroPermissionsOverrideSchema = zod_mini.z.looseObject({ toolsSettings: zod_mini.z.optional(zod_mini.z.looseObject({
16458
+ shell: zod_mini.z.optional(zod_mini.z.looseObject({
16459
+ autoAllowReadonly: zod_mini.z.optional(zod_mini.z.boolean()),
16460
+ denyByDefault: zod_mini.z.optional(zod_mini.z.boolean())
16461
+ })),
16462
+ aws: zod_mini.z.optional(zod_mini.z.looseObject({
16463
+ allowedServices: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
16464
+ deniedServices: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
16465
+ autoAllowReadonly: zod_mini.z.optional(zod_mini.z.boolean())
16466
+ })),
16467
+ web_fetch: zod_mini.z.optional(zod_mini.z.looseObject({
16468
+ trusted: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
16469
+ blocked: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string()))
16470
+ }))
16471
+ })) });
16472
+ /**
16473
+ * Codex CLI-scoped permission override.
16474
+ *
16475
+ * Codex CLI's permission surface is richer than the canonical allow/ask/deny
16476
+ * model: its approval workflow, classic sandbox system, and per-app tool gating
16477
+ * have no canonical category. Author them through a tool-scoped `codexcli`
16478
+ * override whose fields are written verbatim as top-level `.codex/config.toml`
16479
+ * keys (the override wins per key; existing sibling keys the user set directly
16480
+ * are preserved):
16481
+ * - `approval_policy` — `untrusted` | `on-request` | `never`, or a
16482
+ * `{ granular = { … } }` table (kept verbatim; the granular schema has
16483
+ * required fields that are brittle to model as typed keys).
16484
+ * - `sandbox_mode` — `read-only` | `workspace-write` | `danger-full-access`,
16485
+ * with the sibling `sandbox_workspace_write` table (`network_access`,
16486
+ * `writable_roots`, …).
16487
+ * - `apps` — per-app tool gating (`apps.<id>.tools.<tool>.approval_mode` /
16488
+ * `.enabled`, `apps.<id>.default_tools_approval_mode`).
16489
+ * - `approvals_reviewer` — the reviewer-approval surface.
16490
+ *
16491
+ * Two surfaces are deliberately NOT authorable here so the override can never
16492
+ * clobber a feature-owned key: `mcp_servers.*` per-MCP gating is owned by the
16493
+ * MCP feature (`codexcli-mcp.ts` already writes the `mcp_servers` tables in the
16494
+ * same `config.toml`), and `permissions` / `default_permissions` are owned by
16495
+ * the canonical model. Any such key placed in the override is skipped with a
16496
+ * warning. Kept `looseObject` (verbatim passthrough) so future top-level Codex
16497
+ * config keys can be authored without Rulesync modeling each one.
16498
+ *
16499
+ * @see https://developers.openai.com/codex/config-reference
16500
+ * @see https://developers.openai.com/codex/permissions
16501
+ *
16502
+ * @example
16503
+ * { "approval_policy": "on-request", "sandbox_mode": "workspace-write",
16504
+ * "sandbox_workspace_write": { "network_access": true } }
16505
+ */
16506
+ const CodexcliPermissionsOverrideSchema = zod_mini.z.looseObject({
16507
+ approval_policy: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.looseObject({})])),
16508
+ sandbox_mode: zod_mini.z.optional(zod_mini.z.string()),
16509
+ sandbox_workspace_write: zod_mini.z.optional(zod_mini.z.looseObject({})),
16510
+ apps: zod_mini.z.optional(zod_mini.z.looseObject({})),
16511
+ approvals_reviewer: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.looseObject({})]))
16512
+ });
16513
+ /**
16286
16514
  * Permissions configuration.
16287
16515
  * Keys are tool category names (e.g., "bash", "edit", "read", "webfetch").
16288
16516
  * Values are pattern-to-action mappings for that tool category.
16289
16517
  *
16290
16518
  * The optional `opencode`/`hermes`/`cline`/`kilo`/`claudecode`/`vibe`/`cursor`/
16291
16519
  * `qwencode`/`reasonix`/`factorydroid`/`warp`/`junie`/`takt`/`amp`/
16292
- * `antigravity-cli` keys are tool-scoped overrides consumed only by their
16293
- * respective translator (see the matching `*PermissionsOverrideSchema`); every
16294
- * other tool reads the shared `permission` block and ignores them.
16520
+ * `antigravity-cli`/`augmentcode`/`kiro`/`codexcli` keys are tool-scoped
16521
+ * overrides consumed only by their respective translator (see the matching
16522
+ * `*PermissionsOverrideSchema`); every other tool reads the shared `permission`
16523
+ * block and ignores them.
16295
16524
  *
16296
16525
  * @example
16297
16526
  * {
@@ -16315,7 +16544,10 @@ const PermissionsConfigSchema = zod_mini.z.looseObject({
16315
16544
  junie: zod_mini.z.optional(JuniePermissionsOverrideSchema),
16316
16545
  takt: zod_mini.z.optional(TaktPermissionsOverrideSchema),
16317
16546
  amp: zod_mini.z.optional(AmpPermissionsOverrideSchema),
16318
- "antigravity-cli": zod_mini.z.optional(AntigravityCliPermissionsOverrideSchema)
16547
+ "antigravity-cli": zod_mini.z.optional(AntigravityCliPermissionsOverrideSchema),
16548
+ augmentcode: zod_mini.z.optional(AugmentcodePermissionsOverrideSchema),
16549
+ kiro: zod_mini.z.optional(KiroPermissionsOverrideSchema),
16550
+ codexcli: zod_mini.z.optional(CodexcliPermissionsOverrideSchema)
16319
16551
  });
16320
16552
  /**
16321
16553
  * Full permissions file schema including optional $schema field.
@@ -16467,7 +16699,7 @@ function parseAmpSettings(fileContent) {
16467
16699
  const details = errors.map((error) => `${(0, jsonc_parser.printParseErrorCode)(error.error)} at offset ${error.offset}`).join(", ");
16468
16700
  throw new Error(`Failed to parse Amp settings: ${details}`);
16469
16701
  }
16470
- if (!isPlainObject(parsed)) throw new Error("Amp settings must be a JSON object");
16702
+ if (!isPlainObject$1(parsed)) throw new Error("Amp settings must be a JSON object");
16471
16703
  return parsed;
16472
16704
  }
16473
16705
  function toDisableList(value) {
@@ -16494,7 +16726,7 @@ function toPermissionsList(value) {
16494
16726
  if (!Array.isArray(value)) return [];
16495
16727
  const entries = [];
16496
16728
  for (const raw of value) {
16497
- if (!isPlainObject(raw)) continue;
16729
+ if (!isPlainObject$1(raw)) continue;
16498
16730
  const { tool, action } = raw;
16499
16731
  if (typeof tool !== "string" || typeof action !== "string") continue;
16500
16732
  if (action !== "allow" && action !== "reject" && action !== "ask" && action !== "delegate") continue;
@@ -16502,7 +16734,7 @@ function toPermissionsList(value) {
16502
16734
  ...raw,
16503
16735
  tool,
16504
16736
  action,
16505
- ...isPlainObject(raw.matches) ? { matches: raw.matches } : {}
16737
+ ...isPlainObject$1(raw.matches) ? { matches: raw.matches } : {}
16506
16738
  });
16507
16739
  }
16508
16740
  return entries;
@@ -17362,6 +17594,55 @@ function isSpecialEntry(entry) {
17362
17594
  return false;
17363
17595
  }
17364
17596
  /**
17597
+ * A composite identity for a special entry, used to de-duplicate authored
17598
+ * (`augmentcode` override) and preserved (existing-file) special entries so the
17599
+ * same policy is not emitted twice into `toolPermissions`. Every field that can
17600
+ * distinguish two special entries is included.
17601
+ */
17602
+ function specialEntryKey(entry) {
17603
+ return JSON.stringify([
17604
+ entry.toolName,
17605
+ entry.shellInputRegex ?? "",
17606
+ entry.eventType ?? "",
17607
+ entry.permission.type,
17608
+ entry.permission.webhookUrl ?? "",
17609
+ entry.permission.script ?? ""
17610
+ ]);
17611
+ }
17612
+ /**
17613
+ * Stable de-duplication of special entries by {@link specialEntryKey}, keeping
17614
+ * the first occurrence (authored entries lead, so an authored policy wins over
17615
+ * an identical preserved one).
17616
+ */
17617
+ function dedupeSpecialEntries(entries) {
17618
+ const seen = /* @__PURE__ */ new Set();
17619
+ const out = [];
17620
+ for (const entry of entries) {
17621
+ const key = specialEntryKey(entry);
17622
+ if (seen.has(key)) continue;
17623
+ seen.add(key);
17624
+ out.push(entry);
17625
+ }
17626
+ return out;
17627
+ }
17628
+ /**
17629
+ * Validate/normalize the `augmentcode` override's `toolPermissions` array into
17630
+ * typed `AugmentToolPermission` entries, dropping any malformed item (with a
17631
+ * warning so a typo is not lost silently). The override schema is intentionally
17632
+ * loose (verbatim passthrough), so entries are re-parsed through the full entry
17633
+ * schema here to guarantee shape before they are written into the shared
17634
+ * settings file.
17635
+ */
17636
+ function coerceAuthoredEntries(entries, logger) {
17637
+ const out = [];
17638
+ for (const item of entries) {
17639
+ const parsed = AugmentToolPermissionSchema.safeParse(item);
17640
+ if (parsed.success) out.push(parsed.data);
17641
+ else logger?.warn(`AugmentCode permissions: dropping malformed 'augmentcode.toolPermissions' override entry: ${formatError(parsed.error)}.`);
17642
+ }
17643
+ return out;
17644
+ }
17645
+ /**
17365
17646
  * Convert a glob-like pattern into a regex string for AugmentCode's `shellInputRegex`.
17366
17647
  * Maps glob `*` to `.*`, `?` to `.`, escapes other regex metacharacters, and anchors at both ends.
17367
17648
  */
@@ -17492,12 +17773,18 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
17492
17773
  } catch (error) {
17493
17774
  throw new Error(`Failed to parse existing AugmentCode settings at ${filePath}: ${formatError(error)}`, { cause: error });
17494
17775
  }
17776
+ const config = rulesyncPermissions.getJson();
17495
17777
  const generated = convertRulesyncToAugmentEntries({
17496
- config: rulesyncPermissions.getJson(),
17778
+ config,
17497
17779
  logger
17498
17780
  });
17499
17781
  const existingEntries = settings.toolPermissions ?? [];
17500
- const specialEntries = existingEntries.filter((entry) => isSpecialEntry(entry));
17782
+ const override = config.augmentcode;
17783
+ const authoredEntries = override?.toolPermissions ? coerceAuthoredEntries(override.toolPermissions, logger) : [];
17784
+ const authoredSpecials = authoredEntries.filter((entry) => isSpecialEntry(entry));
17785
+ const authoredBasics = authoredEntries.filter((entry) => !isSpecialEntry(entry));
17786
+ const preservedSpecials = override?.toolPermissions ? [] : existingEntries.filter((entry) => isSpecialEntry(entry));
17787
+ const specialEntries = dedupeSpecialEntries([...authoredSpecials, ...preservedSpecials]);
17501
17788
  const basicExistingEntries = existingEntries.filter((entry) => !isSpecialEntry(entry));
17502
17789
  const generatedKeys = new Set(generated.map((e) => `${e.toolName}|${e.shellInputRegex ?? ""}|${e.permission.type}`));
17503
17790
  const preservedBasicEntries = basicExistingEntries.filter((entry) => {
@@ -17508,7 +17795,11 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
17508
17795
  }
17509
17796
  return false;
17510
17797
  });
17511
- const sortedBasic = sortAugmentEntries([...generated, ...preservedBasicEntries]);
17798
+ const sortedBasic = sortAugmentEntries([
17799
+ ...generated,
17800
+ ...preservedBasicEntries,
17801
+ ...authoredBasics
17802
+ ]);
17512
17803
  const merged = {
17513
17804
  ...settings,
17514
17805
  toolPermissions: [...specialEntries, ...sortedBasic]
@@ -17532,11 +17823,14 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
17532
17823
  } catch (error) {
17533
17824
  throw new Error(`Failed to parse AugmentCode permissions content in ${(0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
17534
17825
  }
17535
- const config = convertAugmentToRulesyncPermissions({
17536
- entries: settings.toolPermissions ?? [],
17826
+ const allEntries = settings.toolPermissions ?? [];
17827
+ const specialEntries = allEntries.filter((entry) => isSpecialEntry(entry));
17828
+ const result = { ...convertAugmentToRulesyncPermissions({
17829
+ entries: allEntries.filter((entry) => !isSpecialEntry(entry)),
17537
17830
  logger: moduleLogger$1
17538
- });
17539
- return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(config, null, 2) });
17831
+ }) };
17832
+ if (specialEntries.length > 0) result.augmentcode = { toolPermissions: specialEntries };
17833
+ return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
17540
17834
  }
17541
17835
  validate() {
17542
17836
  try {
@@ -17670,10 +17964,7 @@ function convertAugmentToRulesyncPermissions({ entries, logger }) {
17670
17964
  ]);
17671
17965
  const permission = {};
17672
17966
  for (const entry of entries) {
17673
- if (isSpecialEntry(entry)) {
17674
- logger?.warn(`AugmentCode permissions: skipping advanced entry for tool '${entry.toolName}' (type '${entry.permission.type}'${entry.eventType !== void 0 ? `, eventType '${entry.eventType}'` : ""}) on import; rulesync's permission model cannot represent custom policies, eventType, webhookUrl, or script. Such entries are preserved on generate but not imported.`);
17675
- continue;
17676
- }
17967
+ if (isSpecialEntry(entry)) continue;
17677
17968
  const type = entry.permission.type;
17678
17969
  if (!isBasicAugmentType(type)) continue;
17679
17970
  const canonical = toCanonicalToolName$5(entry.toolName);
@@ -18105,6 +18396,13 @@ const WORKSPACE_WIDE_WRITE_PATTERNS = /* @__PURE__ */ new Set([
18105
18396
  ]);
18106
18397
  const CODEX_MINIMAL_KEY = ":minimal";
18107
18398
  const GLOBAL_WILDCARD_DOMAIN = "*";
18399
+ const CODEXCLI_OVERRIDE_KEYS = [
18400
+ "approval_policy",
18401
+ "sandbox_mode",
18402
+ "sandbox_workspace_write",
18403
+ "apps",
18404
+ "approvals_reviewer"
18405
+ ];
18108
18406
  var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
18109
18407
  static getSettablePaths(_options = {}) {
18110
18408
  return {
@@ -18146,6 +18444,11 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
18146
18444
  });
18147
18445
  parsed.permissions = permissionsTable;
18148
18446
  parsed.default_permissions = RULESYNC_PROFILE_NAME;
18447
+ applyCodexcliOverride({
18448
+ parsed,
18449
+ override: rulesyncPermissions.getJson().codexcli,
18450
+ logger
18451
+ });
18149
18452
  return new CodexcliPermissions({
18150
18453
  outputRoot,
18151
18454
  relativeDirPath: paths.relativeDirPath,
@@ -18170,7 +18473,12 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
18170
18473
  profile,
18171
18474
  domainsHadUnknown
18172
18475
  });
18173
- return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(config, null, 2) });
18476
+ const override = extractCodexcliOverride(table);
18477
+ const result = Object.keys(override).length > 0 ? {
18478
+ ...config,
18479
+ codexcli: override
18480
+ } : config;
18481
+ return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
18174
18482
  }
18175
18483
  validate() {
18176
18484
  return {
@@ -18362,6 +18670,30 @@ function toMutableTable(value) {
18362
18670
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
18363
18671
  return { ...value };
18364
18672
  }
18673
+ function isPlainObject(value) {
18674
+ return value !== null && typeof value === "object" && !Array.isArray(value);
18675
+ }
18676
+ function applyCodexcliOverride({ parsed, override, logger }) {
18677
+ if (!override) return;
18678
+ const allowed = new Set(CODEXCLI_OVERRIDE_KEYS);
18679
+ for (const [key, value] of Object.entries(override)) {
18680
+ if (!allowed.has(key)) {
18681
+ logger?.warn(`Codex CLI permission override key "${key}" is not managed and was skipped. "permissions"/"default_permissions" are owned by the canonical permission model and "mcp_servers" gating by the MCP feature.`);
18682
+ continue;
18683
+ }
18684
+ if (value === void 0) continue;
18685
+ const existing = parsed[key];
18686
+ parsed[key] = isPlainObject(existing) && isPlainObject(value) ? {
18687
+ ...existing,
18688
+ ...value
18689
+ } : value;
18690
+ }
18691
+ }
18692
+ function extractCodexcliOverride(table) {
18693
+ const override = {};
18694
+ for (const key of CODEXCLI_OVERRIDE_KEYS) if (table[key] !== void 0) override[key] = table[key];
18695
+ return override;
18696
+ }
18365
18697
  function toFilesystemRecord(value) {
18366
18698
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
18367
18699
  const result = {};
@@ -18529,7 +18861,11 @@ function toCursorPattern(canonical, pattern) {
18529
18861
  function toCanonicalCategory$1(cursorType, pattern) {
18530
18862
  if (cursorType === "Mcp") {
18531
18863
  const match = pattern.match(/^([^:()]+):([^:()]+)$/);
18532
- if (match) return `${MCP_CANONICAL_PREFIX$1}${match[1] ?? "*"}__${match[2] ?? "*"}`;
18864
+ if (match) {
18865
+ const server = match[1] ?? "*";
18866
+ const tool = match[2] ?? "*";
18867
+ return `${MCP_CANONICAL_PREFIX$1}${server}__${tool}`;
18868
+ }
18533
18869
  return CURSOR_TYPE_TO_CANONICAL[cursorType] ?? cursorType.toLowerCase();
18534
18870
  }
18535
18871
  return CURSOR_TYPE_TO_CANONICAL[cursorType] ?? cursorType.toLowerCase();
@@ -19276,7 +19612,7 @@ var GoosePermissions = class GoosePermissions extends ToolPermissions {
19276
19612
  const existingContent = await readFileContentOrNull(filePath) ?? "";
19277
19613
  let parsed;
19278
19614
  try {
19279
- parsed = existingContent.trim() === "" ? {} : (0, js_yaml.load)(existingContent);
19615
+ parsed = existingContent.trim() === "" ? {} : loadYaml(existingContent);
19280
19616
  } catch (error) {
19281
19617
  throw new Error(`Failed to parse existing Goose permission.yaml at ${filePath}: ${formatError(error)}`, { cause: error });
19282
19618
  }
@@ -19298,7 +19634,7 @@ var GoosePermissions = class GoosePermissions extends ToolPermissions {
19298
19634
  let parsed;
19299
19635
  try {
19300
19636
  const content = this.getFileContent();
19301
- parsed = content.trim() === "" ? {} : (0, js_yaml.load)(content);
19637
+ parsed = content.trim() === "" ? {} : loadYaml(content);
19302
19638
  } catch (error) {
19303
19639
  throw new Error(`Failed to parse Goose permissions content in ${(0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
19304
19640
  }
@@ -20205,6 +20541,13 @@ const KiroAgentSchema = zod_mini.z.looseObject({
20205
20541
  toolsSettings: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.unknown()))
20206
20542
  });
20207
20543
  const UnknownRecordSchema = zod_mini.z.record(zod_mini.z.string(), zod_mini.z.unknown());
20544
+ const CANONICAL_SHELL_KEYS = /* @__PURE__ */ new Set(["allowedCommands", "deniedCommands"]);
20545
+ const CANONICAL_TOOL_SETTINGS_KEYS = /* @__PURE__ */ new Set([
20546
+ "read",
20547
+ "write",
20548
+ "grep",
20549
+ "glob"
20550
+ ]);
20208
20551
  var KiroPermissions = class KiroPermissions extends ToolPermissions {
20209
20552
  static getSettablePaths(_options = {}) {
20210
20553
  return {
@@ -20268,7 +20611,10 @@ var KiroPermissions = class KiroPermissions extends ToolPermissions {
20268
20611
  const allowedTools = new Set(parsed.allowedTools ?? []);
20269
20612
  if (allowedTools.has("web_fetch")) permission.webfetch = { "*": "allow" };
20270
20613
  if (allowedTools.has("web_search")) permission.websearch = { "*": "allow" };
20271
- return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify({ permission }, null, 2) });
20614
+ const kiroOverride = extractKiroOverride(toolsSettings);
20615
+ const result = { permission };
20616
+ if (kiroOverride !== void 0) result.kiro = kiroOverride;
20617
+ return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
20272
20618
  }
20273
20619
  validate() {
20274
20620
  return {
@@ -20318,19 +20664,71 @@ function buildKiroPermissionsFromRulesync({ config, logger, existing }) {
20318
20664
  });
20319
20665
  else logger?.warn(`Kiro permissions do not support category: ${category}. Skipping.`);
20320
20666
  }
20321
- nextToolsSettings.shell = shell;
20667
+ nextToolsSettings.shell = {
20668
+ ...preservedShellFlags(existing),
20669
+ ...shell
20670
+ };
20322
20671
  nextToolsSettings.read = pathTable(pathBuckets.read);
20323
20672
  nextToolsSettings.write = pathTable(pathBuckets.write);
20324
20673
  for (const key of ["grep", "glob"]) {
20325
20674
  const bucket = pathBuckets[key];
20326
20675
  if (bucket && (bucket.allow.length > 0 || bucket.deny.length > 0)) nextToolsSettings[key] = pathTable(bucket);
20327
20676
  }
20677
+ applyKiroOverride({
20678
+ override: config.kiro,
20679
+ nextToolsSettings,
20680
+ logger
20681
+ });
20328
20682
  return {
20329
20683
  ...existing,
20330
20684
  allowedTools: [...nextAllowedTools].toSorted(),
20331
20685
  toolsSettings: nextToolsSettings
20332
20686
  };
20333
20687
  }
20688
+ /**
20689
+ * Non-canonical `toolsSettings.shell` keys already present in the existing agent
20690
+ * config (everything except the canonical `allowed`/`deniedCommands`), so a
20691
+ * regenerate does not silently drop a hand-set `autoAllowReadonly` /
20692
+ * `denyByDefault` when no `kiro` override re-authors it.
20693
+ */
20694
+ function preservedShellFlags(existing) {
20695
+ const existingShell = asRecord$1(asRecord$1(existing.toolsSettings).shell);
20696
+ const flags = {};
20697
+ for (const [key, value] of Object.entries(existingShell)) if (!CANONICAL_SHELL_KEYS.has(key)) flags[key] = value;
20698
+ return flags;
20699
+ }
20700
+ /**
20701
+ * Deep-merge the `kiro` override's `toolsSettings` block into the generated
20702
+ * settings, one `toolsSettings` key at a time so the override's leaf fields win
20703
+ * without clobbering canonical-generated siblings.
20704
+ *
20705
+ * Guards, so the override can only author the non-canonical surfaces it is meant
20706
+ * for and can never weaken a canonical-generated deny:
20707
+ * - prototype-pollution keys are skipped before being used as object keys;
20708
+ * - fully-canonical `toolsSettings` keys (`read`/`write`/`grep`/`glob`) are
20709
+ * rejected outright with a warning (their paths are owned by the canonical
20710
+ * `permission` block);
20711
+ * - for `shell` (partly canonical), the canonical command-list leaves
20712
+ * (`allowed`/`deniedCommands`) are stripped from the override value so only the
20713
+ * auto-trust flags merge.
20714
+ */
20715
+ function applyKiroOverride({ override, nextToolsSettings, logger }) {
20716
+ const overrideToolsSettings = override?.toolsSettings;
20717
+ if (!isPlainObject$1(overrideToolsSettings)) return;
20718
+ for (const [key, value] of Object.entries(overrideToolsSettings)) {
20719
+ if (isPrototypePollutionKey(key)) continue;
20720
+ if (!isPlainObject$1(value)) continue;
20721
+ if (CANONICAL_TOOL_SETTINGS_KEYS.has(key)) {
20722
+ logger?.warn(`Kiro permissions: ignoring 'kiro.toolsSettings.${key}' override; '${key}' paths are driven by the canonical permission block.`);
20723
+ continue;
20724
+ }
20725
+ const mergeValue = key === "shell" ? Object.fromEntries(Object.entries(value).filter(([leaf]) => !CANONICAL_SHELL_KEYS.has(leaf))) : value;
20726
+ nextToolsSettings[key] = {
20727
+ ...asRecord$1(nextToolsSettings[key]),
20728
+ ...mergeValue
20729
+ };
20730
+ }
20731
+ }
20334
20732
  function pathTable(bucket) {
20335
20733
  return {
20336
20734
  allowedPaths: bucket?.allow ?? [],
@@ -20350,6 +20748,31 @@ function asRecord$1(value) {
20350
20748
  const result = UnknownRecordSchema.safeParse(value);
20351
20749
  return result.success ? result.data : {};
20352
20750
  }
20751
+ /**
20752
+ * Build the `kiro` permissions override from a parsed agent config's
20753
+ * `toolsSettings`, lifting the Kiro-specific knobs with no canonical category:
20754
+ * - `shell.*` flags other than the canonical `allowed`/`deniedCommands`
20755
+ * (e.g. `autoAllowReadonly`, `denyByDefault`), verbatim.
20756
+ * - the whole `aws` object (`allowedServices` / `deniedServices` / …), verbatim.
20757
+ * - the whole `web_fetch` object (`trusted` / `blocked`), verbatim.
20758
+ *
20759
+ * Returns `undefined` when none are present so the override key is omitted.
20760
+ */
20761
+ function extractKiroOverride(toolsSettings) {
20762
+ const overrideToolsSettings = {};
20763
+ const shellFlags = {};
20764
+ for (const [key, value] of Object.entries(asRecord$1(toolsSettings.shell))) {
20765
+ if (isPrototypePollutionKey(key)) continue;
20766
+ if (!CANONICAL_SHELL_KEYS.has(key)) shellFlags[key] = value;
20767
+ }
20768
+ if (Object.keys(shellFlags).length > 0) overrideToolsSettings.shell = shellFlags;
20769
+ const aws = asRecord$1(toolsSettings.aws);
20770
+ if (Object.keys(aws).length > 0) overrideToolsSettings.aws = aws;
20771
+ const webFetch = asRecord$1(toolsSettings.web_fetch);
20772
+ if (Object.keys(webFetch).length > 0) overrideToolsSettings.web_fetch = webFetch;
20773
+ if (Object.keys(overrideToolsSettings).length === 0) return void 0;
20774
+ return { toolsSettings: overrideToolsSettings };
20775
+ }
20353
20776
  function asStringArray(value) {
20354
20777
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
20355
20778
  }
@@ -21162,7 +21585,7 @@ var RovodevPermissions = class RovodevPermissions extends ToolPermissions {
21162
21585
  const existingContent = await readFileContentOrNull(filePath) ?? "";
21163
21586
  let parsed;
21164
21587
  try {
21165
- parsed = existingContent.trim() === "" ? {} : (0, js_yaml.load)(existingContent);
21588
+ parsed = existingContent.trim() === "" ? {} : loadYaml(existingContent);
21166
21589
  } catch (error) {
21167
21590
  throw new Error(`Failed to parse existing Rovodev config at ${filePath}: ${formatError(error)}`, { cause: error });
21168
21591
  }
@@ -21188,7 +21611,7 @@ var RovodevPermissions = class RovodevPermissions extends ToolPermissions {
21188
21611
  let parsed;
21189
21612
  try {
21190
21613
  const content = this.getFileContent();
21191
- parsed = content.trim() === "" ? {} : (0, js_yaml.load)(content);
21614
+ parsed = content.trim() === "" ? {} : loadYaml(content);
21192
21615
  } catch (error) {
21193
21616
  throw new Error(`Failed to parse Rovodev permissions content in ${(0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
21194
21617
  }
@@ -21383,9 +21806,9 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
21383
21806
  const rulesyncJson = rulesyncPermissions.getJson();
21384
21807
  const provider = resolveActiveProvider(config);
21385
21808
  const mode = deriveTaktPermissionMode(rulesyncJson);
21386
- const override = isPlainObject(rulesyncJson.takt) ? rulesyncJson.takt : void 0;
21387
- const stepOverrides = isPlainObject(override?.[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? override[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
21388
- const overrideProviderOptions = isPlainObject(override?.[TAKT_PROVIDER_OPTIONS_KEY]) ? override[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
21809
+ const override = isPlainObject$1(rulesyncJson.takt) ? rulesyncJson.takt : void 0;
21810
+ const stepOverrides = isPlainObject$1(override?.[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? override[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
21811
+ const overrideProviderOptions = isPlainObject$1(override?.[TAKT_PROVIDER_OPTIONS_KEY]) ? override[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
21389
21812
  const patch = {
21390
21813
  [TAKT_PROVIDER_PROFILES_KEY]: { [provider]: {
21391
21814
  [TAKT_DEFAULT_PERMISSION_MODE_KEY]: mode,
@@ -21416,12 +21839,12 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
21416
21839
  invalidRootPolicy: "error"
21417
21840
  });
21418
21841
  const provider = resolveActiveProvider(config);
21419
- const profiles = isPlainObject(config[TAKT_PROVIDER_PROFILES_KEY]) ? config[TAKT_PROVIDER_PROFILES_KEY] : {};
21420
- const profile = isPlainObject(profiles[provider]) ? profiles[provider] : {};
21842
+ const profiles = isPlainObject$1(config[TAKT_PROVIDER_PROFILES_KEY]) ? config[TAKT_PROVIDER_PROFILES_KEY] : {};
21843
+ const profile = isPlainObject$1(profiles[provider]) ? profiles[provider] : {};
21421
21844
  const mode = profile[TAKT_DEFAULT_PERMISSION_MODE_KEY];
21422
21845
  const rulesyncConfig = taktModeToRulesyncConfig(mode);
21423
- const stepOverrides = isPlainObject(profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
21424
- const providerOptions = isPlainObject(config[TAKT_PROVIDER_OPTIONS_KEY]) ? config[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
21846
+ const stepOverrides = isPlainObject$1(profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
21847
+ const providerOptions = isPlainObject$1(config[TAKT_PROVIDER_OPTIONS_KEY]) ? config[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
21425
21848
  const taktOverride = {};
21426
21849
  if (stepOverrides && Object.keys(stepOverrides).length > 0) taktOverride[TAKT_STEP_PERMISSION_OVERRIDES_KEY] = stepOverrides;
21427
21850
  if (providerOptions && Object.keys(providerOptions).length > 0) taktOverride[TAKT_PROVIDER_OPTIONS_KEY] = providerOptions;
@@ -21453,7 +21876,7 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
21453
21876
  function resolveActiveProvider(config) {
21454
21877
  if (typeof config[TAKT_PROVIDER_KEY] === "string" && config[TAKT_PROVIDER_KEY].trim() !== "") return config[TAKT_PROVIDER_KEY];
21455
21878
  const profiles = config[TAKT_PROVIDER_PROFILES_KEY];
21456
- if (isPlainObject(profiles)) {
21879
+ if (isPlainObject$1(profiles)) {
21457
21880
  const keys = Object.keys(profiles);
21458
21881
  if (keys.length === 1) return keys[0];
21459
21882
  }
@@ -22785,13 +23208,15 @@ var AgentsmdSkill = class AgentsmdSkill extends SimulatedSkill {
22785
23208
  return { relativeDirPath: AGENTSMD_SKILLS_DIR_PATH };
22786
23209
  }
22787
23210
  static async fromDir(params) {
22788
- return new AgentsmdSkill(await this.fromDirDefault(params));
23211
+ const baseParams = await this.fromDirDefault(params);
23212
+ return new AgentsmdSkill(baseParams);
22789
23213
  }
22790
23214
  static fromRulesyncSkill(params) {
22791
- return new AgentsmdSkill({
23215
+ const baseParams = {
22792
23216
  ...this.fromRulesyncSkillDefault(params),
22793
23217
  relativeDirPath: this.getSettablePaths().relativeDirPath
22794
- });
23218
+ };
23219
+ return new AgentsmdSkill(baseParams);
22795
23220
  }
22796
23221
  static isTargetedByRulesyncSkill(rulesyncSkill) {
22797
23222
  return this.isTargetedByRulesyncSkillDefault({
@@ -22800,7 +23225,8 @@ var AgentsmdSkill = class AgentsmdSkill extends SimulatedSkill {
22800
23225
  });
22801
23226
  }
22802
23227
  static forDeletion(params) {
22803
- return new AgentsmdSkill(this.forDeletionDefault(params));
23228
+ const baseParams = this.forDeletionDefault(params);
23229
+ return new AgentsmdSkill(baseParams);
22804
23230
  }
22805
23231
  };
22806
23232
  const RulesyncSkillFrontmatterSchema = zod_mini.z.looseObject({
@@ -24207,9 +24633,10 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
24207
24633
  })
24208
24634
  });
24209
24635
  const settablePaths = ClaudecodeSkill.getSettablePaths({ global });
24636
+ const relativeDirPath = rulesyncFrontmatter.claudecode?.["scheduled-task"] ? CLAUDECODE_SCHEDULED_TASKS_DIR_PATH : settablePaths.relativeDirPath;
24210
24637
  return new ClaudecodeSkill({
24211
24638
  outputRoot,
24212
- relativeDirPath: rulesyncFrontmatter.claudecode?.["scheduled-task"] ? CLAUDECODE_SCHEDULED_TASKS_DIR_PATH : settablePaths.relativeDirPath,
24639
+ relativeDirPath,
24213
24640
  dirName: rulesyncSkill.getDirName(),
24214
24641
  frontmatter: claudecodeFrontmatter,
24215
24642
  body: rulesyncSkill.getBody(),
@@ -24442,7 +24869,7 @@ function extractOpenaiYamlFile(otherFiles) {
24442
24869
  const rest = [];
24443
24870
  for (const file of otherFiles) {
24444
24871
  if (toPosixPath(file.relativeFilePathToDirPath) === target) try {
24445
- const loaded = (0, js_yaml.load)(file.fileBuffer.toString("utf-8"));
24872
+ const loaded = loadYaml(file.fileBuffer.toString("utf-8"));
24446
24873
  if (loaded !== null && typeof loaded === "object" && !Array.isArray(loaded)) {
24447
24874
  parsed = loaded;
24448
24875
  continue;
@@ -25998,9 +26425,10 @@ var KiloSkill = class KiloSkill extends ToolSkill {
25998
26425
  ...kiloSection?.compatibility !== void 0 && { compatibility: kiloSection.compatibility },
25999
26426
  ...kiloSection?.metadata !== void 0 && { metadata: kiloSection.metadata }
26000
26427
  };
26428
+ const settablePaths = KiloSkill.getSettablePaths({ global });
26001
26429
  return new KiloSkill({
26002
26430
  outputRoot,
26003
- relativeDirPath: KiloSkill.getSettablePaths({ global }).relativeDirPath,
26431
+ relativeDirPath: settablePaths.relativeDirPath,
26004
26432
  dirName: rulesyncSkill.getDirName(),
26005
26433
  frontmatter: kiloFrontmatter,
26006
26434
  body: rulesyncSkill.getBody(),
@@ -26323,9 +26751,10 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
26323
26751
  ...metadata !== void 0 && { metadata },
26324
26752
  ...opencodeSection?.["allowed-tools"] !== void 0 && { "allowed-tools": opencodeSection["allowed-tools"] }
26325
26753
  };
26754
+ const settablePaths = OpenCodeSkill.getSettablePaths({ global });
26326
26755
  return new OpenCodeSkill({
26327
26756
  outputRoot,
26328
- relativeDirPath: OpenCodeSkill.getSettablePaths({ global }).relativeDirPath,
26757
+ relativeDirPath: settablePaths.relativeDirPath,
26329
26758
  dirName: rulesyncSkill.getDirName(),
26330
26759
  frontmatter: opencodeFrontmatter,
26331
26760
  body: rulesyncSkill.getBody(),
@@ -26640,9 +27069,10 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
26640
27069
  ...resolvedUserInvocable !== void 0 && { "user-invocable": resolvedUserInvocable },
26641
27070
  ...resolvedDisableModelInvocation !== void 0 && { "disable-model-invocation": resolvedDisableModelInvocation }
26642
27071
  };
27072
+ const settablePaths = QwencodeSkill.getSettablePaths({ global });
26643
27073
  return new QwencodeSkill({
26644
27074
  outputRoot,
26645
- relativeDirPath: QwencodeSkill.getSettablePaths({ global }).relativeDirPath,
27075
+ relativeDirPath: settablePaths.relativeDirPath,
26646
27076
  dirName: rulesyncSkill.getDirName(),
26647
27077
  frontmatter: qwencodeFrontmatter,
26648
27078
  body: rulesyncSkill.getBody(),
@@ -26693,6 +27123,140 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
26693
27123
  }
26694
27124
  };
26695
27125
  //#endregion
27126
+ //#region src/features/skills/reasonix-skill.ts
27127
+ const ReasonixSkillFrontmatterSchema = zod_mini.z.looseObject({
27128
+ name: zod_mini.z.string(),
27129
+ description: zod_mini.z.string()
27130
+ });
27131
+ /**
27132
+ * Represents a DeepSeek-Reasonix skill directory.
27133
+ *
27134
+ * Reasonix discovers directory-layout skills (`<name>/SKILL.md`) under
27135
+ * `.reasonix/skills/` (project) and `~/.reasonix/skills/` (global); the global
27136
+ * scope is served by the processor supplying the home directory as outputRoot.
27137
+ * @see https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/GUIDE.md
27138
+ */
27139
+ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
27140
+ constructor({ outputRoot = process.cwd(), relativeDirPath = REASONIX_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
27141
+ super({
27142
+ outputRoot,
27143
+ relativeDirPath,
27144
+ dirName,
27145
+ mainFile: {
27146
+ name: SKILL_FILE_NAME,
27147
+ body,
27148
+ frontmatter: { ...frontmatter }
27149
+ },
27150
+ otherFiles,
27151
+ global
27152
+ });
27153
+ if (validate) {
27154
+ const result = this.validate();
27155
+ if (!result.success) throw result.error;
27156
+ }
27157
+ }
27158
+ static getSettablePaths({ global: _global = false } = {}) {
27159
+ return { relativeDirPath: REASONIX_SKILLS_DIR_PATH };
27160
+ }
27161
+ getFrontmatter() {
27162
+ return ReasonixSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
27163
+ }
27164
+ getBody() {
27165
+ return this.mainFile?.body ?? "";
27166
+ }
27167
+ validate() {
27168
+ if (this.mainFile === void 0) return {
27169
+ success: false,
27170
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27171
+ };
27172
+ const result = ReasonixSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27173
+ if (!result.success) return {
27174
+ success: false,
27175
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
27176
+ };
27177
+ return {
27178
+ success: true,
27179
+ error: null
27180
+ };
27181
+ }
27182
+ toRulesyncSkill() {
27183
+ const frontmatter = this.getFrontmatter();
27184
+ const rulesyncFrontmatter = {
27185
+ name: frontmatter.name,
27186
+ description: frontmatter.description,
27187
+ targets: ["*"]
27188
+ };
27189
+ return new RulesyncSkill({
27190
+ outputRoot: this.outputRoot,
27191
+ relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
27192
+ dirName: this.getDirName(),
27193
+ frontmatter: rulesyncFrontmatter,
27194
+ body: this.getBody(),
27195
+ otherFiles: this.getOtherFiles(),
27196
+ validate: true,
27197
+ global: this.global
27198
+ });
27199
+ }
27200
+ static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
27201
+ const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
27202
+ const reasonixFrontmatter = {
27203
+ name: rulesyncFrontmatter.name,
27204
+ description: rulesyncFrontmatter.description
27205
+ };
27206
+ const settablePaths = ReasonixSkill.getSettablePaths({ global });
27207
+ return new ReasonixSkill({
27208
+ outputRoot,
27209
+ relativeDirPath: settablePaths.relativeDirPath,
27210
+ dirName: rulesyncSkill.getDirName(),
27211
+ frontmatter: reasonixFrontmatter,
27212
+ body: rulesyncSkill.getBody(),
27213
+ otherFiles: rulesyncSkill.getOtherFiles(),
27214
+ validate,
27215
+ global
27216
+ });
27217
+ }
27218
+ static isTargetedByRulesyncSkill(rulesyncSkill) {
27219
+ const targets = rulesyncSkill.getFrontmatter().targets;
27220
+ return targets.includes("*") || targets.includes("reasonix");
27221
+ }
27222
+ static async fromDir(params) {
27223
+ const loaded = await this.loadSkillDirContent({
27224
+ ...params,
27225
+ getSettablePaths: ReasonixSkill.getSettablePaths
27226
+ });
27227
+ const result = ReasonixSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27228
+ if (!result.success) {
27229
+ const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27230
+ throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27231
+ }
27232
+ return new ReasonixSkill({
27233
+ outputRoot: loaded.outputRoot,
27234
+ relativeDirPath: loaded.relativeDirPath,
27235
+ dirName: loaded.dirName,
27236
+ frontmatter: result.data,
27237
+ body: loaded.body,
27238
+ otherFiles: loaded.otherFiles,
27239
+ validate: true,
27240
+ global: loaded.global
27241
+ });
27242
+ }
27243
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
27244
+ return new ReasonixSkill({
27245
+ outputRoot,
27246
+ relativeDirPath,
27247
+ dirName,
27248
+ frontmatter: {
27249
+ name: "",
27250
+ description: ""
27251
+ },
27252
+ body: "",
27253
+ otherFiles: [],
27254
+ validate: false,
27255
+ global
27256
+ });
27257
+ }
27258
+ };
27259
+ //#endregion
26696
27260
  //#region src/constants/replit-paths.ts
26697
27261
  const REPLIT_RULE_FILE_NAME = "replit.md";
26698
27262
  const REPLIT_SKILLS_DIR_PATH = (0, node_path.join)(".agents", "skills");
@@ -27061,17 +27625,20 @@ var TaktSkill = class TaktSkill extends ToolSkill {
27061
27625
  featureLabel: "skill",
27062
27626
  sourceLabel
27063
27627
  });
27628
+ const fileName = `${stem}.md`;
27629
+ const relativeDirPath = TAKT_SKILLS_DIR_PATH;
27630
+ const body = prependTaktExtends({
27631
+ extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
27632
+ body: rulesyncSkill.getBody(),
27633
+ featureLabel: "skill",
27634
+ sourceLabel
27635
+ });
27064
27636
  return new TaktSkill({
27065
27637
  outputRoot,
27066
- relativeDirPath: TAKT_SKILLS_DIR_PATH,
27638
+ relativeDirPath,
27067
27639
  dirName: stem,
27068
- fileName: `${stem}.md`,
27069
- body: prependTaktExtends({
27070
- extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
27071
- body: rulesyncSkill.getBody(),
27072
- featureLabel: "skill",
27073
- sourceLabel
27074
- }),
27640
+ fileName,
27641
+ body,
27075
27642
  otherFiles: rulesyncSkill.getOtherFiles(),
27076
27643
  validate,
27077
27644
  global
@@ -27369,9 +27936,10 @@ var WarpSkill = class WarpSkill extends ToolSkill {
27369
27936
  name: rulesyncFrontmatter.name,
27370
27937
  description: rulesyncFrontmatter.description
27371
27938
  };
27939
+ const settablePaths = WarpSkill.getSettablePaths({ global });
27372
27940
  return new WarpSkill({
27373
27941
  outputRoot,
27374
- relativeDirPath: WarpSkill.getSettablePaths({ global }).relativeDirPath,
27942
+ relativeDirPath: settablePaths.relativeDirPath,
27375
27943
  dirName: rulesyncSkill.getDirName(),
27376
27944
  frontmatter: warpFrontmatter,
27377
27945
  body: rulesyncSkill.getBody(),
@@ -27787,6 +28355,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
27787
28355
  supportsGlobal: true
27788
28356
  }
27789
28357
  }],
28358
+ ["reasonix", {
28359
+ class: ReasonixSkill,
28360
+ meta: {
28361
+ supportsProject: true,
28362
+ supportsSimulated: false,
28363
+ supportsGlobal: true
28364
+ }
28365
+ }],
27790
28366
  ["replit", {
27791
28367
  class: ReplitSkill,
27792
28368
  meta: {
@@ -28180,10 +28756,12 @@ var AgentsmdSubagent = class AgentsmdSubagent extends SimulatedSubagent {
28180
28756
  return { relativeDirPath: AGENTSMD_SUBAGENTS_DIR_PATH };
28181
28757
  }
28182
28758
  static async fromFile(params) {
28183
- return new AgentsmdSubagent(await this.fromFileDefault(params));
28759
+ const baseParams = await this.fromFileDefault(params);
28760
+ return new AgentsmdSubagent(baseParams);
28184
28761
  }
28185
28762
  static fromRulesyncSubagent(params) {
28186
- return new AgentsmdSubagent(this.fromRulesyncSubagentDefault(params));
28763
+ const baseParams = this.fromRulesyncSubagentDefault(params);
28764
+ return new AgentsmdSubagent(baseParams);
28187
28765
  }
28188
28766
  static isTargetedByRulesyncSubagent(rulesyncSubagent) {
28189
28767
  return this.isTargetedByRulesyncSubagentDefault({
@@ -28348,11 +28926,12 @@ var QwencodeSubagent = class QwencodeSubagent extends ToolSubagent {
28348
28926
  };
28349
28927
  const body = rulesyncSubagent.getBody();
28350
28928
  const fileContent = stringifyFrontmatter(body, qwencodeSubagentFrontmatter, { avoidBlockScalars: true });
28929
+ const paths = this.getSettablePaths({ global });
28351
28930
  return new QwencodeSubagent({
28352
28931
  outputRoot,
28353
28932
  frontmatter: qwencodeSubagentFrontmatter,
28354
28933
  body,
28355
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
28934
+ relativeDirPath: paths.relativeDirPath,
28356
28935
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
28357
28936
  fileContent,
28358
28937
  validate,
@@ -28476,11 +29055,12 @@ var RovodevSubagent = class RovodevSubagent extends ToolSubagent {
28476
29055
  };
28477
29056
  const body = rulesyncSubagent.getBody();
28478
29057
  const fileContent = stringifyFrontmatter(body, rovodevFrontmatter, { avoidBlockScalars: true });
29058
+ const paths = this.getSettablePaths({ global });
28479
29059
  return new RovodevSubagent({
28480
29060
  outputRoot,
28481
29061
  frontmatter: rovodevFrontmatter,
28482
29062
  body,
28483
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29063
+ relativeDirPath: paths.relativeDirPath,
28484
29064
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
28485
29065
  fileContent,
28486
29066
  validate,
@@ -28611,11 +29191,12 @@ var AugmentcodeSubagent = class AugmentcodeSubagent extends ToolSubagent {
28611
29191
  };
28612
29192
  const body = rulesyncSubagent.getBody();
28613
29193
  const fileContent = stringifyFrontmatter(body, augmentcodeFrontmatter, { avoidBlockScalars: true });
29194
+ const paths = this.getSettablePaths({ global });
28614
29195
  return new AugmentcodeSubagent({
28615
29196
  outputRoot,
28616
29197
  frontmatter: augmentcodeFrontmatter,
28617
29198
  body,
28618
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29199
+ relativeDirPath: paths.relativeDirPath,
28619
29200
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
28620
29201
  fileContent,
28621
29202
  validate,
@@ -28750,11 +29331,12 @@ var ClaudecodeSubagent = class ClaudecodeSubagent extends ToolSubagent {
28750
29331
  const claudecodeFrontmatter = result.data;
28751
29332
  const body = rulesyncSubagent.getBody();
28752
29333
  const fileContent = stringifyFrontmatter(body, claudecodeFrontmatter);
29334
+ const paths = this.getSettablePaths({ global });
28753
29335
  return new ClaudecodeSubagent({
28754
29336
  outputRoot,
28755
29337
  frontmatter: claudecodeFrontmatter,
28756
29338
  body,
28757
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29339
+ relativeDirPath: paths.relativeDirPath,
28758
29340
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
28759
29341
  fileContent,
28760
29342
  validate
@@ -28880,11 +29462,12 @@ var ClineSubagent = class ClineSubagent extends ToolSubagent {
28880
29462
  };
28881
29463
  const body = rulesyncSubagent.getBody();
28882
29464
  const fileContent = stringifyFrontmatter(body, clineFrontmatter, { avoidBlockScalars: true });
29465
+ const paths = this.getSettablePaths({ global });
28883
29466
  return new ClineSubagent({
28884
29467
  outputRoot,
28885
29468
  frontmatter: clineFrontmatter,
28886
29469
  body,
28887
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29470
+ relativeDirPath: paths.relativeDirPath,
28888
29471
  relativeFilePath: rulesyncSubagent.getRelativeFilePath().replace(/\.md$/, ".yaml"),
28889
29472
  fileContent,
28890
29473
  validate,
@@ -29150,7 +29733,8 @@ var CopilotSubagent = class CopilotSubagent extends ToolSubagent {
29150
29733
  const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
29151
29734
  const copilotSection = rulesyncFrontmatter.copilot ?? {};
29152
29735
  const toolsField = copilotSection.tools;
29153
- const mergedTools = ensureRequiredTool(normalizeTools(Array.isArray(toolsField) || typeof toolsField === "string" ? toolsField : void 0));
29736
+ const userTools = normalizeTools(Array.isArray(toolsField) || typeof toolsField === "string" ? toolsField : void 0);
29737
+ const mergedTools = ensureRequiredTool(userTools);
29154
29738
  const copilotFrontmatter = {
29155
29739
  name: rulesyncFrontmatter.name,
29156
29740
  description: rulesyncFrontmatter.description,
@@ -29159,11 +29743,12 @@ var CopilotSubagent = class CopilotSubagent extends ToolSubagent {
29159
29743
  };
29160
29744
  const body = rulesyncSubagent.getBody();
29161
29745
  const fileContent = stringifyFrontmatter(body, copilotFrontmatter);
29746
+ const paths = this.getSettablePaths({ global });
29162
29747
  return new CopilotSubagent({
29163
29748
  outputRoot,
29164
29749
  frontmatter: copilotFrontmatter,
29165
29750
  body,
29166
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29751
+ relativeDirPath: paths.relativeDirPath,
29167
29752
  relativeFilePath: toCopilotAgentFilePath(rulesyncSubagent.getRelativeFilePath()),
29168
29753
  fileContent,
29169
29754
  validate,
@@ -29336,11 +29921,12 @@ var CopilotcliSubagent = class CopilotcliSubagent extends ToolSubagent {
29336
29921
  const copilotCliFrontmatter = result.data;
29337
29922
  const body = rulesyncSubagent.getBody();
29338
29923
  const fileContent = stringifyFrontmatter(body, copilotCliFrontmatter);
29924
+ const paths = this.getSettablePaths({ global });
29339
29925
  return new CopilotcliSubagent({
29340
29926
  outputRoot,
29341
29927
  frontmatter: copilotCliFrontmatter,
29342
29928
  body,
29343
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
29929
+ relativeDirPath: paths.relativeDirPath,
29344
29930
  relativeFilePath: toCopilotCliAgentFilePath(rulesyncSubagent.getRelativeFilePath()),
29345
29931
  fileContent,
29346
29932
  validate,
@@ -29454,11 +30040,12 @@ var CursorSubagent = class CursorSubagent extends ToolSubagent {
29454
30040
  };
29455
30041
  const body = rulesyncSubagent.getBody();
29456
30042
  const fileContent = stringifyFrontmatter(body, cursorFrontmatter, { avoidBlockScalars: true });
30043
+ const paths = this.getSettablePaths({ global });
29457
30044
  return new CursorSubagent({
29458
30045
  outputRoot,
29459
30046
  frontmatter: cursorFrontmatter,
29460
30047
  body,
29461
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
30048
+ relativeDirPath: paths.relativeDirPath,
29462
30049
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
29463
30050
  fileContent,
29464
30051
  validate,
@@ -29892,11 +30479,12 @@ var FactorydroidSubagent = class FactorydroidSubagent extends ToolSubagent {
29892
30479
  const factorydroidFrontmatter = result.data;
29893
30480
  const body = rulesyncSubagent.getBody();
29894
30481
  const fileContent = stringifyFrontmatter(body, factorydroidFrontmatter);
30482
+ const paths = this.getSettablePaths({ global });
29895
30483
  return new FactorydroidSubagent({
29896
30484
  outputRoot,
29897
30485
  frontmatter: factorydroidFrontmatter,
29898
30486
  body,
29899
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
30487
+ relativeDirPath: paths.relativeDirPath,
29900
30488
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
29901
30489
  fileContent,
29902
30490
  validate,
@@ -30034,10 +30622,11 @@ var GooseSubagent = class GooseSubagent extends ToolSubagent {
30034
30622
  instructions,
30035
30623
  ...extraFields
30036
30624
  };
30625
+ const paths = this.getSettablePaths({ global });
30037
30626
  return new GooseSubagent({
30038
30627
  outputRoot,
30039
30628
  recipe,
30040
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
30629
+ relativeDirPath: paths.relativeDirPath,
30041
30630
  relativeFilePath,
30042
30631
  fileContent: (0, js_yaml.dump)(recipe, {
30043
30632
  lineWidth: -1,
@@ -30070,7 +30659,7 @@ var GooseSubagent = class GooseSubagent extends ToolSubagent {
30070
30659
  const fileContent = await readFileContent(filePath);
30071
30660
  let parsed;
30072
30661
  try {
30073
- parsed = (0, js_yaml.load)(fileContent);
30662
+ parsed = loadYaml(fileContent);
30074
30663
  } catch (error) {
30075
30664
  throw new Error(`Failed to parse Goose recipe (${filePath}): ${formatError(error)}`, { cause: error });
30076
30665
  }
@@ -30172,11 +30761,12 @@ var GrokcliSubagent = class GrokcliSubagent extends ToolSubagent {
30172
30761
  };
30173
30762
  const body = rulesyncSubagent.getBody();
30174
30763
  const fileContent = stringifyFrontmatter(body, grokcliSubagentFrontmatter, { avoidBlockScalars: true });
30764
+ const paths = this.getSettablePaths({ global });
30175
30765
  return new GrokcliSubagent({
30176
30766
  outputRoot,
30177
30767
  frontmatter: grokcliSubagentFrontmatter,
30178
30768
  body,
30179
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
30769
+ relativeDirPath: paths.relativeDirPath,
30180
30770
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
30181
30771
  fileContent,
30182
30772
  validate,
@@ -30412,9 +31002,10 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
30412
31002
  }
30413
31003
  static fromRulesyncSubagent({ rulesyncSubagent, outputRoot }) {
30414
31004
  const spec = getSubagentSpec(rulesyncSubagent);
31005
+ const slug = String(spec.slug);
30415
31006
  return new HermesagentSubagent({
30416
31007
  relativeDirPath: HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH,
30417
- relativeFilePath: `${String(spec.slug)}.json`,
31008
+ relativeFilePath: `${slug}.json`,
30418
31009
  fileContent: `${JSON.stringify(spec, null, 2)}\n`,
30419
31010
  outputRoot
30420
31011
  });
@@ -30548,11 +31139,12 @@ var JunieSubagent = class JunieSubagent extends ToolSubagent {
30548
31139
  const junieFrontmatter = result.data;
30549
31140
  const body = rulesyncSubagent.getBody();
30550
31141
  const fileContent = stringifyFrontmatter(body, junieFrontmatter);
31142
+ const paths = this.getSettablePaths({ global });
30551
31143
  return new JunieSubagent({
30552
31144
  outputRoot,
30553
31145
  frontmatter: junieFrontmatter,
30554
31146
  body,
30555
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31147
+ relativeDirPath: paths.relativeDirPath,
30556
31148
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
30557
31149
  fileContent,
30558
31150
  validate,
@@ -30743,11 +31335,12 @@ var KiloSubagent = class KiloSubagent extends OpenCodeStyleSubagent {
30743
31335
  const kiloFrontmatter = parseResult.data;
30744
31336
  const body = rulesyncSubagent.getBody();
30745
31337
  const fileContent = stringifyFrontmatter(body, kiloFrontmatter);
31338
+ const paths = this.getSettablePaths({ global });
30746
31339
  return new KiloSubagent({
30747
31340
  outputRoot,
30748
31341
  frontmatter: kiloFrontmatter,
30749
31342
  body,
30750
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31343
+ relativeDirPath: paths.relativeDirPath,
30751
31344
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
30752
31345
  fileContent,
30753
31346
  validate,
@@ -31019,11 +31612,12 @@ var KiroIdeSubagent = class KiroIdeSubagent extends ToolSubagent {
31019
31612
  const frontmatter = result.data;
31020
31613
  const body = rulesyncSubagent.getBody();
31021
31614
  const fileContent = stringifyFrontmatter(body, frontmatter);
31615
+ const paths = this.getSettablePaths({ global });
31022
31616
  return new KiroIdeSubagent({
31023
31617
  outputRoot,
31024
31618
  frontmatter,
31025
31619
  body,
31026
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31620
+ relativeDirPath: paths.relativeDirPath,
31027
31621
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
31028
31622
  fileContent,
31029
31623
  validate,
@@ -31167,11 +31761,12 @@ var OpenCodeSubagent = class OpenCodeSubagent extends OpenCodeStyleSubagent {
31167
31761
  const opencodeFrontmatter = parseResult.data;
31168
31762
  const body = rulesyncSubagent.getBody();
31169
31763
  const fileContent = stringifyFrontmatter(body, opencodeFrontmatter);
31764
+ const paths = this.getSettablePaths({ global });
31170
31765
  return new OpenCodeSubagent({
31171
31766
  outputRoot,
31172
31767
  frontmatter: opencodeFrontmatter,
31173
31768
  body,
31174
- relativeDirPath: this.getSettablePaths({ global }).relativeDirPath,
31769
+ relativeDirPath: paths.relativeDirPath,
31175
31770
  relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
31176
31771
  fileContent,
31177
31772
  validate,
@@ -31458,7 +32053,7 @@ var RooSubagent = class RooSubagent extends ToolSubagent {
31458
32053
  const fileContent = await readFileContent(filePath);
31459
32054
  let parsed;
31460
32055
  try {
31461
- parsed = (0, js_yaml.load)(fileContent);
32056
+ parsed = loadYaml(fileContent);
31462
32057
  } catch (error) {
31463
32058
  throw new Error(`Failed to parse .roomodes (${filePath}): ${formatError(error)}`, { cause: error });
31464
32059
  }
@@ -32460,11 +33055,12 @@ var AiassistantRule = class AiassistantRule extends ToolRule {
32460
33055
  }
32461
33056
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true }) {
32462
33057
  const relativeDirPath = this.getSettablePaths().nonRoot.relativeDirPath;
33058
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath));
32463
33059
  return new AiassistantRule({
32464
33060
  outputRoot,
32465
33061
  relativeDirPath,
32466
33062
  relativeFilePath,
32467
- fileContent: (await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath))).trim(),
33063
+ fileContent: fileContent.trim(),
32468
33064
  validate,
32469
33065
  root: false
32470
33066
  });
@@ -32565,13 +33161,14 @@ var AmpRule = class AmpRule extends ToolRule {
32565
33161
  };
32566
33162
  }
32567
33163
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
33164
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
32568
33165
  return new AmpRule({
32569
33166
  outputRoot,
32570
33167
  relativeDirPath,
32571
33168
  relativeFilePath,
32572
33169
  fileContent: "",
32573
33170
  validate: false,
32574
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
33171
+ root: isRoot
32575
33172
  });
32576
33173
  }
32577
33174
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -32654,13 +33251,14 @@ var AntigravityCliRule = class AntigravityCliRule extends ToolRule {
32654
33251
  };
32655
33252
  }
32656
33253
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
33254
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
32657
33255
  return new AntigravityCliRule({
32658
33256
  outputRoot,
32659
33257
  relativeDirPath,
32660
33258
  relativeFilePath,
32661
33259
  fileContent: "",
32662
33260
  validate: false,
32663
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
33261
+ root: isRoot
32664
33262
  });
32665
33263
  }
32666
33264
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -33074,13 +33672,14 @@ var AugmentcodeLegacyRule = class AugmentcodeLegacyRule extends ToolRule {
33074
33672
  });
33075
33673
  }
33076
33674
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
33675
+ const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
33077
33676
  return new AugmentcodeLegacyRule({
33078
33677
  outputRoot,
33079
33678
  relativeDirPath,
33080
33679
  relativeFilePath,
33081
33680
  fileContent: "",
33082
33681
  validate: false,
33083
- root: relativeFilePath === this.getSettablePaths().root.relativeFilePath
33682
+ root: isRoot
33084
33683
  });
33085
33684
  }
33086
33685
  };
@@ -33316,13 +33915,14 @@ var ClaudecodeLegacyRule = class ClaudecodeLegacyRule extends ToolRule {
33316
33915
  };
33317
33916
  }
33318
33917
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
33918
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
33319
33919
  return new ClaudecodeLegacyRule({
33320
33920
  outputRoot,
33321
33921
  relativeDirPath,
33322
33922
  relativeFilePath,
33323
33923
  fileContent: "",
33324
33924
  validate: false,
33325
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
33925
+ root: isRoot
33326
33926
  });
33327
33927
  }
33328
33928
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -33421,6 +34021,7 @@ var ClaudecodeRule = class ClaudecodeRule extends ToolRule {
33421
34021
  });
33422
34022
  }
33423
34023
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
34024
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
33424
34025
  return new ClaudecodeRule({
33425
34026
  outputRoot,
33426
34027
  relativeDirPath,
@@ -33428,7 +34029,7 @@ var ClaudecodeRule = class ClaudecodeRule extends ToolRule {
33428
34029
  frontmatter: {},
33429
34030
  body: "",
33430
34031
  validate: false,
33431
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
34032
+ root: isRoot
33432
34033
  });
33433
34034
  }
33434
34035
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
@@ -33944,6 +34545,13 @@ var CopilotRule = class CopilotRule extends ToolRule {
33944
34545
  }
33945
34546
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
33946
34547
  const paths = this.getSettablePaths({ global });
34548
+ const isRoot = sameRelativePath({
34549
+ dir: relativeDirPath,
34550
+ file: relativeFilePath
34551
+ }, {
34552
+ dir: paths.root.relativeDirPath,
34553
+ file: paths.root.relativeFilePath
34554
+ });
33947
34555
  return new CopilotRule({
33948
34556
  outputRoot,
33949
34557
  relativeDirPath,
@@ -33951,13 +34559,7 @@ var CopilotRule = class CopilotRule extends ToolRule {
33951
34559
  frontmatter: {},
33952
34560
  body: "",
33953
34561
  validate: false,
33954
- root: sameRelativePath({
33955
- dir: relativeDirPath,
33956
- file: relativeFilePath
33957
- }, {
33958
- dir: paths.root.relativeDirPath,
33959
- file: paths.root.relativeFilePath
33960
- })
34562
+ root: isRoot
33961
34563
  });
33962
34564
  }
33963
34565
  validate() {
@@ -34621,13 +35223,14 @@ var FactorydroidRule = class FactorydroidRule extends ToolRule {
34621
35223
  }
34622
35224
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
34623
35225
  const paths = this.getSettablePaths({ global });
35226
+ const isRoot = relativeFilePath === paths.root.relativeFilePath && relativeDirPath === paths.root.relativeDirPath;
34624
35227
  return new FactorydroidRule({
34625
35228
  outputRoot,
34626
35229
  relativeDirPath,
34627
35230
  relativeFilePath,
34628
35231
  fileContent: "",
34629
35232
  validate: false,
34630
- root: relativeFilePath === paths.root.relativeFilePath && relativeDirPath === paths.root.relativeDirPath
35233
+ root: isRoot
34631
35234
  });
34632
35235
  }
34633
35236
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
@@ -34723,13 +35326,14 @@ var GooseRule = class GooseRule extends ToolRule {
34723
35326
  }
34724
35327
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
34725
35328
  const paths = this.getSettablePaths({ global });
35329
+ const isRoot = relativeFilePath === paths.root.relativeFilePath && (relativeDirPath === "." || relativeDirPath === paths.root.relativeDirPath);
34726
35330
  return new GooseRule({
34727
35331
  outputRoot,
34728
35332
  relativeDirPath,
34729
35333
  relativeFilePath,
34730
35334
  fileContent: "",
34731
35335
  validate: false,
34732
- root: relativeFilePath === paths.root.relativeFilePath && (relativeDirPath === "." || relativeDirPath === paths.root.relativeDirPath)
35336
+ root: isRoot
34733
35337
  });
34734
35338
  }
34735
35339
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -34933,11 +35537,12 @@ var JunieRule = class JunieRule extends ToolRule {
34933
35537
  const settablePaths = this.getSettablePaths();
34934
35538
  if (!settablePaths.nonRoot) throw new Error("JunieRule project settable paths must include a nonRoot path");
34935
35539
  const relativeDirPath = isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath;
35540
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, (0, node_path.join)(relativeDirPath, relativeFilePath)));
34936
35541
  return new JunieRule({
34937
35542
  outputRoot,
34938
35543
  relativeDirPath,
34939
35544
  relativeFilePath,
34940
- fileContent: await readFileContent((0, node_path.join)(outputRoot, (0, node_path.join)(relativeDirPath, relativeFilePath))),
35545
+ fileContent,
34941
35546
  validate,
34942
35547
  root: isRoot
34943
35548
  });
@@ -34972,13 +35577,14 @@ var JunieRule = class JunieRule extends ToolRule {
34972
35577
  };
34973
35578
  }
34974
35579
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
35580
+ const isRoot = JunieRule.isRootRelativeFilePath(relativeFilePath);
34975
35581
  return new JunieRule({
34976
35582
  outputRoot,
34977
35583
  relativeDirPath,
34978
35584
  relativeFilePath,
34979
35585
  fileContent: "",
34980
35586
  validate: false,
34981
- root: JunieRule.isRootRelativeFilePath(relativeFilePath)
35587
+ root: isRoot
34982
35588
  });
34983
35589
  }
34984
35590
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -35052,13 +35658,14 @@ var KiloRule = class KiloRule extends ToolRule {
35052
35658
  };
35053
35659
  }
35054
35660
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
35661
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
35055
35662
  return new KiloRule({
35056
35663
  outputRoot,
35057
35664
  relativeDirPath,
35058
35665
  relativeFilePath,
35059
35666
  fileContent: "",
35060
35667
  validate: false,
35061
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
35668
+ root: isRoot
35062
35669
  });
35063
35670
  }
35064
35671
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -35147,11 +35754,12 @@ var KiroRule = class KiroRule extends ToolRule {
35147
35754
  const paths = this.getSettablePaths({ global });
35148
35755
  const isRoot = "root" in paths && relativeFilePath === paths.root.relativeFilePath;
35149
35756
  const relativeDirPath = paths.nonRoot?.relativeDirPath ?? buildToolPath(".kiro", "steering");
35757
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath));
35150
35758
  return new KiroRule({
35151
35759
  outputRoot,
35152
35760
  relativeDirPath,
35153
35761
  relativeFilePath,
35154
- fileContent: await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath)),
35762
+ fileContent,
35155
35763
  validate,
35156
35764
  root: isRoot
35157
35765
  });
@@ -35326,13 +35934,14 @@ var OpenCodeRule = class OpenCodeRule extends ToolRule {
35326
35934
  };
35327
35935
  }
35328
35936
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
35937
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
35329
35938
  return new OpenCodeRule({
35330
35939
  outputRoot,
35331
35940
  relativeDirPath,
35332
35941
  relativeFilePath,
35333
35942
  fileContent: "",
35334
35943
  validate: false,
35335
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
35944
+ root: isRoot
35336
35945
  });
35337
35946
  }
35338
35947
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -35417,13 +36026,14 @@ var PiRule = class PiRule extends ToolRule {
35417
36026
  }
35418
36027
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
35419
36028
  const { root } = this.getSettablePaths({ global });
36029
+ const isRoot = relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === root.relativeDirPath);
35420
36030
  return new PiRule({
35421
36031
  outputRoot,
35422
36032
  relativeDirPath,
35423
36033
  relativeFilePath,
35424
36034
  fileContent: "",
35425
36035
  validate: false,
35426
- root: relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === root.relativeDirPath)
36036
+ root: isRoot
35427
36037
  });
35428
36038
  }
35429
36039
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -35651,6 +36261,72 @@ var QwencodeRule = class QwencodeRule extends ToolRule {
35651
36261
  }
35652
36262
  };
35653
36263
  //#endregion
36264
+ //#region src/features/rules/reasonix-rule.ts
36265
+ var ReasonixRule = class ReasonixRule extends ToolRule {
36266
+ constructor({ fileContent, root, ...rest }) {
36267
+ super({
36268
+ ...rest,
36269
+ fileContent,
36270
+ root: root ?? false
36271
+ });
36272
+ }
36273
+ static getSettablePaths({ global = false } = {}) {
36274
+ return { root: {
36275
+ relativeDirPath: global ? REASONIX_GLOBAL_DIR : ".",
36276
+ relativeFilePath: REASONIX_RULE_FILE_NAME
36277
+ } };
36278
+ }
36279
+ static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, validate = true, global = false }) {
36280
+ const { root } = this.getSettablePaths({ global });
36281
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, (0, node_path.join)(root.relativeDirPath, root.relativeFilePath)));
36282
+ return new ReasonixRule({
36283
+ outputRoot,
36284
+ relativeDirPath: root.relativeDirPath,
36285
+ relativeFilePath: root.relativeFilePath,
36286
+ fileContent,
36287
+ validate,
36288
+ root: true
36289
+ });
36290
+ }
36291
+ static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
36292
+ const { root } = this.getSettablePaths({ global });
36293
+ const isRoot = rulesyncRule.getFrontmatter().root ?? false;
36294
+ return new ReasonixRule({
36295
+ outputRoot,
36296
+ relativeDirPath: root.relativeDirPath,
36297
+ relativeFilePath: root.relativeFilePath,
36298
+ fileContent: rulesyncRule.getBody(),
36299
+ validate,
36300
+ root: isRoot
36301
+ });
36302
+ }
36303
+ toRulesyncRule() {
36304
+ return this.toRulesyncRuleDefault();
36305
+ }
36306
+ validate() {
36307
+ return {
36308
+ success: true,
36309
+ error: null
36310
+ };
36311
+ }
36312
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
36313
+ return new ReasonixRule({
36314
+ outputRoot,
36315
+ relativeDirPath,
36316
+ relativeFilePath,
36317
+ fileContent: "",
36318
+ validate: false,
36319
+ root: relativeFilePath === "REASONIX.md" && (relativeDirPath === "." || relativeDirPath === ".reasonix")
36320
+ });
36321
+ }
36322
+ static isTargetedByRulesyncRule(rulesyncRule) {
36323
+ return this.isTargetedByRulesyncRuleDefault({
36324
+ rulesyncRule,
36325
+ toolTarget: "reasonix"
36326
+ });
36327
+ }
36328
+ };
36329
+ //#endregion
35654
36330
  //#region src/features/rules/replit-rule.ts
35655
36331
  /**
35656
36332
  * Rule generator for Replit Agent
@@ -35701,13 +36377,14 @@ var ReplitRule = class ReplitRule extends ToolRule {
35701
36377
  };
35702
36378
  }
35703
36379
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
36380
+ const isRoot = relativeFilePath === this.getSettablePaths().root.relativeFilePath;
35704
36381
  return new ReplitRule({
35705
36382
  outputRoot,
35706
36383
  relativeDirPath,
35707
36384
  relativeFilePath,
35708
36385
  fileContent: "",
35709
36386
  validate: false,
35710
- root: relativeFilePath === this.getSettablePaths().root.relativeFilePath
36387
+ root: isRoot
35711
36388
  });
35712
36389
  }
35713
36390
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -35858,11 +36535,12 @@ var RovodevRule = class RovodevRule extends ToolRule {
35858
36535
  }
35859
36536
  static async fromModularFile({ outputRoot, relativeFilePath, relativeDirPath, validate, global }) {
35860
36537
  if (!this.isAllowedModularRulesRelativePath(relativeFilePath)) throw new Error(`Reserved Rovodev memory basename under modular-rules (not a modular rule): ${(0, node_path.join)(relativeDirPath, relativeFilePath)}`);
36538
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath));
35861
36539
  return new RovodevRule({
35862
36540
  outputRoot,
35863
36541
  relativeDirPath,
35864
36542
  relativeFilePath,
35865
- fileContent: await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath)),
36543
+ fileContent,
35866
36544
  validate,
35867
36545
  global,
35868
36546
  root: false
@@ -35873,11 +36551,12 @@ var RovodevRule = class RovodevRule extends ToolRule {
35873
36551
  const agentsMdExpectedLocationsDescription = "alternativeRoots" in paths && paths.alternativeRoots && paths.alternativeRoots.length > 0 ? `${(0, node_path.join)(paths.root.relativeDirPath, paths.root.relativeFilePath)} or project root` : (0, node_path.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
35874
36552
  if (relativeFilePath !== "AGENTS.md") throw new Error(`Rovodev rules support only AGENTS.md at ${agentsMdExpectedLocationsDescription}, got: ${(0, node_path.join)(relativeDirPath, relativeFilePath)}`);
35875
36553
  if (!(relativeDirPath === paths.root.relativeDirPath || "alternativeRoots" in paths && paths.alternativeRoots?.some((alt) => alt.relativeDirPath === relativeDirPath && alt.relativeFilePath === relativeFilePath))) throw new Error(`Rovodev AGENTS.md must be at ${agentsMdExpectedLocationsDescription}, got: ${(0, node_path.join)(relativeDirPath, relativeFilePath)}`);
36554
+ const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath));
35876
36555
  return new RovodevRule({
35877
36556
  outputRoot,
35878
36557
  relativeDirPath,
35879
36558
  relativeFilePath,
35880
- fileContent: await readFileContent((0, node_path.join)(outputRoot, relativeDirPath, relativeFilePath)),
36559
+ fileContent,
35881
36560
  validate,
35882
36561
  global,
35883
36562
  root: true
@@ -36068,16 +36747,18 @@ var TaktRule = class TaktRule extends ToolRule {
36068
36747
  sourceLabel
36069
36748
  });
36070
36749
  const relativeFilePath = `${stem}.md`;
36750
+ const relativeDirPath = resolveTaktRuleFacet(taktSection?.facet) === "output-contracts" ? TAKT_OUTPUT_CONTRACTS_DIR_PATH : TAKT_RULES_DIR_PATH;
36751
+ const body = prependTaktExtends({
36752
+ extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
36753
+ body: rulesyncRule.getBody(),
36754
+ featureLabel: "rule",
36755
+ sourceLabel
36756
+ });
36071
36757
  return new TaktRule({
36072
36758
  outputRoot,
36073
- relativeDirPath: resolveTaktRuleFacet(taktSection?.facet) === "output-contracts" ? TAKT_OUTPUT_CONTRACTS_DIR_PATH : TAKT_RULES_DIR_PATH,
36759
+ relativeDirPath,
36074
36760
  relativeFilePath,
36075
- body: prependTaktExtends({
36076
- extendsName: typeof taktSection?.extends === "string" ? taktSection.extends : void 0,
36077
- body: rulesyncRule.getBody(),
36078
- featureLabel: "rule",
36079
- sourceLabel
36080
- }),
36761
+ body,
36081
36762
  validate,
36082
36763
  root: false
36083
36764
  });
@@ -36145,13 +36826,14 @@ var VibeRule = class VibeRule extends ToolRule {
36145
36826
  };
36146
36827
  }
36147
36828
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
36829
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
36148
36830
  return new VibeRule({
36149
36831
  outputRoot,
36150
36832
  relativeDirPath,
36151
36833
  relativeFilePath,
36152
36834
  fileContent: "",
36153
36835
  validate: false,
36154
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
36836
+ root: isRoot
36155
36837
  });
36156
36838
  }
36157
36839
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -36213,13 +36895,14 @@ var WarpRule = class WarpRule extends ToolRule {
36213
36895
  }
36214
36896
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
36215
36897
  const { root } = this.getSettablePaths();
36898
+ const isRoot = relativeFilePath === root.relativeFilePath && relativeDirPath === root.relativeDirPath;
36216
36899
  return new WarpRule({
36217
36900
  outputRoot,
36218
36901
  relativeDirPath,
36219
36902
  relativeFilePath,
36220
36903
  fileContent: "",
36221
36904
  validate: false,
36222
- root: relativeFilePath === root.relativeFilePath && relativeDirPath === root.relativeDirPath
36905
+ root: isRoot
36223
36906
  });
36224
36907
  }
36225
36908
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -36284,13 +36967,14 @@ var ZedRule = class ZedRule extends ToolRule {
36284
36967
  };
36285
36968
  }
36286
36969
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
36970
+ const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
36287
36971
  return new ZedRule({
36288
36972
  outputRoot,
36289
36973
  relativeDirPath,
36290
36974
  relativeFilePath,
36291
36975
  fileContent: "",
36292
36976
  validate: false,
36293
- root: relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath
36977
+ root: isRoot
36294
36978
  });
36295
36979
  }
36296
36980
  static isTargetedByRulesyncRule(rulesyncRule) {
@@ -36563,6 +37247,15 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
36563
37247
  additionalConventions: { subagents: { subagentClass: QwencodeSubagent } }
36564
37248
  }
36565
37249
  }],
37250
+ ["reasonix", {
37251
+ class: ReasonixRule,
37252
+ meta: {
37253
+ extension: "md",
37254
+ supportsGlobal: true,
37255
+ ruleDiscoveryMode: "auto",
37256
+ foldsNonRootIntoRoot: true
37257
+ }
37258
+ }],
36566
37259
  ["replit", {
36567
37260
  class: ReplitRule,
36568
37261
  meta: {
@@ -37007,19 +37700,24 @@ As this project's AI coding tool, you must follow the additional conventions bel
37007
37700
  const localRootToolRules = await (async () => {
37008
37701
  if (!forDeletion || this.global || factory.meta.localRootMode !== "separate-local-file" || !factory.meta.localRootFileName) return [];
37009
37702
  const fileName = factory.meta.localRootFileName;
37010
- if (factory.class.getLocalRootDeletionGlob) return buildDeletionRulesFromPaths(await findFilesByGlobs(factory.class.getLocalRootDeletionGlob({
37011
- outputRoot: this.outputRoot,
37012
- fileName
37013
- })));
37703
+ if (factory.class.getLocalRootDeletionGlob) {
37704
+ const filePaths = await findFilesByGlobs(factory.class.getLocalRootDeletionGlob({
37705
+ outputRoot: this.outputRoot,
37706
+ fileName
37707
+ }));
37708
+ return buildDeletionRulesFromPaths(filePaths);
37709
+ }
37014
37710
  if (!settablePaths.root) return [];
37015
- return buildDeletionRulesFromPaths(await findFilesWithFallback((0, node_path.join)(this.outputRoot, settablePaths.root.relativeDirPath ?? ".", fileName), settablePaths.alternativeRoots, (alt) => (0, node_path.join)(this.outputRoot, alt.relativeDirPath, fileName)));
37711
+ const filePaths = await findFilesWithFallback((0, node_path.join)(this.outputRoot, settablePaths.root.relativeDirPath ?? ".", fileName), settablePaths.alternativeRoots, (alt) => (0, node_path.join)(this.outputRoot, alt.relativeDirPath, fileName));
37712
+ return buildDeletionRulesFromPaths(filePaths);
37016
37713
  })();
37017
37714
  this.logger.debug(`Found ${localRootToolRules.length} local root tool rule files for deletion`);
37018
37715
  const rootMirrorDeletionRules = await (async () => {
37019
37716
  if (!forDeletion || this.global || !factory.meta.mirrorsRootToAgentsMd || !factory.class.getRootMirrorDeletionGlobs) return [];
37020
37717
  const { primaryGlob, mirrorGlob } = factory.class.getRootMirrorDeletionGlobs({ outputRoot: this.outputRoot });
37021
37718
  if ((await findFilesByGlobs(primaryGlob)).length === 0) return [];
37022
- return buildDeletionRulesFromPaths(await findFilesByGlobs(mirrorGlob));
37719
+ const mirrorPaths = await findFilesByGlobs(mirrorGlob);
37720
+ return buildDeletionRulesFromPaths(mirrorPaths);
37023
37721
  })();
37024
37722
  const nonRootToolRules = await (async () => {
37025
37723
  if (!settablePaths.nonRoot) return [];
@@ -37448,7 +38146,6 @@ const SHARED_WRITE_FEATURE_ORDER = [
37448
38146
  "permissions",
37449
38147
  "rules"
37450
38148
  ];
37451
- const SHARED_WRITE_FEATURES = new Set(SHARED_WRITE_FEATURE_ORDER);
37452
38149
  const TARGETS_NOT_DERIVED = /* @__PURE__ */ new Set(["augmentcode-legacy", "claudecode-legacy"]);
37453
38150
  const sharedFileKey = (path) => {
37454
38151
  const dir = path.relativeDirPath.replace(/\\/g, "/").replace(/\/$/, "");
@@ -37471,7 +38168,13 @@ const settablePathsForScope = (cls, global) => {
37471
38168
  paths.push(settable.root);
37472
38169
  for (const alt of settable.alternativeRoots ?? []) paths.push(alt);
37473
38170
  }
37474
- for (const path of cls.getExtraSharedWritePaths?.({ global }) ?? []) if (path.relativeFilePath) paths.push(path);
38171
+ let extra;
38172
+ try {
38173
+ extra = cls.getExtraSharedWritePaths?.({ global }) ?? [];
38174
+ } catch {
38175
+ return paths;
38176
+ }
38177
+ for (const path of extra) if (path.relativeFilePath) paths.push(path);
37475
38178
  return paths;
37476
38179
  };
37477
38180
  const collectFactoryPaths = (factory) => [...settablePathsForScope(factory.class, false), ...settablePathsForScope(factory.class, true)];
@@ -37484,7 +38187,6 @@ const deriveSharedFileWriters = () => {
37484
38187
  const byKey = /* @__PURE__ */ new Map();
37485
38188
  const pathByKey = /* @__PURE__ */ new Map();
37486
38189
  for (const entry of PROCESSOR_REGISTRY) {
37487
- if (!SHARED_WRITE_FEATURES.has(entry.feature)) continue;
37488
38190
  const factories = entry.factory;
37489
38191
  for (const [tool, factory] of factories) {
37490
38192
  if (TARGETS_NOT_DERIVED.has(tool)) continue;
@@ -38906,6 +39608,12 @@ Object.defineProperty(exports, "listDirectoryFiles", {
38906
39608
  return listDirectoryFiles;
38907
39609
  }
38908
39610
  });
39611
+ Object.defineProperty(exports, "loadYaml", {
39612
+ enumerable: true,
39613
+ get: function() {
39614
+ return loadYaml;
39615
+ }
39616
+ });
38909
39617
  Object.defineProperty(exports, "readFileContent", {
38910
39618
  enumerable: true,
38911
39619
  get: function() {