rulesync 12.0.0 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ import { parse as parse$1, stringify } from "smol-toml";
12
12
  import matter from "gray-matter";
13
13
  import { YAMLException, dump, load } from "js-yaml";
14
14
  import { omit } from "es-toolkit/object";
15
+ import { createHash } from "node:crypto";
15
16
  import { encode } from "@toon-format/toon";
16
17
  //#region src/types/features.ts
17
18
  const ALL_FEATURES = [
@@ -22,7 +23,8 @@ const ALL_FEATURES = [
22
23
  "commands",
23
24
  "skills",
24
25
  "hooks",
25
- "permissions"
26
+ "permissions",
27
+ "checks"
26
28
  ];
27
29
  const ALL_FEATURES_WITH_WILDCARD = [...ALL_FEATURES, "*"];
28
30
  const FeatureSchema = z.enum(ALL_FEATURES);
@@ -96,6 +98,7 @@ const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
96
98
  const RULESYNC_RULES_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "rules");
97
99
  const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "commands");
98
100
  const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "subagents");
101
+ const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "checks");
99
102
  const RULESYNC_MCP_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
100
103
  const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
101
104
  const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
@@ -361,6 +364,7 @@ const permissionsProcessorToolTargetTuple = [
361
364
  "warp",
362
365
  "zed"
363
366
  ];
367
+ const checksProcessorToolTargetTuple = ["amp"];
364
368
  //#endregion
365
369
  //#region src/types/tool-targets.ts
366
370
  const ALL_TOOL_TARGETS = [...new Set([
@@ -371,7 +375,8 @@ const ALL_TOOL_TARGETS = [...new Set([
371
375
  subagentsProcessorToolTargetTuple,
372
376
  skillsProcessorToolTargetTuple,
373
377
  hooksProcessorToolTargetTuple,
374
- permissionsProcessorToolTargetTuple
378
+ permissionsProcessorToolTargetTuple,
379
+ checksProcessorToolTargetTuple
375
380
  ].flat())];
376
381
  const ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
377
382
  const ToolTargetSchema = z.enum(ALL_TOOL_TARGETS);
@@ -1445,7 +1450,7 @@ function isPlainObject$1(value) {
1445
1450
  /**
1446
1451
  * Type guard to check if a value is an array of strings.
1447
1452
  */
1448
- function isStringArray(value) {
1453
+ function isStringArray$1(value) {
1449
1454
  return Array.isArray(value) && value.every((item) => typeof item === "string");
1450
1455
  }
1451
1456
  //#endregion
@@ -1693,13 +1698,17 @@ var FeatureProcessor = class {
1693
1698
  }
1694
1699
  };
1695
1700
  //#endregion
1696
- //#region src/constants/agentsmd-paths.ts
1697
- const AGENTSMD_DIR = ".agents";
1698
- const AGENTSMD_MEMORIES_DIR_PATH = join(AGENTSMD_DIR, "memories");
1699
- const AGENTSMD_COMMANDS_DIR_PATH = join(AGENTSMD_DIR, "commands");
1700
- const AGENTSMD_SKILLS_DIR_PATH = join(AGENTSMD_DIR, "skills");
1701
- const AGENTSMD_SUBAGENTS_DIR_PATH = join(AGENTSMD_DIR, "subagents");
1702
- const AGENTSMD_RULE_FILE_NAME = "AGENTS.md";
1701
+ //#region src/constants/amp-paths.ts
1702
+ const AMP_DIR = ".amp";
1703
+ const AMP_GLOBAL_DIR = join(".config", "amp");
1704
+ const AMP_AGENTS_DIR = ".agents";
1705
+ const AMP_SKILLS_PROJECT_DIR = join(AMP_AGENTS_DIR, "skills");
1706
+ const AMP_SKILLS_GLOBAL_DIR = join(".config", "agents", "skills");
1707
+ const AMP_CHECKS_PROJECT_DIR = join(AMP_AGENTS_DIR, "checks");
1708
+ const AMP_CHECKS_GLOBAL_DIR = join(AMP_GLOBAL_DIR, "checks");
1709
+ const AMP_RULE_FILE_NAME = "AGENTS.md";
1710
+ const AMP_SETTINGS_FILE_NAME = "settings.json";
1711
+ const AMP_SETTINGS_JSONC_FILE_NAME = "settings.jsonc";
1703
1712
  //#endregion
1704
1713
  //#region src/types/ai-file.ts
1705
1714
  var AiFile = class {
@@ -1773,6 +1782,414 @@ var AiFile = class {
1773
1782
  }
1774
1783
  };
1775
1784
  //#endregion
1785
+ //#region src/types/rulesync-file.ts
1786
+ var RulesyncFile = class extends AiFile {
1787
+ static async fromFile(_params) {
1788
+ throw new Error("Please implement this method in the subclass.");
1789
+ }
1790
+ };
1791
+ //#endregion
1792
+ //#region src/features/checks/rulesync-check.ts
1793
+ const RulesyncCheckFrontmatterSchema = z.looseObject({
1794
+ targets: z._default(RulesyncTargetsSchema, ["*"]),
1795
+ description: z.optional(z.string()),
1796
+ severity: z.optional(z.enum([
1797
+ "low",
1798
+ "medium",
1799
+ "high",
1800
+ "critical"
1801
+ ])),
1802
+ tools: z.optional(z.array(z.string()))
1803
+ });
1804
+ var RulesyncCheck = class RulesyncCheck extends RulesyncFile {
1805
+ frontmatter;
1806
+ body;
1807
+ constructor({ frontmatter, body, ...rest }) {
1808
+ const parseResult = RulesyncCheckFrontmatterSchema.safeParse(frontmatter);
1809
+ if (!parseResult.success && rest.validate !== false) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`);
1810
+ const parsedFrontmatter = parseResult.success ? {
1811
+ ...frontmatter,
1812
+ ...parseResult.data
1813
+ } : {
1814
+ ...frontmatter,
1815
+ targets: frontmatter?.targets ?? ["*"]
1816
+ };
1817
+ super({
1818
+ ...rest,
1819
+ fileContent: stringifyFrontmatter(body, parsedFrontmatter)
1820
+ });
1821
+ this.frontmatter = parsedFrontmatter;
1822
+ this.body = body;
1823
+ }
1824
+ static getSettablePaths() {
1825
+ return { relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH };
1826
+ }
1827
+ getFrontmatter() {
1828
+ return this.frontmatter;
1829
+ }
1830
+ getBody() {
1831
+ return this.body;
1832
+ }
1833
+ validate() {
1834
+ if (!this.frontmatter) return {
1835
+ success: true,
1836
+ error: null
1837
+ };
1838
+ const result = RulesyncCheckFrontmatterSchema.safeParse(this.frontmatter);
1839
+ if (result.success) return {
1840
+ success: true,
1841
+ error: null
1842
+ };
1843
+ else return {
1844
+ success: false,
1845
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
1846
+ };
1847
+ }
1848
+ static async fromFile({ outputRoot = process.cwd(), relativeFilePath }) {
1849
+ const filePath = join(outputRoot, RULESYNC_CHECKS_RELATIVE_DIR_PATH, relativeFilePath);
1850
+ const { frontmatter, body: content, hasFrontmatter } = parseFrontmatter(await readFileContent(filePath), filePath);
1851
+ if (!hasFrontmatter) throw new Error(`Missing frontmatter in ${filePath}. Rulesync files must begin with a YAML frontmatter block delimited by '---'.`);
1852
+ const result = RulesyncCheckFrontmatterSchema.safeParse(frontmatter);
1853
+ if (!result.success) throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
1854
+ const filename = basename(relativeFilePath);
1855
+ return new RulesyncCheck({
1856
+ outputRoot,
1857
+ relativeDirPath: this.getSettablePaths().relativeDirPath,
1858
+ relativeFilePath: filename,
1859
+ frontmatter: result.data,
1860
+ body: content.trim()
1861
+ });
1862
+ }
1863
+ };
1864
+ //#endregion
1865
+ //#region src/types/tool-file.ts
1866
+ var ToolFile = class extends AiFile {};
1867
+ //#endregion
1868
+ //#region src/features/checks/tool-check.ts
1869
+ var ToolCheck = class extends ToolFile {
1870
+ static getSettablePaths(_options = {}) {
1871
+ throw new Error("Please implement this method in the subclass.");
1872
+ }
1873
+ static async fromFile(_params) {
1874
+ throw new Error("Please implement this method in the subclass.");
1875
+ }
1876
+ /**
1877
+ * Create a minimal instance for deletion purposes.
1878
+ * This method does not read or parse file content, making it safe to use
1879
+ * even when files have old/incompatible formats.
1880
+ */
1881
+ static forDeletion(_params) {
1882
+ throw new Error("Please implement this method in the subclass.");
1883
+ }
1884
+ static fromRulesyncCheck(_params) {
1885
+ throw new Error("Please implement this method in the subclass.");
1886
+ }
1887
+ static isTargetedByRulesyncCheck(_rulesyncCheck) {
1888
+ throw new Error("Please implement this method in the subclass.");
1889
+ }
1890
+ static isTargetedByRulesyncCheckDefault({ rulesyncCheck, toolTarget }) {
1891
+ const targets = rulesyncCheck.getFrontmatter().targets;
1892
+ if (!targets) return true;
1893
+ if (targets.includes("*")) return true;
1894
+ if (targets.includes(toolTarget)) return true;
1895
+ return false;
1896
+ }
1897
+ static filterToolSpecificSection(rawSection, excludeFields) {
1898
+ const filtered = {};
1899
+ for (const [key, value] of Object.entries(rawSection)) if (!excludeFields.includes(key)) filtered[key] = value;
1900
+ return filtered;
1901
+ }
1902
+ };
1903
+ //#endregion
1904
+ //#region src/features/checks/amp-check.ts
1905
+ const AmpCheckFrontmatterSchema = z.looseObject({
1906
+ name: z.string(),
1907
+ description: z.optional(z.string()),
1908
+ "severity-default": z.optional(z.enum([
1909
+ "low",
1910
+ "medium",
1911
+ "high",
1912
+ "critical"
1913
+ ])),
1914
+ tools: z.optional(z.array(z.string()))
1915
+ });
1916
+ /**
1917
+ * Represents an Amp code review check.
1918
+ *
1919
+ * Amp natively reads code review checks as Markdown files with YAML frontmatter,
1920
+ * scoped to the project (`.agents/checks/`) and user-wide (`~/.config/amp/checks/`).
1921
+ * Each check runs as a per-check subagent during code review.
1922
+ * @see https://ampcode.com/manual
1923
+ */
1924
+ var AmpCheck = class AmpCheck extends ToolCheck {
1925
+ frontmatter;
1926
+ body;
1927
+ constructor({ frontmatter, body, fileContent, ...rest }) {
1928
+ if (rest.validate !== false) {
1929
+ const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
1930
+ if (!result.success) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
1931
+ }
1932
+ super({
1933
+ ...rest,
1934
+ fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
1935
+ });
1936
+ this.frontmatter = frontmatter;
1937
+ this.body = body;
1938
+ }
1939
+ static getSettablePaths({ global = false } = {}) {
1940
+ return { relativeDirPath: global ? AMP_CHECKS_GLOBAL_DIR : AMP_CHECKS_PROJECT_DIR };
1941
+ }
1942
+ getFrontmatter() {
1943
+ return this.frontmatter;
1944
+ }
1945
+ getBody() {
1946
+ return this.body;
1947
+ }
1948
+ toRulesyncCheck() {
1949
+ const { name: _name, description, "severity-default": severityDefault, tools, ...restFields } = this.frontmatter;
1950
+ return new RulesyncCheck({
1951
+ outputRoot: ".",
1952
+ frontmatter: {
1953
+ targets: ["*"],
1954
+ ...description !== void 0 && { description },
1955
+ ...severityDefault !== void 0 && { severity: severityDefault },
1956
+ ...tools !== void 0 && { tools },
1957
+ ...restFields
1958
+ },
1959
+ body: this.body,
1960
+ relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,
1961
+ relativeFilePath: this.getRelativeFilePath(),
1962
+ validate: true
1963
+ });
1964
+ }
1965
+ static fromRulesyncCheck({ outputRoot = process.cwd(), rulesyncCheck, validate = true, global = false }) {
1966
+ const rulesyncFrontmatter = rulesyncCheck.getFrontmatter();
1967
+ const relativeFilePath = rulesyncCheck.getRelativeFilePath();
1968
+ const name = basename(relativeFilePath, ".md");
1969
+ const { targets: _targets, description, severity, tools, ...restFields } = rulesyncFrontmatter;
1970
+ const toolTargetKeys = new Set(ALL_TOOL_TARGETS);
1971
+ const passthroughFields = Object.fromEntries(Object.entries(restFields).filter(([key]) => !toolTargetKeys.has(key) && key !== "name"));
1972
+ const ampSection = this.filterToolSpecificSection(rulesyncFrontmatter.amp ?? {}, ["name"]);
1973
+ const rawAmpFrontmatter = {
1974
+ name,
1975
+ ...description !== void 0 && { description },
1976
+ ...severity !== void 0 && { "severity-default": severity },
1977
+ ...tools !== void 0 && { tools },
1978
+ ...passthroughFields,
1979
+ ...ampSection
1980
+ };
1981
+ const result = AmpCheckFrontmatterSchema.safeParse(rawAmpFrontmatter);
1982
+ if (!result.success) throw new Error(`Invalid amp check frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
1983
+ const ampFrontmatter = result.data;
1984
+ const body = rulesyncCheck.getBody();
1985
+ const fileContent = stringifyFrontmatter(body, ampFrontmatter);
1986
+ const paths = this.getSettablePaths({ global });
1987
+ return new AmpCheck({
1988
+ outputRoot,
1989
+ frontmatter: ampFrontmatter,
1990
+ body,
1991
+ relativeDirPath: paths.relativeDirPath,
1992
+ relativeFilePath,
1993
+ fileContent,
1994
+ validate
1995
+ });
1996
+ }
1997
+ validate() {
1998
+ if (!this.frontmatter) return {
1999
+ success: true,
2000
+ error: null
2001
+ };
2002
+ const result = AmpCheckFrontmatterSchema.safeParse(this.frontmatter);
2003
+ if (result.success) return {
2004
+ success: true,
2005
+ error: null
2006
+ };
2007
+ else return {
2008
+ success: false,
2009
+ error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
2010
+ };
2011
+ }
2012
+ static isTargetedByRulesyncCheck(rulesyncCheck) {
2013
+ return this.isTargetedByRulesyncCheckDefault({
2014
+ rulesyncCheck,
2015
+ toolTarget: "amp"
2016
+ });
2017
+ }
2018
+ static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
2019
+ const paths = this.getSettablePaths({ global });
2020
+ const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
2021
+ const fileContent = await readFileContent(filePath);
2022
+ const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
2023
+ const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
2024
+ if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
2025
+ return new AmpCheck({
2026
+ outputRoot,
2027
+ relativeDirPath: paths.relativeDirPath,
2028
+ relativeFilePath,
2029
+ frontmatter: result.data,
2030
+ body: content.trim(),
2031
+ fileContent,
2032
+ validate
2033
+ });
2034
+ }
2035
+ static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
2036
+ return new AmpCheck({
2037
+ outputRoot,
2038
+ relativeDirPath,
2039
+ relativeFilePath,
2040
+ frontmatter: { name: "" },
2041
+ body: "",
2042
+ fileContent: "",
2043
+ validate: false
2044
+ });
2045
+ }
2046
+ };
2047
+ //#endregion
2048
+ //#region src/features/checks/checks-processor.ts
2049
+ const ChecksProcessorToolTargetSchema = z.enum(checksProcessorToolTargetTuple);
2050
+ /**
2051
+ * Factory Map mapping tool targets to their check factories.
2052
+ * Using Map to preserve insertion order for consistent iteration.
2053
+ */
2054
+ const toolCheckFactories = /* @__PURE__ */ new Map([["amp", {
2055
+ class: AmpCheck,
2056
+ meta: {
2057
+ supportsGlobal: true,
2058
+ filePattern: "*.md"
2059
+ }
2060
+ }]]);
2061
+ const defaultGetFactory$6 = (target) => {
2062
+ const factory = toolCheckFactories.get(target);
2063
+ if (!factory) throw new Error(`Unsupported tool target: ${target}`);
2064
+ return factory;
2065
+ };
2066
+ const allToolTargetKeys$5 = [...toolCheckFactories.keys()];
2067
+ const checksProcessorToolTargets = allToolTargetKeys$5;
2068
+ const checksProcessorToolTargetsGlobal = allToolTargetKeys$5.filter((target) => {
2069
+ return toolCheckFactories.get(target)?.meta.supportsGlobal ?? false;
2070
+ });
2071
+ var ChecksProcessor = class extends FeatureProcessor {
2072
+ toolTarget;
2073
+ global;
2074
+ getFactory;
2075
+ constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, global = false, getFactory = defaultGetFactory$6, dryRun = false, logger }) {
2076
+ super({
2077
+ outputRoot,
2078
+ inputRoot,
2079
+ dryRun,
2080
+ logger
2081
+ });
2082
+ const result = ChecksProcessorToolTargetSchema.safeParse(toolTarget);
2083
+ if (!result.success) throw new Error(`Invalid tool target for ChecksProcessor: ${toolTarget}. ${formatError(result.error)}`);
2084
+ this.toolTarget = result.data;
2085
+ this.global = global;
2086
+ this.getFactory = getFactory;
2087
+ }
2088
+ async convertRulesyncFilesToToolFiles(rulesyncFiles) {
2089
+ const rulesyncChecks = rulesyncFiles.filter((file) => file instanceof RulesyncCheck);
2090
+ const factory = this.getFactory(this.toolTarget);
2091
+ return rulesyncChecks.filter((rulesyncCheck) => factory.class.isTargetedByRulesyncCheck(rulesyncCheck)).map((rulesyncCheck) => factory.class.fromRulesyncCheck({
2092
+ outputRoot: this.outputRoot,
2093
+ relativeDirPath: RulesyncCheck.getSettablePaths().relativeDirPath,
2094
+ rulesyncCheck,
2095
+ global: this.global
2096
+ }));
2097
+ }
2098
+ async convertToolFilesToRulesyncFiles(toolFiles) {
2099
+ return toolFiles.filter((file) => file instanceof ToolCheck).map((toolCheck) => toolCheck.toRulesyncCheck());
2100
+ }
2101
+ /**
2102
+ * Implementation of abstract method from Processor
2103
+ * Load and parse rulesync check files from .rulesync/checks/ directory
2104
+ */
2105
+ async loadRulesyncFiles() {
2106
+ const checksDir = join(this.inputRoot, RulesyncCheck.getSettablePaths().relativeDirPath);
2107
+ if (!await directoryExists(checksDir)) {
2108
+ this.logger.debug(`Rulesync checks directory not found: ${checksDir}`);
2109
+ return [];
2110
+ }
2111
+ const mdFiles = (await listDirectoryFiles(checksDir)).filter((file) => file.endsWith(".md"));
2112
+ if (mdFiles.length === 0) {
2113
+ this.logger.debug(`No markdown files found in rulesync checks directory: ${checksDir}`);
2114
+ return [];
2115
+ }
2116
+ this.logger.debug(`Found ${mdFiles.length} check files in ${checksDir}`);
2117
+ const rulesyncChecks = [];
2118
+ for (const mdFile of mdFiles) {
2119
+ const filepath = join(checksDir, mdFile);
2120
+ try {
2121
+ const rulesyncCheck = await RulesyncCheck.fromFile({
2122
+ outputRoot: this.inputRoot,
2123
+ relativeFilePath: mdFile,
2124
+ validate: true
2125
+ });
2126
+ rulesyncChecks.push(rulesyncCheck);
2127
+ this.logger.debug(`Successfully loaded check: ${mdFile}`);
2128
+ } catch (error) {
2129
+ this.logger.warn(`Failed to load check file ${filepath}: ${formatError(error)}`);
2130
+ continue;
2131
+ }
2132
+ }
2133
+ this.logger.debug(`Successfully loaded ${rulesyncChecks.length} rulesync checks`);
2134
+ return rulesyncChecks;
2135
+ }
2136
+ /**
2137
+ * Implementation of abstract method from Processor
2138
+ * Load tool-specific check files and parse them into ToolCheck instances
2139
+ */
2140
+ async loadToolFiles({ forDeletion = false } = {}) {
2141
+ const factory = this.getFactory(this.toolTarget);
2142
+ const paths = factory.class.getSettablePaths({ global: this.global });
2143
+ const baseDir = join(this.outputRoot, paths.relativeDirPath);
2144
+ const checkFilePaths = await findFilesByGlobs(join(baseDir, factory.meta.filePattern));
2145
+ const toRelativeFilePath = (path) => relative(baseDir, path);
2146
+ if (forDeletion) return checkFilePaths.map((path) => factory.class.forDeletion({
2147
+ outputRoot: this.outputRoot,
2148
+ relativeDirPath: paths.relativeDirPath,
2149
+ relativeFilePath: toRelativeFilePath(path),
2150
+ global: this.global
2151
+ })).filter((check) => check.isDeletable());
2152
+ const loaded = await Promise.all(checkFilePaths.map((path) => factory.class.fromFile({
2153
+ outputRoot: this.outputRoot,
2154
+ relativeDirPath: paths.relativeDirPath,
2155
+ relativeFilePath: toRelativeFilePath(path),
2156
+ global: this.global
2157
+ })));
2158
+ this.logger.debug(`Successfully loaded ${loaded.length} ${this.toolTarget} checks from ${paths.relativeDirPath}`);
2159
+ return loaded;
2160
+ }
2161
+ /**
2162
+ * Implementation of abstract method from FeatureProcessor
2163
+ * Return the tool targets that this processor supports
2164
+ */
2165
+ static getToolTargets({ global = false } = {}) {
2166
+ if (global) return [...checksProcessorToolTargetsGlobal];
2167
+ return [...checksProcessorToolTargets];
2168
+ }
2169
+ static getToolTargetsSimulated() {
2170
+ return [];
2171
+ }
2172
+ /**
2173
+ * Get the factory for a specific tool target.
2174
+ * This is a static version of the internal getFactory for external use.
2175
+ * @param target - The tool target. Must be a valid ChecksProcessorToolTarget.
2176
+ * @returns The factory for the target, or undefined if not found.
2177
+ */
2178
+ static getFactory(target) {
2179
+ const result = ChecksProcessorToolTargetSchema.safeParse(target);
2180
+ if (!result.success) return;
2181
+ return toolCheckFactories.get(result.data);
2182
+ }
2183
+ };
2184
+ //#endregion
2185
+ //#region src/constants/agentsmd-paths.ts
2186
+ const AGENTSMD_DIR = ".agents";
2187
+ const AGENTSMD_MEMORIES_DIR_PATH = join(AGENTSMD_DIR, "memories");
2188
+ const AGENTSMD_COMMANDS_DIR_PATH = join(AGENTSMD_DIR, "commands");
2189
+ const AGENTSMD_SKILLS_DIR_PATH = join(AGENTSMD_DIR, "skills");
2190
+ const AGENTSMD_SUBAGENTS_DIR_PATH = join(AGENTSMD_DIR, "subagents");
2191
+ const AGENTSMD_RULE_FILE_NAME = "AGENTS.md";
2192
+ //#endregion
1776
2193
  //#region src/features/commands/tool-command.ts
1777
2194
  /**
1778
2195
  * Abstract base class for AI development tool-specific command formats.
@@ -2020,13 +2437,6 @@ const AntigravityCommandFrontmatterSchema = z.looseObject({
2020
2437
  ...AntigravityWorkflowFrontmatterSchema.shape
2021
2438
  });
2022
2439
  //#endregion
2023
- //#region src/types/rulesync-file.ts
2024
- var RulesyncFile = class extends AiFile {
2025
- static async fromFile(_params) {
2026
- throw new Error("Please implement this method in the subclass.");
2027
- }
2028
- };
2029
- //#endregion
2030
2440
  //#region src/features/commands/rulesync-command.ts
2031
2441
  const RulesyncCommandFrontmatterSchema = z.looseObject({
2032
2442
  targets: z._default(RulesyncTargetsSchema, ["*"]),
@@ -3087,135 +3497,118 @@ var CursorCommand = class CursorCommand extends ToolCommand {
3087
3497
  //#endregion
3088
3498
  //#region src/constants/devin-paths.ts
3089
3499
  const DEVIN_DIR = ".devin";
3090
- const CODEIUM_WINDSURF_DIR = join(".codeium", "windsurf");
3091
- const DEVIN_WORKFLOWS_DIR_PATH = join(DEVIN_DIR, "workflows");
3092
3500
  const DEVIN_SKILLS_DIR_PATH = join(DEVIN_DIR, "skills");
3093
3501
  const DEVIN_AGENTS_DIR_PATH = join(DEVIN_DIR, "agents");
3094
3502
  const DEVIN_GLOBAL_CONFIG_DIR_PATH = join(".config", "devin");
3095
3503
  const DEVIN_GLOBAL_AGENTS_DIR_PATH = join(DEVIN_GLOBAL_CONFIG_DIR_PATH, "agents");
3096
3504
  const DEVIN_GLOBAL_SKILLS_DIR_PATH = join(DEVIN_GLOBAL_CONFIG_DIR_PATH, "skills");
3097
- const CODEIUM_WINDSURF_GLOBAL_WORKFLOWS_DIR_PATH = join(CODEIUM_WINDSURF_DIR, "global_workflows");
3098
3505
  const DEVIN_CONFIG_FILE_NAME = "config.json";
3099
3506
  const DEVIN_HOOKS_V1_FILE_NAME = "hooks.v1.json";
3100
3507
  const DEVIN_GLOBAL_AGENTS_FILE_NAME = "AGENTS.md";
3101
3508
  const DEVIN_IGNORE_FILE_NAME = ".devinignore";
3102
3509
  const DEVIN_LEGACY_IGNORE_FILE_NAME = ".codeiumignore";
3103
3510
  //#endregion
3511
+ //#region src/constants/general.ts
3512
+ const SKILL_FILE_NAME$1 = "SKILL.md";
3513
+ //#endregion
3514
+ //#region src/features/commands/command-skill-ownership.ts
3515
+ /**
3516
+ * Slug used for the per-command `<slug>/SKILL.md` directory when a tool's
3517
+ * commands are emitted onto its skills surface (Devin, Hermes Agent).
3518
+ */
3519
+ function commandSlug(relativeFilePath) {
3520
+ return basename(relativeFilePath, ".md").replace(/[^a-zA-Z0-9_-]/g, "-");
3521
+ }
3522
+ /**
3523
+ * Whether a rulesync command exists whose slug matches `dirName`.
3524
+ *
3525
+ * Used by the skills-surface `isDirOwned` hooks of tools whose commands are
3526
+ * emitted as `<slug>/SKILL.md` into the skills tree: a directory matching a
3527
+ * current command slug is owned by the commands feature, so the skills
3528
+ * feature must neither import it as a skill nor delete it as an orphan
3529
+ * skill. Once the command is removed from `.rulesync/commands/`, the
3530
+ * directory stops matching and the skills feature cleans it up as a regular
3531
+ * orphan.
3532
+ */
3533
+ async function rulesyncCommandSlugExists({ inputRoot, dirName }) {
3534
+ return (await findFilesByGlobs(join(inputRoot, RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "**", "*.md"))).some((filePath) => commandSlug(basename(filePath)) === dirName);
3535
+ }
3536
+ //#endregion
3104
3537
  //#region src/features/commands/devin-command.ts
3105
- const DevinCommandFrontmatterSchema = z.looseObject({ description: z.optional(z.string()) });
3538
+ function commandSkillContent$1(rulesyncCommand) {
3539
+ const slug = commandSlug(rulesyncCommand.getRelativeFilePath());
3540
+ const description = rulesyncCommand.getFrontmatter().description ?? `${slug} command`;
3541
+ return stringifyFrontmatter(rulesyncCommand.getBody().trim(), {
3542
+ name: slug,
3543
+ description
3544
+ });
3545
+ }
3106
3546
  /**
3107
- * Represents a Devin (Cascade, now Devin Desktop) workflow command.
3108
- * Devin supports workflows in both project mode under .devin/workflows/
3109
- * (preferred since the Devin Desktop rebrand; .devin/workflows/ is the
3110
- * legacy fallback the tool still reads) and global mode under
3111
- * ~/.codeium/windsurf/global_workflows/ (unchanged by the rebrand).
3547
+ * Represents a Devin slash command, emitted as a Devin Skill.
3548
+ *
3549
+ * Devin's extensibility docs no longer document a standalone
3550
+ * workflows/commands component reusable prompts invoked as slash commands
3551
+ * are Skills (`/name`). Commands are therefore emitted onto the native skills
3552
+ * surface, one `SKILL.md` per command: `.devin/skills/<slug>/SKILL.md`
3553
+ * (project) and `~/.config/devin/skills/<slug>/SKILL.md` (global). The legacy
3554
+ * Windsurf/Cascade-era `.devin/workflows/` and
3555
+ * `~/.codeium/windsurf/global_workflows/` locations are no longer emitted.
3556
+ *
3557
+ * Import and deletion are intentionally no-ops for this target: the skills
3558
+ * feature owns the `.devin/skills/` tree, so importing it as commands would
3559
+ * double-import every skill (mirrors the Hermes Agent commands target).
3560
+ *
3561
+ * @see https://docs.devin.ai/cli/extensibility
3562
+ * @see https://docs.devin.ai/cli/extensibility/skills/overview
3112
3563
  */
3113
3564
  var DevinCommand = class DevinCommand extends ToolCommand {
3114
- frontmatter;
3115
- body;
3116
- constructor({ frontmatter, body, ...rest }) {
3117
- if (rest.validate) {
3118
- const result = DevinCommandFrontmatterSchema.safeParse(frontmatter);
3119
- if (!result.success) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
3120
- }
3121
- super({
3122
- ...rest,
3123
- fileContent: stringifyFrontmatter(body, frontmatter)
3565
+ static isTargetedByRulesyncCommand(rulesyncCommand) {
3566
+ return this.isTargetedByRulesyncCommandDefault({
3567
+ rulesyncCommand,
3568
+ toolTarget: "devin"
3124
3569
  });
3125
- this.frontmatter = frontmatter;
3126
- this.body = body;
3127
3570
  }
3128
3571
  static getSettablePaths({ global = false } = {}) {
3129
- if (global) return { relativeDirPath: CODEIUM_WINDSURF_GLOBAL_WORKFLOWS_DIR_PATH };
3130
- return { relativeDirPath: DEVIN_WORKFLOWS_DIR_PATH };
3572
+ return { relativeDirPath: global ? DEVIN_GLOBAL_SKILLS_DIR_PATH : DEVIN_SKILLS_DIR_PATH };
3131
3573
  }
3132
- getBody() {
3133
- return this.body;
3134
- }
3135
- getFrontmatter() {
3136
- return this.frontmatter;
3137
- }
3138
- toRulesyncCommand() {
3139
- const { description, ...restFields } = this.frontmatter;
3140
- const rulesyncFrontmatter = {
3141
- targets: ["*"],
3142
- description,
3143
- ...Object.keys(restFields).length > 0 && { devin: restFields }
3144
- };
3145
- const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
3146
- return new RulesyncCommand({
3147
- outputRoot: process.cwd(),
3148
- frontmatter: rulesyncFrontmatter,
3149
- body: this.body,
3150
- relativeDirPath: RulesyncCommand.getSettablePaths().relativeDirPath,
3151
- relativeFilePath: this.relativeFilePath,
3152
- fileContent,
3153
- validate: true
3154
- });
3155
- }
3156
- static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
3157
- const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
3158
- const devinFields = rulesyncFrontmatter.devin ?? {};
3159
- const devinFrontmatter = {
3160
- description: rulesyncFrontmatter.description,
3161
- ...devinFields
3162
- };
3163
- const body = rulesyncCommand.getBody();
3164
- const paths = this.getSettablePaths({ global });
3165
- return new DevinCommand({
3166
- outputRoot,
3167
- frontmatter: devinFrontmatter,
3168
- body,
3169
- relativeDirPath: paths.relativeDirPath,
3170
- relativeFilePath: rulesyncCommand.getRelativeFilePath(),
3171
- validate
3574
+ constructor({ slug, ...params }) {
3575
+ super({
3576
+ ...params,
3577
+ ...slug !== void 0 && {
3578
+ relativeDirPath: join(params.relativeDirPath, slug),
3579
+ relativeFilePath: "SKILL.md"
3580
+ }
3172
3581
  });
3173
3582
  }
3174
3583
  validate() {
3175
- if (!this.frontmatter) return {
3176
- success: true,
3177
- error: null
3178
- };
3179
- const result = DevinCommandFrontmatterSchema.safeParse(this.frontmatter);
3180
- if (result.success) return {
3584
+ return {
3181
3585
  success: true,
3182
3586
  error: null
3183
3587
  };
3184
- else return {
3185
- success: false,
3186
- error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
3187
- };
3188
3588
  }
3189
- static isTargetedByRulesyncCommand(rulesyncCommand) {
3190
- return this.isTargetedByRulesyncCommandDefault({
3191
- rulesyncCommand,
3192
- toolTarget: "devin"
3589
+ toRulesyncCommand() {
3590
+ const slug = basename(dirname(this.getRelativePathFromCwd()));
3591
+ const { frontmatter, body } = parseFrontmatter(this.getFileContent(), this.getFilePath());
3592
+ const description = typeof frontmatter.description === "string" ? frontmatter.description : void 0;
3593
+ return new RulesyncCommand({
3594
+ relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH,
3595
+ relativeFilePath: `${slug}.md`,
3596
+ frontmatter: { description },
3597
+ body: body.trimStart()
3193
3598
  });
3194
3599
  }
3195
- static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
3196
- const paths = this.getSettablePaths({ global });
3197
- const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
3198
- const { frontmatter, body: content } = parseFrontmatter(await readFileContent(filePath), filePath);
3199
- const result = DevinCommandFrontmatterSchema.safeParse(frontmatter);
3200
- if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
3600
+ static fromRulesyncCommand({ outputRoot, rulesyncCommand, global = false }) {
3601
+ const paths = DevinCommand.getSettablePaths({ global });
3201
3602
  return new DevinCommand({
3202
3603
  outputRoot,
3203
3604
  relativeDirPath: paths.relativeDirPath,
3204
- relativeFilePath,
3205
- frontmatter: result.data,
3206
- body: content.trim(),
3207
- validate
3605
+ relativeFilePath: SKILL_FILE_NAME$1,
3606
+ slug: commandSlug(rulesyncCommand.getRelativeFilePath()),
3607
+ fileContent: commandSkillContent$1(rulesyncCommand)
3208
3608
  });
3209
3609
  }
3210
- static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
3211
- return new DevinCommand({
3212
- outputRoot,
3213
- relativeDirPath,
3214
- relativeFilePath,
3215
- frontmatter: { description: "" },
3216
- body: "",
3217
- validate: false
3218
- });
3610
+ getFileContent() {
3611
+ return this.fileContent;
3219
3612
  }
3220
3613
  };
3221
3614
  //#endregion
@@ -3543,10 +3936,7 @@ const HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_MANIFEST_PATH = join(HERMESAGENT_RUL
3543
3936
  const HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_INIT_PATH = join(HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_DIR_PATH, "__init__.py");
3544
3937
  //#endregion
3545
3938
  //#region src/features/commands/hermesagent-command.ts
3546
- const SKILL_FILE_NAME$1 = "SKILL.md";
3547
- function commandSlug(relativeFilePath) {
3548
- return basename(relativeFilePath, ".md").replace(/[^a-zA-Z0-9_-]/g, "-");
3549
- }
3939
+ const SKILL_FILE_NAME = "SKILL.md";
3550
3940
  function commandSkillContent(rulesyncCommand) {
3551
3941
  const slug = commandSlug(rulesyncCommand.getRelativeFilePath());
3552
3942
  const description = rulesyncCommand.getFrontmatter().description ?? `${slug} command`;
@@ -3563,7 +3953,7 @@ var HermesagentCommand = class HermesagentCommand extends ToolCommand {
3563
3953
  static getSettablePaths({ slug = "command" } = {}) {
3564
3954
  return {
3565
3955
  relativeDirPath: join(HERMESAGENT_SKILLS_DIR_PATH, slug),
3566
- relativeFilePath: SKILL_FILE_NAME$1
3956
+ relativeFilePath: SKILL_FILE_NAME
3567
3957
  };
3568
3958
  }
3569
3959
  constructor({ slug, ...params }) {
@@ -3594,7 +3984,7 @@ var HermesagentCommand = class HermesagentCommand extends ToolCommand {
3594
3984
  return new HermesagentCommand({
3595
3985
  outputRoot,
3596
3986
  relativeDirPath: "",
3597
- relativeFilePath: SKILL_FILE_NAME$1,
3987
+ relativeFilePath: SKILL_FILE_NAME,
3598
3988
  slug: commandSlug(rulesyncCommand.getRelativeFilePath()),
3599
3989
  fileContent: commandSkillContent(rulesyncCommand)
3600
3990
  });
@@ -4829,6 +5219,7 @@ const PI_AGENT_SKILLS_DIR_PATH = join(PI_AGENT_DIR, "skills");
4829
5219
  const PI_PROMPTS_DIR_PATH = join(".pi", "prompts");
4830
5220
  const PI_SKILLS_DIR_PATH = join(".pi", "skills");
4831
5221
  const PI_RULE_FILE_NAME = "AGENTS.md";
5222
+ const PI_APPEND_SYSTEM_FILE_NAME = "APPEND_SYSTEM.md";
4832
5223
  //#endregion
4833
5224
  //#region src/features/commands/pi-command.ts
4834
5225
  /**
@@ -5363,9 +5754,6 @@ const ROVODEV_AGENTS_SKILLS_DIR_PATH = join(".agents", "skills");
5363
5754
  const ROVODEV_PROMPTS_FILE_NAME = "prompts.yml";
5364
5755
  const ROVODEV_PROMPTS_DIR_PATH = join(ROVODEV_DIR, "prompts");
5365
5756
  //#endregion
5366
- //#region src/types/tool-file.ts
5367
- var ToolFile = class extends AiFile {};
5368
- //#endregion
5369
5757
  //#region src/features/commands/rovodev-command.ts
5370
5758
  /**
5371
5759
  * Rovo Dev CLI "saved prompts": a file-based custom-command surface made of a
@@ -5854,7 +6242,8 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
5854
6242
  supportsProject: false,
5855
6243
  supportsGlobal: true,
5856
6244
  isSimulated: false,
5857
- supportsSubdirectory: true
6245
+ supportsSubdirectory: true,
6246
+ skipToolFileScan: true
5858
6247
  }
5859
6248
  }],
5860
6249
  ["junie", {
@@ -5984,7 +6373,8 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
5984
6373
  supportsProject: true,
5985
6374
  supportsGlobal: true,
5986
6375
  isSimulated: false,
5987
- supportsSubdirectory: false
6376
+ supportsSubdirectory: false,
6377
+ skipToolFileScan: true
5988
6378
  }
5989
6379
  }]
5990
6380
  ]);
@@ -6087,6 +6477,7 @@ var CommandsProcessor = class extends FeatureProcessor {
6087
6477
  */
6088
6478
  async loadToolFiles({ forDeletion = false } = {}) {
6089
6479
  const factory = this.getFactory(this.toolTarget);
6480
+ if (factory.meta.skipToolFileScan) return [];
6090
6481
  const paths = factory.class.getSettablePaths({ global: this.global });
6091
6482
  const outputRootFull = join(this.outputRoot, paths.relativeDirPath);
6092
6483
  const commandFilePaths = await findFilesByGlobs(factory.meta.supportsSubdirectory ? join(outputRootFull, "**", `*.${factory.meta.extension}`) : join(outputRootFull, `*.${factory.meta.extension}`));
@@ -6196,7 +6587,10 @@ const HookDefinitionSchema = z.looseObject({
6196
6587
  type: z.optional(z.enum([
6197
6588
  "command",
6198
6589
  "prompt",
6199
- "http"
6590
+ "http",
6591
+ "agent",
6592
+ "mcp_tool",
6593
+ "function"
6200
6594
  ])),
6201
6595
  url: z.optional(safeString),
6202
6596
  timeout: z.optional(z.number()),
@@ -6209,12 +6603,71 @@ const HookDefinitionSchema = z.looseObject({
6209
6603
  sequential: z.optional(z.boolean()),
6210
6604
  async: z.optional(z.boolean()),
6211
6605
  env: z.optional(z.record(z.string(), safeString)),
6212
- shell: z.optional(safeString),
6606
+ shell: z.optional(z.enum(["bash", "powershell"])),
6213
6607
  statusMessage: z.optional(safeString),
6214
6608
  headers: z.optional(z.record(z.string(), safeString)),
6215
6609
  allowedEnvVars: z.optional(z.array(z.string())),
6216
- once: z.optional(z.boolean())
6610
+ once: z.optional(z.boolean()),
6611
+ server: z.optional(safeString),
6612
+ tool: z.optional(safeString),
6613
+ input: z.optional(z.looseObject({})),
6614
+ model: z.optional(safeString)
6217
6615
  });
6616
+ /**
6617
+ * All canonical hook event names.
6618
+ * Each tool supports a subset of these events.
6619
+ */
6620
+ const HOOK_EVENTS = [
6621
+ "sessionStart",
6622
+ "sessionEnd",
6623
+ "preToolUse",
6624
+ "postToolUse",
6625
+ "preModelInvocation",
6626
+ "postModelInvocation",
6627
+ "beforeSubmitPrompt",
6628
+ "stop",
6629
+ "subagentStop",
6630
+ "preCompact",
6631
+ "postCompact",
6632
+ "contextOffload",
6633
+ "postToolUseFailure",
6634
+ "subagentStart",
6635
+ "beforeShellExecution",
6636
+ "afterShellExecution",
6637
+ "beforeMCPExecution",
6638
+ "afterMCPExecution",
6639
+ "beforeReadFile",
6640
+ "afterFileEdit",
6641
+ "beforeAgentResponse",
6642
+ "afterAgentResponse",
6643
+ "afterAgentThought",
6644
+ "beforeTabFileRead",
6645
+ "afterTabFileEdit",
6646
+ "permissionRequest",
6647
+ "notification",
6648
+ "setup",
6649
+ "afterError",
6650
+ "beforeToolSelection",
6651
+ "worktreeCreate",
6652
+ "worktreeRemove",
6653
+ "workspaceOpen",
6654
+ "messageDisplay",
6655
+ "todoCreated",
6656
+ "todoCompleted",
6657
+ "stopFailure",
6658
+ "instructionsLoaded",
6659
+ "userPromptExpansion",
6660
+ "postToolBatch",
6661
+ "permissionDenied",
6662
+ "taskCreated",
6663
+ "taskCompleted",
6664
+ "teammateIdle",
6665
+ "configChange",
6666
+ "cwdChanged",
6667
+ "fileChanged",
6668
+ "elicitation",
6669
+ "elicitationResult"
6670
+ ];
6218
6671
  /** Hook events supported by Cursor. */
6219
6672
  const CURSOR_HOOK_EVENTS = [
6220
6673
  "sessionStart",
@@ -6689,12 +7142,28 @@ const CANONICAL_TO_HERMESAGENT_EVENT_NAMES = {
6689
7142
  */
6690
7143
  const HERMESAGENT_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_HERMESAGENT_EVENT_NAMES).map(([k, v]) => [v, k]));
6691
7144
  const hooksRecordSchema = z.record(z.string(), z.array(HookDefinitionSchema));
7145
+ const HOOK_EVENT_SET = new Set(HOOK_EVENTS);
7146
+ /** Whether `value` is a canonical hook event name. */
7147
+ const isHookEvent = (value) => HOOK_EVENT_SET.has(value);
7148
+ /**
7149
+ * Top-level `hooks` record whose keys must be canonical event names, so typos
7150
+ * are rejected at parse time. Keys are validated with a refinement (instead of
7151
+ * an enum key schema) to keep the inferred type a plain string record.
7152
+ *
7153
+ * The per-tool override blocks below deliberately keep the lenient
7154
+ * `hooksRecordSchema`: some are documented to pass tool-native event keys
7155
+ * through verbatim (e.g. kiro-ide's IDE-only `PostFileSave`/`PreTaskExec`
7156
+ * triggers), which the canonical enum would reject.
7157
+ */
7158
+ const canonicalHooksRecordSchema = z.record(z.string(), z.array(HookDefinitionSchema)).check(z.refine((record) => Object.keys(record).every((key) => HOOK_EVENT_SET.has(key)), { error: (issue) => {
7159
+ return `unknown hook event name(s): ${Object.keys(issue.input ?? {}).filter((key) => !HOOK_EVENT_SET.has(key)).join(", ")}`;
7160
+ } }));
6692
7161
  /**
6693
7162
  * Canonical hooks config (canonical event names in camelCase).
6694
7163
  */
6695
7164
  const HooksConfigSchema = z.looseObject({
6696
7165
  version: z.optional(z.number()),
6697
- hooks: hooksRecordSchema,
7166
+ hooks: canonicalHooksRecordSchema,
6698
7167
  cursor: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
6699
7168
  claudecode: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
6700
7169
  copilot: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
@@ -7131,6 +7600,20 @@ const CANONICAL_TO_GROKCLI_EVENT_NAMES = {
7131
7600
  */
7132
7601
  const GROKCLI_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_GROKCLI_EVENT_NAMES).map(([k, v]) => [v, k]));
7133
7602
  //#endregion
7603
+ //#region src/utils/object.ts
7604
+ /**
7605
+ * Return a shallow copy of `obj` keeping only the entries whose value is
7606
+ * neither `undefined` nor `null`.
7607
+ *
7608
+ * Used to assemble generated config objects without one conditional spread per
7609
+ * optional field (which would otherwise exceed the lint complexity budget).
7610
+ */
7611
+ function compact(obj) {
7612
+ const result = {};
7613
+ for (const [key, value] of Object.entries(obj)) if (value !== void 0 && value !== null) result[key] = value;
7614
+ return result;
7615
+ }
7616
+ //#endregion
7134
7617
  //#region src/features/hooks/tool-hooks-converter.ts
7135
7618
  function isToolMatcherEntry(x) {
7136
7619
  if (x === null || typeof x !== "object") return false;
@@ -7188,6 +7671,25 @@ function importBooleanPassthroughFields({ h, converterConfig }) {
7188
7671
  return Object.fromEntries((converterConfig.booleanPassthroughFields ?? []).filter(({ tool }) => typeof h[tool] === "boolean").map(({ canonical, tool }) => [canonical, h[tool]]));
7189
7672
  }
7190
7673
  /**
7674
+ * Emit the payload fields specific to a hook type — `url`/`headers`/
7675
+ * `allowedEnvVars` for http, `server`/`tool`/`input` for mcp_tool, `model`
7676
+ * for prompt/agent. https://code.claude.com/docs/en/hooks
7677
+ */
7678
+ function emitTypePayloadFields({ def, hookType, converterConfig }) {
7679
+ if (hookType === "http") return compact({
7680
+ url: def.url,
7681
+ headers: def.headers,
7682
+ allowedEnvVars: def.allowedEnvVars
7683
+ });
7684
+ if (hookType === "mcp_tool") return compact({
7685
+ server: def.server,
7686
+ tool: def.tool,
7687
+ input: def.input
7688
+ });
7689
+ if ((hookType === "prompt" || hookType === "agent") && converterConfig.emitsPromptModel) return compact({ model: def.model });
7690
+ return {};
7691
+ }
7692
+ /**
7191
7693
  * Convert the definitions of a single matcher group into tool hook entries,
7192
7694
  * honoring supported hook types and passthrough fields.
7193
7695
  */
@@ -7209,6 +7711,11 @@ function buildToolHooks({ defs, converterConfig }) {
7209
7711
  ...command !== void 0 && command !== null && { command },
7210
7712
  ...def.timeout !== void 0 && def.timeout !== null && { timeout: def.timeout },
7211
7713
  ...def.prompt !== void 0 && def.prompt !== null && { prompt: def.prompt },
7714
+ ...emitTypePayloadFields({
7715
+ def,
7716
+ hookType,
7717
+ converterConfig
7718
+ }),
7212
7719
  ...converterConfig.passthroughFields?.includes("name") && def.name !== void 0 && def.name !== null && { name: def.name },
7213
7720
  ...converterConfig.passthroughFields?.includes("description") && def.description !== void 0 && def.description !== null && { description: def.description }
7214
7721
  });
@@ -7275,6 +7782,46 @@ function stripCommandPrefix({ command, converterConfig }) {
7275
7782
  return cmd;
7276
7783
  }
7277
7784
  /**
7785
+ * Hook types preserved verbatim on import — Claude Code's five documented
7786
+ * handler types. Anything else is coerced to `command` as before.
7787
+ * https://code.claude.com/docs/en/hooks
7788
+ */
7789
+ const IMPORTED_HOOK_TYPES = /* @__PURE__ */ new Set([
7790
+ "command",
7791
+ "prompt",
7792
+ "http",
7793
+ "mcp_tool",
7794
+ "agent"
7795
+ ]);
7796
+ function isImportedHookType(value) {
7797
+ return typeof value === "string" && IMPORTED_HOOK_TYPES.has(value);
7798
+ }
7799
+ function isStringRecord(value) {
7800
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
7801
+ return Object.values(value).every((v) => typeof v === "string");
7802
+ }
7803
+ function isStringArray(value) {
7804
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
7805
+ }
7806
+ /**
7807
+ * Import the payload fields specific to a hook type, type-checking each raw
7808
+ * value before it enters the canonical definition.
7809
+ */
7810
+ function importTypePayloadFields({ h, hookType }) {
7811
+ if (hookType === "http") return {
7812
+ ...typeof h.url === "string" && { url: h.url },
7813
+ ...isStringRecord(h.headers) && { headers: h.headers },
7814
+ ...isStringArray(h.allowedEnvVars) && { allowedEnvVars: h.allowedEnvVars }
7815
+ };
7816
+ if (hookType === "mcp_tool") return {
7817
+ ...typeof h.server === "string" && { server: h.server },
7818
+ ...typeof h.tool === "string" && { tool: h.tool },
7819
+ ...h.input !== null && typeof h.input === "object" && !Array.isArray(h.input) && { input: h.input }
7820
+ };
7821
+ if (hookType === "prompt" || hookType === "agent") return typeof h.model === "string" ? { model: h.model } : {};
7822
+ return {};
7823
+ }
7824
+ /**
7278
7825
  * Convert a single tool hook record into a canonical hook definition.
7279
7826
  */
7280
7827
  function toolHookToCanonical({ h, rawEntry, converterConfig }) {
@@ -7282,7 +7829,7 @@ function toolHookToCanonical({ h, rawEntry, converterConfig }) {
7282
7829
  command: h.command,
7283
7830
  converterConfig
7284
7831
  });
7285
- const hookType = h.type === "command" || h.type === "prompt" ? h.type : "command";
7832
+ const hookType = isImportedHookType(h.type) ? h.type : "command";
7286
7833
  const timeout = typeof h.timeout === "number" ? h.timeout : void 0;
7287
7834
  const prompt = typeof h.prompt === "string" ? h.prompt : void 0;
7288
7835
  return {
@@ -7290,6 +7837,10 @@ function toolHookToCanonical({ h, rawEntry, converterConfig }) {
7290
7837
  ...command !== void 0 && command !== null && { command },
7291
7838
  ...timeout !== void 0 && timeout !== null && { timeout },
7292
7839
  ...prompt !== void 0 && prompt !== null && { prompt },
7840
+ ...importTypePayloadFields({
7841
+ h,
7842
+ hookType
7843
+ }),
7293
7844
  ...converterConfig.passthroughFields?.includes("name") && typeof h.name === "string" && { name: h.name },
7294
7845
  ...converterConfig.passthroughFields?.includes("description") && typeof h.description === "string" && { description: h.description },
7295
7846
  ...importBooleanPassthroughFields({
@@ -7309,6 +7860,32 @@ function toolMatcherEntryToCanonical({ rawEntry, converterConfig }) {
7309
7860
  converterConfig
7310
7861
  }));
7311
7862
  }
7863
+ /**
7864
+ * Assemble the canonical hooks config a tool importer writes to
7865
+ * `.rulesync/hooks.json`.
7866
+ *
7867
+ * The top-level `hooks` record only accepts canonical event names, so any
7868
+ * imported native event key without a canonical mapping is moved under the
7869
+ * importing tool's own override block (`<overrideKey>.hooks`), whose keys stay
7870
+ * lenient. This mirrors the generate direction — override blocks pass
7871
+ * tool-native keys through verbatim — so documented native triggers (e.g.
7872
+ * kiro-ide's `PostFileSave`) survive an import → generate round-trip instead
7873
+ * of failing canonical validation.
7874
+ */
7875
+ function buildImportedHooksConfig({ hooks, overrideKey, version = 1, extraOverride }) {
7876
+ const canonical = {};
7877
+ const native = {};
7878
+ for (const [event, defs] of Object.entries(hooks)) if (isHookEvent(event)) canonical[event] = defs;
7879
+ else native[event] = defs;
7880
+ const override = { ...extraOverride };
7881
+ if (Object.keys(native).length > 0) override.hooks = native;
7882
+ const config = {
7883
+ version,
7884
+ hooks: canonical
7885
+ };
7886
+ if (Object.keys(override).length > 0) config[overrideKey] = override;
7887
+ return config;
7888
+ }
7312
7889
  function toolHooksToCanonical({ hooks, converterConfig }) {
7313
7890
  if (hooks === null || hooks === void 0 || typeof hooks !== "object") return {};
7314
7891
  const canonical = {};
@@ -7479,7 +8056,8 @@ const ANTIGRAVITY_CONVERTER_CONFIG = {
7479
8056
  "preModelInvocation",
7480
8057
  "postModelInvocation",
7481
8058
  "stop"
7482
- ])
8059
+ ]),
8060
+ supportedHookTypes: /* @__PURE__ */ new Set(["command"])
7483
8061
  };
7484
8062
  /**
7485
8063
  * Antigravity's `hooks.json` is keyed by a named hook whose value holds the
@@ -7586,10 +8164,11 @@ var AntigravityHooks = class extends ToolHooks {
7586
8164
  hooks: flattenAntigravityHooks(parsed),
7587
8165
  converterConfig: ANTIGRAVITY_CONVERTER_CONFIG
7588
8166
  });
7589
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
7590
- version: 1,
7591
- hooks
7592
- }, null, 2) });
8167
+ const overrideKey = this.constructor.getOverrideKey();
8168
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
8169
+ hooks,
8170
+ overrideKey
8171
+ }), null, 2) });
7593
8172
  }
7594
8173
  validate() {
7595
8174
  return {
@@ -7710,7 +8289,8 @@ const AUGMENTCODE_CONVERTER_CONFIG = {
7710
8289
  "sessionEnd",
7711
8290
  "stop",
7712
8291
  "notification"
7713
- ])
8292
+ ]),
8293
+ supportedHookTypes: /* @__PURE__ */ new Set(["command"])
7714
8294
  };
7715
8295
  /**
7716
8296
  * AugmentCode (Auggie CLI) lifecycle hooks.
@@ -7792,10 +8372,10 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
7792
8372
  hooks: settings.hooks,
7793
8373
  converterConfig: AUGMENTCODE_CONVERTER_CONFIG
7794
8374
  });
7795
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
7796
- version: 1,
7797
- hooks
7798
- }, null, 2) });
8375
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
8376
+ hooks,
8377
+ overrideKey: "augmentcode"
8378
+ }), null, 2) });
7799
8379
  }
7800
8380
  validate() {
7801
8381
  return {
@@ -7830,7 +8410,15 @@ const CLAUDE_CONVERTER_CONFIG = {
7830
8410
  "taskCompleted",
7831
8411
  "teammateIdle",
7832
8412
  "cwdChanged"
7833
- ])
8413
+ ]),
8414
+ supportedHookTypes: /* @__PURE__ */ new Set([
8415
+ "command",
8416
+ "prompt",
8417
+ "http",
8418
+ "mcp_tool",
8419
+ "agent"
8420
+ ]),
8421
+ emitsPromptModel: true
7834
8422
  };
7835
8423
  var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
7836
8424
  constructor(params) {
@@ -7895,10 +8483,10 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
7895
8483
  hooks: settings.hooks,
7896
8484
  converterConfig: CLAUDE_CONVERTER_CONFIG
7897
8485
  });
7898
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
7899
- version: 1,
7900
- hooks
7901
- }, null, 2) });
8486
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
8487
+ hooks,
8488
+ overrideKey: "claudecode"
8489
+ }), null, 2) });
7902
8490
  }
7903
8491
  validate() {
7904
8492
  return {
@@ -8041,10 +8629,10 @@ var CodexcliHooks = class CodexcliHooks extends ToolHooks {
8041
8629
  hooks: parsed.hooks,
8042
8630
  converterConfig: CODEXCLI_CONVERTER_CONFIG
8043
8631
  });
8044
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8045
- version: 1,
8046
- hooks
8047
- }, null, 2) });
8632
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
8633
+ hooks,
8634
+ overrideKey: "codexcli"
8635
+ }), null, 2) });
8048
8636
  }
8049
8637
  validate() {
8050
8638
  return {
@@ -8212,10 +8800,10 @@ var CopilotHooks = class CopilotHooks extends ToolHooks {
8212
8800
  throw new Error(`Failed to parse Copilot hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
8213
8801
  }
8214
8802
  const hooks = copilotHooksToCanonical(parsed.hooks, options?.logger);
8215
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8216
- version: 1,
8217
- hooks
8218
- }, null, 2) });
8803
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
8804
+ hooks,
8805
+ overrideKey: "copilot"
8806
+ }), null, 2) });
8219
8807
  }
8220
8808
  validate() {
8221
8809
  return {
@@ -8234,20 +8822,6 @@ var CopilotHooks = class CopilotHooks extends ToolHooks {
8234
8822
  }
8235
8823
  };
8236
8824
  //#endregion
8237
- //#region src/utils/object.ts
8238
- /**
8239
- * Return a shallow copy of `obj` keeping only the entries whose value is
8240
- * neither `undefined` nor `null`.
8241
- *
8242
- * Used to assemble generated config objects without one conditional spread per
8243
- * optional field (which would otherwise exceed the lint complexity budget).
8244
- */
8245
- function compact(obj) {
8246
- const result = {};
8247
- for (const [key, value] of Object.entries(obj)) if (value !== void 0 && value !== null) result[key] = value;
8248
- return result;
8249
- }
8250
- //#endregion
8251
8825
  //#region src/features/hooks/copilotcli-hooks.ts
8252
8826
  /**
8253
8827
  * GitHub Copilot CLI hooks.
@@ -8380,7 +8954,7 @@ function buildCopilotCliEntriesForEvent({ eventName, definitions, canonicalSchem
8380
8954
  ...timeoutPart,
8381
8955
  ...rest
8382
8956
  });
8383
- else entries.push({
8957
+ else if (hookType === "command") entries.push({
8384
8958
  type: "command",
8385
8959
  ...matcherPart,
8386
8960
  ...compact({
@@ -8532,10 +9106,10 @@ var CopilotcliHooks = class CopilotcliHooks extends ToolHooks {
8532
9106
  throw new Error(`Failed to parse Copilot CLI hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
8533
9107
  }
8534
9108
  const hooks = copilotCliHooksToCanonical(parsed.hooks, options?.logger);
8535
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8536
- version: 1,
8537
- hooks
8538
- }, null, 2) });
9109
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9110
+ hooks,
9111
+ overrideKey: "copilotcli"
9112
+ }), null, 2) });
8539
9113
  }
8540
9114
  validate() {
8541
9115
  return {
@@ -8590,9 +9164,10 @@ var CursorHooks = class CursorHooks extends ToolHooks {
8590
9164
  ...config.cursor?.hooks
8591
9165
  };
8592
9166
  const mappedHooks = {};
9167
+ const cursorSupportedTypes = /* @__PURE__ */ new Set(["command", "prompt"]);
8593
9168
  for (const [eventName, defs] of Object.entries(mergedHooks)) {
8594
9169
  const cursorEventName = CANONICAL_TO_CURSOR_EVENT_NAMES[eventName] ?? eventName;
8595
- mappedHooks[cursorEventName] = defs.map((def) => ({
9170
+ const mappedDefs = defs.filter((def) => cursorSupportedTypes.has(def.type ?? "command")).map((def) => ({
8596
9171
  ...def.type !== void 0 && def.type !== null && { type: def.type },
8597
9172
  ...def.command !== void 0 && def.command !== null && { command: def.command },
8598
9173
  ...def.timeout !== void 0 && def.timeout !== null && { timeout: def.timeout },
@@ -8601,6 +9176,7 @@ var CursorHooks = class CursorHooks extends ToolHooks {
8601
9176
  ...def.prompt !== void 0 && def.prompt !== null && { prompt: def.prompt },
8602
9177
  ...def.failClosed !== void 0 && def.failClosed !== null && { failClosed: def.failClosed }
8603
9178
  }));
9179
+ if (mappedDefs.length > 0) mappedHooks[cursorEventName] = mappedDefs;
8604
9180
  }
8605
9181
  const cursorConfig = {
8606
9182
  version: config.version ?? 1,
@@ -8627,10 +9203,11 @@ var CursorHooks = class CursorHooks extends ToolHooks {
8627
9203
  canonicalHooks[eventName] = defs;
8628
9204
  }
8629
9205
  const version = parsed.version ?? 1;
8630
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8631
- version,
8632
- hooks: canonicalHooks
8633
- }, null, 2) });
9206
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9207
+ hooks: canonicalHooks,
9208
+ overrideKey: "cursor",
9209
+ version
9210
+ }), null, 2) });
8634
9211
  }
8635
9212
  validate() {
8636
9213
  return {
@@ -8685,7 +9262,7 @@ function canonicalToDeepagentsHooks(config) {
8685
9262
  const deepagentsEvent = CANONICAL_TO_DEEPAGENTS_EVENT_NAMES[canonicalEvent];
8686
9263
  if (!deepagentsEvent) continue;
8687
9264
  for (const def of definitions) {
8688
- if (def.type === "prompt") continue;
9265
+ if ((def.type ?? "command") !== "command") continue;
8689
9266
  if (!def.command) continue;
8690
9267
  if (def.matcher) continue;
8691
9268
  entries.push({
@@ -8775,10 +9352,10 @@ var DeepagentsHooks = class DeepagentsHooks extends ToolHooks {
8775
9352
  throw new Error(`Failed to parse deepagents hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
8776
9353
  }
8777
9354
  const hooks = deepagentsToCanonicalHooks(isDeepagentsHooksFile(parsed) ? parsed.hooks : []);
8778
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8779
- version: 1,
8780
- hooks
8781
- }, null, 2) });
9355
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9356
+ hooks,
9357
+ overrideKey: "deepagents"
9358
+ }), null, 2) });
8782
9359
  }
8783
9360
  validate() {
8784
9361
  return {
@@ -8907,10 +9484,10 @@ var DevinHooks = class DevinHooks extends ToolHooks {
8907
9484
  hooks: this.getRelativeFilePath() === "config.json" ? isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {} : parsed,
8908
9485
  converterConfig: DEVIN_CONVERTER_CONFIG
8909
9486
  });
8910
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
8911
- version: 1,
8912
- hooks
8913
- }, null, 2) });
9487
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9488
+ hooks,
9489
+ overrideKey: "devin"
9490
+ }), null, 2) });
8914
9491
  }
8915
9492
  validate() {
8916
9493
  return {
@@ -8934,7 +9511,8 @@ const FACTORYDROID_CONVERTER_CONFIG = {
8934
9511
  supportedEvents: FACTORYDROID_HOOK_EVENTS,
8935
9512
  canonicalToToolEventNames: CANONICAL_TO_FACTORYDROID_EVENT_NAMES,
8936
9513
  toolToCanonicalEventNames: FACTORYDROID_TO_CANONICAL_EVENT_NAMES,
8937
- projectDirVar: "$FACTORY_PROJECT_DIR"
9514
+ projectDirVar: "$FACTORY_PROJECT_DIR",
9515
+ supportedHookTypes: /* @__PURE__ */ new Set(["command", "prompt"])
8938
9516
  };
8939
9517
  var FactorydroidHooks = class FactorydroidHooks extends ToolHooks {
8940
9518
  constructor(params) {
@@ -9002,10 +9580,10 @@ var FactorydroidHooks = class FactorydroidHooks extends ToolHooks {
9002
9580
  hooks: settings.hooks,
9003
9581
  converterConfig: FACTORYDROID_CONVERTER_CONFIG
9004
9582
  });
9005
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9006
- version: 1,
9007
- hooks
9008
- }, null, 2) });
9583
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9584
+ hooks,
9585
+ overrideKey: "factorydroid"
9586
+ }), null, 2) });
9009
9587
  }
9010
9588
  validate() {
9011
9589
  return {
@@ -9096,10 +9674,10 @@ var GooseHooks = class GooseHooks extends ToolHooks {
9096
9674
  hooks: parsed.hooks && typeof parsed.hooks === "object" && !Array.isArray(parsed.hooks) ? Object.fromEntries(Object.entries(parsed.hooks).filter(([eventName]) => Object.hasOwn(GOOSE_TO_CANONICAL_EVENT_NAMES, eventName))) : parsed.hooks,
9097
9675
  converterConfig: GOOSE_CONVERTER_CONFIG
9098
9676
  });
9099
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9100
- version: 1,
9101
- hooks
9102
- }, null, 2) });
9677
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9678
+ hooks,
9679
+ overrideKey: "goose"
9680
+ }), null, 2) });
9103
9681
  }
9104
9682
  validate() {
9105
9683
  return {
@@ -9257,10 +9835,10 @@ var GrokcliHooks = class GrokcliHooks extends ToolHooks {
9257
9835
  hooks: isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {},
9258
9836
  converterConfig: GROKCLI_CONVERTER_CONFIG
9259
9837
  });
9260
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9261
- version: 1,
9262
- hooks
9263
- }, null, 2) });
9838
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
9839
+ hooks,
9840
+ overrideKey: "grokcli"
9841
+ }), null, 2) });
9264
9842
  }
9265
9843
  validate() {
9266
9844
  return {
@@ -9421,10 +9999,10 @@ var HermesagentHooks = class HermesagentHooks extends ToolHooks {
9421
9999
  format: "yaml",
9422
10000
  fileContent: this.getFileContent()
9423
10001
  }).hooks);
9424
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9425
- version: 1,
9426
- hooks
9427
- }, null, 2) });
10002
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
10003
+ hooks,
10004
+ overrideKey: "hermesagent"
10005
+ }), null, 2) });
9428
10006
  }
9429
10007
  static fromRulesyncHooks({ outputRoot, rulesyncHooks, logger }) {
9430
10008
  const config = rulesyncHooks.getJson();
@@ -9527,10 +10105,10 @@ var JunieHooks = class JunieHooks extends ToolHooks {
9527
10105
  hooks: settings.hooks,
9528
10106
  converterConfig: JUNIE_CONVERTER_CONFIG
9529
10107
  });
9530
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9531
- version: 1,
9532
- hooks
9533
- }, null, 2) });
10108
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
10109
+ hooks,
10110
+ overrideKey: "junie"
10111
+ }), null, 2) });
9534
10112
  }
9535
10113
  validate() {
9536
10114
  return {
@@ -9575,7 +10153,7 @@ function collectOpencodeStyleHandlers({ effectiveHooks, eventMap, namedEventHand
9575
10153
  if (!toolEvent) continue;
9576
10154
  const handlers = [];
9577
10155
  for (const def of definitions) {
9578
- if (def.type === "prompt") continue;
10156
+ if ((def.type ?? "command") !== "command") continue;
9579
10157
  if (!def.command) continue;
9580
10158
  handlers.push({
9581
10159
  command: def.command,
@@ -9880,10 +10458,11 @@ var KiroHooks = class KiroHooks extends ToolHooks {
9880
10458
  throw new Error(`Failed to parse Kiro hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
9881
10459
  }
9882
10460
  const hooks = kiroHooksToCanonical(agentConfig.hooks);
9883
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
9884
- version: 1,
9885
- hooks
9886
- }, null, 2) });
10461
+ const overrideKey = this.constructor.getOverrideKey();
10462
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
10463
+ hooks,
10464
+ overrideKey
10465
+ }), null, 2) });
9887
10466
  }
9888
10467
  validate() {
9889
10468
  return {
@@ -10092,10 +10671,10 @@ var KiroIdeHooks = class KiroIdeHooks extends ToolHooks {
10092
10671
  throw new Error(`Failed to parse Kiro IDE hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
10093
10672
  }
10094
10673
  const hooks = kiroIdeHooksToCanonical(parsed.hooks ?? []);
10095
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
10096
- version: 1,
10097
- hooks
10098
- }, null, 2) });
10674
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
10675
+ hooks,
10676
+ overrideKey: "kiro-ide"
10677
+ }), null, 2) });
10099
10678
  }
10100
10679
  validate() {
10101
10680
  return {
@@ -10219,11 +10798,18 @@ function canonicalToQwencodeHooks(config) {
10219
10798
  ...sharedHooks,
10220
10799
  ...config.qwencode?.hooks
10221
10800
  };
10801
+ const qwencodeSupportedTypes = /* @__PURE__ */ new Set([
10802
+ "command",
10803
+ "prompt",
10804
+ "http",
10805
+ "function"
10806
+ ]);
10222
10807
  const qwencode = {};
10223
10808
  for (const [eventName, definitions] of Object.entries(effectiveHooks)) {
10224
10809
  const qwencodeEventName = CANONICAL_TO_QWENCODE_EVENT_NAMES[eventName] ?? eventName;
10225
10810
  const byMatcher = /* @__PURE__ */ new Map();
10226
10811
  for (const def of definitions) {
10812
+ if (!qwencodeSupportedTypes.has(def.type ?? "command")) continue;
10227
10813
  const key = def.matcher ?? "";
10228
10814
  const list = byMatcher.get(key);
10229
10815
  if (list) list.push(def);
@@ -10283,9 +10869,10 @@ function qwencodeMatcherEntryToCanonical(entry) {
10283
10869
  const sequential = entry.sequential === true;
10284
10870
  const matcher = entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" ? entry.matcher : void 0;
10285
10871
  for (const h of hooks) {
10286
- const hookType = h.type === "command" || h.type === "prompt" || h.type === "http" ? h.type : "command";
10872
+ const hookType = h.type === "command" || h.type === "prompt" || h.type === "http" || h.type === "function" ? h.type : "command";
10287
10873
  const isHttp = hookType === "http";
10288
10874
  const isCommand = hookType === "command";
10875
+ const shell = h.shell === "bash" || h.shell === "powershell" ? h.shell : void 0;
10289
10876
  defs.push({
10290
10877
  type: hookType,
10291
10878
  ...compact({
@@ -10297,7 +10884,7 @@ function qwencodeMatcherEntryToCanonical(entry) {
10297
10884
  statusMessage: h.statusMessage,
10298
10885
  async: isCommand ? h.async : void 0,
10299
10886
  env: isCommand ? h.env : void 0,
10300
- shell: isCommand ? h.shell : void 0,
10887
+ shell: isCommand ? shell : void 0,
10301
10888
  headers: isHttp ? h.headers : void 0,
10302
10889
  allowedEnvVars: isHttp ? h.allowedEnvVars : void 0,
10303
10890
  once: isHttp ? h.once : void 0,
@@ -10384,15 +10971,11 @@ var QwencodeHooks = class QwencodeHooks extends ToolHooks {
10384
10971
  } catch (error) {
10385
10972
  throw new Error(`Failed to parse Qwen Code hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
10386
10973
  }
10387
- const hooks = qwencodeHooksToCanonical(settings.hooks);
10388
- const canonical = typeof settings.disableAllHooks === "boolean" ? {
10389
- version: 1,
10390
- hooks,
10391
- qwencode: { disableAllHooks: settings.disableAllHooks }
10392
- } : {
10393
- version: 1,
10394
- hooks
10395
- };
10974
+ const canonical = buildImportedHooksConfig({
10975
+ hooks: qwencodeHooksToCanonical(settings.hooks),
10976
+ overrideKey: "qwencode",
10977
+ ...typeof settings.disableAllHooks === "boolean" && { extraOverride: { disableAllHooks: settings.disableAllHooks } }
10978
+ });
10396
10979
  return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(canonical, null, 2) });
10397
10980
  }
10398
10981
  validate() {
@@ -10554,10 +11137,10 @@ var ReasonixHooks = class ReasonixHooks extends ToolHooks {
10554
11137
  throw new Error(`Failed to parse Reasonix hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
10555
11138
  }
10556
11139
  const hooks = reasonixHooksToCanonical(settings.hooks);
10557
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
10558
- version: 1,
10559
- hooks
10560
- }, null, 2) });
11140
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
11141
+ hooks,
11142
+ overrideKey: "reasonix"
11143
+ }), null, 2) });
10561
11144
  }
10562
11145
  validate() {
10563
11146
  return {
@@ -10780,10 +11363,10 @@ var VibeHooks = class VibeHooks extends ToolHooks {
10780
11363
  throw new Error(`Failed to parse Vibe hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
10781
11364
  }
10782
11365
  const hooks = vibeHooksToCanonical(parsed);
10783
- return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
10784
- version: 1,
10785
- hooks
10786
- }, null, 2) });
11366
+ return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
11367
+ hooks,
11368
+ overrideKey: "vibe"
11369
+ }), null, 2) });
10787
11370
  }
10788
11371
  validate() {
10789
11372
  try {
@@ -10870,7 +11453,13 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
10870
11453
  supportsImport: true
10871
11454
  },
10872
11455
  supportedEvents: CLAUDE_HOOK_EVENTS,
10873
- supportedHookTypes: ["command", "prompt"],
11456
+ supportedHookTypes: [
11457
+ "command",
11458
+ "prompt",
11459
+ "http",
11460
+ "mcp_tool",
11461
+ "agent"
11462
+ ],
10874
11463
  supportsMatcher: true
10875
11464
  }],
10876
11465
  ["codexcli", {
@@ -11062,7 +11651,12 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
11062
11651
  supportsImport: true
11063
11652
  },
11064
11653
  supportedEvents: QWENCODE_HOOK_EVENTS,
11065
- supportedHookTypes: ["command"],
11654
+ supportedHookTypes: [
11655
+ "command",
11656
+ "prompt",
11657
+ "http",
11658
+ "function"
11659
+ ],
11066
11660
  supportsMatcher: true
11067
11661
  }],
11068
11662
  ["reasonix", {
@@ -12364,16 +12958,6 @@ var IgnoreProcessor = class extends FeatureProcessor {
12364
12958
  }
12365
12959
  };
12366
12960
  //#endregion
12367
- //#region src/constants/amp-paths.ts
12368
- const AMP_DIR = ".amp";
12369
- const AMP_GLOBAL_DIR = join(".config", "amp");
12370
- const AMP_AGENTS_DIR = ".agents";
12371
- const AMP_SKILLS_PROJECT_DIR = join(AMP_AGENTS_DIR, "skills");
12372
- const AMP_SKILLS_GLOBAL_DIR = join(".config", "agents", "skills");
12373
- const AMP_RULE_FILE_NAME = "AGENTS.md";
12374
- const AMP_SETTINGS_FILE_NAME = "settings.json";
12375
- const AMP_SETTINGS_JSONC_FILE_NAME = "settings.jsonc";
12376
- //#endregion
12377
12961
  //#region src/types/mcp.ts
12378
12962
  const EnvVarNameSchema = z.string().check(refine((value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), "envVars entries must be valid environment variable names"));
12379
12963
  const McpServerSchema = z.looseObject({
@@ -13465,10 +14049,19 @@ function mapOauthFromCodex(oauth) {
13465
14049
  }
13466
14050
  const CODEX_MCP_SERVER_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
13467
14051
  function normalizeCodexMcpServerName(name) {
13468
- if (PROTOTYPE_POLLUTION_KEYS.has(name)) return null;
13469
- if (CODEX_MCP_SERVER_NAME_PATTERN.test(name)) return name;
14052
+ if (!PROTOTYPE_POLLUTION_KEYS.has(name) && CODEX_MCP_SERVER_NAME_PATTERN.test(name)) return {
14053
+ codexName: name,
14054
+ usedFallback: false
14055
+ };
13470
14056
  const normalizedName = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
13471
- return normalizedName && !PROTOTYPE_POLLUTION_KEYS.has(normalizedName) ? normalizedName : null;
14057
+ if (normalizedName && !PROTOTYPE_POLLUTION_KEYS.has(normalizedName)) return {
14058
+ codexName: normalizedName,
14059
+ usedFallback: false
14060
+ };
14061
+ return {
14062
+ codexName: `mcp_${createHash("sha256").update(name).digest("hex").slice(0, 8)}`,
14063
+ usedFallback: true
14064
+ };
13472
14065
  }
13473
14066
  function convertFromCodexFormat(codexMcp) {
13474
14067
  const result = {};
@@ -13482,7 +14075,7 @@ function convertFromCodexFormat(codexMcp) {
13482
14075
  } else if (key === "oauth" && isRecord(value)) converted[key] = mapOauthFromCodex(value);
13483
14076
  else if (Object.hasOwn(CODEX_TO_RULESYNC_FIELD_MAP, key)) {
13484
14077
  const mappedKey = CODEX_TO_RULESYNC_FIELD_MAP[key];
13485
- if (mappedKey) if (isStringArray(value)) converted[mappedKey] = value;
14078
+ if (mappedKey) if (isStringArray$1(value)) converted[mappedKey] = value;
13486
14079
  else warnWithFallback(void 0, `Ignored malformed array for ${key} in MCP server ${name}`);
13487
14080
  } else converted[key] = value;
13488
14081
  }
@@ -13494,12 +14087,9 @@ function convertToCodexFormat(mcpServers) {
13494
14087
  const result = {};
13495
14088
  const originalNames = /* @__PURE__ */ new Map();
13496
14089
  for (const [name, config] of Object.entries(mcpServers)) {
13497
- const codexName = normalizeCodexMcpServerName(name);
13498
- if (codexName === null) {
13499
- warnWithFallback(void 0, `MCP server "${name}" could not be normalized to a valid Codex MCP server name and was skipped.`);
13500
- continue;
13501
- }
13502
14090
  if (!isRecord(config)) continue;
14091
+ const { codexName, usedFallback } = normalizeCodexMcpServerName(name);
14092
+ if (usedFallback) warnWithFallback(void 0, `MCP server "${name}" cannot be represented as a Codex MCP server name (ASCII [a-zA-Z0-9_-] only), so the stable fallback name "${codexName}" was used. Rename the server in .rulesync/mcp.json to choose a readable Codex name.`);
13503
14093
  const converted = {};
13504
14094
  for (const [key, value] of Object.entries(config)) {
13505
14095
  if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
@@ -13508,12 +14098,12 @@ function convertToCodexFormat(mcpServers) {
13508
14098
  } else if (key === "oauth" && isRecord(value)) converted[key] = mapOauthToCodex(value);
13509
14099
  else if (Object.hasOwn(RULESYNC_TO_CODEX_FIELD_MAP, key)) {
13510
14100
  const mappedKey = RULESYNC_TO_CODEX_FIELD_MAP[key];
13511
- if (mappedKey) if (isStringArray(value)) converted[mappedKey] = value;
14101
+ if (mappedKey) if (isStringArray$1(value)) converted[mappedKey] = value;
13512
14102
  else warnWithFallback(void 0, `[CodexCliMcp] Skipping invalid value type for mapped key '${key}': expected string array, got ${typeof value}`);
13513
14103
  } else converted[key] = value;
13514
14104
  }
13515
14105
  const previousName = originalNames.get(codexName);
13516
- if (previousName !== void 0) warnWithFallback(void 0, `Codex MCP server name collision: "${previousName}" and "${name}" both normalize to "${codexName}". Only the last processed server will be used.`);
14106
+ if (previousName !== void 0) warnWithFallback(void 0, `Codex MCP server name collision: "${previousName}" and "${name}" both normalize to "${codexName}"; "${name}" (processed last) overwrites "${previousName}".`);
13517
14107
  originalNames.set(codexName, name);
13518
14108
  result[codexName] = converted;
13519
14109
  }
@@ -13580,7 +14170,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
13580
14170
  const rawServer = isRecord(rawMcpServers) ? rawMcpServers[serverName] : void 0;
13581
14171
  return [serverName, {
13582
14172
  ...serverConfig,
13583
- ...isRecord(rawServer) && isStringArray(rawServer.envVars) ? { envVars: rawServer.envVars } : {}
14173
+ ...isRecord(rawServer) && isStringArray$1(rawServer.envVars) ? { envVars: rawServer.envVars } : {}
13584
14174
  }];
13585
14175
  })));
13586
14176
  const filteredMcpServers = this.removeEmptyEntries(converted);
@@ -14317,11 +14907,11 @@ function applyGooseStdioFields(ext, config) {
14317
14907
  if (Array.isArray(command)) {
14318
14908
  if (typeof command[0] === "string") ext.cmd = command[0];
14319
14909
  const rest = command.slice(1).filter((c) => typeof c === "string");
14320
- const args = isStringArray(config.args) ? config.args : [];
14910
+ const args = isStringArray$1(config.args) ? config.args : [];
14321
14911
  if (rest.length > 0 || args.length > 0) ext.args = [...rest, ...args];
14322
14912
  } else if (typeof command === "string") {
14323
14913
  ext.cmd = command;
14324
- if (isStringArray(config.args)) ext.args = config.args;
14914
+ if (isStringArray$1(config.args)) ext.args = config.args;
14325
14915
  }
14326
14916
  if (isPlainObject$1(config.env)) ext.envs = omitPrototypePollutionKeys(config.env);
14327
14917
  }
@@ -14379,7 +14969,7 @@ function convertFromGooseFormat(extensions) {
14379
14969
  else if (type === "streamable_http") server.type = "http";
14380
14970
  else if (type === "stdio") server.type = "stdio";
14381
14971
  if (typeof ext.cmd === "string") server.command = ext.cmd;
14382
- if (isStringArray(ext.args)) server.args = ext.args;
14972
+ if (isStringArray$1(ext.args)) server.args = ext.args;
14383
14973
  if (isPlainObject$1(ext.envs)) server.env = omitPrototypePollutionKeys(ext.envs);
14384
14974
  if (typeof ext.uri === "string") server.url = ext.uri;
14385
14975
  if (isPlainObject$1(ext.headers)) server.headers = omitPrototypePollutionKeys(ext.headers);
@@ -14399,11 +14989,11 @@ function buildGoosePluginStdioServer(config) {
14399
14989
  if (Array.isArray(command)) {
14400
14990
  if (typeof command[0] === "string") server.command = command[0];
14401
14991
  const rest = command.slice(1).filter((c) => typeof c === "string");
14402
- const args = isStringArray(config.args) ? config.args : [];
14992
+ const args = isStringArray$1(config.args) ? config.args : [];
14403
14993
  if (rest.length > 0 || args.length > 0) server.args = [...rest, ...args];
14404
14994
  } else if (typeof command === "string") {
14405
14995
  server.command = command;
14406
- if (isStringArray(config.args)) server.args = config.args;
14996
+ if (isStringArray$1(config.args)) server.args = config.args;
14407
14997
  }
14408
14998
  if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
14409
14999
  if (typeof config.cwd === "string") server.cwd = config.cwd;
@@ -14716,7 +15306,7 @@ function resolveHermesTimeout(config) {
14716
15306
  */
14717
15307
  function copyHermesAdvancedFields(source, target) {
14718
15308
  if (typeof source.auth === "string") target.auth = source.auth;
14719
- if (typeof source.client_cert === "string" || isStringArray(source.client_cert)) target.client_cert = source.client_cert;
15309
+ if (typeof source.client_cert === "string" || isStringArray$1(source.client_cert)) target.client_cert = source.client_cert;
14720
15310
  if (typeof source.client_key === "string") target.client_key = source.client_key;
14721
15311
  if (typeof source.connect_timeout === "number") target.connect_timeout = source.connect_timeout;
14722
15312
  if (typeof source.supports_parallel_tool_calls === "boolean") target.supports_parallel_tool_calls = source.supports_parallel_tool_calls;
@@ -14735,8 +15325,8 @@ function copyHermesAdvancedFields(source, target) {
14735
15325
  */
14736
15326
  function buildHermesToolsBlock(config) {
14737
15327
  const tools = {};
14738
- if (isStringArray(config.enabledTools)) tools.include = config.enabledTools;
14739
- if (isStringArray(config.disabledTools)) tools.exclude = config.disabledTools;
15328
+ if (isStringArray$1(config.enabledTools)) tools.include = config.enabledTools;
15329
+ if (isStringArray$1(config.disabledTools)) tools.exclude = config.disabledTools;
14740
15330
  if (typeof config.promptsEnabled === "boolean") tools.prompts = config.promptsEnabled;
14741
15331
  if (typeof config.resourcesEnabled === "boolean") tools.resources = config.resourcesEnabled;
14742
15332
  return tools;
@@ -14748,8 +15338,8 @@ function buildHermesToolsBlock(config) {
14748
15338
  * `promptsEnabled`/`resourcesEnabled` top-level toggles.
14749
15339
  */
14750
15340
  function applyHermesToolsBlock(hermesTools, server) {
14751
- if (isStringArray(hermesTools.include)) server.enabledTools = hermesTools.include;
14752
- if (isStringArray(hermesTools.exclude)) server.disabledTools = hermesTools.exclude;
15341
+ if (isStringArray$1(hermesTools.include)) server.enabledTools = hermesTools.include;
15342
+ if (isStringArray$1(hermesTools.exclude)) server.disabledTools = hermesTools.exclude;
14753
15343
  if (typeof hermesTools.prompts === "boolean") server.promptsEnabled = hermesTools.prompts;
14754
15344
  if (typeof hermesTools.resources === "boolean") server.resourcesEnabled = hermesTools.resources;
14755
15345
  }
@@ -14773,11 +15363,11 @@ function convertServerToHermes(config) {
14773
15363
  if (Array.isArray(command)) {
14774
15364
  if (typeof command[0] === "string") out.command = command[0];
14775
15365
  const rest = command.slice(1).filter((c) => typeof c === "string");
14776
- const args = isStringArray(config.args) ? config.args : [];
15366
+ const args = isStringArray$1(config.args) ? config.args : [];
14777
15367
  if (rest.length > 0 || args.length > 0) out.args = [...rest, ...args];
14778
15368
  } else if (typeof command === "string") {
14779
15369
  out.command = command;
14780
- if (isStringArray(config.args)) out.args = config.args;
15370
+ if (isStringArray$1(config.args)) out.args = config.args;
14781
15371
  }
14782
15372
  if (isPlainObject$1(config.env)) out.env = omitPrototypePollutionKeys(config.env);
14783
15373
  } else if (url !== void 0) {
@@ -14825,7 +15415,7 @@ function convertFromHermesFormat(mcpServers) {
14825
15415
  if (PROTOTYPE_POLLUTION_KEYS.has(name) || !isRecord(config)) continue;
14826
15416
  const server = {};
14827
15417
  if (typeof config.command === "string") server.command = config.command;
14828
- if (isStringArray(config.args)) server.args = config.args;
15418
+ if (isStringArray$1(config.args)) server.args = config.args;
14829
15419
  if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
14830
15420
  if (typeof config.url === "string") server.url = config.url;
14831
15421
  if (isPlainObject$1(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
@@ -17150,7 +17740,11 @@ const VibePermissionsOverrideSchema = z.looseObject({ permission: z.optional(z.r
17150
17740
  */
17151
17741
  const CursorPermissionsOverrideSchema = z.looseObject({
17152
17742
  permission: z.optional(ToolScopedPermissionSchema),
17153
- approvalMode: z.optional(z.string()),
17743
+ approvalMode: z.optional(z.enum([
17744
+ "allowlist",
17745
+ "auto-review",
17746
+ "unrestricted"
17747
+ ])),
17154
17748
  sandbox: z.optional(z.looseObject({}))
17155
17749
  });
17156
17750
  /**
@@ -17238,7 +17832,11 @@ const FactorydroidPermissionsOverrideSchema = z.looseObject({
17238
17832
  */
17239
17833
  const WarpPermissionsOverrideSchema = z.looseObject({
17240
17834
  permission: z.optional(ToolScopedPermissionSchema),
17241
- agent_mode_coding_permissions: z.optional(z.string()),
17835
+ agent_mode_coding_permissions: z.optional(z.enum([
17836
+ "always_ask_before_reading",
17837
+ "always_allow_reading",
17838
+ "allow_reading_specific_files"
17839
+ ])),
17242
17840
  agent_mode_coding_file_read_allowlist: z.optional(z.array(z.string())),
17243
17841
  agent_mode_execute_readonly_commands: z.optional(z.boolean())
17244
17842
  });
@@ -17284,7 +17882,11 @@ const JuniePermissionsOverrideSchema = z.looseObject({
17284
17882
  */
17285
17883
  const TaktPermissionsOverrideSchema = z.looseObject({
17286
17884
  permission: z.optional(ToolScopedPermissionSchema),
17287
- step_permission_overrides: z.optional(z.record(z.string(), z.string())),
17885
+ step_permission_overrides: z.optional(z.record(z.string(), z.enum([
17886
+ "readonly",
17887
+ "edit",
17888
+ "full"
17889
+ ]))),
17288
17890
  provider_options: z.optional(z.looseObject({}))
17289
17891
  });
17290
17892
  /**
@@ -17314,9 +17916,15 @@ const AmpPermissionsOverrideSchema = z.looseObject({
17314
17916
  permission: z.optional(ToolScopedPermissionSchema),
17315
17917
  permissions: z.optional(z.array(z.looseObject({
17316
17918
  tool: z.string(),
17317
- action: z.string()
17919
+ action: z.enum([
17920
+ "allow",
17921
+ "ask",
17922
+ "reject",
17923
+ "delegate"
17924
+ ]),
17925
+ context: z.optional(z.enum(["thread", "subagent"]))
17318
17926
  }))),
17319
- mcpPermissions: z.optional(z.array(z.looseObject({}))),
17927
+ mcpPermissions: z.optional(z.array(z.looseObject({ action: z.enum(["allow", "reject"]) }))),
17320
17928
  guardedFiles: z.optional(z.looseObject({ allowlist: z.optional(z.array(z.string())) })),
17321
17929
  dangerouslyAllowAll: z.optional(z.boolean())
17322
17930
  });
@@ -17341,7 +17949,12 @@ const AmpPermissionsOverrideSchema = z.looseObject({
17341
17949
  */
17342
17950
  const AntigravityCliPermissionsOverrideSchema = z.looseObject({
17343
17951
  permission: z.optional(ToolScopedPermissionSchema),
17344
- toolPermission: z.optional(z.string()),
17952
+ toolPermission: z.optional(z.enum([
17953
+ "request-review",
17954
+ "proceed-in-sandbox",
17955
+ "always-proceed",
17956
+ "strict"
17957
+ ])),
17345
17958
  enableTerminalSandbox: z.optional(z.boolean())
17346
17959
  });
17347
17960
  /**
@@ -17370,7 +17983,14 @@ const AugmentcodePermissionsOverrideSchema = z.looseObject({
17370
17983
  permission: z.optional(ToolScopedPermissionSchema),
17371
17984
  toolPermissions: z.optional(z.array(z.looseObject({
17372
17985
  toolName: z.string(),
17373
- permission: z.looseObject({ type: z.string() })
17986
+ eventType: z.optional(z.enum(["tool-call", "tool-response"])),
17987
+ permission: z.looseObject({ type: z.enum([
17988
+ "allow",
17989
+ "deny",
17990
+ "ask-user",
17991
+ "webhook-policy",
17992
+ "script-policy"
17993
+ ]) })
17374
17994
  })))
17375
17995
  });
17376
17996
  /**
@@ -17460,12 +18080,20 @@ const CodexApprovalsReviewerSchema = z.enum([
17460
18080
  * `[permissions.rulesync]` profile may extend. Codex ships three built-in
17461
18081
  * profiles (`:read-only`, `:workspace`, `:danger-full-access`; the leading
17462
18082
  * colon is reserved for built-ins), but `extends` rejects
17463
- * `:danger-full-access` at config load time, so only the two extendable
17464
- * baselines are accepted here. The value list is exported so the Codex CLI
17465
- * translator derives its import-side baseline check from the same source.
18083
+ * `:danger-full-access` at config load time, so only these two are valid
18084
+ * `extends` parents. The value list is exported so the Codex CLI translator
18085
+ * derives its import-side baseline check from the same source.
17466
18086
  * @see https://learn.chatgpt.com/docs/permissions
17467
18087
  */
17468
- const CODEX_BASE_PERMISSION_PROFILES = [":read-only", ":workspace"];
18088
+ const CODEX_EXTENDABLE_BASELINE_PROFILES = [":read-only", ":workspace"];
18089
+ /**
18090
+ * All accepted `codexcli.base_permission_profile` values. `:danger-full-access`
18091
+ * cannot be an `extends` parent, so selecting it makes rulesync emit
18092
+ * `default_permissions = ":danger-full-access"` directly and skip the managed
18093
+ * `[permissions.rulesync]` profile entirely (there is no sandbox for
18094
+ * filesystem/network rules to refine in that mode).
18095
+ */
18096
+ const CODEX_BASE_PERMISSION_PROFILES = [...CODEX_EXTENDABLE_BASELINE_PROFILES, ":danger-full-access"];
17469
18097
  const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
17470
18098
  /**
17471
18099
  * Codex CLI-scoped permission override.
@@ -17476,10 +18104,14 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
17476
18104
  * override whose fields are written verbatim as top-level `.codex/config.toml`
17477
18105
  * keys (the override wins per key; existing sibling keys the user set directly
17478
18106
  * are preserved):
17479
- * - `base_permission_profile` — the built-in profile the managed
17480
- * `[permissions.rulesync]` profile extends (`:read-only` | `:workspace`).
17481
- * Unlike the other keys it is not a top-level config key: it is emitted as
17482
- * the profile's `extends` value. Defaults to `:workspace` when unspecified.
18107
+ * - `base_permission_profile` — the built-in baseline profile (`:read-only` |
18108
+ * `:workspace` | `:danger-full-access`). Unlike the other keys it is not a
18109
+ * top-level config key: the extendable baselines are emitted as the managed
18110
+ * `[permissions.rulesync]` profile's `extends` value, while
18111
+ * `:danger-full-access` (which Codex rejects as an `extends` parent) is
18112
+ * selected directly via `default_permissions` and skips the managed profile
18113
+ * entirely — canonical filesystem/network rules are ignored in that mode.
18114
+ * Defaults to `:workspace` when unspecified.
17483
18115
  * - `approval_policy` — `untrusted` | `on-request` (legacy alias `on-failure`) |
17484
18116
  * `never`, or a `{ granular = { … } }` table (kept verbatim; the granular
17485
18117
  * schema has required fields that are brittle to model as typed keys).
@@ -17500,13 +18132,14 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
17500
18132
  * Defaults to `auto_review` when neither the override nor the existing
17501
18133
  * config sets it.
17502
18134
  * - `git_write_rules` — whether the managed profile's `:workspace_roots` table
17503
- * emits the default `.git` carve-outs (`".git/**" = "write"` with
17504
- * `".git/config" = "read"` kept read-only as a security guard). Codex's
18135
+ * emits the default `.git` carve-out (`".git/**" = "write"`). Codex's
17505
18136
  * `:workspace` baseline makes `.git` read-only, which denies basic git
17506
18137
  * workflows (commit/stage writes to `.git/index`, `.git/objects`, refs,
17507
- * logs), so the carve-outs are emitted by default. Defaults to `true`; only
17508
- * an explicit `false` suppresses them. Like `base_permission_profile` it is
17509
- * consumed by the profile builder, not written as a top-level config key.
18138
+ * logs; everyday commands like `git remote add` or `git push -u` write to
18139
+ * `.git/config`), so the carve-out is emitted by default. Defaults to
18140
+ * `true`; only an explicit `false` suppresses it. Like
18141
+ * `base_permission_profile` it is consumed by the profile builder, not
18142
+ * written as a top-level config key.
17510
18143
  *
17511
18144
  * Two surfaces are deliberately NOT authorable here so the override can never
17512
18145
  * clobber a feature-owned key: `mcp_servers.*` per-MCP gating is owned by the
@@ -19503,15 +20136,13 @@ const RULESYNC_PROFILE_NAME = "rulesync";
19503
20136
  const CODEX_WORKSPACE_ROOTS_KEY = ":workspace_roots";
19504
20137
  const CODEX_WORKSPACE_BASELINE = ":workspace";
19505
20138
  const CODEX_READ_ONLY_BASELINE = ":read-only";
19506
- const CODEX_EXTENDABLE_BASELINES = new Set(CODEX_BASE_PERMISSION_PROFILES);
20139
+ const CODEX_DANGER_FULL_ACCESS_BASELINE = ":danger-full-access";
20140
+ const CODEX_EXTENDABLE_BASELINES = new Set(CODEX_EXTENDABLE_BASELINE_PROFILES);
19507
20141
  const CODEX_DEFAULT_APPROVAL_POLICY = "on-request";
19508
20142
  const CODEX_DEFAULT_APPROVALS_REVIEWER = "auto_review";
19509
20143
  const CODEX_GLOB_SCAN_MAX_DEPTH = 8;
19510
20144
  const CODEX_MINIMAL_KEY = ":minimal";
19511
- const CODEX_GIT_WRITE_RULES = {
19512
- ".git/**": "write",
19513
- ".git/config": "read"
19514
- };
20145
+ const CODEX_GIT_WRITE_RULES = { ".git/**": "write" };
19515
20146
  const GLOBAL_WILDCARD_DOMAIN = "*";
19516
20147
  var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
19517
20148
  static getSettablePaths(_options = {}) {
@@ -19539,8 +20170,40 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
19539
20170
  const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
19540
20171
  const existingContent = await readFileContentOrNull(filePath) ?? "";
19541
20172
  const existing = toMutableTable(smolToml.parse(existingContent || smolToml.stringify({})));
20173
+ const canonicalConfig = rulesyncPermissions.getJson();
20174
+ if (canonicalConfig.codexcli?.base_permission_profile === CODEX_DANGER_FULL_ACCESS_BASELINE) {
20175
+ const ignoredCategories = Object.entries(canonicalConfig.permission).filter(([category, rules]) => category !== "bash" && Object.keys(rules).length > 0).map(([category]) => category);
20176
+ if (ignoredCategories.length > 0) logger?.warn(`Codex CLI baseline ":danger-full-access" removes the sandbox, so canonical ${ignoredCategories.join("/")} rules are not representable and are ignored for Codex CLI.`);
20177
+ const permissionsTable = toMutableTable(existing.permissions);
20178
+ if (permissionsTable[RULESYNC_PROFILE_NAME] !== void 0) {
20179
+ logger?.warn(`Codex CLI baseline ":danger-full-access" prunes the managed "[permissions.${RULESYNC_PROFILE_NAME}]" profile; any hand-written keys inside it (e.g. network settings) are removed. Move them to a sibling profile or re-add them after switching baselines.`);
20180
+ delete permissionsTable[RULESYNC_PROFILE_NAME];
20181
+ }
20182
+ const overridePatch = computeCodexcliOverridePatch({
20183
+ existing,
20184
+ override: canonicalConfig.codexcli,
20185
+ logger
20186
+ });
20187
+ return new CodexcliPermissions({
20188
+ outputRoot,
20189
+ relativeDirPath: paths.relativeDirPath,
20190
+ relativeFilePath: paths.relativeFilePath,
20191
+ fileContent: applySharedConfigPatch({
20192
+ fileKey: sharedConfigFileKey(paths),
20193
+ feature: "permissions",
20194
+ existingContent,
20195
+ patch: {
20196
+ permissions: Object.keys(permissionsTable).length > 0 ? permissionsTable : void 0,
20197
+ default_permissions: CODEX_DANGER_FULL_ACCESS_BASELINE,
20198
+ ...overridePatch
20199
+ },
20200
+ filePath
20201
+ }),
20202
+ validate
20203
+ });
20204
+ }
19542
20205
  const newProfile = convertRulesyncToCodexProfile({
19543
- config: rulesyncPermissions.getJson(),
20206
+ config: canonicalConfig,
19544
20207
  logger
19545
20208
  });
19546
20209
  const permissionsTable = toMutableTable(existing.permissions);
@@ -19601,6 +20264,7 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
19601
20264
  });
19602
20265
  const override = extractCodexcliOverride(table);
19603
20266
  if (typeof profile?.extends === "string" && CODEX_EXTENDABLE_BASELINES.has(profile.extends)) override.base_permission_profile = profile.extends;
20267
+ if (defaultProfile === CODEX_DANGER_FULL_ACCESS_BASELINE) override.base_permission_profile = CODEX_DANGER_FULL_ACCESS_BASELINE;
19604
20268
  const result = Object.keys(override).length > 0 ? {
19605
20269
  ...config,
19606
20270
  codexcli: override
@@ -19656,16 +20320,10 @@ function convertRulesyncToCodexProfile({ config, logger }) {
19656
20320
  const filesystem = { [CODEX_MINIMAL_KEY]: "read" };
19657
20321
  const workspaceRootFilesystem = {};
19658
20322
  const domains = {};
20323
+ const filesystemCategoryRules = {};
19659
20324
  for (const [toolName, rules] of Object.entries(config.permission)) {
19660
20325
  if (toolName === "read" || toolName === "edit" || toolName === "write") {
19661
- const mapAction = toolName === "read" ? mapReadAction : mapWriteAction;
19662
- for (const [pattern, action] of Object.entries(rules)) addFilesystemRule({
19663
- filesystem,
19664
- workspaceRootFilesystem,
19665
- pattern,
19666
- access: mapAction(action),
19667
- logger
19668
- });
20326
+ filesystemCategoryRules[toolName] = rules;
19669
20327
  continue;
19670
20328
  }
19671
20329
  if (toolName === "webfetch") {
@@ -19678,6 +20336,16 @@ function convertRulesyncToCodexProfile({ config, logger }) {
19678
20336
  }
19679
20337
  logger?.warn(`Codex CLI permissions support only read/edit/write/webfetch categories. Skipping: ${toolName}`);
19680
20338
  }
20339
+ for (const [pattern, access] of mergeFilesystemCategoryRules({
20340
+ categoryRules: filesystemCategoryRules,
20341
+ logger
20342
+ })) addFilesystemRule({
20343
+ filesystem,
20344
+ workspaceRootFilesystem,
20345
+ pattern,
20346
+ access,
20347
+ logger
20348
+ });
19681
20349
  applyDefaultGitWriteRules({
19682
20350
  config,
19683
20351
  filesystem,
@@ -19958,6 +20626,67 @@ function mapReadAction(action) {
19958
20626
  function mapWriteAction(action) {
19959
20627
  return action === "allow" ? "write" : "deny";
19960
20628
  }
20629
+ /**
20630
+ * Merge the canonical read/edit/write category rules into one Codex access
20631
+ * level per path pattern (Codex models a single `deny` < `read` < `write`
20632
+ * level, with no `ask`).
20633
+ *
20634
+ * - `edit` and `write` collapse onto Codex's write side; when both carry the
20635
+ * same pattern, the more restrictive action wins (`deny` > `ask` > `allow`).
20636
+ * - `read: allow` + write-side `allow` → `"write"`.
20637
+ * - `read: allow` + write-side non-allow → `"read"` (readable but not
20638
+ * writable — exactly what Codex's `"read"` level expresses).
20639
+ * - `read` non-allow → `"deny"` regardless of the write side; a contradictory
20640
+ * write-side `allow` (unreadable but writable is not expressible in Codex)
20641
+ * is warned about.
20642
+ * - Single-category patterns keep the existing mapReadAction/mapWriteAction
20643
+ * mappings.
20644
+ *
20645
+ * Iteration order is read → edit → write with first-seen pattern order, so
20646
+ * the emitted table is stable regardless of the authored category order.
20647
+ * Note the merge is one-way: `"{path}" = "read"` imports back as
20648
+ * `read: allow` only (the explicit write-side deny is implied by Codex's
20649
+ * access level and not re-materialized).
20650
+ */
20651
+ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
20652
+ const readRules = categoryRules.read ?? {};
20653
+ const writeSideRestrictiveness = {
20654
+ deny: 2,
20655
+ ask: 1,
20656
+ allow: 0
20657
+ };
20658
+ const writeSideRules = {};
20659
+ for (const category of ["edit", "write"]) for (const [pattern, action] of Object.entries(categoryRules[category] ?? {})) {
20660
+ const existing = writeSideRules[pattern];
20661
+ if (existing === void 0 || writeSideRestrictiveness[action] > writeSideRestrictiveness[existing]) writeSideRules[pattern] = action;
20662
+ }
20663
+ const patterns = [];
20664
+ const seen = /* @__PURE__ */ new Set();
20665
+ for (const pattern of [...Object.keys(readRules), ...Object.keys(writeSideRules)]) if (!seen.has(pattern)) {
20666
+ seen.add(pattern);
20667
+ patterns.push(pattern);
20668
+ }
20669
+ const merged = [];
20670
+ for (const pattern of patterns) {
20671
+ const readAction = readRules[pattern];
20672
+ const writeAction = writeSideRules[pattern];
20673
+ if (readAction === void 0) {
20674
+ merged.push([pattern, mapWriteAction(writeAction)]);
20675
+ continue;
20676
+ }
20677
+ if (writeAction === void 0) {
20678
+ merged.push([pattern, mapReadAction(readAction)]);
20679
+ continue;
20680
+ }
20681
+ if (readAction === "allow") {
20682
+ merged.push([pattern, writeAction === "allow" ? "write" : "read"]);
20683
+ continue;
20684
+ }
20685
+ if (writeAction === "allow") logger?.warn(`Codex CLI cannot express "writable but not readable": pattern "${pattern}" has read: ${readAction} and a write-side allow. Emitting "deny".`);
20686
+ merged.push([pattern, "deny"]);
20687
+ }
20688
+ return merged;
20689
+ }
19961
20690
  function buildCodexBashRulesContent(config) {
19962
20691
  const bashRules = config.permission.bash ?? {};
19963
20692
  const entries = Object.entries(bashRules);
@@ -20909,7 +21638,7 @@ function convertRulesyncToGoosePermissionConfig({ config, logger }) {
20909
21638
  function convertGoosePermissionConfigToRulesync(userPermission) {
20910
21639
  const permission = {};
20911
21640
  for (const key of GOOSE_PERMISSION_LIST_KEYS) {
20912
- const toolNames = isStringArray(userPermission[key]) ? userPermission[key] : [];
21641
+ const toolNames = isStringArray$1(userPermission[key]) ? userPermission[key] : [];
20913
21642
  const action = GOOSE_LIST_TO_ACTION[key];
20914
21643
  for (const toolName of toolNames) {
20915
21644
  const category = GOOSE_TO_RULESYNC_TOOL_NAME[toolName] ?? toolName;
@@ -21149,7 +21878,7 @@ const ACTION_RANK = {
21149
21878
  * (mirrors the Cursor adapter's preservation of unmanaged types).
21150
21879
  */
21151
21880
  function unmanagedEntries(existingPermission, key) {
21152
- return (isStringArray(existingPermission[key]) ? existingPermission[key] : []).filter((entry) => parseGrokEntry(entry) === null);
21881
+ return (isStringArray$1(existingPermission[key]) ? existingPermission[key] : []).filter((entry) => parseGrokEntry(entry) === null);
21153
21882
  }
21154
21883
  /**
21155
21884
  * Bucket canonical rules into Grok's `[permission]` allow/deny/ask arrays of
@@ -21190,9 +21919,9 @@ function buildGrokPermissionArrays(config, existingPermission, logger) {
21190
21919
  * arrays resolves to the strictest action.
21191
21920
  */
21192
21921
  function parseGrokPermissionArrays(permission) {
21193
- const allow = isStringArray(permission.allow) ? permission.allow : void 0;
21194
- const deny = isStringArray(permission.deny) ? permission.deny : void 0;
21195
- const ask = isStringArray(permission.ask) ? permission.ask : void 0;
21922
+ const allow = isStringArray$1(permission.allow) ? permission.allow : void 0;
21923
+ const deny = isStringArray$1(permission.deny) ? permission.deny : void 0;
21924
+ const ask = isStringArray$1(permission.ask) ? permission.ask : void 0;
21196
21925
  if ((allow?.length ?? 0) + (deny?.length ?? 0) + (ask?.length ?? 0) === 0) return null;
21197
21926
  const result = {};
21198
21927
  const apply = (entries, action) => {
@@ -22973,7 +23702,7 @@ function convertRovodevToolPermissionsToRulesync(toolPermissions) {
22973
23702
  permission[category][CATCH_ALL_PATTERN$1] = value;
22974
23703
  }
22975
23704
  }
22976
- if (isStringArray(toolPermissions.allowedExternalPaths)) for (const path of toolPermissions.allowedExternalPaths) {
23705
+ if (isStringArray$1(toolPermissions.allowedExternalPaths)) for (const path of toolPermissions.allowedExternalPaths) {
22977
23706
  permission.read ??= {};
22978
23707
  permission.read[path] = "allow";
22979
23708
  }
@@ -23533,8 +24262,8 @@ var WarpPermissions = class WarpPermissions extends ToolPermissions {
23533
24262
  const agents = isRecord(settings.agents) ? settings.agents : {};
23534
24263
  const profiles = isRecord(agents.profiles) ? agents.profiles : {};
23535
24264
  const config = convertWarpToRulesyncPermissions({
23536
- allow: isStringArray(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
23537
- deny: isStringArray(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
24265
+ allow: isStringArray$1(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
24266
+ deny: isStringArray$1(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
23538
24267
  });
23539
24268
  const warpOverride = {};
23540
24269
  for (const key of WARP_OVERRIDE_KEYS) if (profiles[key] !== void 0) warpOverride[key] = profiles[key];
@@ -24114,9 +24843,6 @@ var PermissionsProcessor = class extends FeatureProcessor {
24114
24843
  }
24115
24844
  };
24116
24845
  //#endregion
24117
- //#region src/constants/general.ts
24118
- const SKILL_FILE_NAME = "SKILL.md";
24119
- //#endregion
24120
24846
  //#region src/types/ai-dir.ts
24121
24847
  var AiDir = class {
24122
24848
  /**
@@ -24317,10 +25043,10 @@ var ToolSkill = class extends AiDir {
24317
25043
  const settablePaths = getSettablePaths({ global });
24318
25044
  const actualRelativeDirPath = relativeDirPath ?? settablePaths.relativeDirPath;
24319
25045
  const skillDirPath = join(outputRoot, actualRelativeDirPath, dirName);
24320
- const skillFilePath = join(skillDirPath, SKILL_FILE_NAME);
24321
- if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME} not found in ${skillDirPath}`);
25046
+ const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
25047
+ if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
24322
25048
  const { frontmatter, body: content } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
24323
- const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME);
25049
+ const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME$1);
24324
25050
  return {
24325
25051
  outputRoot,
24326
25052
  relativeDirPath: actualRelativeDirPath,
@@ -24362,7 +25088,7 @@ var SimulatedSkill = class extends ToolSkill {
24362
25088
  relativeDirPath,
24363
25089
  dirName,
24364
25090
  mainFile: {
24365
- name: SKILL_FILE_NAME,
25091
+ name: SKILL_FILE_NAME$1,
24366
25092
  body,
24367
25093
  frontmatter: { ...frontmatter }
24368
25094
  },
@@ -24420,12 +25146,12 @@ var SimulatedSkill = class extends ToolSkill {
24420
25146
  const settablePaths = this.getSettablePaths();
24421
25147
  const actualRelativeDirPath = relativeDirPath ?? settablePaths.relativeDirPath;
24422
25148
  const skillDirPath = join(outputRoot, actualRelativeDirPath, dirName);
24423
- const skillFilePath = join(skillDirPath, SKILL_FILE_NAME);
24424
- if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME} not found in ${skillDirPath}`);
25149
+ const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
25150
+ if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
24425
25151
  const { frontmatter, body: content } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
24426
25152
  const result = SimulatedSkillFrontmatterSchema.safeParse(frontmatter);
24427
25153
  if (!result.success) throw new Error(`Invalid frontmatter in ${skillFilePath}: ${formatError(result.error)}`);
24428
- const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME);
25154
+ const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME$1);
24429
25155
  return {
24430
25156
  outputRoot,
24431
25157
  relativeDirPath: actualRelativeDirPath,
@@ -24635,7 +25361,7 @@ var RulesyncSkill = class RulesyncSkill extends AiDir {
24635
25361
  relativeDirPath,
24636
25362
  dirName,
24637
25363
  mainFile: {
24638
- name: SKILL_FILE_NAME,
25364
+ name: SKILL_FILE_NAME$1,
24639
25365
  body,
24640
25366
  frontmatter: { ...frontmatter }
24641
25367
  },
@@ -24670,13 +25396,13 @@ var RulesyncSkill = class RulesyncSkill extends AiDir {
24670
25396
  }
24671
25397
  static async fromDir({ outputRoot = process.cwd(), relativeDirPath = RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName, global = false }) {
24672
25398
  const skillDirPath = join(outputRoot, relativeDirPath, dirName);
24673
- const skillFilePath = join(skillDirPath, SKILL_FILE_NAME);
24674
- if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME} not found in ${skillDirPath}`);
25399
+ const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
25400
+ if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
24675
25401
  const { frontmatter, body: content, hasFrontmatter } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
24676
25402
  if (!hasFrontmatter) throw new Error(`Missing frontmatter in ${skillFilePath}. Rulesync files must begin with a YAML frontmatter block delimited by '---'.`);
24677
25403
  const result = RulesyncSkillFrontmatterSchema.safeParse(frontmatter);
24678
25404
  if (!result.success) throw new Error(`Invalid frontmatter in ${skillFilePath}: ${formatError(result.error)}`);
24679
- const otherFiles = await this.collectOtherFiles(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME);
25405
+ const otherFiles = await this.collectOtherFiles(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME$1);
24680
25406
  return new RulesyncSkill({
24681
25407
  outputRoot,
24682
25408
  relativeDirPath,
@@ -24716,7 +25442,7 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
24716
25442
  relativeDirPath,
24717
25443
  dirName,
24718
25444
  mainFile: {
24719
- name: SKILL_FILE_NAME,
25445
+ name: SKILL_FILE_NAME$1,
24720
25446
  body,
24721
25447
  frontmatter: { ...frontmatter }
24722
25448
  },
@@ -24743,7 +25469,7 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
24743
25469
  validate() {
24744
25470
  if (!this.mainFile) return {
24745
25471
  success: false,
24746
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
25472
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
24747
25473
  };
24748
25474
  const result = RovodevSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
24749
25475
  if (!result.success) return {
@@ -24819,10 +25545,10 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
24819
25545
  const result = RovodevSkillFrontmatterSchema.safeParse(loaded.frontmatter);
24820
25546
  if (!result.success) {
24821
25547
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
24822
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
25548
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
24823
25549
  }
24824
25550
  if (result.data.name !== loaded.dirName) {
24825
- const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
25551
+ const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
24826
25552
  throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
24827
25553
  }
24828
25554
  return new RovodevSkill({
@@ -24987,7 +25713,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
24987
25713
  relativeDirPath,
24988
25714
  dirName,
24989
25715
  mainFile: {
24990
- name: SKILL_FILE_NAME,
25716
+ name: SKILL_FILE_NAME$1,
24991
25717
  body,
24992
25718
  frontmatter: { ...frontmatter }
24993
25719
  },
@@ -25011,7 +25737,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
25011
25737
  validate() {
25012
25738
  if (!this.mainFile) return {
25013
25739
  success: false,
25014
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
25740
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25015
25741
  };
25016
25742
  const result = AgentsSkillsSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25017
25743
  if (!result.success) return {
@@ -25083,7 +25809,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
25083
25809
  const result = AgentsSkillsSkillFrontmatterSchema.safeParse(loaded.frontmatter);
25084
25810
  if (!result.success) {
25085
25811
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25086
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
25812
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25087
25813
  }
25088
25814
  return new this({
25089
25815
  outputRoot: loaded.outputRoot,
@@ -25140,7 +25866,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
25140
25866
  relativeDirPath,
25141
25867
  dirName,
25142
25868
  mainFile: {
25143
- name: SKILL_FILE_NAME,
25869
+ name: SKILL_FILE_NAME$1,
25144
25870
  body,
25145
25871
  frontmatter: { ...frontmatter }
25146
25872
  },
@@ -25165,7 +25891,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
25165
25891
  validate() {
25166
25892
  if (!this.mainFile) return {
25167
25893
  success: false,
25168
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
25894
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25169
25895
  };
25170
25896
  const result = AiassistantSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25171
25897
  if (!result.success) return {
@@ -25225,7 +25951,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
25225
25951
  const result = AiassistantSkillFrontmatterSchema.safeParse(loaded.frontmatter);
25226
25952
  if (!result.success) {
25227
25953
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25228
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
25954
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25229
25955
  }
25230
25956
  return new AiassistantSkill({
25231
25957
  outputRoot: loaded.outputRoot,
@@ -25276,7 +26002,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
25276
26002
  relativeDirPath,
25277
26003
  dirName,
25278
26004
  mainFile: {
25279
- name: SKILL_FILE_NAME,
26005
+ name: SKILL_FILE_NAME$1,
25280
26006
  body,
25281
26007
  frontmatter: { ...frontmatter }
25282
26008
  },
@@ -25300,7 +26026,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
25300
26026
  validate() {
25301
26027
  if (!this.mainFile) return {
25302
26028
  success: false,
25303
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26029
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25304
26030
  };
25305
26031
  const result = AmpSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25306
26032
  if (!result.success) return {
@@ -25360,7 +26086,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
25360
26086
  const result = AmpSkillFrontmatterSchema.safeParse(loaded.frontmatter);
25361
26087
  if (!result.success) {
25362
26088
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25363
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
26089
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25364
26090
  }
25365
26091
  return new AmpSkill({
25366
26092
  outputRoot: loaded.outputRoot,
@@ -25416,7 +26142,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
25416
26142
  relativeDirPath,
25417
26143
  dirName,
25418
26144
  mainFile: {
25419
- name: SKILL_FILE_NAME,
26145
+ name: SKILL_FILE_NAME$1,
25420
26146
  body,
25421
26147
  frontmatter: { ...frontmatter }
25422
26148
  },
@@ -25449,7 +26175,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
25449
26175
  validate() {
25450
26176
  if (this.mainFile === void 0) return {
25451
26177
  success: false,
25452
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26178
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25453
26179
  };
25454
26180
  const result = AntigravitySkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25455
26181
  if (!result.success) return {
@@ -25509,7 +26235,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
25509
26235
  const result = AntigravitySkillFrontmatterSchema.safeParse(loaded.frontmatter);
25510
26236
  if (!result.success) {
25511
26237
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25512
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
26238
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25513
26239
  }
25514
26240
  return new this({
25515
26241
  outputRoot: loaded.outputRoot,
@@ -25593,7 +26319,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
25593
26319
  relativeDirPath,
25594
26320
  dirName,
25595
26321
  mainFile: {
25596
- name: SKILL_FILE_NAME,
26322
+ name: SKILL_FILE_NAME$1,
25597
26323
  body,
25598
26324
  frontmatter: { ...frontmatter }
25599
26325
  },
@@ -25620,7 +26346,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
25620
26346
  validate() {
25621
26347
  if (this.mainFile === void 0) return {
25622
26348
  success: false,
25623
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26349
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25624
26350
  };
25625
26351
  const result = AugmentcodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25626
26352
  if (!result.success) return {
@@ -25680,7 +26406,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
25680
26406
  const result = AugmentcodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
25681
26407
  if (!result.success) {
25682
26408
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25683
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
26409
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25684
26410
  }
25685
26411
  return new AugmentcodeSkill({
25686
26412
  outputRoot: loaded.outputRoot,
@@ -25821,7 +26547,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
25821
26547
  relativeDirPath,
25822
26548
  dirName,
25823
26549
  mainFile: {
25824
- name: SKILL_FILE_NAME,
26550
+ name: SKILL_FILE_NAME$1,
25825
26551
  body,
25826
26552
  frontmatter: { ...frontmatter }
25827
26553
  },
@@ -25848,7 +26574,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
25848
26574
  validate() {
25849
26575
  if (this.mainFile === void 0) return {
25850
26576
  success: false,
25851
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26577
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
25852
26578
  };
25853
26579
  const result = ClaudecodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
25854
26580
  if (!result.success) return {
@@ -25936,7 +26662,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
25936
26662
  const result = ClaudecodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
25937
26663
  if (!result.success) {
25938
26664
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
25939
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
26665
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
25940
26666
  }
25941
26667
  return new ClaudecodeSkill({
25942
26668
  outputRoot: loaded.outputRoot,
@@ -25982,7 +26708,7 @@ var ClineSkill = class ClineSkill extends ToolSkill {
25982
26708
  relativeDirPath,
25983
26709
  dirName,
25984
26710
  mainFile: {
25985
- name: SKILL_FILE_NAME,
26711
+ name: SKILL_FILE_NAME$1,
25986
26712
  body,
25987
26713
  frontmatter: { ...frontmatter }
25988
26714
  },
@@ -26006,7 +26732,7 @@ var ClineSkill = class ClineSkill extends ToolSkill {
26006
26732
  validate() {
26007
26733
  if (!this.mainFile) return {
26008
26734
  success: false,
26009
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26735
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26010
26736
  };
26011
26737
  const result = ClineSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26012
26738
  if (!result.success) return {
@@ -26070,10 +26796,10 @@ var ClineSkill = class ClineSkill extends ToolSkill {
26070
26796
  const result = ClineSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26071
26797
  if (!result.success) {
26072
26798
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26073
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
26799
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26074
26800
  }
26075
26801
  if (result.data.name !== loaded.dirName) {
26076
- const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
26802
+ const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
26077
26803
  throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
26078
26804
  }
26079
26805
  return new ClineSkill({
@@ -26187,7 +26913,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
26187
26913
  relativeDirPath,
26188
26914
  dirName,
26189
26915
  mainFile: {
26190
- name: SKILL_FILE_NAME,
26916
+ name: SKILL_FILE_NAME$1,
26191
26917
  body,
26192
26918
  frontmatter: { ...frontmatter }
26193
26919
  },
@@ -26211,7 +26937,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
26211
26937
  validate() {
26212
26938
  if (!this.mainFile) return {
26213
26939
  success: false,
26214
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
26940
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26215
26941
  };
26216
26942
  const result = CodexCliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26217
26943
  if (!result.success) return {
@@ -26289,7 +27015,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
26289
27015
  const result = CodexCliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26290
27016
  if (!result.success) {
26291
27017
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26292
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27018
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26293
27019
  }
26294
27020
  return new CodexCliSkill({
26295
27021
  outputRoot: loaded.outputRoot,
@@ -26341,7 +27067,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
26341
27067
  relativeDirPath,
26342
27068
  dirName,
26343
27069
  mainFile: {
26344
- name: SKILL_FILE_NAME,
27070
+ name: SKILL_FILE_NAME$1,
26345
27071
  body,
26346
27072
  frontmatter: { ...frontmatter }
26347
27073
  },
@@ -26366,7 +27092,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
26366
27092
  validate() {
26367
27093
  if (!this.mainFile) return {
26368
27094
  success: false,
26369
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27095
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26370
27096
  };
26371
27097
  const result = CopilotSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26372
27098
  if (!result.success) return {
@@ -26433,7 +27159,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
26433
27159
  const result = CopilotSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26434
27160
  if (!result.success) {
26435
27161
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26436
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27162
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26437
27163
  }
26438
27164
  return new CopilotSkill({
26439
27165
  outputRoot: loaded.outputRoot,
@@ -26487,7 +27213,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
26487
27213
  relativeDirPath,
26488
27214
  dirName,
26489
27215
  mainFile: {
26490
- name: SKILL_FILE_NAME,
27216
+ name: SKILL_FILE_NAME$1,
26491
27217
  body,
26492
27218
  frontmatter: { ...frontmatter }
26493
27219
  },
@@ -26512,7 +27238,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
26512
27238
  validate() {
26513
27239
  if (!this.mainFile) return {
26514
27240
  success: false,
26515
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27241
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26516
27242
  };
26517
27243
  const result = CopilotcliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26518
27244
  if (!result.success) return {
@@ -26581,7 +27307,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
26581
27307
  const result = CopilotcliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26582
27308
  if (!result.success) {
26583
27309
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26584
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27310
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26585
27311
  }
26586
27312
  return new CopilotcliSkill({
26587
27313
  outputRoot: loaded.outputRoot,
@@ -26631,7 +27357,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
26631
27357
  relativeDirPath,
26632
27358
  dirName,
26633
27359
  mainFile: {
26634
- name: SKILL_FILE_NAME,
27360
+ name: SKILL_FILE_NAME$1,
26635
27361
  body,
26636
27362
  frontmatter: { ...frontmatter }
26637
27363
  },
@@ -26655,7 +27381,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
26655
27381
  validate() {
26656
27382
  if (!this.mainFile) return {
26657
27383
  success: false,
26658
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27384
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26659
27385
  };
26660
27386
  const result = CursorSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26661
27387
  if (!result.success) return {
@@ -26729,7 +27455,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
26729
27455
  const result = CursorSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26730
27456
  if (!result.success) {
26731
27457
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26732
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27458
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26733
27459
  }
26734
27460
  return new CursorSkill({
26735
27461
  outputRoot: loaded.outputRoot,
@@ -26776,7 +27502,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
26776
27502
  relativeDirPath,
26777
27503
  dirName,
26778
27504
  mainFile: {
26779
- name: SKILL_FILE_NAME,
27505
+ name: SKILL_FILE_NAME$1,
26780
27506
  body,
26781
27507
  frontmatter: { ...frontmatter }
26782
27508
  },
@@ -26800,7 +27526,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
26800
27526
  validate() {
26801
27527
  if (!this.mainFile) return {
26802
27528
  success: false,
26803
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27529
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26804
27530
  };
26805
27531
  const result = DeepagentsSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26806
27532
  if (!result.success) return {
@@ -26876,7 +27602,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
26876
27602
  const result = DeepagentsSkillFrontmatterSchema.safeParse(loaded.frontmatter);
26877
27603
  if (!result.success) {
26878
27604
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
26879
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27605
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
26880
27606
  }
26881
27607
  return new DeepagentsSkill({
26882
27608
  outputRoot: loaded.outputRoot,
@@ -26927,7 +27653,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
26927
27653
  relativeDirPath,
26928
27654
  dirName,
26929
27655
  mainFile: {
26930
- name: SKILL_FILE_NAME,
27656
+ name: SKILL_FILE_NAME$1,
26931
27657
  body,
26932
27658
  frontmatter: { ...frontmatter }
26933
27659
  },
@@ -26952,7 +27678,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
26952
27678
  validate() {
26953
27679
  if (!this.mainFile) return {
26954
27680
  success: false,
26955
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27681
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
26956
27682
  };
26957
27683
  const result = DevinSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
26958
27684
  if (!result.success) return {
@@ -27004,6 +27730,18 @@ var DevinSkill = class DevinSkill extends ToolSkill {
27004
27730
  const targets = rulesyncSkill.getFrontmatter().targets;
27005
27731
  return targets.includes("*") || targets.includes("devin");
27006
27732
  }
27733
+ /**
27734
+ * Commands are emitted into this same skills tree as `<slug>/SKILL.md`
27735
+ * (see `DevinCommand`), so a directory matching a current rulesync command
27736
+ * slug is owned by the commands feature: it must not be imported as a
27737
+ * skill nor deleted as an orphan skill.
27738
+ */
27739
+ static async isDirOwned({ dirName, inputRoot }) {
27740
+ return !await rulesyncCommandSlugExists({
27741
+ inputRoot,
27742
+ dirName
27743
+ });
27744
+ }
27007
27745
  static async fromDir(params) {
27008
27746
  const loaded = await this.loadSkillDirContent({
27009
27747
  ...params,
@@ -27012,7 +27750,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
27012
27750
  const result = DevinSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27013
27751
  if (!result.success) {
27014
27752
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27015
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27753
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27016
27754
  }
27017
27755
  return new DevinSkill({
27018
27756
  outputRoot: loaded.outputRoot,
@@ -27064,7 +27802,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
27064
27802
  relativeDirPath,
27065
27803
  dirName,
27066
27804
  mainFile: {
27067
- name: SKILL_FILE_NAME,
27805
+ name: SKILL_FILE_NAME$1,
27068
27806
  body,
27069
27807
  frontmatter: { ...frontmatter }
27070
27808
  },
@@ -27088,7 +27826,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
27088
27826
  validate() {
27089
27827
  if (this.mainFile === void 0) return {
27090
27828
  success: false,
27091
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27829
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27092
27830
  };
27093
27831
  const result = FactorydroidSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27094
27832
  if (!result.success) return {
@@ -27163,7 +27901,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
27163
27901
  const result = FactorydroidSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27164
27902
  if (!result.success) {
27165
27903
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27166
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
27904
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27167
27905
  }
27168
27906
  return new FactorydroidSkill({
27169
27907
  outputRoot: loaded.outputRoot,
@@ -27210,7 +27948,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
27210
27948
  relativeDirPath,
27211
27949
  dirName,
27212
27950
  mainFile: {
27213
- name: SKILL_FILE_NAME,
27951
+ name: SKILL_FILE_NAME$1,
27214
27952
  body,
27215
27953
  frontmatter: { ...frontmatter }
27216
27954
  },
@@ -27235,7 +27973,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
27235
27973
  validate() {
27236
27974
  if (!this.mainFile) return {
27237
27975
  success: false,
27238
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
27976
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27239
27977
  };
27240
27978
  const result = GooseSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27241
27979
  if (!result.success) return {
@@ -27295,7 +28033,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
27295
28033
  const result = GooseSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27296
28034
  if (!result.success) {
27297
28035
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27298
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28036
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27299
28037
  }
27300
28038
  return new GooseSkill({
27301
28039
  outputRoot: loaded.outputRoot,
@@ -27348,7 +28086,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
27348
28086
  relativeDirPath,
27349
28087
  dirName,
27350
28088
  mainFile: {
27351
- name: SKILL_FILE_NAME,
28089
+ name: SKILL_FILE_NAME$1,
27352
28090
  body,
27353
28091
  frontmatter: { ...frontmatter }
27354
28092
  },
@@ -27372,7 +28110,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
27372
28110
  validate() {
27373
28111
  if (this.mainFile === void 0) return {
27374
28112
  success: false,
27375
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28113
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27376
28114
  };
27377
28115
  const result = GrokcliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27378
28116
  if (!result.success) return {
@@ -27432,7 +28170,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
27432
28170
  const result = GrokcliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27433
28171
  if (!result.success) {
27434
28172
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27435
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28173
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27436
28174
  }
27437
28175
  return new GrokcliSkill({
27438
28176
  outputRoot: loaded.outputRoot,
@@ -27467,6 +28205,18 @@ var HermesagentSkill = class extends AgentsSkillsSkill {
27467
28205
  static getSettablePaths() {
27468
28206
  return { relativeDirPath: HERMESAGENT_SKILLS_DIR_PATH };
27469
28207
  }
28208
+ /**
28209
+ * Commands are emitted into this same skills tree as `<slug>/SKILL.md`
28210
+ * (see `HermesagentCommand`), so a directory matching a current rulesync
28211
+ * command slug is owned by the commands feature: it must not be imported
28212
+ * as a skill nor deleted as an orphan skill.
28213
+ */
28214
+ static async isDirOwned({ dirName, inputRoot }) {
28215
+ return !await rulesyncCommandSlugExists({
28216
+ inputRoot,
28217
+ dirName
28218
+ });
28219
+ }
27470
28220
  constructor(params) {
27471
28221
  super({
27472
28222
  ...params,
@@ -27491,7 +28241,7 @@ var JunieSkill = class JunieSkill extends ToolSkill {
27491
28241
  relativeDirPath,
27492
28242
  dirName,
27493
28243
  mainFile: {
27494
- name: SKILL_FILE_NAME,
28244
+ name: SKILL_FILE_NAME$1,
27495
28245
  body,
27496
28246
  frontmatter: { ...frontmatter }
27497
28247
  },
@@ -27515,7 +28265,7 @@ var JunieSkill = class JunieSkill extends ToolSkill {
27515
28265
  validate() {
27516
28266
  if (!this.mainFile) return {
27517
28267
  success: false,
27518
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28268
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27519
28269
  };
27520
28270
  const result = JunieSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27521
28271
  if (!result.success) return {
@@ -27579,10 +28329,10 @@ var JunieSkill = class JunieSkill extends ToolSkill {
27579
28329
  const result = JunieSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27580
28330
  if (!result.success) {
27581
28331
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27582
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28332
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27583
28333
  }
27584
28334
  if (result.data.name !== loaded.dirName) {
27585
- const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
28335
+ const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
27586
28336
  throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
27587
28337
  }
27588
28338
  return new JunieSkill({
@@ -27630,7 +28380,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
27630
28380
  relativeDirPath,
27631
28381
  dirName,
27632
28382
  mainFile: {
27633
- name: SKILL_FILE_NAME,
28383
+ name: SKILL_FILE_NAME$1,
27634
28384
  body,
27635
28385
  frontmatter: { ...frontmatter }
27636
28386
  },
@@ -27654,7 +28404,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
27654
28404
  validate() {
27655
28405
  if (this.mainFile === void 0) return {
27656
28406
  success: false,
27657
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28407
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27658
28408
  };
27659
28409
  const result = KiloSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27660
28410
  if (!result.success) return {
@@ -27726,7 +28476,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
27726
28476
  const result = KiloSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27727
28477
  if (!result.success) {
27728
28478
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27729
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28479
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27730
28480
  }
27731
28481
  return new KiloSkill({
27732
28482
  outputRoot: loaded.outputRoot,
@@ -27772,7 +28522,7 @@ var KiroSkill = class KiroSkill extends ToolSkill {
27772
28522
  relativeDirPath,
27773
28523
  dirName,
27774
28524
  mainFile: {
27775
- name: SKILL_FILE_NAME,
28525
+ name: SKILL_FILE_NAME$1,
27776
28526
  body,
27777
28527
  frontmatter: { ...frontmatter }
27778
28528
  },
@@ -27796,7 +28546,7 @@ var KiroSkill = class KiroSkill extends ToolSkill {
27796
28546
  validate() {
27797
28547
  if (!this.mainFile) return {
27798
28548
  success: false,
27799
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28549
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27800
28550
  };
27801
28551
  const result = KiroSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27802
28552
  if (!result.success) return {
@@ -27860,10 +28610,10 @@ var KiroSkill = class KiroSkill extends ToolSkill {
27860
28610
  const result = KiroSkillFrontmatterSchema.safeParse(loaded.frontmatter);
27861
28611
  if (!result.success) {
27862
28612
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
27863
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28613
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
27864
28614
  }
27865
28615
  if (result.data.name !== loaded.dirName) {
27866
- const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
28616
+ const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
27867
28617
  throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
27868
28618
  }
27869
28619
  return new KiroSkill({
@@ -27946,7 +28696,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
27946
28696
  relativeDirPath,
27947
28697
  dirName,
27948
28698
  mainFile: {
27949
- name: SKILL_FILE_NAME,
28699
+ name: SKILL_FILE_NAME$1,
27950
28700
  body,
27951
28701
  frontmatter: { ...frontmatter }
27952
28702
  },
@@ -27973,7 +28723,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
27973
28723
  validate() {
27974
28724
  if (this.mainFile === void 0) return {
27975
28725
  success: false,
27976
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28726
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
27977
28727
  };
27978
28728
  const result = OpenCodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
27979
28729
  if (!result.success) return {
@@ -28052,7 +28802,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
28052
28802
  const result = OpenCodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28053
28803
  if (!result.success) {
28054
28804
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28055
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28805
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28056
28806
  }
28057
28807
  return new OpenCodeSkill({
28058
28808
  outputRoot: loaded.outputRoot,
@@ -28113,7 +28863,7 @@ var PiSkill = class PiSkill extends ToolSkill {
28113
28863
  relativeDirPath: resolvedDirPath,
28114
28864
  dirName,
28115
28865
  mainFile: {
28116
- name: SKILL_FILE_NAME,
28866
+ name: SKILL_FILE_NAME$1,
28117
28867
  body,
28118
28868
  frontmatter: { ...frontmatter }
28119
28869
  },
@@ -28138,7 +28888,7 @@ var PiSkill = class PiSkill extends ToolSkill {
28138
28888
  validate() {
28139
28889
  if (!this.mainFile) return {
28140
28890
  success: false,
28141
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
28891
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
28142
28892
  };
28143
28893
  const result = PiSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
28144
28894
  if (!result.success) return {
@@ -28213,7 +28963,7 @@ var PiSkill = class PiSkill extends ToolSkill {
28213
28963
  const result = PiSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28214
28964
  if (!result.success) {
28215
28965
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28216
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
28966
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28217
28967
  }
28218
28968
  return new PiSkill({
28219
28969
  outputRoot: loaded.outputRoot,
@@ -28266,7 +29016,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
28266
29016
  relativeDirPath,
28267
29017
  dirName,
28268
29018
  mainFile: {
28269
- name: SKILL_FILE_NAME,
29019
+ name: SKILL_FILE_NAME$1,
28270
29020
  body,
28271
29021
  frontmatter: { ...frontmatter }
28272
29022
  },
@@ -28290,7 +29040,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
28290
29040
  validate() {
28291
29041
  if (this.mainFile === void 0) return {
28292
29042
  success: false,
28293
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29043
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
28294
29044
  };
28295
29045
  const result = QwencodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
28296
29046
  if (!result.success) return {
@@ -28370,7 +29120,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
28370
29120
  const result = QwencodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28371
29121
  if (!result.success) {
28372
29122
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28373
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
29123
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28374
29124
  }
28375
29125
  return new QwencodeSkill({
28376
29126
  outputRoot: loaded.outputRoot,
@@ -28420,7 +29170,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
28420
29170
  relativeDirPath,
28421
29171
  dirName,
28422
29172
  mainFile: {
28423
- name: SKILL_FILE_NAME,
29173
+ name: SKILL_FILE_NAME$1,
28424
29174
  body,
28425
29175
  frontmatter: { ...frontmatter }
28426
29176
  },
@@ -28444,7 +29194,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
28444
29194
  validate() {
28445
29195
  if (this.mainFile === void 0) return {
28446
29196
  success: false,
28447
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29197
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
28448
29198
  };
28449
29199
  const result = ReasonixSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
28450
29200
  if (!result.success) return {
@@ -28504,7 +29254,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
28504
29254
  const result = ReasonixSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28505
29255
  if (!result.success) {
28506
29256
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28507
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
29257
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28508
29258
  }
28509
29259
  return new ReasonixSkill({
28510
29260
  outputRoot: loaded.outputRoot,
@@ -28527,7 +29277,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
28527
29277
  * skills-feature ownership, matching the previous behavior for such dirs.
28528
29278
  */
28529
29279
  static async isDirOwned({ outputRoot, relativeDirPath, dirName }) {
28530
- const skillFilePath = join(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME);
29280
+ const skillFilePath = join(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME$1);
28531
29281
  try {
28532
29282
  const { frontmatter } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
28533
29283
  return frontmatter["runAs"] !== REASONIX_SUBAGENT_RUN_AS;
@@ -28577,7 +29327,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
28577
29327
  relativeDirPath,
28578
29328
  dirName,
28579
29329
  mainFile: {
28580
- name: SKILL_FILE_NAME,
29330
+ name: SKILL_FILE_NAME$1,
28581
29331
  body,
28582
29332
  frontmatter: { ...frontmatter }
28583
29333
  },
@@ -28601,7 +29351,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
28601
29351
  validate() {
28602
29352
  if (!this.mainFile) return {
28603
29353
  success: false,
28604
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29354
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
28605
29355
  };
28606
29356
  const result = ReplitSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
28607
29357
  if (!result.success) return {
@@ -28669,7 +29419,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
28669
29419
  const result = ReplitSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28670
29420
  if (!result.success) {
28671
29421
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28672
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
29422
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28673
29423
  }
28674
29424
  return new ReplitSkill({
28675
29425
  outputRoot: loaded.outputRoot,
@@ -28716,7 +29466,7 @@ var RooSkill = class RooSkill extends ToolSkill {
28716
29466
  relativeDirPath,
28717
29467
  dirName,
28718
29468
  mainFile: {
28719
- name: SKILL_FILE_NAME,
29469
+ name: SKILL_FILE_NAME$1,
28720
29470
  body,
28721
29471
  frontmatter: { ...frontmatter }
28722
29472
  },
@@ -28740,7 +29490,7 @@ var RooSkill = class RooSkill extends ToolSkill {
28740
29490
  validate() {
28741
29491
  if (!this.mainFile) return {
28742
29492
  success: false,
28743
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29493
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
28744
29494
  };
28745
29495
  const result = RooSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
28746
29496
  if (!result.success) return {
@@ -28804,10 +29554,10 @@ var RooSkill = class RooSkill extends ToolSkill {
28804
29554
  const result = RooSkillFrontmatterSchema.safeParse(loaded.frontmatter);
28805
29555
  if (!result.success) {
28806
29556
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
28807
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
29557
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
28808
29558
  }
28809
29559
  if (result.data.name !== loaded.dirName) {
28810
- const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
29560
+ const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
28811
29561
  throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
28812
29562
  }
28813
29563
  return new RooSkill({
@@ -29024,7 +29774,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
29024
29774
  relativeDirPath,
29025
29775
  dirName,
29026
29776
  mainFile: {
29027
- name: SKILL_FILE_NAME,
29777
+ name: SKILL_FILE_NAME$1,
29028
29778
  body,
29029
29779
  frontmatter: { ...frontmatter }
29030
29780
  },
@@ -29051,7 +29801,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
29051
29801
  validate() {
29052
29802
  if (!this.mainFile) return {
29053
29803
  success: false,
29054
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29804
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
29055
29805
  };
29056
29806
  const result = VibeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
29057
29807
  if (!result.success) return {
@@ -29115,7 +29865,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
29115
29865
  const result = VibeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
29116
29866
  if (!result.success) {
29117
29867
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
29118
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
29868
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
29119
29869
  }
29120
29870
  return new VibeSkill({
29121
29871
  outputRoot: loaded.outputRoot,
@@ -29171,7 +29921,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
29171
29921
  relativeDirPath,
29172
29922
  dirName,
29173
29923
  mainFile: {
29174
- name: SKILL_FILE_NAME,
29924
+ name: SKILL_FILE_NAME$1,
29175
29925
  body,
29176
29926
  frontmatter: { ...frontmatter }
29177
29927
  },
@@ -29195,7 +29945,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
29195
29945
  validate() {
29196
29946
  if (this.mainFile === void 0) return {
29197
29947
  success: false,
29198
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
29948
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
29199
29949
  };
29200
29950
  const result = WarpSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
29201
29951
  if (!result.success) return {
@@ -29255,7 +30005,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
29255
30005
  const result = WarpSkillFrontmatterSchema.safeParse(loaded.frontmatter);
29256
30006
  if (!result.success) {
29257
30007
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
29258
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
30008
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
29259
30009
  }
29260
30010
  return new WarpSkill({
29261
30011
  outputRoot: loaded.outputRoot,
@@ -29303,7 +30053,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
29303
30053
  relativeDirPath,
29304
30054
  dirName,
29305
30055
  mainFile: {
29306
- name: SKILL_FILE_NAME,
30056
+ name: SKILL_FILE_NAME$1,
29307
30057
  body,
29308
30058
  frontmatter: { ...frontmatter }
29309
30059
  },
@@ -29327,7 +30077,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
29327
30077
  validate() {
29328
30078
  if (!this.mainFile) return {
29329
30079
  success: false,
29330
- error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
30080
+ error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
29331
30081
  };
29332
30082
  const result = ZedSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
29333
30083
  if (!result.success) return {
@@ -29396,7 +30146,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
29396
30146
  const result = ZedSkillFrontmatterSchema.safeParse(loaded.frontmatter);
29397
30147
  if (!result.success) {
29398
30148
  const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
29399
- throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
30149
+ throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
29400
30150
  }
29401
30151
  return new ZedSkill({
29402
30152
  outputRoot: loaded.outputRoot,
@@ -29836,7 +30586,8 @@ var SkillsProcessor = class extends DirFeatureProcessor {
29836
30586
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
29837
30587
  outputRoot: this.outputRoot,
29838
30588
  relativeDirPath: root,
29839
- dirName
30589
+ dirName,
30590
+ inputRoot: this.inputRoot
29840
30591
  })) continue;
29841
30592
  seenDirNames.add(dirName);
29842
30593
  loadEntries.push({
@@ -29867,7 +30618,8 @@ var SkillsProcessor = class extends DirFeatureProcessor {
29867
30618
  if (factory.class.isDirOwned && !await factory.class.isDirOwned({
29868
30619
  outputRoot: this.outputRoot,
29869
30620
  relativeDirPath: root,
29870
- dirName
30621
+ dirName,
30622
+ inputRoot: this.inputRoot
29871
30623
  })) continue;
29872
30624
  const toolSkill = factory.class.forDeletion({
29873
30625
  outputRoot: this.outputRoot,
@@ -33268,7 +34020,7 @@ var ReasonixSubagent = class ReasonixSubagent extends ToolSubagent {
33268
34020
  frontmatter: reasonixFrontmatter,
33269
34021
  body,
33270
34022
  relativeDirPath: paths.relativeDirPath,
33271
- relativeFilePath: join(subagentName, SKILL_FILE_NAME),
34023
+ relativeFilePath: join(subagentName, SKILL_FILE_NAME$1),
33272
34024
  fileContent,
33273
34025
  validate,
33274
34026
  global
@@ -34274,6 +35026,7 @@ const RulesyncRuleFrontmatterSchema = z.object({
34274
35026
  name: z.optional(z.string()),
34275
35027
  description: z.optional(z.string())
34276
35028
  })),
35029
+ pi: z.optional(z.looseObject({ systemPrompt: z.optional(z.enum(["append"])) })),
34277
35030
  takt: z.optional(z.looseObject({
34278
35031
  name: z.optional(z.string()),
34279
35032
  extends: z.optional(z.string()),
@@ -34437,6 +35190,16 @@ var ToolRule = class extends ToolFile {
34437
35190
  isRoot() {
34438
35191
  return this.root;
34439
35192
  }
35193
+ /**
35194
+ * Whether this rule must be left out of the root rule's reference/MCP
35195
+ * instruction listings even though it is a non-root survivor. Used by files
35196
+ * the tool loads through its own mechanism (e.g. Pi's `APPEND_SYSTEM.md`,
35197
+ * which Pi appends to the system prompt itself — referencing it from
35198
+ * `AGENTS.md` would double-load the content).
35199
+ */
35200
+ isExcludedFromRootReferences() {
35201
+ return false;
35202
+ }
34440
35203
  getDescription() {
34441
35204
  return this.description;
34442
35205
  }
@@ -36783,6 +37546,15 @@ var FactorydroidRule = class FactorydroidRule extends ToolRule {
36783
37546
  * is `undefined`). This mirrors the grokcli, warp, and deepagents targets.
36784
37547
  *
36785
37548
  * Goose uses plain markdown files (.goosehints) without frontmatter.
37549
+ *
37550
+ * Global scope emits only `~/.config/goose/.goosehints`. Goose v1.41.0 (PR
37551
+ * block/goose#9736) additionally loads the vendor-neutral
37552
+ * `~/.agents/AGENTS.md` alongside the config-dir hints, but rulesync
37553
+ * deliberately does not emit that shared path from the goose target: the
37554
+ * config-dir hints remain fully loaded (no capability loss), and the
37555
+ * cross-tool `~/.agents/AGENTS.md` is already written by targets that own it
37556
+ * (e.g. cline in global mode) — a second writer would need cross-target
37557
+ * shared-file coordination for zero gain (decision recorded in issue #2207).
36786
37558
  */
36787
37559
  var GooseRule = class GooseRule extends ToolRule {
36788
37560
  static getSettablePaths({ global } = {}) {
@@ -36984,14 +37756,21 @@ var HermesagentRule = class HermesagentRule extends ToolRule {
36984
37756
  /**
36985
37757
  * Rule generator for JetBrains Junie AI coding agent
36986
37758
  *
36987
- * Generates `.junie/AGENTS.md` files based on rulesync rule content. `.junie/AGENTS.md`
36988
- * is the preferred guideline file in current Junie; the legacy `.junie/guidelines.md`
36989
- * is still read by Junie and is accepted as an import fallback, but generation always
36990
- * targets `.junie/AGENTS.md`. Junie uses plain markdown without frontmatter requirements.
36991
- *
36992
- * Global (user) scope writes a single `~/.junie/AGENTS.md` file. Junie merges these
36993
- * user-scope guidelines with the project `.junie/AGENTS.md` (project takes priority on
36994
- * conflicts); memory files (`.junie/memories/`) remain project-scoped only.
37759
+ * Generates `.junie/AGENTS.md` files based on rulesync rule content. Junie CLI
37760
+ * resolves project guidelines **first-match-wins**: `.junie/AGENTS.md` → root
37761
+ * `AGENTS.md` legacy `.junie/guidelines.md` / `.junie/guidelines/`. Only the
37762
+ * first match is loaded, it documents no `@`-reference or file-inclusion
37763
+ * mechanism, and no `.junie/memories/` read path exists — so non-root rules
37764
+ * are folded into the single root `.junie/AGENTS.md` by the RulesProcessor
37765
+ * (`nonRoot` is `undefined`, mirroring the grokcli / warp / deepagents
37766
+ * targets; decision recorded in issue #2211). The legacy
37767
+ * `.junie/guidelines.md` is still accepted as an import fallback, but
37768
+ * generation always targets `.junie/AGENTS.md`. Junie uses plain markdown
37769
+ * without frontmatter requirements.
37770
+ *
37771
+ * Global (user) scope writes a single `~/.junie/AGENTS.md` file. Junie merges
37772
+ * these user-scope guidelines with the project guidelines (both are included
37773
+ * and marked clearly).
36995
37774
  *
36996
37775
  * @see https://junie.jetbrains.com/docs/junie-ide-plugin.html
36997
37776
  * @see https://junie.jetbrains.com/docs/guidelines-and-memory.html
@@ -37010,15 +37789,12 @@ var JunieRule = class JunieRule extends ToolRule {
37010
37789
  alternativeRoots: [{
37011
37790
  relativeDirPath: buildToolPath(JUNIE_DIR, ".", excludeToolDir),
37012
37791
  relativeFilePath: JUNIE_LEGACY_RULE_FILE_NAME
37013
- }],
37014
- nonRoot: { relativeDirPath: buildToolPath(JUNIE_DIR, "memories", excludeToolDir) }
37792
+ }]
37015
37793
  };
37016
37794
  }
37017
37795
  /**
37018
37796
  * Determines whether a given relative file path refers to a root guideline file.
37019
37797
  * The preferred file is `AGENTS.md`; the legacy `guidelines.md` is still accepted.
37020
- * Memory files live under `.junie/memories/` and are passed in as bare filenames
37021
- * (e.g. `memo.md`), so a top-level `AGENTS.md`/`guidelines.md` is the root entry.
37022
37798
  */
37023
37799
  static isRootRelativeFilePath(relativeFilePath) {
37024
37800
  return relativeFilePath === "AGENTS.md" || relativeFilePath === "guidelines.md";
@@ -37037,10 +37813,7 @@ var JunieRule = class JunieRule extends ToolRule {
37037
37813
  root: true
37038
37814
  });
37039
37815
  }
37040
- const isRoot = JunieRule.isRootRelativeFilePath(relativeFilePath);
37041
- const settablePaths = this.getSettablePaths();
37042
- if (!settablePaths.nonRoot) throw new Error("JunieRule project settable paths must include a nonRoot path");
37043
- const relativeDirPath = isRoot ? settablePaths.root.relativeDirPath : settablePaths.nonRoot.relativeDirPath;
37816
+ const relativeDirPath = this.getSettablePaths().root.relativeDirPath;
37044
37817
  const fileContent = await readFileContent(join(outputRoot, join(relativeDirPath, relativeFilePath)));
37045
37818
  return new JunieRule({
37046
37819
  outputRoot,
@@ -37048,7 +37821,7 @@ var JunieRule = class JunieRule extends ToolRule {
37048
37821
  relativeFilePath,
37049
37822
  fileContent,
37050
37823
  validate,
37051
- root: isRoot
37824
+ root: JunieRule.isRootRelativeFilePath(relativeFilePath)
37052
37825
  });
37053
37826
  }
37054
37827
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
@@ -37063,13 +37836,15 @@ var JunieRule = class JunieRule extends ToolRule {
37063
37836
  rootPath: paths.root
37064
37837
  }));
37065
37838
  }
37066
- return new JunieRule(this.buildToolRuleParamsDefault({
37839
+ const { root } = this.getSettablePaths();
37840
+ return new JunieRule({
37067
37841
  outputRoot,
37068
- rulesyncRule,
37842
+ relativeDirPath: root.relativeDirPath,
37843
+ relativeFilePath: root.relativeFilePath,
37844
+ fileContent: rulesyncRule.getBody(),
37069
37845
  validate,
37070
- rootPath: this.getSettablePaths().root,
37071
- nonRootPath: this.getSettablePaths().nonRoot
37072
- }));
37846
+ root: rulesyncRule.getFrontmatter().root ?? false
37847
+ });
37073
37848
  }
37074
37849
  toRulesyncRule() {
37075
37850
  return this.toRulesyncRuleDefault();
@@ -37472,31 +38247,68 @@ var OpenCodeRule = class OpenCodeRule extends ToolRule {
37472
38247
  * RulesProcessor (there is no separate non-root output location — `nonRoot` is
37473
38248
  * `undefined`). This mirrors the codexcli, grokcli, warp, and deepagents targets.
37474
38249
  *
37475
- * Pi also loads two system-prompt instruction files that rulesync does NOT emit:
38250
+ * Pi also loads two system-prompt instruction files. `.pi/APPEND_SYSTEM.md`
38251
+ * (global `~/.pi/agent/APPEND_SYSTEM.md`) *appends* to the default system prompt,
38252
+ * and rulesync emits it from any rule that opts in via the `pi.systemPrompt:
38253
+ * append` frontmatter block: those bodies are routed here instead of being folded
38254
+ * into `AGENTS.md`, and multiple opted-in rules concatenate in source order.
37476
38255
  * `.pi/SYSTEM.md` (global `~/.pi/agent/SYSTEM.md`) *replaces* the default system
37477
- * prompt entirely, and `.pi/APPEND_SYSTEM.md` (global
37478
- * `~/.pi/agent/APPEND_SYSTEM.md`) *appends* to it. rulesync's rules model only
37479
- * routes a designated `root` rule to a single context file and has no convention
37480
- * for marking a rule as "replace" vs "append" the system prompt, so these
37481
- * surfaces are documented in docs/reference/file-formats.md and left to be
37482
- * authored by hand rather than mapped to a speculative new frontmatter flag.
38256
+ * prompt entirely which silently disables Pi's built-in tool instructions — so
38257
+ * rulesync deliberately never emits it and leaves it to be authored by hand.
38258
+ * See docs/reference/file-formats.md.
37483
38259
  */
37484
38260
  var PiRule = class PiRule extends ToolRule {
37485
- constructor({ fileContent, root, ...rest }) {
38261
+ appendSystemPrompt;
38262
+ constructor({ fileContent, root, appendSystemPrompt = false, ...rest }) {
37486
38263
  super({
37487
38264
  ...rest,
37488
38265
  fileContent,
37489
38266
  root: root ?? false
37490
38267
  });
38268
+ this.appendSystemPrompt = appendSystemPrompt;
37491
38269
  }
37492
38270
  static getSettablePaths({ global = false, excludeToolDir } = {}) {
37493
- return { root: {
37494
- relativeDirPath: global ? buildToolPath(".pi", "agent", excludeToolDir) : ".",
37495
- relativeFilePath: PI_RULE_FILE_NAME
37496
- } };
38271
+ return {
38272
+ root: {
38273
+ relativeDirPath: global ? buildToolPath(".pi", "agent", excludeToolDir) : ".",
38274
+ relativeFilePath: PI_RULE_FILE_NAME
38275
+ },
38276
+ appendSystemPrompt: {
38277
+ relativeDirPath: global ? buildToolPath(".pi", "agent", excludeToolDir) : ".pi",
38278
+ relativeFilePath: PI_APPEND_SYSTEM_FILE_NAME
38279
+ }
38280
+ };
37497
38281
  }
37498
- static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, validate = true, global = false }) {
37499
- const { root } = this.getSettablePaths({ global });
38282
+ /**
38283
+ * Extra fixed files this tool manages beyond the root rule. The
38284
+ * RulesProcessor enumerates these for import and deletion so a stale
38285
+ * `APPEND_SYSTEM.md` is cleaned up once no rule opts in anymore.
38286
+ */
38287
+ static getExtraFixedFiles({ global = false } = {}) {
38288
+ return [this.getSettablePaths({ global }).appendSystemPrompt];
38289
+ }
38290
+ /**
38291
+ * Pi appends `APPEND_SYSTEM.md` to the system prompt itself, so listing it in
38292
+ * the root rule's reference section (toon/explicit discovery modes) would
38293
+ * double-load the content.
38294
+ */
38295
+ isExcludedFromRootReferences() {
38296
+ return this.appendSystemPrompt;
38297
+ }
38298
+ static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
38299
+ const { root, appendSystemPrompt } = this.getSettablePaths({ global });
38300
+ if (relativeFilePath === "APPEND_SYSTEM.md") {
38301
+ const fileContent = await readFileContent(join(outputRoot, join(appendSystemPrompt.relativeDirPath, appendSystemPrompt.relativeFilePath)));
38302
+ return new PiRule({
38303
+ outputRoot,
38304
+ relativeDirPath: appendSystemPrompt.relativeDirPath,
38305
+ relativeFilePath: appendSystemPrompt.relativeFilePath,
38306
+ fileContent,
38307
+ validate,
38308
+ root: false,
38309
+ appendSystemPrompt: true
38310
+ });
38311
+ }
37500
38312
  const fileContent = await readFileContent(join(outputRoot, join(root.relativeDirPath, root.relativeFilePath)));
37501
38313
  return new PiRule({
37502
38314
  outputRoot,
@@ -37508,8 +38320,18 @@ var PiRule = class PiRule extends ToolRule {
37508
38320
  });
37509
38321
  }
37510
38322
  static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
37511
- const { root } = this.getSettablePaths({ global });
37512
- const isRoot = rulesyncRule.getFrontmatter().root ?? false;
38323
+ const { root, appendSystemPrompt } = this.getSettablePaths({ global });
38324
+ const frontmatter = rulesyncRule.getFrontmatter();
38325
+ if (!frontmatter.root && frontmatter.pi?.systemPrompt === "append") return new PiRule({
38326
+ outputRoot,
38327
+ relativeDirPath: appendSystemPrompt.relativeDirPath,
38328
+ relativeFilePath: appendSystemPrompt.relativeFilePath,
38329
+ fileContent: rulesyncRule.getBody(),
38330
+ validate,
38331
+ root: false,
38332
+ appendSystemPrompt: true
38333
+ });
38334
+ const isRoot = frontmatter.root ?? false;
37513
38335
  return new PiRule({
37514
38336
  outputRoot,
37515
38337
  relativeDirPath: root.relativeDirPath,
@@ -37520,6 +38342,17 @@ var PiRule = class PiRule extends ToolRule {
37520
38342
  });
37521
38343
  }
37522
38344
  toRulesyncRule() {
38345
+ if (this.appendSystemPrompt) return new RulesyncRule({
38346
+ outputRoot: process.cwd(),
38347
+ relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
38348
+ relativeFilePath: PI_APPEND_SYSTEM_FILE_NAME,
38349
+ frontmatter: {
38350
+ root: false,
38351
+ targets: ["pi"],
38352
+ pi: { systemPrompt: "append" }
38353
+ },
38354
+ body: this.getFileContent()
38355
+ });
37523
38356
  return this.toRulesyncRuleDefault();
37524
38357
  }
37525
38358
  validate() {
@@ -37530,6 +38363,15 @@ var PiRule = class PiRule extends ToolRule {
37530
38363
  }
37531
38364
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
37532
38365
  const { root } = this.getSettablePaths({ global });
38366
+ if (relativeFilePath === "APPEND_SYSTEM.md") return new PiRule({
38367
+ outputRoot,
38368
+ relativeDirPath,
38369
+ relativeFilePath,
38370
+ fileContent: "",
38371
+ validate: false,
38372
+ root: false,
38373
+ appendSystemPrompt: true
38374
+ });
37533
38375
  const isRoot = relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === root.relativeDirPath);
37534
38376
  return new PiRule({
37535
38377
  outputRoot,
@@ -38689,7 +39531,8 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
38689
39531
  meta: {
38690
39532
  extension: "md",
38691
39533
  supportsGlobal: true,
38692
- ruleDiscoveryMode: "toon"
39534
+ ruleDiscoveryMode: "auto",
39535
+ foldsNonRootIntoRoot: true
38693
39536
  }
38694
39537
  }],
38695
39538
  ["kilo", {
@@ -38955,7 +39798,7 @@ var RulesProcessor = class extends FeatureProcessor {
38955
39798
  */
38956
39799
  async buildMcpInstructionFiles({ toolRules, meta }) {
38957
39800
  if (!meta.mcpInstructionsRegistrar || this.global) return [];
38958
- const instructionPaths = toolRules.filter((rule) => !rule.isRoot()).map((rule) => toPosixPath(join(rule.getRelativeDirPath(), rule.getRelativeFilePath())));
39801
+ const instructionPaths = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences()).map((rule) => toPosixPath(join(rule.getRelativeDirPath(), rule.getRelativeFilePath())));
38959
39802
  if (instructionPaths.length === 0) return [];
38960
39803
  return [await meta.mcpInstructionsRegistrar.fromInstructions({
38961
39804
  outputRoot: this.outputRoot,
@@ -38987,7 +39830,7 @@ var RulesProcessor = class extends FeatureProcessor {
38987
39830
  const toolRelativeDirPath = skillClass.getSettablePaths({ global: this.global }).relativeDirPath;
38988
39831
  return this.skills.filter((skill) => skillClass.isTargetedByRulesyncSkill(skill)).map((skill) => {
38989
39832
  const frontmatter = skill.getFrontmatter();
38990
- const relativePath = join(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME);
39833
+ const relativePath = join(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME$1);
38991
39834
  return {
38992
39835
  name: frontmatter.name,
38993
39836
  description: frontmatter.description,
@@ -39011,11 +39854,25 @@ var RulesProcessor = class extends FeatureProcessor {
39011
39854
  */
39012
39855
  foldNonRootRulesIntoRootRule(toolRules) {
39013
39856
  if (toolRules.length <= 1) return;
39014
- const target = toolRules.find((rule) => rule.isRoot()) ?? toolRules[0];
39015
- if (!target) return;
39016
- const mergedContent = [target, ...toolRules.filter((rule) => rule !== target)].map((rule) => rule.getFileContent().trim()).filter((content) => content.length > 0).join("\n\n");
39017
- target.setFileContent(mergedContent);
39018
- for (let i = toolRules.length - 1; i >= 0; i--) if (toolRules[i] !== target) toolRules.splice(i, 1);
39857
+ const groups = /* @__PURE__ */ new Map();
39858
+ for (const rule of toolRules) {
39859
+ const path = join(rule.getRelativeDirPath(), rule.getRelativeFilePath());
39860
+ const group = groups.get(path);
39861
+ if (group) group.push(rule);
39862
+ else groups.set(path, [rule]);
39863
+ }
39864
+ const survivors = /* @__PURE__ */ new Set();
39865
+ for (const group of groups.values()) {
39866
+ const target = group.find((rule) => rule.isRoot()) ?? group[0];
39867
+ if (!target) continue;
39868
+ const mergedContent = [target, ...group.filter((rule) => rule !== target)].map((rule) => rule.getFileContent().trim()).filter((content) => content.length > 0).join("\n\n");
39869
+ target.setFileContent(mergedContent);
39870
+ survivors.add(target);
39871
+ }
39872
+ for (let i = toolRules.length - 1; i >= 0; i--) {
39873
+ const rule = toolRules[i];
39874
+ if (rule && !survivors.has(rule)) toolRules.splice(i, 1);
39875
+ }
39019
39876
  }
39020
39877
  /**
39021
39878
  * Handle localRoot rule generation based on tool target.
@@ -39225,6 +40082,27 @@ As this project's AI coding tool, you must follow the additional conventions bel
39225
40082
  const mirrorPaths = await findFilesByGlobs(mirrorGlob);
39226
40083
  return buildDeletionRulesFromPaths(mirrorPaths);
39227
40084
  })();
40085
+ const extraFixedToolRules = await (async () => {
40086
+ const extraFiles = factory.class.getExtraFixedFiles?.({ global: this.global });
40087
+ if (!extraFiles || extraFiles.length === 0) return [];
40088
+ const filePaths = await findFilesByGlobs(extraFiles.map((file) => join(this.outputRoot, file.relativeDirPath, file.relativeFilePath)));
40089
+ if (filePaths.length === 0) return [];
40090
+ if (forDeletion) return buildDeletionRulesFromPaths(filePaths);
40091
+ return await Promise.all(filePaths.map((filePath) => {
40092
+ const relativeDirPath = resolveRelativeDirPath(filePath);
40093
+ checkPathTraversal({
40094
+ relativePath: relativeDirPath,
40095
+ intendedRootDir: this.outputRoot
40096
+ });
40097
+ return factory.class.fromFile({
40098
+ outputRoot: this.outputRoot,
40099
+ relativeDirPath,
40100
+ relativeFilePath: basename(filePath),
40101
+ global: this.global
40102
+ });
40103
+ }));
40104
+ })();
40105
+ this.logger.debug(`Found ${extraFixedToolRules.length} extra fixed tool rule files`);
39228
40106
  const nonRootToolRules = await (async () => {
39229
40107
  if (!settablePaths.nonRoot) return [];
39230
40108
  const nonRootOutputRoot = join(this.outputRoot, settablePaths.nonRoot.relativeDirPath);
@@ -39260,6 +40138,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
39260
40138
  ...rootToolRules,
39261
40139
  ...localRootToolRules,
39262
40140
  ...rootMirrorDeletionRules,
40141
+ ...extraFixedToolRules,
39263
40142
  ...nonRootToolRules
39264
40143
  ];
39265
40144
  } catch (error) {
@@ -39287,7 +40166,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
39287
40166
  return toolRuleFactories.get(result.data);
39288
40167
  }
39289
40168
  generateToonReferencesSection(toolRules) {
39290
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
40169
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences());
39291
40170
  if (toolRulesWithoutRoot.length === 0) return "";
39292
40171
  const lines = [];
39293
40172
  lines.push("Please also reference the following rules as needed. The list below is provided in TOON format, and `@` stands for the project root directory.");
@@ -39303,7 +40182,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
39303
40182
  return lines.join("\n") + "\n\n";
39304
40183
  }
39305
40184
  generateReferencesSection(toolRules) {
39306
- const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
40185
+ const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences());
39307
40186
  if (toolRulesWithoutRoot.length === 0) return "";
39308
40187
  const lines = [];
39309
40188
  lines.push("Please also reference the following rules as needed:");
@@ -39324,7 +40203,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
39324
40203
  */
39325
40204
  async function convertFromTool(params) {
39326
40205
  const ctx = params;
39327
- const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount] = [
40206
+ const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount, checksCount] = [
39328
40207
  await runFeatureConvert(ctx, buildRulesStrategy(ctx)),
39329
40208
  await runFeatureConvert(ctx, buildIgnoreStrategy(ctx)),
39330
40209
  await runFeatureConvert(ctx, buildMcpStrategy(ctx)),
@@ -39332,7 +40211,8 @@ async function convertFromTool(params) {
39332
40211
  await runFeatureConvert(ctx, buildSubagentsStrategy(ctx)),
39333
40212
  await runFeatureConvert(ctx, buildSkillsStrategy(ctx)),
39334
40213
  await runFeatureConvert(ctx, buildHooksStrategy(ctx)),
39335
- await runFeatureConvert(ctx, buildPermissionsStrategy(ctx))
40214
+ await runFeatureConvert(ctx, buildPermissionsStrategy(ctx)),
40215
+ await runFeatureConvert(ctx, buildChecksStrategy(ctx))
39336
40216
  ];
39337
40217
  return {
39338
40218
  rulesCount,
@@ -39342,7 +40222,8 @@ async function convertFromTool(params) {
39342
40222
  subagentsCount,
39343
40223
  skillsCount,
39344
40224
  hooksCount,
39345
- permissionsCount
40225
+ permissionsCount,
40226
+ checksCount
39346
40227
  };
39347
40228
  }
39348
40229
  async function runFeatureConvert(ctx, strategy) {
@@ -39575,6 +40456,27 @@ function buildPermissionsStrategy(ctx) {
39575
40456
  write: (p, files) => p.writeAiFiles(files)
39576
40457
  };
39577
40458
  }
40459
+ function buildChecksStrategy(ctx) {
40460
+ const { config, logger } = ctx;
40461
+ const global = config.getGlobal();
40462
+ const outputRoot = getOutputRoot(config);
40463
+ return {
40464
+ feature: "checks",
40465
+ itemLabel: "check file(s)",
40466
+ allTargets: ChecksProcessor.getToolTargets({ global }),
40467
+ createProcessor: ({ toolTarget, dryRun }) => new ChecksProcessor({
40468
+ outputRoot,
40469
+ toolTarget,
40470
+ global,
40471
+ dryRun,
40472
+ logger
40473
+ }),
40474
+ loadSource: (p) => p.loadToolFiles(),
40475
+ toRulesync: (p, files) => p.convertToolFilesToRulesyncFiles(files),
40476
+ fromRulesync: (p, files) => p.convertRulesyncFilesToToolFiles(files),
40477
+ write: (p, files) => p.writeAiFiles(files)
40478
+ };
40479
+ }
39578
40480
  //#endregion
39579
40481
  //#region src/types/processor-registry.ts
39580
40482
  const PROCESSOR_REGISTRY = [
@@ -39625,6 +40527,12 @@ const PROCESSOR_REGISTRY = [
39625
40527
  processor: PermissionsProcessor,
39626
40528
  schema: PermissionsProcessorToolTargetSchema,
39627
40529
  factory: toolPermissionsFactories
40530
+ },
40531
+ {
40532
+ feature: "checks",
40533
+ processor: ChecksProcessor,
40534
+ schema: ChecksProcessorToolTargetSchema,
40535
+ factory: toolCheckFactories
39628
40536
  }
39629
40537
  ];
39630
40538
  const getProcessorRegistryEntry = (feature) => {
@@ -39974,6 +40882,7 @@ const GENERATION_STEP_GRAPH = [
39974
40882
  id: "permissions",
39975
40883
  ...sharedWriteMeta("permissions")
39976
40884
  },
40885
+ { id: "checks" },
39977
40886
  {
39978
40887
  id: "rules",
39979
40888
  ...sharedWriteMeta("rules"),
@@ -40059,6 +40968,10 @@ async function generate(params) {
40059
40968
  config,
40060
40969
  logger
40061
40970
  }),
40971
+ checks: () => generateChecksCore({
40972
+ config,
40973
+ logger
40974
+ }),
40062
40975
  rules: () => generateRulesCore({
40063
40976
  config,
40064
40977
  logger,
@@ -40095,6 +41008,8 @@ async function generate(params) {
40095
41008
  hooksPaths: get("hooks").paths,
40096
41009
  permissionsCount: get("permissions").count,
40097
41010
  permissionsPaths: get("permissions").paths,
41011
+ checksCount: get("checks").count,
41012
+ checksPaths: get("checks").paths,
40098
41013
  skills: skillsResult.skills,
40099
41014
  hasDiff
40100
41015
  };
@@ -40463,6 +41378,44 @@ async function generatePermissionsCore(params) {
40463
41378
  hasDiff
40464
41379
  };
40465
41380
  }
41381
+ async function generateChecksCore(params) {
41382
+ const { config, logger } = params;
41383
+ let totalCount = 0;
41384
+ const allPaths = [];
41385
+ let hasDiff = false;
41386
+ const supportedChecksTargets = ChecksProcessor.getToolTargets({ global: config.getGlobal() });
41387
+ const toolTargets = intersection(config.getTargets(), supportedChecksTargets);
41388
+ warnUnsupportedTargets({
41389
+ config,
41390
+ supportedTargets: supportedChecksTargets,
41391
+ featureName: "checks",
41392
+ logger
41393
+ });
41394
+ for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
41395
+ if (!config.getFeatures(toolTarget).includes("checks")) continue;
41396
+ const processor = new ChecksProcessor({
41397
+ outputRoot,
41398
+ inputRoot: config.getInputRoot(),
41399
+ toolTarget,
41400
+ global: config.getGlobal(),
41401
+ dryRun: config.isPreviewMode(),
41402
+ logger
41403
+ });
41404
+ const result = await processFeatureWithRulesyncFiles({
41405
+ config,
41406
+ processor,
41407
+ rulesyncFiles: await processor.loadRulesyncFiles()
41408
+ });
41409
+ totalCount += result.count;
41410
+ allPaths.push(...result.paths);
41411
+ if (result.hasDiff) hasDiff = true;
41412
+ }
41413
+ return {
41414
+ count: totalCount,
41415
+ paths: allPaths,
41416
+ hasDiff
41417
+ };
41418
+ }
40466
41419
  //#endregion
40467
41420
  //#region src/lib/import.ts
40468
41421
  /**
@@ -40520,6 +41473,11 @@ async function importFromTool(params) {
40520
41473
  config,
40521
41474
  tool,
40522
41475
  logger
41476
+ }),
41477
+ checksCount: await importChecksCore({
41478
+ config,
41479
+ tool,
41480
+ logger
40523
41481
  })
40524
41482
  };
40525
41483
  }
@@ -40736,7 +41694,28 @@ async function importPermissionsCore(params) {
40736
41694
  if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} permissions file(s)`);
40737
41695
  return writtenCount;
40738
41696
  }
41697
+ async function importChecksCore(params) {
41698
+ const { config, tool, logger } = params;
41699
+ if (!config.getFeatures(tool).includes("checks")) return 0;
41700
+ const global = config.getGlobal();
41701
+ if (!ChecksProcessor.getToolTargets({ global }).includes(tool)) return 0;
41702
+ const checksProcessor = new ChecksProcessor({
41703
+ outputRoot: config.getOutputRoots()[0] ?? ".",
41704
+ toolTarget: tool,
41705
+ global,
41706
+ logger
41707
+ });
41708
+ const toolFiles = await checksProcessor.loadToolFiles();
41709
+ if (toolFiles.length === 0) {
41710
+ logger.warn(`No check files found for ${tool}. Skipping import.`);
41711
+ return 0;
41712
+ }
41713
+ const rulesyncFiles = await checksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
41714
+ const { count: writtenCount } = await checksProcessor.writeAiFiles(rulesyncFiles);
41715
+ if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} check files`);
41716
+ return writtenCount;
41717
+ }
40739
41718
  //#endregion
40740
- export { removeFile as $, CLAUDECODE_SKILLS_DIR_PATH as A, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as At, ErrorCodes as B, RulesyncHooks as C, RULESYNC_PERMISSIONS_FILE_NAME as Ct, CLAUDECODE_LOCAL_RULE_FILE_NAME as D, RULESYNC_RELATIVE_DIR_PATH as Dt, CLAUDECODE_DIR as E, RULESYNC_PERMISSIONS_SCHEMA_URL as Et, ConfigResolver as F, fileExists as G, createTempDirectory as H, findControlCharacter as I, getHomeDirectory as J, findFilesByGlobs as K, ConsoleLogger as L, RulesyncCommandFrontmatterSchema as M, formatError as Mt, stringifyFrontmatter as N, ALL_FEATURES as Nt, CLAUDECODE_MEMORIES_DIR_NAME as O, RULESYNC_RULES_RELATIVE_DIR_PATH as Ot, loadYaml as P, ALL_FEATURES_WITH_WILDCARD as Pt, removeDirectory as Q, JsonLogger as R, HooksProcessor as S, RULESYNC_OVERVIEW_FILE_NAME as St, CODEXCLI_DIR as T, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Tt, directoryExists as U, checkPathTraversal as V, ensureDir as W, listDirectoryFiles as X, isSymlink as Y, readFileContent as Z, RulesyncPermissions as _, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as _t, convertFromTool as a, ToolTargetSchema as at, IgnoreProcessor as b, RULESYNC_MCP_RELATIVE_FILE_PATH as bt, RulesyncRuleFrontmatterSchema as c, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as ct, RulesyncSubagentFrontmatterSchema as d, RULESYNC_CONFIG_SCHEMA_URL as dt, removeTempDirectory as et, SkillsProcessor as f, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as ft, SKILL_FILE_NAME as g, RULESYNC_IGNORE_RELATIVE_FILE_PATH as gt, RulesyncSkillFrontmatterSchema as h, RULESYNC_HOOKS_RELATIVE_FILE_PATH as ht, getProcessorRegistryEntry as i, ALL_TOOL_TARGETS_WITH_WILDCARD as it, RulesyncCommand as j, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as jt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as k, RULESYNC_SKILLS_RELATIVE_DIR_PATH as kt, SubagentsProcessor as l, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as lt, RulesyncSkill as m, RULESYNC_HOOKS_JSONC_FILE_NAME as mt, checkRulesyncDirExists as n, writeFileContent as nt, RulesProcessor as o, MAX_FILE_SIZE as ot, getLocalSkillDirNames as p, RULESYNC_HOOKS_FILE_NAME as pt, getFileSize as q, generate as r, ALL_TOOL_TARGETS as rt, RulesyncRule as s, RULESYNC_AIIGNORE_FILE_NAME as st, importFromTool as t, toPosixPath as tt, RulesyncSubagent as u, RULESYNC_CONFIG_RELATIVE_FILE_PATH as ut, McpProcessor as v, RULESYNC_MCP_FILE_NAME as vt, CommandsProcessor as w, RULESYNC_PERMISSIONS_JSONC_FILE_NAME as wt, RulesyncIgnore as x, RULESYNC_MCP_SCHEMA_URL as xt, RulesyncMcp as y, RULESYNC_MCP_JSONC_FILE_NAME as yt, CLIError as z };
41719
+ export { isSymlink as $, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as A, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as At, findControlCharacter as B, CommandsProcessor as C, RULESYNC_MCP_FILE_NAME as Ct, CLAUDECODE_DIR as D, RULESYNC_OVERVIEW_FILE_NAME as Dt, CODEXCLI_DIR as E, RULESYNC_MCP_SCHEMA_URL as Et, RulesyncCheck as F, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Ft, checkPathTraversal as G, JsonLogger as H, RulesyncCheckFrontmatterSchema as I, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as It, ensureDir as J, createTempDirectory as K, stringifyFrontmatter as L, formatError as Lt, RulesyncCommand as M, RULESYNC_RELATIVE_DIR_PATH as Mt, RulesyncCommandFrontmatterSchema as N, RULESYNC_RULES_RELATIVE_DIR_PATH as Nt, CLAUDECODE_LOCAL_RULE_FILE_NAME as O, RULESYNC_PERMISSIONS_FILE_NAME as Ot, ChecksProcessor as P, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Pt, getHomeDirectory as Q, loadYaml as R, ALL_FEATURES as Rt, RulesyncHooks as S, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as St, CODEXCLI_BASH_RULES_FILE_NAME as T, RULESYNC_MCP_RELATIVE_FILE_PATH as Tt, CLIError as U, ConsoleLogger as V, ErrorCodes as W, findFilesByGlobs as X, fileExists as Y, getFileSize as Z, McpProcessor as _, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as _t, convertFromTool as a, toPosixPath as at, RulesyncIgnore as b, RULESYNC_HOOKS_RELATIVE_FILE_PATH as bt, RulesyncRuleFrontmatterSchema as c, ALL_TOOL_TARGETS_WITH_WILDCARD as ct, RulesyncSubagentFrontmatterSchema as d, RULESYNC_AIIGNORE_FILE_NAME as dt, listDirectoryFiles as et, SkillsProcessor as f, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as ft, RulesyncPermissions as g, RULESYNC_CONFIG_SCHEMA_URL as gt, RulesyncSkillFrontmatterSchema as h, RULESYNC_CONFIG_RELATIVE_FILE_PATH as ht, getProcessorRegistryEntry as i, removeTempDirectory as it, CLAUDECODE_SKILLS_DIR_PATH as j, RULESYNC_PERMISSIONS_SCHEMA_URL as jt, CLAUDECODE_MEMORIES_DIR_NAME as k, RULESYNC_PERMISSIONS_JSONC_FILE_NAME as kt, SubagentsProcessor as l, ToolTargetSchema as lt, RulesyncSkill as m, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as mt, checkRulesyncDirExists as n, removeDirectory as nt, RulesProcessor as o, writeFileContent as ot, getLocalSkillDirNames as p, RULESYNC_CHECKS_RELATIVE_DIR_PATH as pt, directoryExists as q, generate as r, removeFile as rt, RulesyncRule as s, ALL_TOOL_TARGETS as st, importFromTool as t, readFileContent as tt, RulesyncSubagent as u, MAX_FILE_SIZE as ut, RulesyncMcp as v, RULESYNC_HOOKS_FILE_NAME as vt, SKILL_FILE_NAME$1 as w, RULESYNC_MCP_JSONC_FILE_NAME as wt, HooksProcessor as x, RULESYNC_IGNORE_RELATIVE_FILE_PATH as xt, IgnoreProcessor as y, RULESYNC_HOOKS_JSONC_FILE_NAME as yt, ConfigResolver as z, ALL_FEATURES_WITH_WILDCARD as zt };
40741
41720
 
40742
- //# sourceMappingURL=import-hM4jDZn1.js.map
41721
+ //# sourceMappingURL=import-CMSHVMqU.js.map