rulesync 12.0.0 → 14.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.
- package/README.md +39 -39
- package/dist/cli/index.cjs +1162 -34
- package/dist/cli/index.js +1162 -34
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-hM4jDZn1.js → import-CSnC5vl7.js} +1645 -486
- package/dist/import-CSnC5vl7.js.map +1 -0
- package/dist/{import-C0N0Lo_F.cjs → import-Dh9PCQKq.cjs} +1693 -498
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-hM4jDZn1.js.map +0 -1
|
@@ -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");
|
|
@@ -109,6 +112,7 @@ const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
|
109
112
|
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$1(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
110
113
|
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$1(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
|
|
111
114
|
const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
|
|
115
|
+
const RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync-npm.lock.json";
|
|
112
116
|
const RULESYNC_MCP_FILE_NAME = "mcp.json";
|
|
113
117
|
const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
|
|
114
118
|
const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.json";
|
|
@@ -341,6 +345,7 @@ const permissionsProcessorToolTargetTuple = [
|
|
|
341
345
|
"claudecode",
|
|
342
346
|
"cline",
|
|
343
347
|
"codexcli",
|
|
348
|
+
"copilot",
|
|
344
349
|
"cursor",
|
|
345
350
|
"devin",
|
|
346
351
|
"factorydroid",
|
|
@@ -361,6 +366,7 @@ const permissionsProcessorToolTargetTuple = [
|
|
|
361
366
|
"warp",
|
|
362
367
|
"zed"
|
|
363
368
|
];
|
|
369
|
+
const checksProcessorToolTargetTuple = ["amp"];
|
|
364
370
|
//#endregion
|
|
365
371
|
//#region src/types/tool-targets.ts
|
|
366
372
|
const ALL_TOOL_TARGETS = [...new Set([
|
|
@@ -371,7 +377,8 @@ const ALL_TOOL_TARGETS = [...new Set([
|
|
|
371
377
|
subagentsProcessorToolTargetTuple,
|
|
372
378
|
skillsProcessorToolTargetTuple,
|
|
373
379
|
hooksProcessorToolTargetTuple,
|
|
374
|
-
permissionsProcessorToolTargetTuple
|
|
380
|
+
permissionsProcessorToolTargetTuple,
|
|
381
|
+
checksProcessorToolTargetTuple
|
|
375
382
|
].flat())];
|
|
376
383
|
const ALL_TOOL_TARGETS_WITH_WILDCARD = [...ALL_TOOL_TARGETS, "*"];
|
|
377
384
|
const ToolTargetSchema = z.enum(ALL_TOOL_TARGETS);
|
|
@@ -850,9 +857,15 @@ const GITIGNORE_DESTINATION_KEY = "gitignoreDestination";
|
|
|
850
857
|
const SourceEntrySchema = z.object({
|
|
851
858
|
source: z.string().check(minLength(1, "source must be a non-empty string")),
|
|
852
859
|
skills: optional(z.array(z.string())),
|
|
853
|
-
transport: optional(z.enum([
|
|
860
|
+
transport: optional(z.enum([
|
|
861
|
+
"github",
|
|
862
|
+
"git",
|
|
863
|
+
"npm"
|
|
864
|
+
])),
|
|
854
865
|
ref: optional(z.string().check(refine((v) => !v.startsWith("-"), "ref must not start with \"-\""), refine((v) => !hasControlCharacters(v), "ref must not contain control characters"))),
|
|
855
866
|
path: optional(z.string().check(refine((v) => !v.includes(".."), "path must not contain \"..\""), refine((v) => !isAbsolute(v), "path must not be absolute"), refine((v) => !hasControlCharacters(v), "path must not contain control characters"))),
|
|
867
|
+
registry: optional(z.string().check(refine((v) => v.startsWith("https://") || v.startsWith("http://"), "registry must be an http(s) URL"), refine((v) => !hasControlCharacters(v), "registry must not contain control characters"))),
|
|
868
|
+
tokenEnv: optional(z.string().check(refine((v) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(v), "tokenEnv must be a valid environment variable name"))),
|
|
856
869
|
agent: optional(z.enum([
|
|
857
870
|
"github-copilot",
|
|
858
871
|
"claude-code",
|
|
@@ -862,7 +875,7 @@ const SourceEntrySchema = z.object({
|
|
|
862
875
|
"antigravity"
|
|
863
876
|
])),
|
|
864
877
|
scope: optional(z.enum(["project", "user"]))
|
|
865
|
-
});
|
|
878
|
+
}).check(refine((entry) => entry.registry === void 0 && entry.tokenEnv === void 0 || entry.transport === "npm", "\"registry\" and \"tokenEnv\" are only valid with transport \"npm\""));
|
|
866
879
|
const ConfigParamsSchema = z.object({
|
|
867
880
|
outputRoots: z.union([z.array(z.string()), z.record(z.string(), z.union([z.string(), z.array(z.string())]))]),
|
|
868
881
|
targets: RulesyncConfigTargetsSchema,
|
|
@@ -1445,7 +1458,7 @@ function isPlainObject$1(value) {
|
|
|
1445
1458
|
/**
|
|
1446
1459
|
* Type guard to check if a value is an array of strings.
|
|
1447
1460
|
*/
|
|
1448
|
-
function isStringArray(value) {
|
|
1461
|
+
function isStringArray$1(value) {
|
|
1449
1462
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1450
1463
|
}
|
|
1451
1464
|
//#endregion
|
|
@@ -1693,13 +1706,17 @@ var FeatureProcessor = class {
|
|
|
1693
1706
|
}
|
|
1694
1707
|
};
|
|
1695
1708
|
//#endregion
|
|
1696
|
-
//#region src/constants/
|
|
1697
|
-
const
|
|
1698
|
-
const
|
|
1699
|
-
const
|
|
1700
|
-
const
|
|
1701
|
-
const
|
|
1702
|
-
const
|
|
1709
|
+
//#region src/constants/amp-paths.ts
|
|
1710
|
+
const AMP_DIR = ".amp";
|
|
1711
|
+
const AMP_GLOBAL_DIR = join(".config", "amp");
|
|
1712
|
+
const AMP_AGENTS_DIR = ".agents";
|
|
1713
|
+
const AMP_SKILLS_PROJECT_DIR = join(AMP_AGENTS_DIR, "skills");
|
|
1714
|
+
const AMP_SKILLS_GLOBAL_DIR = join(".config", "agents", "skills");
|
|
1715
|
+
const AMP_CHECKS_PROJECT_DIR = join(AMP_AGENTS_DIR, "checks");
|
|
1716
|
+
const AMP_CHECKS_GLOBAL_DIR = join(AMP_GLOBAL_DIR, "checks");
|
|
1717
|
+
const AMP_RULE_FILE_NAME = "AGENTS.md";
|
|
1718
|
+
const AMP_SETTINGS_FILE_NAME = "settings.json";
|
|
1719
|
+
const AMP_SETTINGS_JSONC_FILE_NAME = "settings.jsonc";
|
|
1703
1720
|
//#endregion
|
|
1704
1721
|
//#region src/types/ai-file.ts
|
|
1705
1722
|
var AiFile = class {
|
|
@@ -1773,6 +1790,414 @@ var AiFile = class {
|
|
|
1773
1790
|
}
|
|
1774
1791
|
};
|
|
1775
1792
|
//#endregion
|
|
1793
|
+
//#region src/types/rulesync-file.ts
|
|
1794
|
+
var RulesyncFile = class extends AiFile {
|
|
1795
|
+
static async fromFile(_params) {
|
|
1796
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
//#endregion
|
|
1800
|
+
//#region src/features/checks/rulesync-check.ts
|
|
1801
|
+
const RulesyncCheckFrontmatterSchema = z.looseObject({
|
|
1802
|
+
targets: z._default(RulesyncTargetsSchema, ["*"]),
|
|
1803
|
+
description: z.optional(z.string()),
|
|
1804
|
+
severity: z.optional(z.enum([
|
|
1805
|
+
"low",
|
|
1806
|
+
"medium",
|
|
1807
|
+
"high",
|
|
1808
|
+
"critical"
|
|
1809
|
+
])),
|
|
1810
|
+
tools: z.optional(z.array(z.string()))
|
|
1811
|
+
});
|
|
1812
|
+
var RulesyncCheck = class RulesyncCheck extends RulesyncFile {
|
|
1813
|
+
frontmatter;
|
|
1814
|
+
body;
|
|
1815
|
+
constructor({ frontmatter, body, ...rest }) {
|
|
1816
|
+
const parseResult = RulesyncCheckFrontmatterSchema.safeParse(frontmatter);
|
|
1817
|
+
if (!parseResult.success && rest.validate !== false) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(parseResult.error)}`);
|
|
1818
|
+
const parsedFrontmatter = parseResult.success ? {
|
|
1819
|
+
...frontmatter,
|
|
1820
|
+
...parseResult.data
|
|
1821
|
+
} : {
|
|
1822
|
+
...frontmatter,
|
|
1823
|
+
targets: frontmatter?.targets ?? ["*"]
|
|
1824
|
+
};
|
|
1825
|
+
super({
|
|
1826
|
+
...rest,
|
|
1827
|
+
fileContent: stringifyFrontmatter(body, parsedFrontmatter)
|
|
1828
|
+
});
|
|
1829
|
+
this.frontmatter = parsedFrontmatter;
|
|
1830
|
+
this.body = body;
|
|
1831
|
+
}
|
|
1832
|
+
static getSettablePaths() {
|
|
1833
|
+
return { relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH };
|
|
1834
|
+
}
|
|
1835
|
+
getFrontmatter() {
|
|
1836
|
+
return this.frontmatter;
|
|
1837
|
+
}
|
|
1838
|
+
getBody() {
|
|
1839
|
+
return this.body;
|
|
1840
|
+
}
|
|
1841
|
+
validate() {
|
|
1842
|
+
if (!this.frontmatter) return {
|
|
1843
|
+
success: true,
|
|
1844
|
+
error: null
|
|
1845
|
+
};
|
|
1846
|
+
const result = RulesyncCheckFrontmatterSchema.safeParse(this.frontmatter);
|
|
1847
|
+
if (result.success) return {
|
|
1848
|
+
success: true,
|
|
1849
|
+
error: null
|
|
1850
|
+
};
|
|
1851
|
+
else return {
|
|
1852
|
+
success: false,
|
|
1853
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath }) {
|
|
1857
|
+
const filePath = join(outputRoot, RULESYNC_CHECKS_RELATIVE_DIR_PATH, relativeFilePath);
|
|
1858
|
+
const { frontmatter, body: content, hasFrontmatter } = parseFrontmatter(await readFileContent(filePath), filePath);
|
|
1859
|
+
if (!hasFrontmatter) throw new Error(`Missing frontmatter in ${filePath}. Rulesync files must begin with a YAML frontmatter block delimited by '---'.`);
|
|
1860
|
+
const result = RulesyncCheckFrontmatterSchema.safeParse(frontmatter);
|
|
1861
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
|
|
1862
|
+
const filename = basename(relativeFilePath);
|
|
1863
|
+
return new RulesyncCheck({
|
|
1864
|
+
outputRoot,
|
|
1865
|
+
relativeDirPath: this.getSettablePaths().relativeDirPath,
|
|
1866
|
+
relativeFilePath: filename,
|
|
1867
|
+
frontmatter: result.data,
|
|
1868
|
+
body: content.trim()
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
//#endregion
|
|
1873
|
+
//#region src/types/tool-file.ts
|
|
1874
|
+
var ToolFile = class extends AiFile {};
|
|
1875
|
+
//#endregion
|
|
1876
|
+
//#region src/features/checks/tool-check.ts
|
|
1877
|
+
var ToolCheck = class extends ToolFile {
|
|
1878
|
+
static getSettablePaths(_options = {}) {
|
|
1879
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1880
|
+
}
|
|
1881
|
+
static async fromFile(_params) {
|
|
1882
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1883
|
+
}
|
|
1884
|
+
/**
|
|
1885
|
+
* Create a minimal instance for deletion purposes.
|
|
1886
|
+
* This method does not read or parse file content, making it safe to use
|
|
1887
|
+
* even when files have old/incompatible formats.
|
|
1888
|
+
*/
|
|
1889
|
+
static forDeletion(_params) {
|
|
1890
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1891
|
+
}
|
|
1892
|
+
static fromRulesyncCheck(_params) {
|
|
1893
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1894
|
+
}
|
|
1895
|
+
static isTargetedByRulesyncCheck(_rulesyncCheck) {
|
|
1896
|
+
throw new Error("Please implement this method in the subclass.");
|
|
1897
|
+
}
|
|
1898
|
+
static isTargetedByRulesyncCheckDefault({ rulesyncCheck, toolTarget }) {
|
|
1899
|
+
const targets = rulesyncCheck.getFrontmatter().targets;
|
|
1900
|
+
if (!targets) return true;
|
|
1901
|
+
if (targets.includes("*")) return true;
|
|
1902
|
+
if (targets.includes(toolTarget)) return true;
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
static filterToolSpecificSection(rawSection, excludeFields) {
|
|
1906
|
+
const filtered = {};
|
|
1907
|
+
for (const [key, value] of Object.entries(rawSection)) if (!excludeFields.includes(key)) filtered[key] = value;
|
|
1908
|
+
return filtered;
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
//#endregion
|
|
1912
|
+
//#region src/features/checks/amp-check.ts
|
|
1913
|
+
const AmpCheckFrontmatterSchema = z.looseObject({
|
|
1914
|
+
name: z.string(),
|
|
1915
|
+
description: z.optional(z.string()),
|
|
1916
|
+
"severity-default": z.optional(z.enum([
|
|
1917
|
+
"low",
|
|
1918
|
+
"medium",
|
|
1919
|
+
"high",
|
|
1920
|
+
"critical"
|
|
1921
|
+
])),
|
|
1922
|
+
tools: z.optional(z.array(z.string()))
|
|
1923
|
+
});
|
|
1924
|
+
/**
|
|
1925
|
+
* Represents an Amp code review check.
|
|
1926
|
+
*
|
|
1927
|
+
* Amp natively reads code review checks as Markdown files with YAML frontmatter,
|
|
1928
|
+
* scoped to the project (`.agents/checks/`) and user-wide (`~/.config/amp/checks/`).
|
|
1929
|
+
* Each check runs as a per-check subagent during code review.
|
|
1930
|
+
* @see https://ampcode.com/manual
|
|
1931
|
+
*/
|
|
1932
|
+
var AmpCheck = class AmpCheck extends ToolCheck {
|
|
1933
|
+
frontmatter;
|
|
1934
|
+
body;
|
|
1935
|
+
constructor({ frontmatter, body, fileContent, ...rest }) {
|
|
1936
|
+
if (rest.validate !== false) {
|
|
1937
|
+
const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
|
|
1938
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
|
|
1939
|
+
}
|
|
1940
|
+
super({
|
|
1941
|
+
...rest,
|
|
1942
|
+
fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
|
|
1943
|
+
});
|
|
1944
|
+
this.frontmatter = frontmatter;
|
|
1945
|
+
this.body = body;
|
|
1946
|
+
}
|
|
1947
|
+
static getSettablePaths({ global = false } = {}) {
|
|
1948
|
+
return { relativeDirPath: global ? AMP_CHECKS_GLOBAL_DIR : AMP_CHECKS_PROJECT_DIR };
|
|
1949
|
+
}
|
|
1950
|
+
getFrontmatter() {
|
|
1951
|
+
return this.frontmatter;
|
|
1952
|
+
}
|
|
1953
|
+
getBody() {
|
|
1954
|
+
return this.body;
|
|
1955
|
+
}
|
|
1956
|
+
toRulesyncCheck() {
|
|
1957
|
+
const { name: _name, description, "severity-default": severityDefault, tools, ...restFields } = this.frontmatter;
|
|
1958
|
+
return new RulesyncCheck({
|
|
1959
|
+
outputRoot: ".",
|
|
1960
|
+
frontmatter: {
|
|
1961
|
+
targets: ["*"],
|
|
1962
|
+
...description !== void 0 && { description },
|
|
1963
|
+
...severityDefault !== void 0 && { severity: severityDefault },
|
|
1964
|
+
...tools !== void 0 && { tools },
|
|
1965
|
+
...restFields
|
|
1966
|
+
},
|
|
1967
|
+
body: this.body,
|
|
1968
|
+
relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,
|
|
1969
|
+
relativeFilePath: this.getRelativeFilePath(),
|
|
1970
|
+
validate: true
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
static fromRulesyncCheck({ outputRoot = process.cwd(), rulesyncCheck, validate = true, global = false }) {
|
|
1974
|
+
const rulesyncFrontmatter = rulesyncCheck.getFrontmatter();
|
|
1975
|
+
const relativeFilePath = rulesyncCheck.getRelativeFilePath();
|
|
1976
|
+
const name = basename(relativeFilePath, ".md");
|
|
1977
|
+
const { targets: _targets, description, severity, tools, ...restFields } = rulesyncFrontmatter;
|
|
1978
|
+
const toolTargetKeys = new Set(ALL_TOOL_TARGETS);
|
|
1979
|
+
const passthroughFields = Object.fromEntries(Object.entries(restFields).filter(([key]) => !toolTargetKeys.has(key) && key !== "name"));
|
|
1980
|
+
const ampSection = this.filterToolSpecificSection(rulesyncFrontmatter.amp ?? {}, ["name"]);
|
|
1981
|
+
const rawAmpFrontmatter = {
|
|
1982
|
+
name,
|
|
1983
|
+
...description !== void 0 && { description },
|
|
1984
|
+
...severity !== void 0 && { "severity-default": severity },
|
|
1985
|
+
...tools !== void 0 && { tools },
|
|
1986
|
+
...passthroughFields,
|
|
1987
|
+
...ampSection
|
|
1988
|
+
};
|
|
1989
|
+
const result = AmpCheckFrontmatterSchema.safeParse(rawAmpFrontmatter);
|
|
1990
|
+
if (!result.success) throw new Error(`Invalid amp check frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
|
|
1991
|
+
const ampFrontmatter = result.data;
|
|
1992
|
+
const body = rulesyncCheck.getBody();
|
|
1993
|
+
const fileContent = stringifyFrontmatter(body, ampFrontmatter);
|
|
1994
|
+
const paths = this.getSettablePaths({ global });
|
|
1995
|
+
return new AmpCheck({
|
|
1996
|
+
outputRoot,
|
|
1997
|
+
frontmatter: ampFrontmatter,
|
|
1998
|
+
body,
|
|
1999
|
+
relativeDirPath: paths.relativeDirPath,
|
|
2000
|
+
relativeFilePath,
|
|
2001
|
+
fileContent,
|
|
2002
|
+
validate
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
validate() {
|
|
2006
|
+
if (!this.frontmatter) return {
|
|
2007
|
+
success: true,
|
|
2008
|
+
error: null
|
|
2009
|
+
};
|
|
2010
|
+
const result = AmpCheckFrontmatterSchema.safeParse(this.frontmatter);
|
|
2011
|
+
if (result.success) return {
|
|
2012
|
+
success: true,
|
|
2013
|
+
error: null
|
|
2014
|
+
};
|
|
2015
|
+
else return {
|
|
2016
|
+
success: false,
|
|
2017
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
static isTargetedByRulesyncCheck(rulesyncCheck) {
|
|
2021
|
+
return this.isTargetedByRulesyncCheckDefault({
|
|
2022
|
+
rulesyncCheck,
|
|
2023
|
+
toolTarget: "amp"
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
2027
|
+
const paths = this.getSettablePaths({ global });
|
|
2028
|
+
const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
|
|
2029
|
+
const fileContent = await readFileContent(filePath);
|
|
2030
|
+
const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
|
|
2031
|
+
const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
|
|
2032
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
|
|
2033
|
+
return new AmpCheck({
|
|
2034
|
+
outputRoot,
|
|
2035
|
+
relativeDirPath: paths.relativeDirPath,
|
|
2036
|
+
relativeFilePath,
|
|
2037
|
+
frontmatter: result.data,
|
|
2038
|
+
body: content.trim(),
|
|
2039
|
+
fileContent,
|
|
2040
|
+
validate
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
2044
|
+
return new AmpCheck({
|
|
2045
|
+
outputRoot,
|
|
2046
|
+
relativeDirPath,
|
|
2047
|
+
relativeFilePath,
|
|
2048
|
+
frontmatter: { name: "" },
|
|
2049
|
+
body: "",
|
|
2050
|
+
fileContent: "",
|
|
2051
|
+
validate: false
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
};
|
|
2055
|
+
//#endregion
|
|
2056
|
+
//#region src/features/checks/checks-processor.ts
|
|
2057
|
+
const ChecksProcessorToolTargetSchema = z.enum(checksProcessorToolTargetTuple);
|
|
2058
|
+
/**
|
|
2059
|
+
* Factory Map mapping tool targets to their check factories.
|
|
2060
|
+
* Using Map to preserve insertion order for consistent iteration.
|
|
2061
|
+
*/
|
|
2062
|
+
const toolCheckFactories = /* @__PURE__ */ new Map([["amp", {
|
|
2063
|
+
class: AmpCheck,
|
|
2064
|
+
meta: {
|
|
2065
|
+
supportsGlobal: true,
|
|
2066
|
+
filePattern: "*.md"
|
|
2067
|
+
}
|
|
2068
|
+
}]]);
|
|
2069
|
+
const defaultGetFactory$6 = (target) => {
|
|
2070
|
+
const factory = toolCheckFactories.get(target);
|
|
2071
|
+
if (!factory) throw new Error(`Unsupported tool target: ${target}`);
|
|
2072
|
+
return factory;
|
|
2073
|
+
};
|
|
2074
|
+
const allToolTargetKeys$5 = [...toolCheckFactories.keys()];
|
|
2075
|
+
const checksProcessorToolTargets = allToolTargetKeys$5;
|
|
2076
|
+
const checksProcessorToolTargetsGlobal = allToolTargetKeys$5.filter((target) => {
|
|
2077
|
+
return toolCheckFactories.get(target)?.meta.supportsGlobal ?? false;
|
|
2078
|
+
});
|
|
2079
|
+
var ChecksProcessor = class extends FeatureProcessor {
|
|
2080
|
+
toolTarget;
|
|
2081
|
+
global;
|
|
2082
|
+
getFactory;
|
|
2083
|
+
constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, global = false, getFactory = defaultGetFactory$6, dryRun = false, logger }) {
|
|
2084
|
+
super({
|
|
2085
|
+
outputRoot,
|
|
2086
|
+
inputRoot,
|
|
2087
|
+
dryRun,
|
|
2088
|
+
logger
|
|
2089
|
+
});
|
|
2090
|
+
const result = ChecksProcessorToolTargetSchema.safeParse(toolTarget);
|
|
2091
|
+
if (!result.success) throw new Error(`Invalid tool target for ChecksProcessor: ${toolTarget}. ${formatError(result.error)}`);
|
|
2092
|
+
this.toolTarget = result.data;
|
|
2093
|
+
this.global = global;
|
|
2094
|
+
this.getFactory = getFactory;
|
|
2095
|
+
}
|
|
2096
|
+
async convertRulesyncFilesToToolFiles(rulesyncFiles) {
|
|
2097
|
+
const rulesyncChecks = rulesyncFiles.filter((file) => file instanceof RulesyncCheck);
|
|
2098
|
+
const factory = this.getFactory(this.toolTarget);
|
|
2099
|
+
return rulesyncChecks.filter((rulesyncCheck) => factory.class.isTargetedByRulesyncCheck(rulesyncCheck)).map((rulesyncCheck) => factory.class.fromRulesyncCheck({
|
|
2100
|
+
outputRoot: this.outputRoot,
|
|
2101
|
+
relativeDirPath: RulesyncCheck.getSettablePaths().relativeDirPath,
|
|
2102
|
+
rulesyncCheck,
|
|
2103
|
+
global: this.global
|
|
2104
|
+
}));
|
|
2105
|
+
}
|
|
2106
|
+
async convertToolFilesToRulesyncFiles(toolFiles) {
|
|
2107
|
+
return toolFiles.filter((file) => file instanceof ToolCheck).map((toolCheck) => toolCheck.toRulesyncCheck());
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Implementation of abstract method from Processor
|
|
2111
|
+
* Load and parse rulesync check files from .rulesync/checks/ directory
|
|
2112
|
+
*/
|
|
2113
|
+
async loadRulesyncFiles() {
|
|
2114
|
+
const checksDir = join(this.inputRoot, RulesyncCheck.getSettablePaths().relativeDirPath);
|
|
2115
|
+
if (!await directoryExists(checksDir)) {
|
|
2116
|
+
this.logger.debug(`Rulesync checks directory not found: ${checksDir}`);
|
|
2117
|
+
return [];
|
|
2118
|
+
}
|
|
2119
|
+
const mdFiles = (await listDirectoryFiles(checksDir)).filter((file) => file.endsWith(".md"));
|
|
2120
|
+
if (mdFiles.length === 0) {
|
|
2121
|
+
this.logger.debug(`No markdown files found in rulesync checks directory: ${checksDir}`);
|
|
2122
|
+
return [];
|
|
2123
|
+
}
|
|
2124
|
+
this.logger.debug(`Found ${mdFiles.length} check files in ${checksDir}`);
|
|
2125
|
+
const rulesyncChecks = [];
|
|
2126
|
+
for (const mdFile of mdFiles) {
|
|
2127
|
+
const filepath = join(checksDir, mdFile);
|
|
2128
|
+
try {
|
|
2129
|
+
const rulesyncCheck = await RulesyncCheck.fromFile({
|
|
2130
|
+
outputRoot: this.inputRoot,
|
|
2131
|
+
relativeFilePath: mdFile,
|
|
2132
|
+
validate: true
|
|
2133
|
+
});
|
|
2134
|
+
rulesyncChecks.push(rulesyncCheck);
|
|
2135
|
+
this.logger.debug(`Successfully loaded check: ${mdFile}`);
|
|
2136
|
+
} catch (error) {
|
|
2137
|
+
this.logger.warn(`Failed to load check file ${filepath}: ${formatError(error)}`);
|
|
2138
|
+
continue;
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
this.logger.debug(`Successfully loaded ${rulesyncChecks.length} rulesync checks`);
|
|
2142
|
+
return rulesyncChecks;
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Implementation of abstract method from Processor
|
|
2146
|
+
* Load tool-specific check files and parse them into ToolCheck instances
|
|
2147
|
+
*/
|
|
2148
|
+
async loadToolFiles({ forDeletion = false } = {}) {
|
|
2149
|
+
const factory = this.getFactory(this.toolTarget);
|
|
2150
|
+
const paths = factory.class.getSettablePaths({ global: this.global });
|
|
2151
|
+
const baseDir = join(this.outputRoot, paths.relativeDirPath);
|
|
2152
|
+
const checkFilePaths = await findFilesByGlobs(join(baseDir, factory.meta.filePattern));
|
|
2153
|
+
const toRelativeFilePath = (path) => relative(baseDir, path);
|
|
2154
|
+
if (forDeletion) return checkFilePaths.map((path) => factory.class.forDeletion({
|
|
2155
|
+
outputRoot: this.outputRoot,
|
|
2156
|
+
relativeDirPath: paths.relativeDirPath,
|
|
2157
|
+
relativeFilePath: toRelativeFilePath(path),
|
|
2158
|
+
global: this.global
|
|
2159
|
+
})).filter((check) => check.isDeletable());
|
|
2160
|
+
const loaded = await Promise.all(checkFilePaths.map((path) => factory.class.fromFile({
|
|
2161
|
+
outputRoot: this.outputRoot,
|
|
2162
|
+
relativeDirPath: paths.relativeDirPath,
|
|
2163
|
+
relativeFilePath: toRelativeFilePath(path),
|
|
2164
|
+
global: this.global
|
|
2165
|
+
})));
|
|
2166
|
+
this.logger.debug(`Successfully loaded ${loaded.length} ${this.toolTarget} checks from ${paths.relativeDirPath}`);
|
|
2167
|
+
return loaded;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Implementation of abstract method from FeatureProcessor
|
|
2171
|
+
* Return the tool targets that this processor supports
|
|
2172
|
+
*/
|
|
2173
|
+
static getToolTargets({ global = false } = {}) {
|
|
2174
|
+
if (global) return [...checksProcessorToolTargetsGlobal];
|
|
2175
|
+
return [...checksProcessorToolTargets];
|
|
2176
|
+
}
|
|
2177
|
+
static getToolTargetsSimulated() {
|
|
2178
|
+
return [];
|
|
2179
|
+
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Get the factory for a specific tool target.
|
|
2182
|
+
* This is a static version of the internal getFactory for external use.
|
|
2183
|
+
* @param target - The tool target. Must be a valid ChecksProcessorToolTarget.
|
|
2184
|
+
* @returns The factory for the target, or undefined if not found.
|
|
2185
|
+
*/
|
|
2186
|
+
static getFactory(target) {
|
|
2187
|
+
const result = ChecksProcessorToolTargetSchema.safeParse(target);
|
|
2188
|
+
if (!result.success) return;
|
|
2189
|
+
return toolCheckFactories.get(result.data);
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
//#endregion
|
|
2193
|
+
//#region src/constants/agentsmd-paths.ts
|
|
2194
|
+
const AGENTSMD_DIR = ".agents";
|
|
2195
|
+
const AGENTSMD_MEMORIES_DIR_PATH = join(AGENTSMD_DIR, "memories");
|
|
2196
|
+
const AGENTSMD_COMMANDS_DIR_PATH = join(AGENTSMD_DIR, "commands");
|
|
2197
|
+
const AGENTSMD_SKILLS_DIR_PATH = join(AGENTSMD_DIR, "skills");
|
|
2198
|
+
const AGENTSMD_SUBAGENTS_DIR_PATH = join(AGENTSMD_DIR, "subagents");
|
|
2199
|
+
const AGENTSMD_RULE_FILE_NAME = "AGENTS.md";
|
|
2200
|
+
//#endregion
|
|
1776
2201
|
//#region src/features/commands/tool-command.ts
|
|
1777
2202
|
/**
|
|
1778
2203
|
* Abstract base class for AI development tool-specific command formats.
|
|
@@ -2020,13 +2445,6 @@ const AntigravityCommandFrontmatterSchema = z.looseObject({
|
|
|
2020
2445
|
...AntigravityWorkflowFrontmatterSchema.shape
|
|
2021
2446
|
});
|
|
2022
2447
|
//#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
2448
|
//#region src/features/commands/rulesync-command.ts
|
|
2031
2449
|
const RulesyncCommandFrontmatterSchema = z.looseObject({
|
|
2032
2450
|
targets: z._default(RulesyncTargetsSchema, ["*"]),
|
|
@@ -2829,6 +3247,7 @@ const COPILOT_HOOKS_DIR_PATH = join(GITHUB_DIR, "hooks");
|
|
|
2829
3247
|
const COPILOT_HOOKS_FILE_NAME = "copilot-hooks.json";
|
|
2830
3248
|
const COPILOT_MCP_DIR = ".vscode";
|
|
2831
3249
|
const COPILOT_MCP_FILE_NAME = "mcp.json";
|
|
3250
|
+
const COPILOT_VSCODE_SETTINGS_FILE_NAME = "settings.json";
|
|
2832
3251
|
const COPILOTCLI_MCP_FILE_NAME = "mcp-config.json";
|
|
2833
3252
|
const COPILOTCLI_PROJECT_MCP_FILE_NAME = "mcp.json";
|
|
2834
3253
|
const COPILOTCLI_AGENTS_DIR_PATH = join(COPILOT_DIR, "agents");
|
|
@@ -3087,135 +3506,118 @@ var CursorCommand = class CursorCommand extends ToolCommand {
|
|
|
3087
3506
|
//#endregion
|
|
3088
3507
|
//#region src/constants/devin-paths.ts
|
|
3089
3508
|
const DEVIN_DIR = ".devin";
|
|
3090
|
-
const CODEIUM_WINDSURF_DIR = join(".codeium", "windsurf");
|
|
3091
|
-
const DEVIN_WORKFLOWS_DIR_PATH = join(DEVIN_DIR, "workflows");
|
|
3092
3509
|
const DEVIN_SKILLS_DIR_PATH = join(DEVIN_DIR, "skills");
|
|
3093
3510
|
const DEVIN_AGENTS_DIR_PATH = join(DEVIN_DIR, "agents");
|
|
3094
3511
|
const DEVIN_GLOBAL_CONFIG_DIR_PATH = join(".config", "devin");
|
|
3095
3512
|
const DEVIN_GLOBAL_AGENTS_DIR_PATH = join(DEVIN_GLOBAL_CONFIG_DIR_PATH, "agents");
|
|
3096
3513
|
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
3514
|
const DEVIN_CONFIG_FILE_NAME = "config.json";
|
|
3099
3515
|
const DEVIN_HOOKS_V1_FILE_NAME = "hooks.v1.json";
|
|
3100
3516
|
const DEVIN_GLOBAL_AGENTS_FILE_NAME = "AGENTS.md";
|
|
3101
3517
|
const DEVIN_IGNORE_FILE_NAME = ".devinignore";
|
|
3102
3518
|
const DEVIN_LEGACY_IGNORE_FILE_NAME = ".codeiumignore";
|
|
3103
3519
|
//#endregion
|
|
3520
|
+
//#region src/constants/general.ts
|
|
3521
|
+
const SKILL_FILE_NAME$1 = "SKILL.md";
|
|
3522
|
+
//#endregion
|
|
3523
|
+
//#region src/features/commands/command-skill-ownership.ts
|
|
3524
|
+
/**
|
|
3525
|
+
* Slug used for the per-command `<slug>/SKILL.md` directory when a tool's
|
|
3526
|
+
* commands are emitted onto its skills surface (Devin, Hermes Agent).
|
|
3527
|
+
*/
|
|
3528
|
+
function commandSlug(relativeFilePath) {
|
|
3529
|
+
return basename(relativeFilePath, ".md").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
3530
|
+
}
|
|
3531
|
+
/**
|
|
3532
|
+
* Whether a rulesync command exists whose slug matches `dirName`.
|
|
3533
|
+
*
|
|
3534
|
+
* Used by the skills-surface `isDirOwned` hooks of tools whose commands are
|
|
3535
|
+
* emitted as `<slug>/SKILL.md` into the skills tree: a directory matching a
|
|
3536
|
+
* current command slug is owned by the commands feature, so the skills
|
|
3537
|
+
* feature must neither import it as a skill nor delete it as an orphan
|
|
3538
|
+
* skill. Once the command is removed from `.rulesync/commands/`, the
|
|
3539
|
+
* directory stops matching and the skills feature cleans it up as a regular
|
|
3540
|
+
* orphan.
|
|
3541
|
+
*/
|
|
3542
|
+
async function rulesyncCommandSlugExists({ inputRoot, dirName }) {
|
|
3543
|
+
return (await findFilesByGlobs(join(inputRoot, RULESYNC_COMMANDS_RELATIVE_DIR_PATH, "**", "*.md"))).some((filePath) => commandSlug(basename(filePath)) === dirName);
|
|
3544
|
+
}
|
|
3545
|
+
//#endregion
|
|
3104
3546
|
//#region src/features/commands/devin-command.ts
|
|
3105
|
-
|
|
3547
|
+
function commandSkillContent$1(rulesyncCommand) {
|
|
3548
|
+
const slug = commandSlug(rulesyncCommand.getRelativeFilePath());
|
|
3549
|
+
const description = rulesyncCommand.getFrontmatter().description ?? `${slug} command`;
|
|
3550
|
+
return stringifyFrontmatter(rulesyncCommand.getBody().trim(), {
|
|
3551
|
+
name: slug,
|
|
3552
|
+
description
|
|
3553
|
+
});
|
|
3554
|
+
}
|
|
3106
3555
|
/**
|
|
3107
|
-
* Represents a Devin
|
|
3108
|
-
*
|
|
3109
|
-
*
|
|
3110
|
-
*
|
|
3111
|
-
*
|
|
3556
|
+
* Represents a Devin slash command, emitted as a Devin Skill.
|
|
3557
|
+
*
|
|
3558
|
+
* Devin's extensibility docs no longer document a standalone
|
|
3559
|
+
* workflows/commands component — reusable prompts invoked as slash commands
|
|
3560
|
+
* are Skills (`/name`). Commands are therefore emitted onto the native skills
|
|
3561
|
+
* surface, one `SKILL.md` per command: `.devin/skills/<slug>/SKILL.md`
|
|
3562
|
+
* (project) and `~/.config/devin/skills/<slug>/SKILL.md` (global). The legacy
|
|
3563
|
+
* Windsurf/Cascade-era `.devin/workflows/` and
|
|
3564
|
+
* `~/.codeium/windsurf/global_workflows/` locations are no longer emitted.
|
|
3565
|
+
*
|
|
3566
|
+
* Import and deletion are intentionally no-ops for this target: the skills
|
|
3567
|
+
* feature owns the `.devin/skills/` tree, so importing it as commands would
|
|
3568
|
+
* double-import every skill (mirrors the Hermes Agent commands target).
|
|
3569
|
+
*
|
|
3570
|
+
* @see https://docs.devin.ai/cli/extensibility
|
|
3571
|
+
* @see https://docs.devin.ai/cli/extensibility/skills/overview
|
|
3112
3572
|
*/
|
|
3113
3573
|
var DevinCommand = class DevinCommand extends ToolCommand {
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
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)
|
|
3574
|
+
static isTargetedByRulesyncCommand(rulesyncCommand) {
|
|
3575
|
+
return this.isTargetedByRulesyncCommandDefault({
|
|
3576
|
+
rulesyncCommand,
|
|
3577
|
+
toolTarget: "devin"
|
|
3124
3578
|
});
|
|
3125
|
-
this.frontmatter = frontmatter;
|
|
3126
|
-
this.body = body;
|
|
3127
3579
|
}
|
|
3128
3580
|
static getSettablePaths({ global = false } = {}) {
|
|
3129
|
-
|
|
3130
|
-
return { relativeDirPath: DEVIN_WORKFLOWS_DIR_PATH };
|
|
3131
|
-
}
|
|
3132
|
-
getBody() {
|
|
3133
|
-
return this.body;
|
|
3581
|
+
return { relativeDirPath: global ? DEVIN_GLOBAL_SKILLS_DIR_PATH : DEVIN_SKILLS_DIR_PATH };
|
|
3134
3582
|
}
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
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
|
|
3583
|
+
constructor({ slug, ...params }) {
|
|
3584
|
+
super({
|
|
3585
|
+
...params,
|
|
3586
|
+
...slug !== void 0 && {
|
|
3587
|
+
relativeDirPath: join(params.relativeDirPath, slug),
|
|
3588
|
+
relativeFilePath: "SKILL.md"
|
|
3589
|
+
}
|
|
3172
3590
|
});
|
|
3173
3591
|
}
|
|
3174
3592
|
validate() {
|
|
3175
|
-
|
|
3176
|
-
success: true,
|
|
3177
|
-
error: null
|
|
3178
|
-
};
|
|
3179
|
-
const result = DevinCommandFrontmatterSchema.safeParse(this.frontmatter);
|
|
3180
|
-
if (result.success) return {
|
|
3593
|
+
return {
|
|
3181
3594
|
success: true,
|
|
3182
3595
|
error: null
|
|
3183
3596
|
};
|
|
3184
|
-
else return {
|
|
3185
|
-
success: false,
|
|
3186
|
-
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${join(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
3187
|
-
};
|
|
3188
3597
|
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3598
|
+
toRulesyncCommand() {
|
|
3599
|
+
const slug = basename(dirname(this.getRelativePathFromCwd()));
|
|
3600
|
+
const { frontmatter, body } = parseFrontmatter(this.getFileContent(), this.getFilePath());
|
|
3601
|
+
const description = typeof frontmatter.description === "string" ? frontmatter.description : void 0;
|
|
3602
|
+
return new RulesyncCommand({
|
|
3603
|
+
relativeDirPath: RULESYNC_COMMANDS_RELATIVE_DIR_PATH,
|
|
3604
|
+
relativeFilePath: `${slug}.md`,
|
|
3605
|
+
frontmatter: { description },
|
|
3606
|
+
body: body.trimStart()
|
|
3193
3607
|
});
|
|
3194
3608
|
}
|
|
3195
|
-
static
|
|
3196
|
-
const paths =
|
|
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)}`);
|
|
3609
|
+
static fromRulesyncCommand({ outputRoot, rulesyncCommand, global = false }) {
|
|
3610
|
+
const paths = DevinCommand.getSettablePaths({ global });
|
|
3201
3611
|
return new DevinCommand({
|
|
3202
3612
|
outputRoot,
|
|
3203
3613
|
relativeDirPath: paths.relativeDirPath,
|
|
3204
|
-
relativeFilePath,
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
validate
|
|
3614
|
+
relativeFilePath: SKILL_FILE_NAME$1,
|
|
3615
|
+
slug: commandSlug(rulesyncCommand.getRelativeFilePath()),
|
|
3616
|
+
fileContent: commandSkillContent$1(rulesyncCommand)
|
|
3208
3617
|
});
|
|
3209
3618
|
}
|
|
3210
|
-
|
|
3211
|
-
return
|
|
3212
|
-
outputRoot,
|
|
3213
|
-
relativeDirPath,
|
|
3214
|
-
relativeFilePath,
|
|
3215
|
-
frontmatter: { description: "" },
|
|
3216
|
-
body: "",
|
|
3217
|
-
validate: false
|
|
3218
|
-
});
|
|
3619
|
+
getFileContent() {
|
|
3620
|
+
return this.fileContent;
|
|
3219
3621
|
}
|
|
3220
3622
|
};
|
|
3221
3623
|
//#endregion
|
|
@@ -3543,10 +3945,7 @@ const HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_MANIFEST_PATH = join(HERMESAGENT_RUL
|
|
|
3543
3945
|
const HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_INIT_PATH = join(HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_DIR_PATH, "__init__.py");
|
|
3544
3946
|
//#endregion
|
|
3545
3947
|
//#region src/features/commands/hermesagent-command.ts
|
|
3546
|
-
const SKILL_FILE_NAME
|
|
3547
|
-
function commandSlug(relativeFilePath) {
|
|
3548
|
-
return basename(relativeFilePath, ".md").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
3549
|
-
}
|
|
3948
|
+
const SKILL_FILE_NAME = "SKILL.md";
|
|
3550
3949
|
function commandSkillContent(rulesyncCommand) {
|
|
3551
3950
|
const slug = commandSlug(rulesyncCommand.getRelativeFilePath());
|
|
3552
3951
|
const description = rulesyncCommand.getFrontmatter().description ?? `${slug} command`;
|
|
@@ -3563,7 +3962,7 @@ var HermesagentCommand = class HermesagentCommand extends ToolCommand {
|
|
|
3563
3962
|
static getSettablePaths({ slug = "command" } = {}) {
|
|
3564
3963
|
return {
|
|
3565
3964
|
relativeDirPath: join(HERMESAGENT_SKILLS_DIR_PATH, slug),
|
|
3566
|
-
relativeFilePath: SKILL_FILE_NAME
|
|
3965
|
+
relativeFilePath: SKILL_FILE_NAME
|
|
3567
3966
|
};
|
|
3568
3967
|
}
|
|
3569
3968
|
constructor({ slug, ...params }) {
|
|
@@ -3594,7 +3993,7 @@ var HermesagentCommand = class HermesagentCommand extends ToolCommand {
|
|
|
3594
3993
|
return new HermesagentCommand({
|
|
3595
3994
|
outputRoot,
|
|
3596
3995
|
relativeDirPath: "",
|
|
3597
|
-
relativeFilePath: SKILL_FILE_NAME
|
|
3996
|
+
relativeFilePath: SKILL_FILE_NAME,
|
|
3598
3997
|
slug: commandSlug(rulesyncCommand.getRelativeFilePath()),
|
|
3599
3998
|
fileContent: commandSkillContent(rulesyncCommand)
|
|
3600
3999
|
});
|
|
@@ -4254,6 +4653,15 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
4254
4653
|
}
|
|
4255
4654
|
}
|
|
4256
4655
|
},
|
|
4656
|
+
".vscode/settings.json": {
|
|
4657
|
+
format: "jsonc",
|
|
4658
|
+
invalidRootPolicy: "error",
|
|
4659
|
+
jsoncParseErrors: "error",
|
|
4660
|
+
features: { permissions: {
|
|
4661
|
+
kind: "replace-owned-keys",
|
|
4662
|
+
ownedKeys: ["chat.tools.terminal.autoApprove"]
|
|
4663
|
+
} }
|
|
4664
|
+
},
|
|
4257
4665
|
".qwen/settings.json": {
|
|
4258
4666
|
format: "json",
|
|
4259
4667
|
features: {
|
|
@@ -4829,6 +5237,7 @@ const PI_AGENT_SKILLS_DIR_PATH = join(PI_AGENT_DIR, "skills");
|
|
|
4829
5237
|
const PI_PROMPTS_DIR_PATH = join(".pi", "prompts");
|
|
4830
5238
|
const PI_SKILLS_DIR_PATH = join(".pi", "skills");
|
|
4831
5239
|
const PI_RULE_FILE_NAME = "AGENTS.md";
|
|
5240
|
+
const PI_APPEND_SYSTEM_FILE_NAME = "APPEND_SYSTEM.md";
|
|
4832
5241
|
//#endregion
|
|
4833
5242
|
//#region src/features/commands/pi-command.ts
|
|
4834
5243
|
/**
|
|
@@ -5363,9 +5772,6 @@ const ROVODEV_AGENTS_SKILLS_DIR_PATH = join(".agents", "skills");
|
|
|
5363
5772
|
const ROVODEV_PROMPTS_FILE_NAME = "prompts.yml";
|
|
5364
5773
|
const ROVODEV_PROMPTS_DIR_PATH = join(ROVODEV_DIR, "prompts");
|
|
5365
5774
|
//#endregion
|
|
5366
|
-
//#region src/types/tool-file.ts
|
|
5367
|
-
var ToolFile = class extends AiFile {};
|
|
5368
|
-
//#endregion
|
|
5369
5775
|
//#region src/features/commands/rovodev-command.ts
|
|
5370
5776
|
/**
|
|
5371
5777
|
* Rovo Dev CLI "saved prompts": a file-based custom-command surface made of a
|
|
@@ -5854,7 +6260,8 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
|
|
|
5854
6260
|
supportsProject: false,
|
|
5855
6261
|
supportsGlobal: true,
|
|
5856
6262
|
isSimulated: false,
|
|
5857
|
-
supportsSubdirectory: true
|
|
6263
|
+
supportsSubdirectory: true,
|
|
6264
|
+
skipToolFileScan: true
|
|
5858
6265
|
}
|
|
5859
6266
|
}],
|
|
5860
6267
|
["junie", {
|
|
@@ -5984,7 +6391,8 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
|
|
|
5984
6391
|
supportsProject: true,
|
|
5985
6392
|
supportsGlobal: true,
|
|
5986
6393
|
isSimulated: false,
|
|
5987
|
-
supportsSubdirectory: false
|
|
6394
|
+
supportsSubdirectory: false,
|
|
6395
|
+
skipToolFileScan: true
|
|
5988
6396
|
}
|
|
5989
6397
|
}]
|
|
5990
6398
|
]);
|
|
@@ -6087,6 +6495,7 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
6087
6495
|
*/
|
|
6088
6496
|
async loadToolFiles({ forDeletion = false } = {}) {
|
|
6089
6497
|
const factory = this.getFactory(this.toolTarget);
|
|
6498
|
+
if (factory.meta.skipToolFileScan) return [];
|
|
6090
6499
|
const paths = factory.class.getSettablePaths({ global: this.global });
|
|
6091
6500
|
const outputRootFull = join(this.outputRoot, paths.relativeDirPath);
|
|
6092
6501
|
const commandFilePaths = await findFilesByGlobs(factory.meta.supportsSubdirectory ? join(outputRootFull, "**", `*.${factory.meta.extension}`) : join(outputRootFull, `*.${factory.meta.extension}`));
|
|
@@ -6196,7 +6605,10 @@ const HookDefinitionSchema = z.looseObject({
|
|
|
6196
6605
|
type: z.optional(z.enum([
|
|
6197
6606
|
"command",
|
|
6198
6607
|
"prompt",
|
|
6199
|
-
"http"
|
|
6608
|
+
"http",
|
|
6609
|
+
"agent",
|
|
6610
|
+
"mcp_tool",
|
|
6611
|
+
"function"
|
|
6200
6612
|
])),
|
|
6201
6613
|
url: z.optional(safeString),
|
|
6202
6614
|
timeout: z.optional(z.number()),
|
|
@@ -6209,12 +6621,72 @@ const HookDefinitionSchema = z.looseObject({
|
|
|
6209
6621
|
sequential: z.optional(z.boolean()),
|
|
6210
6622
|
async: z.optional(z.boolean()),
|
|
6211
6623
|
env: z.optional(z.record(z.string(), safeString)),
|
|
6212
|
-
shell: z.optional(
|
|
6624
|
+
shell: z.optional(z.enum(["bash", "powershell"])),
|
|
6213
6625
|
statusMessage: z.optional(safeString),
|
|
6214
6626
|
headers: z.optional(z.record(z.string(), safeString)),
|
|
6215
6627
|
allowedEnvVars: z.optional(z.array(z.string())),
|
|
6216
|
-
once: z.optional(z.boolean())
|
|
6628
|
+
once: z.optional(z.boolean()),
|
|
6629
|
+
server: z.optional(safeString),
|
|
6630
|
+
tool: z.optional(safeString),
|
|
6631
|
+
input: z.optional(z.looseObject({})),
|
|
6632
|
+
model: z.optional(safeString),
|
|
6633
|
+
if: z.optional(safeString)
|
|
6217
6634
|
});
|
|
6635
|
+
/**
|
|
6636
|
+
* All canonical hook event names.
|
|
6637
|
+
* Each tool supports a subset of these events.
|
|
6638
|
+
*/
|
|
6639
|
+
const HOOK_EVENTS = [
|
|
6640
|
+
"sessionStart",
|
|
6641
|
+
"sessionEnd",
|
|
6642
|
+
"preToolUse",
|
|
6643
|
+
"postToolUse",
|
|
6644
|
+
"preModelInvocation",
|
|
6645
|
+
"postModelInvocation",
|
|
6646
|
+
"beforeSubmitPrompt",
|
|
6647
|
+
"stop",
|
|
6648
|
+
"subagentStop",
|
|
6649
|
+
"preCompact",
|
|
6650
|
+
"postCompact",
|
|
6651
|
+
"contextOffload",
|
|
6652
|
+
"postToolUseFailure",
|
|
6653
|
+
"subagentStart",
|
|
6654
|
+
"beforeShellExecution",
|
|
6655
|
+
"afterShellExecution",
|
|
6656
|
+
"beforeMCPExecution",
|
|
6657
|
+
"afterMCPExecution",
|
|
6658
|
+
"beforeReadFile",
|
|
6659
|
+
"afterFileEdit",
|
|
6660
|
+
"beforeAgentResponse",
|
|
6661
|
+
"afterAgentResponse",
|
|
6662
|
+
"afterAgentThought",
|
|
6663
|
+
"beforeTabFileRead",
|
|
6664
|
+
"afterTabFileEdit",
|
|
6665
|
+
"permissionRequest",
|
|
6666
|
+
"notification",
|
|
6667
|
+
"setup",
|
|
6668
|
+
"afterError",
|
|
6669
|
+
"beforeToolSelection",
|
|
6670
|
+
"worktreeCreate",
|
|
6671
|
+
"worktreeRemove",
|
|
6672
|
+
"workspaceOpen",
|
|
6673
|
+
"messageDisplay",
|
|
6674
|
+
"todoCreated",
|
|
6675
|
+
"todoCompleted",
|
|
6676
|
+
"stopFailure",
|
|
6677
|
+
"instructionsLoaded",
|
|
6678
|
+
"userPromptExpansion",
|
|
6679
|
+
"postToolBatch",
|
|
6680
|
+
"permissionDenied",
|
|
6681
|
+
"taskCreated",
|
|
6682
|
+
"taskCompleted",
|
|
6683
|
+
"teammateIdle",
|
|
6684
|
+
"configChange",
|
|
6685
|
+
"cwdChanged",
|
|
6686
|
+
"fileChanged",
|
|
6687
|
+
"elicitation",
|
|
6688
|
+
"elicitationResult"
|
|
6689
|
+
];
|
|
6218
6690
|
/** Hook events supported by Cursor. */
|
|
6219
6691
|
const CURSOR_HOOK_EVENTS = [
|
|
6220
6692
|
"sessionStart",
|
|
@@ -6689,12 +7161,28 @@ const CANONICAL_TO_HERMESAGENT_EVENT_NAMES = {
|
|
|
6689
7161
|
*/
|
|
6690
7162
|
const HERMESAGENT_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_HERMESAGENT_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
6691
7163
|
const hooksRecordSchema = z.record(z.string(), z.array(HookDefinitionSchema));
|
|
7164
|
+
const HOOK_EVENT_SET = new Set(HOOK_EVENTS);
|
|
7165
|
+
/** Whether `value` is a canonical hook event name. */
|
|
7166
|
+
const isHookEvent = (value) => HOOK_EVENT_SET.has(value);
|
|
7167
|
+
/**
|
|
7168
|
+
* Top-level `hooks` record whose keys must be canonical event names, so typos
|
|
7169
|
+
* are rejected at parse time. Keys are validated with a refinement (instead of
|
|
7170
|
+
* an enum key schema) to keep the inferred type a plain string record.
|
|
7171
|
+
*
|
|
7172
|
+
* The per-tool override blocks below deliberately keep the lenient
|
|
7173
|
+
* `hooksRecordSchema`: some are documented to pass tool-native event keys
|
|
7174
|
+
* through verbatim (e.g. kiro-ide's IDE-only `PostFileSave`/`PreTaskExec`
|
|
7175
|
+
* triggers), which the canonical enum would reject.
|
|
7176
|
+
*/
|
|
7177
|
+
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) => {
|
|
7178
|
+
return `unknown hook event name(s): ${Object.keys(issue.input ?? {}).filter((key) => !HOOK_EVENT_SET.has(key)).join(", ")}`;
|
|
7179
|
+
} }));
|
|
6692
7180
|
/**
|
|
6693
7181
|
* Canonical hooks config (canonical event names in camelCase).
|
|
6694
7182
|
*/
|
|
6695
7183
|
const HooksConfigSchema = z.looseObject({
|
|
6696
7184
|
version: z.optional(z.number()),
|
|
6697
|
-
hooks:
|
|
7185
|
+
hooks: canonicalHooksRecordSchema,
|
|
6698
7186
|
cursor: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6699
7187
|
claudecode: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6700
7188
|
copilot: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
@@ -7131,6 +7619,20 @@ const CANONICAL_TO_GROKCLI_EVENT_NAMES = {
|
|
|
7131
7619
|
*/
|
|
7132
7620
|
const GROKCLI_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_GROKCLI_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
7133
7621
|
//#endregion
|
|
7622
|
+
//#region src/utils/object.ts
|
|
7623
|
+
/**
|
|
7624
|
+
* Return a shallow copy of `obj` keeping only the entries whose value is
|
|
7625
|
+
* neither `undefined` nor `null`.
|
|
7626
|
+
*
|
|
7627
|
+
* Used to assemble generated config objects without one conditional spread per
|
|
7628
|
+
* optional field (which would otherwise exceed the lint complexity budget).
|
|
7629
|
+
*/
|
|
7630
|
+
function compact(obj) {
|
|
7631
|
+
const result = {};
|
|
7632
|
+
for (const [key, value] of Object.entries(obj)) if (value !== void 0 && value !== null) result[key] = value;
|
|
7633
|
+
return result;
|
|
7634
|
+
}
|
|
7635
|
+
//#endregion
|
|
7134
7636
|
//#region src/features/hooks/tool-hooks-converter.ts
|
|
7135
7637
|
function isToolMatcherEntry(x) {
|
|
7136
7638
|
if (x === null || typeof x !== "object") return false;
|
|
@@ -7188,6 +7690,41 @@ function importBooleanPassthroughFields({ h, converterConfig }) {
|
|
|
7188
7690
|
return Object.fromEntries((converterConfig.booleanPassthroughFields ?? []).filter(({ tool }) => typeof h[tool] === "boolean").map(({ canonical, tool }) => [canonical, h[tool]]));
|
|
7189
7691
|
}
|
|
7190
7692
|
/**
|
|
7693
|
+
* Emit the configured string passthrough fields on the tool side, mapping each
|
|
7694
|
+
* canonical field name to its (possibly renamed) tool field name. Only non-empty
|
|
7695
|
+
* string values are carried through.
|
|
7696
|
+
*/
|
|
7697
|
+
function emitStringPassthroughFields({ def, converterConfig }) {
|
|
7698
|
+
return Object.fromEntries((converterConfig.stringPassthroughFields ?? []).filter(({ canonical }) => typeof def[canonical] === "string" && def[canonical] !== "").map(({ canonical, tool }) => [tool, def[canonical]]));
|
|
7699
|
+
}
|
|
7700
|
+
/**
|
|
7701
|
+
* Import the configured string passthrough fields back into canonical fields,
|
|
7702
|
+
* reversing {@link emitStringPassthroughFields}. Only non-empty string values
|
|
7703
|
+
* are read.
|
|
7704
|
+
*/
|
|
7705
|
+
function importStringPassthroughFields({ h, converterConfig }) {
|
|
7706
|
+
return Object.fromEntries((converterConfig.stringPassthroughFields ?? []).filter(({ tool }) => typeof h[tool] === "string" && h[tool] !== "").map(({ canonical, tool }) => [canonical, h[tool]]));
|
|
7707
|
+
}
|
|
7708
|
+
/**
|
|
7709
|
+
* Emit the payload fields specific to a hook type — `url`/`headers`/
|
|
7710
|
+
* `allowedEnvVars` for http, `server`/`tool`/`input` for mcp_tool, `model`
|
|
7711
|
+
* for prompt/agent. https://code.claude.com/docs/en/hooks
|
|
7712
|
+
*/
|
|
7713
|
+
function emitTypePayloadFields({ def, hookType, converterConfig }) {
|
|
7714
|
+
if (hookType === "http") return compact({
|
|
7715
|
+
url: def.url,
|
|
7716
|
+
headers: def.headers,
|
|
7717
|
+
allowedEnvVars: def.allowedEnvVars
|
|
7718
|
+
});
|
|
7719
|
+
if (hookType === "mcp_tool") return compact({
|
|
7720
|
+
server: def.server,
|
|
7721
|
+
tool: def.tool,
|
|
7722
|
+
input: def.input
|
|
7723
|
+
});
|
|
7724
|
+
if ((hookType === "prompt" || hookType === "agent") && converterConfig.emitsPromptModel) return compact({ model: def.model });
|
|
7725
|
+
return {};
|
|
7726
|
+
}
|
|
7727
|
+
/**
|
|
7191
7728
|
* Convert the definitions of a single matcher group into tool hook entries,
|
|
7192
7729
|
* honoring supported hook types and passthrough fields.
|
|
7193
7730
|
*/
|
|
@@ -7205,10 +7742,19 @@ function buildToolHooks({ defs, converterConfig }) {
|
|
|
7205
7742
|
def,
|
|
7206
7743
|
converterConfig
|
|
7207
7744
|
}),
|
|
7745
|
+
...emitStringPassthroughFields({
|
|
7746
|
+
def,
|
|
7747
|
+
converterConfig
|
|
7748
|
+
}),
|
|
7208
7749
|
type: hookType,
|
|
7209
7750
|
...command !== void 0 && command !== null && { command },
|
|
7210
7751
|
...def.timeout !== void 0 && def.timeout !== null && { timeout: def.timeout },
|
|
7211
7752
|
...def.prompt !== void 0 && def.prompt !== null && { prompt: def.prompt },
|
|
7753
|
+
...emitTypePayloadFields({
|
|
7754
|
+
def,
|
|
7755
|
+
hookType,
|
|
7756
|
+
converterConfig
|
|
7757
|
+
}),
|
|
7212
7758
|
...converterConfig.passthroughFields?.includes("name") && def.name !== void 0 && def.name !== null && { name: def.name },
|
|
7213
7759
|
...converterConfig.passthroughFields?.includes("description") && def.description !== void 0 && def.description !== null && { description: def.description }
|
|
7214
7760
|
});
|
|
@@ -7275,6 +7821,46 @@ function stripCommandPrefix({ command, converterConfig }) {
|
|
|
7275
7821
|
return cmd;
|
|
7276
7822
|
}
|
|
7277
7823
|
/**
|
|
7824
|
+
* Hook types preserved verbatim on import — Claude Code's five documented
|
|
7825
|
+
* handler types. Anything else is coerced to `command` as before.
|
|
7826
|
+
* https://code.claude.com/docs/en/hooks
|
|
7827
|
+
*/
|
|
7828
|
+
const IMPORTED_HOOK_TYPES = /* @__PURE__ */ new Set([
|
|
7829
|
+
"command",
|
|
7830
|
+
"prompt",
|
|
7831
|
+
"http",
|
|
7832
|
+
"mcp_tool",
|
|
7833
|
+
"agent"
|
|
7834
|
+
]);
|
|
7835
|
+
function isImportedHookType(value) {
|
|
7836
|
+
return typeof value === "string" && IMPORTED_HOOK_TYPES.has(value);
|
|
7837
|
+
}
|
|
7838
|
+
function isStringRecord(value) {
|
|
7839
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7840
|
+
return Object.values(value).every((v) => typeof v === "string");
|
|
7841
|
+
}
|
|
7842
|
+
function isStringArray(value) {
|
|
7843
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
7844
|
+
}
|
|
7845
|
+
/**
|
|
7846
|
+
* Import the payload fields specific to a hook type, type-checking each raw
|
|
7847
|
+
* value before it enters the canonical definition.
|
|
7848
|
+
*/
|
|
7849
|
+
function importTypePayloadFields({ h, hookType }) {
|
|
7850
|
+
if (hookType === "http") return {
|
|
7851
|
+
...typeof h.url === "string" && { url: h.url },
|
|
7852
|
+
...isStringRecord(h.headers) && { headers: h.headers },
|
|
7853
|
+
...isStringArray(h.allowedEnvVars) && { allowedEnvVars: h.allowedEnvVars }
|
|
7854
|
+
};
|
|
7855
|
+
if (hookType === "mcp_tool") return {
|
|
7856
|
+
...typeof h.server === "string" && { server: h.server },
|
|
7857
|
+
...typeof h.tool === "string" && { tool: h.tool },
|
|
7858
|
+
...h.input !== null && typeof h.input === "object" && !Array.isArray(h.input) && { input: h.input }
|
|
7859
|
+
};
|
|
7860
|
+
if (hookType === "prompt" || hookType === "agent") return typeof h.model === "string" ? { model: h.model } : {};
|
|
7861
|
+
return {};
|
|
7862
|
+
}
|
|
7863
|
+
/**
|
|
7278
7864
|
* Convert a single tool hook record into a canonical hook definition.
|
|
7279
7865
|
*/
|
|
7280
7866
|
function toolHookToCanonical({ h, rawEntry, converterConfig }) {
|
|
@@ -7282,7 +7868,7 @@ function toolHookToCanonical({ h, rawEntry, converterConfig }) {
|
|
|
7282
7868
|
command: h.command,
|
|
7283
7869
|
converterConfig
|
|
7284
7870
|
});
|
|
7285
|
-
const hookType = h.type
|
|
7871
|
+
const hookType = isImportedHookType(h.type) ? h.type : "command";
|
|
7286
7872
|
const timeout = typeof h.timeout === "number" ? h.timeout : void 0;
|
|
7287
7873
|
const prompt = typeof h.prompt === "string" ? h.prompt : void 0;
|
|
7288
7874
|
return {
|
|
@@ -7290,12 +7876,20 @@ function toolHookToCanonical({ h, rawEntry, converterConfig }) {
|
|
|
7290
7876
|
...command !== void 0 && command !== null && { command },
|
|
7291
7877
|
...timeout !== void 0 && timeout !== null && { timeout },
|
|
7292
7878
|
...prompt !== void 0 && prompt !== null && { prompt },
|
|
7879
|
+
...importTypePayloadFields({
|
|
7880
|
+
h,
|
|
7881
|
+
hookType
|
|
7882
|
+
}),
|
|
7293
7883
|
...converterConfig.passthroughFields?.includes("name") && typeof h.name === "string" && { name: h.name },
|
|
7294
7884
|
...converterConfig.passthroughFields?.includes("description") && typeof h.description === "string" && { description: h.description },
|
|
7295
7885
|
...importBooleanPassthroughFields({
|
|
7296
7886
|
h,
|
|
7297
7887
|
converterConfig
|
|
7298
7888
|
}),
|
|
7889
|
+
...importStringPassthroughFields({
|
|
7890
|
+
h,
|
|
7891
|
+
converterConfig
|
|
7892
|
+
}),
|
|
7299
7893
|
...rawEntry.matcher !== void 0 && rawEntry.matcher !== null && rawEntry.matcher !== "" && { matcher: rawEntry.matcher }
|
|
7300
7894
|
};
|
|
7301
7895
|
}
|
|
@@ -7309,6 +7903,32 @@ function toolMatcherEntryToCanonical({ rawEntry, converterConfig }) {
|
|
|
7309
7903
|
converterConfig
|
|
7310
7904
|
}));
|
|
7311
7905
|
}
|
|
7906
|
+
/**
|
|
7907
|
+
* Assemble the canonical hooks config a tool importer writes to
|
|
7908
|
+
* `.rulesync/hooks.json`.
|
|
7909
|
+
*
|
|
7910
|
+
* The top-level `hooks` record only accepts canonical event names, so any
|
|
7911
|
+
* imported native event key without a canonical mapping is moved under the
|
|
7912
|
+
* importing tool's own override block (`<overrideKey>.hooks`), whose keys stay
|
|
7913
|
+
* lenient. This mirrors the generate direction — override blocks pass
|
|
7914
|
+
* tool-native keys through verbatim — so documented native triggers (e.g.
|
|
7915
|
+
* kiro-ide's `PostFileSave`) survive an import → generate round-trip instead
|
|
7916
|
+
* of failing canonical validation.
|
|
7917
|
+
*/
|
|
7918
|
+
function buildImportedHooksConfig({ hooks, overrideKey, version = 1, extraOverride }) {
|
|
7919
|
+
const canonical = {};
|
|
7920
|
+
const native = {};
|
|
7921
|
+
for (const [event, defs] of Object.entries(hooks)) if (isHookEvent(event)) canonical[event] = defs;
|
|
7922
|
+
else native[event] = defs;
|
|
7923
|
+
const override = { ...extraOverride };
|
|
7924
|
+
if (Object.keys(native).length > 0) override.hooks = native;
|
|
7925
|
+
const config = {
|
|
7926
|
+
version,
|
|
7927
|
+
hooks: canonical
|
|
7928
|
+
};
|
|
7929
|
+
if (Object.keys(override).length > 0) config[overrideKey] = override;
|
|
7930
|
+
return config;
|
|
7931
|
+
}
|
|
7312
7932
|
function toolHooksToCanonical({ hooks, converterConfig }) {
|
|
7313
7933
|
if (hooks === null || hooks === void 0 || typeof hooks !== "object") return {};
|
|
7314
7934
|
const canonical = {};
|
|
@@ -7479,7 +8099,8 @@ const ANTIGRAVITY_CONVERTER_CONFIG = {
|
|
|
7479
8099
|
"preModelInvocation",
|
|
7480
8100
|
"postModelInvocation",
|
|
7481
8101
|
"stop"
|
|
7482
|
-
])
|
|
8102
|
+
]),
|
|
8103
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command"])
|
|
7483
8104
|
};
|
|
7484
8105
|
/**
|
|
7485
8106
|
* Antigravity's `hooks.json` is keyed by a named hook whose value holds the
|
|
@@ -7586,10 +8207,11 @@ var AntigravityHooks = class extends ToolHooks {
|
|
|
7586
8207
|
hooks: flattenAntigravityHooks(parsed),
|
|
7587
8208
|
converterConfig: ANTIGRAVITY_CONVERTER_CONFIG
|
|
7588
8209
|
});
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
hooks
|
|
7592
|
-
|
|
8210
|
+
const overrideKey = this.constructor.getOverrideKey();
|
|
8211
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
8212
|
+
hooks,
|
|
8213
|
+
overrideKey
|
|
8214
|
+
}), null, 2) });
|
|
7593
8215
|
}
|
|
7594
8216
|
validate() {
|
|
7595
8217
|
return {
|
|
@@ -7710,7 +8332,8 @@ const AUGMENTCODE_CONVERTER_CONFIG = {
|
|
|
7710
8332
|
"sessionEnd",
|
|
7711
8333
|
"stop",
|
|
7712
8334
|
"notification"
|
|
7713
|
-
])
|
|
8335
|
+
]),
|
|
8336
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command"])
|
|
7714
8337
|
};
|
|
7715
8338
|
/**
|
|
7716
8339
|
* AugmentCode (Auggie CLI) lifecycle hooks.
|
|
@@ -7792,10 +8415,10 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
7792
8415
|
hooks: settings.hooks,
|
|
7793
8416
|
converterConfig: AUGMENTCODE_CONVERTER_CONFIG
|
|
7794
8417
|
});
|
|
7795
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
}, null, 2) });
|
|
8418
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
8419
|
+
hooks,
|
|
8420
|
+
overrideKey: "augmentcode"
|
|
8421
|
+
}), null, 2) });
|
|
7799
8422
|
}
|
|
7800
8423
|
validate() {
|
|
7801
8424
|
return {
|
|
@@ -7830,7 +8453,19 @@ const CLAUDE_CONVERTER_CONFIG = {
|
|
|
7830
8453
|
"taskCompleted",
|
|
7831
8454
|
"teammateIdle",
|
|
7832
8455
|
"cwdChanged"
|
|
7833
|
-
])
|
|
8456
|
+
]),
|
|
8457
|
+
supportedHookTypes: /* @__PURE__ */ new Set([
|
|
8458
|
+
"command",
|
|
8459
|
+
"prompt",
|
|
8460
|
+
"http",
|
|
8461
|
+
"mcp_tool",
|
|
8462
|
+
"agent"
|
|
8463
|
+
]),
|
|
8464
|
+
emitsPromptModel: true,
|
|
8465
|
+
stringPassthroughFields: [{
|
|
8466
|
+
canonical: "if",
|
|
8467
|
+
tool: "if"
|
|
8468
|
+
}]
|
|
7834
8469
|
};
|
|
7835
8470
|
var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
|
|
7836
8471
|
constructor(params) {
|
|
@@ -7895,10 +8530,10 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
|
|
|
7895
8530
|
hooks: settings.hooks,
|
|
7896
8531
|
converterConfig: CLAUDE_CONVERTER_CONFIG
|
|
7897
8532
|
});
|
|
7898
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
}, null, 2) });
|
|
8533
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
8534
|
+
hooks,
|
|
8535
|
+
overrideKey: "claudecode"
|
|
8536
|
+
}), null, 2) });
|
|
7902
8537
|
}
|
|
7903
8538
|
validate() {
|
|
7904
8539
|
return {
|
|
@@ -8041,10 +8676,10 @@ var CodexcliHooks = class CodexcliHooks extends ToolHooks {
|
|
|
8041
8676
|
hooks: parsed.hooks,
|
|
8042
8677
|
converterConfig: CODEXCLI_CONVERTER_CONFIG
|
|
8043
8678
|
});
|
|
8044
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
}, null, 2) });
|
|
8679
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
8680
|
+
hooks,
|
|
8681
|
+
overrideKey: "codexcli"
|
|
8682
|
+
}), null, 2) });
|
|
8048
8683
|
}
|
|
8049
8684
|
validate() {
|
|
8050
8685
|
return {
|
|
@@ -8212,10 +8847,10 @@ var CopilotHooks = class CopilotHooks extends ToolHooks {
|
|
|
8212
8847
|
throw new Error(`Failed to parse Copilot hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
8213
8848
|
}
|
|
8214
8849
|
const hooks = copilotHooksToCanonical(parsed.hooks, options?.logger);
|
|
8215
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
}, null, 2) });
|
|
8850
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
8851
|
+
hooks,
|
|
8852
|
+
overrideKey: "copilot"
|
|
8853
|
+
}), null, 2) });
|
|
8219
8854
|
}
|
|
8220
8855
|
validate() {
|
|
8221
8856
|
return {
|
|
@@ -8234,20 +8869,6 @@ var CopilotHooks = class CopilotHooks extends ToolHooks {
|
|
|
8234
8869
|
}
|
|
8235
8870
|
};
|
|
8236
8871
|
//#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
8872
|
//#region src/features/hooks/copilotcli-hooks.ts
|
|
8252
8873
|
/**
|
|
8253
8874
|
* GitHub Copilot CLI hooks.
|
|
@@ -8380,7 +9001,7 @@ function buildCopilotCliEntriesForEvent({ eventName, definitions, canonicalSchem
|
|
|
8380
9001
|
...timeoutPart,
|
|
8381
9002
|
...rest
|
|
8382
9003
|
});
|
|
8383
|
-
else entries.push({
|
|
9004
|
+
else if (hookType === "command") entries.push({
|
|
8384
9005
|
type: "command",
|
|
8385
9006
|
...matcherPart,
|
|
8386
9007
|
...compact({
|
|
@@ -8532,10 +9153,10 @@ var CopilotcliHooks = class CopilotcliHooks extends ToolHooks {
|
|
|
8532
9153
|
throw new Error(`Failed to parse Copilot CLI hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
8533
9154
|
}
|
|
8534
9155
|
const hooks = copilotCliHooksToCanonical(parsed.hooks, options?.logger);
|
|
8535
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
}, null, 2) });
|
|
9156
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9157
|
+
hooks,
|
|
9158
|
+
overrideKey: "copilotcli"
|
|
9159
|
+
}), null, 2) });
|
|
8539
9160
|
}
|
|
8540
9161
|
validate() {
|
|
8541
9162
|
return {
|
|
@@ -8590,9 +9211,10 @@ var CursorHooks = class CursorHooks extends ToolHooks {
|
|
|
8590
9211
|
...config.cursor?.hooks
|
|
8591
9212
|
};
|
|
8592
9213
|
const mappedHooks = {};
|
|
9214
|
+
const cursorSupportedTypes = /* @__PURE__ */ new Set(["command", "prompt"]);
|
|
8593
9215
|
for (const [eventName, defs] of Object.entries(mergedHooks)) {
|
|
8594
9216
|
const cursorEventName = CANONICAL_TO_CURSOR_EVENT_NAMES[eventName] ?? eventName;
|
|
8595
|
-
|
|
9217
|
+
const mappedDefs = defs.filter((def) => cursorSupportedTypes.has(def.type ?? "command")).map((def) => ({
|
|
8596
9218
|
...def.type !== void 0 && def.type !== null && { type: def.type },
|
|
8597
9219
|
...def.command !== void 0 && def.command !== null && { command: def.command },
|
|
8598
9220
|
...def.timeout !== void 0 && def.timeout !== null && { timeout: def.timeout },
|
|
@@ -8601,6 +9223,7 @@ var CursorHooks = class CursorHooks extends ToolHooks {
|
|
|
8601
9223
|
...def.prompt !== void 0 && def.prompt !== null && { prompt: def.prompt },
|
|
8602
9224
|
...def.failClosed !== void 0 && def.failClosed !== null && { failClosed: def.failClosed }
|
|
8603
9225
|
}));
|
|
9226
|
+
if (mappedDefs.length > 0) mappedHooks[cursorEventName] = mappedDefs;
|
|
8604
9227
|
}
|
|
8605
9228
|
const cursorConfig = {
|
|
8606
9229
|
version: config.version ?? 1,
|
|
@@ -8627,10 +9250,11 @@ var CursorHooks = class CursorHooks extends ToolHooks {
|
|
|
8627
9250
|
canonicalHooks[eventName] = defs;
|
|
8628
9251
|
}
|
|
8629
9252
|
const version = parsed.version ?? 1;
|
|
8630
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
9253
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9254
|
+
hooks: canonicalHooks,
|
|
9255
|
+
overrideKey: "cursor",
|
|
9256
|
+
version
|
|
9257
|
+
}), null, 2) });
|
|
8634
9258
|
}
|
|
8635
9259
|
validate() {
|
|
8636
9260
|
return {
|
|
@@ -8685,7 +9309,7 @@ function canonicalToDeepagentsHooks(config) {
|
|
|
8685
9309
|
const deepagentsEvent = CANONICAL_TO_DEEPAGENTS_EVENT_NAMES[canonicalEvent];
|
|
8686
9310
|
if (!deepagentsEvent) continue;
|
|
8687
9311
|
for (const def of definitions) {
|
|
8688
|
-
if (def.type
|
|
9312
|
+
if ((def.type ?? "command") !== "command") continue;
|
|
8689
9313
|
if (!def.command) continue;
|
|
8690
9314
|
if (def.matcher) continue;
|
|
8691
9315
|
entries.push({
|
|
@@ -8775,10 +9399,10 @@ var DeepagentsHooks = class DeepagentsHooks extends ToolHooks {
|
|
|
8775
9399
|
throw new Error(`Failed to parse deepagents hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
8776
9400
|
}
|
|
8777
9401
|
const hooks = deepagentsToCanonicalHooks(isDeepagentsHooksFile(parsed) ? parsed.hooks : []);
|
|
8778
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
}, null, 2) });
|
|
9402
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9403
|
+
hooks,
|
|
9404
|
+
overrideKey: "deepagents"
|
|
9405
|
+
}), null, 2) });
|
|
8782
9406
|
}
|
|
8783
9407
|
validate() {
|
|
8784
9408
|
return {
|
|
@@ -8907,10 +9531,10 @@ var DevinHooks = class DevinHooks extends ToolHooks {
|
|
|
8907
9531
|
hooks: this.getRelativeFilePath() === "config.json" ? isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {} : parsed,
|
|
8908
9532
|
converterConfig: DEVIN_CONVERTER_CONFIG
|
|
8909
9533
|
});
|
|
8910
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
}, null, 2) });
|
|
9534
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9535
|
+
hooks,
|
|
9536
|
+
overrideKey: "devin"
|
|
9537
|
+
}), null, 2) });
|
|
8914
9538
|
}
|
|
8915
9539
|
validate() {
|
|
8916
9540
|
return {
|
|
@@ -8934,7 +9558,8 @@ const FACTORYDROID_CONVERTER_CONFIG = {
|
|
|
8934
9558
|
supportedEvents: FACTORYDROID_HOOK_EVENTS,
|
|
8935
9559
|
canonicalToToolEventNames: CANONICAL_TO_FACTORYDROID_EVENT_NAMES,
|
|
8936
9560
|
toolToCanonicalEventNames: FACTORYDROID_TO_CANONICAL_EVENT_NAMES,
|
|
8937
|
-
projectDirVar: "$FACTORY_PROJECT_DIR"
|
|
9561
|
+
projectDirVar: "$FACTORY_PROJECT_DIR",
|
|
9562
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command", "prompt"])
|
|
8938
9563
|
};
|
|
8939
9564
|
var FactorydroidHooks = class FactorydroidHooks extends ToolHooks {
|
|
8940
9565
|
constructor(params) {
|
|
@@ -9002,10 +9627,10 @@ var FactorydroidHooks = class FactorydroidHooks extends ToolHooks {
|
|
|
9002
9627
|
hooks: settings.hooks,
|
|
9003
9628
|
converterConfig: FACTORYDROID_CONVERTER_CONFIG
|
|
9004
9629
|
});
|
|
9005
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
}, null, 2) });
|
|
9630
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9631
|
+
hooks,
|
|
9632
|
+
overrideKey: "factorydroid"
|
|
9633
|
+
}), null, 2) });
|
|
9009
9634
|
}
|
|
9010
9635
|
validate() {
|
|
9011
9636
|
return {
|
|
@@ -9096,10 +9721,10 @@ var GooseHooks = class GooseHooks extends ToolHooks {
|
|
|
9096
9721
|
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
9722
|
converterConfig: GOOSE_CONVERTER_CONFIG
|
|
9098
9723
|
});
|
|
9099
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
}, null, 2) });
|
|
9724
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9725
|
+
hooks,
|
|
9726
|
+
overrideKey: "goose"
|
|
9727
|
+
}), null, 2) });
|
|
9103
9728
|
}
|
|
9104
9729
|
validate() {
|
|
9105
9730
|
return {
|
|
@@ -9257,10 +9882,10 @@ var GrokcliHooks = class GrokcliHooks extends ToolHooks {
|
|
|
9257
9882
|
hooks: isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {},
|
|
9258
9883
|
converterConfig: GROKCLI_CONVERTER_CONFIG
|
|
9259
9884
|
});
|
|
9260
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
}, null, 2) });
|
|
9885
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
9886
|
+
hooks,
|
|
9887
|
+
overrideKey: "grokcli"
|
|
9888
|
+
}), null, 2) });
|
|
9264
9889
|
}
|
|
9265
9890
|
validate() {
|
|
9266
9891
|
return {
|
|
@@ -9421,10 +10046,10 @@ var HermesagentHooks = class HermesagentHooks extends ToolHooks {
|
|
|
9421
10046
|
format: "yaml",
|
|
9422
10047
|
fileContent: this.getFileContent()
|
|
9423
10048
|
}).hooks);
|
|
9424
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
}, null, 2) });
|
|
10049
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
10050
|
+
hooks,
|
|
10051
|
+
overrideKey: "hermesagent"
|
|
10052
|
+
}), null, 2) });
|
|
9428
10053
|
}
|
|
9429
10054
|
static fromRulesyncHooks({ outputRoot, rulesyncHooks, logger }) {
|
|
9430
10055
|
const config = rulesyncHooks.getJson();
|
|
@@ -9527,10 +10152,10 @@ var JunieHooks = class JunieHooks extends ToolHooks {
|
|
|
9527
10152
|
hooks: settings.hooks,
|
|
9528
10153
|
converterConfig: JUNIE_CONVERTER_CONFIG
|
|
9529
10154
|
});
|
|
9530
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
}, null, 2) });
|
|
10155
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
10156
|
+
hooks,
|
|
10157
|
+
overrideKey: "junie"
|
|
10158
|
+
}), null, 2) });
|
|
9534
10159
|
}
|
|
9535
10160
|
validate() {
|
|
9536
10161
|
return {
|
|
@@ -9575,7 +10200,7 @@ function collectOpencodeStyleHandlers({ effectiveHooks, eventMap, namedEventHand
|
|
|
9575
10200
|
if (!toolEvent) continue;
|
|
9576
10201
|
const handlers = [];
|
|
9577
10202
|
for (const def of definitions) {
|
|
9578
|
-
if (def.type
|
|
10203
|
+
if ((def.type ?? "command") !== "command") continue;
|
|
9579
10204
|
if (!def.command) continue;
|
|
9580
10205
|
handlers.push({
|
|
9581
10206
|
command: def.command,
|
|
@@ -9880,10 +10505,11 @@ var KiroHooks = class KiroHooks extends ToolHooks {
|
|
|
9880
10505
|
throw new Error(`Failed to parse Kiro hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
9881
10506
|
}
|
|
9882
10507
|
const hooks = kiroHooksToCanonical(agentConfig.hooks);
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
hooks
|
|
9886
|
-
|
|
10508
|
+
const overrideKey = this.constructor.getOverrideKey();
|
|
10509
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
10510
|
+
hooks,
|
|
10511
|
+
overrideKey
|
|
10512
|
+
}), null, 2) });
|
|
9887
10513
|
}
|
|
9888
10514
|
validate() {
|
|
9889
10515
|
return {
|
|
@@ -10092,10 +10718,10 @@ var KiroIdeHooks = class KiroIdeHooks extends ToolHooks {
|
|
|
10092
10718
|
throw new Error(`Failed to parse Kiro IDE hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
10093
10719
|
}
|
|
10094
10720
|
const hooks = kiroIdeHooksToCanonical(parsed.hooks ?? []);
|
|
10095
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
}, null, 2) });
|
|
10721
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
10722
|
+
hooks,
|
|
10723
|
+
overrideKey: "kiro-ide"
|
|
10724
|
+
}), null, 2) });
|
|
10099
10725
|
}
|
|
10100
10726
|
validate() {
|
|
10101
10727
|
return {
|
|
@@ -10219,11 +10845,18 @@ function canonicalToQwencodeHooks(config) {
|
|
|
10219
10845
|
...sharedHooks,
|
|
10220
10846
|
...config.qwencode?.hooks
|
|
10221
10847
|
};
|
|
10848
|
+
const qwencodeSupportedTypes = /* @__PURE__ */ new Set([
|
|
10849
|
+
"command",
|
|
10850
|
+
"prompt",
|
|
10851
|
+
"http",
|
|
10852
|
+
"function"
|
|
10853
|
+
]);
|
|
10222
10854
|
const qwencode = {};
|
|
10223
10855
|
for (const [eventName, definitions] of Object.entries(effectiveHooks)) {
|
|
10224
10856
|
const qwencodeEventName = CANONICAL_TO_QWENCODE_EVENT_NAMES[eventName] ?? eventName;
|
|
10225
10857
|
const byMatcher = /* @__PURE__ */ new Map();
|
|
10226
10858
|
for (const def of definitions) {
|
|
10859
|
+
if (!qwencodeSupportedTypes.has(def.type ?? "command")) continue;
|
|
10227
10860
|
const key = def.matcher ?? "";
|
|
10228
10861
|
const list = byMatcher.get(key);
|
|
10229
10862
|
if (list) list.push(def);
|
|
@@ -10283,9 +10916,10 @@ function qwencodeMatcherEntryToCanonical(entry) {
|
|
|
10283
10916
|
const sequential = entry.sequential === true;
|
|
10284
10917
|
const matcher = entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" ? entry.matcher : void 0;
|
|
10285
10918
|
for (const h of hooks) {
|
|
10286
|
-
const hookType = h.type === "command" || h.type === "prompt" || h.type === "http" ? h.type : "command";
|
|
10919
|
+
const hookType = h.type === "command" || h.type === "prompt" || h.type === "http" || h.type === "function" ? h.type : "command";
|
|
10287
10920
|
const isHttp = hookType === "http";
|
|
10288
10921
|
const isCommand = hookType === "command";
|
|
10922
|
+
const shell = h.shell === "bash" || h.shell === "powershell" ? h.shell : void 0;
|
|
10289
10923
|
defs.push({
|
|
10290
10924
|
type: hookType,
|
|
10291
10925
|
...compact({
|
|
@@ -10297,7 +10931,7 @@ function qwencodeMatcherEntryToCanonical(entry) {
|
|
|
10297
10931
|
statusMessage: h.statusMessage,
|
|
10298
10932
|
async: isCommand ? h.async : void 0,
|
|
10299
10933
|
env: isCommand ? h.env : void 0,
|
|
10300
|
-
shell: isCommand ?
|
|
10934
|
+
shell: isCommand ? shell : void 0,
|
|
10301
10935
|
headers: isHttp ? h.headers : void 0,
|
|
10302
10936
|
allowedEnvVars: isHttp ? h.allowedEnvVars : void 0,
|
|
10303
10937
|
once: isHttp ? h.once : void 0,
|
|
@@ -10384,15 +11018,11 @@ var QwencodeHooks = class QwencodeHooks extends ToolHooks {
|
|
|
10384
11018
|
} catch (error) {
|
|
10385
11019
|
throw new Error(`Failed to parse Qwen Code hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
10386
11020
|
}
|
|
10387
|
-
const
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
} : {
|
|
10393
|
-
version: 1,
|
|
10394
|
-
hooks
|
|
10395
|
-
};
|
|
11021
|
+
const canonical = buildImportedHooksConfig({
|
|
11022
|
+
hooks: qwencodeHooksToCanonical(settings.hooks),
|
|
11023
|
+
overrideKey: "qwencode",
|
|
11024
|
+
...typeof settings.disableAllHooks === "boolean" && { extraOverride: { disableAllHooks: settings.disableAllHooks } }
|
|
11025
|
+
});
|
|
10396
11026
|
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(canonical, null, 2) });
|
|
10397
11027
|
}
|
|
10398
11028
|
validate() {
|
|
@@ -10554,10 +11184,10 @@ var ReasonixHooks = class ReasonixHooks extends ToolHooks {
|
|
|
10554
11184
|
throw new Error(`Failed to parse Reasonix hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
10555
11185
|
}
|
|
10556
11186
|
const hooks = reasonixHooksToCanonical(settings.hooks);
|
|
10557
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
}, null, 2) });
|
|
11187
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
11188
|
+
hooks,
|
|
11189
|
+
overrideKey: "reasonix"
|
|
11190
|
+
}), null, 2) });
|
|
10561
11191
|
}
|
|
10562
11192
|
validate() {
|
|
10563
11193
|
return {
|
|
@@ -10780,10 +11410,10 @@ var VibeHooks = class VibeHooks extends ToolHooks {
|
|
|
10780
11410
|
throw new Error(`Failed to parse Vibe hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
10781
11411
|
}
|
|
10782
11412
|
const hooks = vibeHooksToCanonical(parsed);
|
|
10783
|
-
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
}, null, 2) });
|
|
11413
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
11414
|
+
hooks,
|
|
11415
|
+
overrideKey: "vibe"
|
|
11416
|
+
}), null, 2) });
|
|
10787
11417
|
}
|
|
10788
11418
|
validate() {
|
|
10789
11419
|
try {
|
|
@@ -10870,7 +11500,13 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
10870
11500
|
supportsImport: true
|
|
10871
11501
|
},
|
|
10872
11502
|
supportedEvents: CLAUDE_HOOK_EVENTS,
|
|
10873
|
-
supportedHookTypes: [
|
|
11503
|
+
supportedHookTypes: [
|
|
11504
|
+
"command",
|
|
11505
|
+
"prompt",
|
|
11506
|
+
"http",
|
|
11507
|
+
"mcp_tool",
|
|
11508
|
+
"agent"
|
|
11509
|
+
],
|
|
10874
11510
|
supportsMatcher: true
|
|
10875
11511
|
}],
|
|
10876
11512
|
["codexcli", {
|
|
@@ -11062,7 +11698,12 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
11062
11698
|
supportsImport: true
|
|
11063
11699
|
},
|
|
11064
11700
|
supportedEvents: QWENCODE_HOOK_EVENTS,
|
|
11065
|
-
supportedHookTypes: [
|
|
11701
|
+
supportedHookTypes: [
|
|
11702
|
+
"command",
|
|
11703
|
+
"prompt",
|
|
11704
|
+
"http",
|
|
11705
|
+
"function"
|
|
11706
|
+
],
|
|
11066
11707
|
supportsMatcher: true
|
|
11067
11708
|
}],
|
|
11068
11709
|
["reasonix", {
|
|
@@ -12364,16 +13005,6 @@ var IgnoreProcessor = class extends FeatureProcessor {
|
|
|
12364
13005
|
}
|
|
12365
13006
|
};
|
|
12366
13007
|
//#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
13008
|
//#region src/types/mcp.ts
|
|
12378
13009
|
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
13010
|
const McpServerSchema = z.looseObject({
|
|
@@ -13465,10 +14096,19 @@ function mapOauthFromCodex(oauth) {
|
|
|
13465
14096
|
}
|
|
13466
14097
|
const CODEX_MCP_SERVER_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
13467
14098
|
function normalizeCodexMcpServerName(name) {
|
|
13468
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(name)) return
|
|
13469
|
-
|
|
14099
|
+
if (!PROTOTYPE_POLLUTION_KEYS.has(name) && CODEX_MCP_SERVER_NAME_PATTERN.test(name)) return {
|
|
14100
|
+
codexName: name,
|
|
14101
|
+
usedFallback: false
|
|
14102
|
+
};
|
|
13470
14103
|
const normalizedName = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
13471
|
-
|
|
14104
|
+
if (normalizedName && !PROTOTYPE_POLLUTION_KEYS.has(normalizedName)) return {
|
|
14105
|
+
codexName: normalizedName,
|
|
14106
|
+
usedFallback: false
|
|
14107
|
+
};
|
|
14108
|
+
return {
|
|
14109
|
+
codexName: `mcp_${createHash("sha256").update(name).digest("hex").slice(0, 8)}`,
|
|
14110
|
+
usedFallback: true
|
|
14111
|
+
};
|
|
13472
14112
|
}
|
|
13473
14113
|
function convertFromCodexFormat(codexMcp) {
|
|
13474
14114
|
const result = {};
|
|
@@ -13482,7 +14122,7 @@ function convertFromCodexFormat(codexMcp) {
|
|
|
13482
14122
|
} else if (key === "oauth" && isRecord(value)) converted[key] = mapOauthFromCodex(value);
|
|
13483
14123
|
else if (Object.hasOwn(CODEX_TO_RULESYNC_FIELD_MAP, key)) {
|
|
13484
14124
|
const mappedKey = CODEX_TO_RULESYNC_FIELD_MAP[key];
|
|
13485
|
-
if (mappedKey) if (isStringArray(value)) converted[mappedKey] = value;
|
|
14125
|
+
if (mappedKey) if (isStringArray$1(value)) converted[mappedKey] = value;
|
|
13486
14126
|
else warnWithFallback(void 0, `Ignored malformed array for ${key} in MCP server ${name}`);
|
|
13487
14127
|
} else converted[key] = value;
|
|
13488
14128
|
}
|
|
@@ -13494,12 +14134,9 @@ function convertToCodexFormat(mcpServers) {
|
|
|
13494
14134
|
const result = {};
|
|
13495
14135
|
const originalNames = /* @__PURE__ */ new Map();
|
|
13496
14136
|
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
14137
|
if (!isRecord(config)) continue;
|
|
14138
|
+
const { codexName, usedFallback } = normalizeCodexMcpServerName(name);
|
|
14139
|
+
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
14140
|
const converted = {};
|
|
13504
14141
|
for (const [key, value] of Object.entries(config)) {
|
|
13505
14142
|
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
@@ -13508,12 +14145,12 @@ function convertToCodexFormat(mcpServers) {
|
|
|
13508
14145
|
} else if (key === "oauth" && isRecord(value)) converted[key] = mapOauthToCodex(value);
|
|
13509
14146
|
else if (Object.hasOwn(RULESYNC_TO_CODEX_FIELD_MAP, key)) {
|
|
13510
14147
|
const mappedKey = RULESYNC_TO_CODEX_FIELD_MAP[key];
|
|
13511
|
-
if (mappedKey) if (isStringArray(value)) converted[mappedKey] = value;
|
|
14148
|
+
if (mappedKey) if (isStringArray$1(value)) converted[mappedKey] = value;
|
|
13512
14149
|
else warnWithFallback(void 0, `[CodexCliMcp] Skipping invalid value type for mapped key '${key}': expected string array, got ${typeof value}`);
|
|
13513
14150
|
} else converted[key] = value;
|
|
13514
14151
|
}
|
|
13515
14152
|
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}"
|
|
14153
|
+
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
14154
|
originalNames.set(codexName, name);
|
|
13518
14155
|
result[codexName] = converted;
|
|
13519
14156
|
}
|
|
@@ -13580,7 +14217,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
13580
14217
|
const rawServer = isRecord(rawMcpServers) ? rawMcpServers[serverName] : void 0;
|
|
13581
14218
|
return [serverName, {
|
|
13582
14219
|
...serverConfig,
|
|
13583
|
-
...isRecord(rawServer) && isStringArray(rawServer.envVars) ? { envVars: rawServer.envVars } : {}
|
|
14220
|
+
...isRecord(rawServer) && isStringArray$1(rawServer.envVars) ? { envVars: rawServer.envVars } : {}
|
|
13584
14221
|
}];
|
|
13585
14222
|
})));
|
|
13586
14223
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
@@ -14317,11 +14954,11 @@ function applyGooseStdioFields(ext, config) {
|
|
|
14317
14954
|
if (Array.isArray(command)) {
|
|
14318
14955
|
if (typeof command[0] === "string") ext.cmd = command[0];
|
|
14319
14956
|
const rest = command.slice(1).filter((c) => typeof c === "string");
|
|
14320
|
-
const args = isStringArray(config.args) ? config.args : [];
|
|
14957
|
+
const args = isStringArray$1(config.args) ? config.args : [];
|
|
14321
14958
|
if (rest.length > 0 || args.length > 0) ext.args = [...rest, ...args];
|
|
14322
14959
|
} else if (typeof command === "string") {
|
|
14323
14960
|
ext.cmd = command;
|
|
14324
|
-
if (isStringArray(config.args)) ext.args = config.args;
|
|
14961
|
+
if (isStringArray$1(config.args)) ext.args = config.args;
|
|
14325
14962
|
}
|
|
14326
14963
|
if (isPlainObject$1(config.env)) ext.envs = omitPrototypePollutionKeys(config.env);
|
|
14327
14964
|
}
|
|
@@ -14379,7 +15016,7 @@ function convertFromGooseFormat(extensions) {
|
|
|
14379
15016
|
else if (type === "streamable_http") server.type = "http";
|
|
14380
15017
|
else if (type === "stdio") server.type = "stdio";
|
|
14381
15018
|
if (typeof ext.cmd === "string") server.command = ext.cmd;
|
|
14382
|
-
if (isStringArray(ext.args)) server.args = ext.args;
|
|
15019
|
+
if (isStringArray$1(ext.args)) server.args = ext.args;
|
|
14383
15020
|
if (isPlainObject$1(ext.envs)) server.env = omitPrototypePollutionKeys(ext.envs);
|
|
14384
15021
|
if (typeof ext.uri === "string") server.url = ext.uri;
|
|
14385
15022
|
if (isPlainObject$1(ext.headers)) server.headers = omitPrototypePollutionKeys(ext.headers);
|
|
@@ -14399,11 +15036,11 @@ function buildGoosePluginStdioServer(config) {
|
|
|
14399
15036
|
if (Array.isArray(command)) {
|
|
14400
15037
|
if (typeof command[0] === "string") server.command = command[0];
|
|
14401
15038
|
const rest = command.slice(1).filter((c) => typeof c === "string");
|
|
14402
|
-
const args = isStringArray(config.args) ? config.args : [];
|
|
15039
|
+
const args = isStringArray$1(config.args) ? config.args : [];
|
|
14403
15040
|
if (rest.length > 0 || args.length > 0) server.args = [...rest, ...args];
|
|
14404
15041
|
} else if (typeof command === "string") {
|
|
14405
15042
|
server.command = command;
|
|
14406
|
-
if (isStringArray(config.args)) server.args = config.args;
|
|
15043
|
+
if (isStringArray$1(config.args)) server.args = config.args;
|
|
14407
15044
|
}
|
|
14408
15045
|
if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
|
|
14409
15046
|
if (typeof config.cwd === "string") server.cwd = config.cwd;
|
|
@@ -14716,7 +15353,7 @@ function resolveHermesTimeout(config) {
|
|
|
14716
15353
|
*/
|
|
14717
15354
|
function copyHermesAdvancedFields(source, target) {
|
|
14718
15355
|
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;
|
|
15356
|
+
if (typeof source.client_cert === "string" || isStringArray$1(source.client_cert)) target.client_cert = source.client_cert;
|
|
14720
15357
|
if (typeof source.client_key === "string") target.client_key = source.client_key;
|
|
14721
15358
|
if (typeof source.connect_timeout === "number") target.connect_timeout = source.connect_timeout;
|
|
14722
15359
|
if (typeof source.supports_parallel_tool_calls === "boolean") target.supports_parallel_tool_calls = source.supports_parallel_tool_calls;
|
|
@@ -14735,8 +15372,8 @@ function copyHermesAdvancedFields(source, target) {
|
|
|
14735
15372
|
*/
|
|
14736
15373
|
function buildHermesToolsBlock(config) {
|
|
14737
15374
|
const tools = {};
|
|
14738
|
-
if (isStringArray(config.enabledTools)) tools.include = config.enabledTools;
|
|
14739
|
-
if (isStringArray(config.disabledTools)) tools.exclude = config.disabledTools;
|
|
15375
|
+
if (isStringArray$1(config.enabledTools)) tools.include = config.enabledTools;
|
|
15376
|
+
if (isStringArray$1(config.disabledTools)) tools.exclude = config.disabledTools;
|
|
14740
15377
|
if (typeof config.promptsEnabled === "boolean") tools.prompts = config.promptsEnabled;
|
|
14741
15378
|
if (typeof config.resourcesEnabled === "boolean") tools.resources = config.resourcesEnabled;
|
|
14742
15379
|
return tools;
|
|
@@ -14748,8 +15385,8 @@ function buildHermesToolsBlock(config) {
|
|
|
14748
15385
|
* `promptsEnabled`/`resourcesEnabled` top-level toggles.
|
|
14749
15386
|
*/
|
|
14750
15387
|
function applyHermesToolsBlock(hermesTools, server) {
|
|
14751
|
-
if (isStringArray(hermesTools.include)) server.enabledTools = hermesTools.include;
|
|
14752
|
-
if (isStringArray(hermesTools.exclude)) server.disabledTools = hermesTools.exclude;
|
|
15388
|
+
if (isStringArray$1(hermesTools.include)) server.enabledTools = hermesTools.include;
|
|
15389
|
+
if (isStringArray$1(hermesTools.exclude)) server.disabledTools = hermesTools.exclude;
|
|
14753
15390
|
if (typeof hermesTools.prompts === "boolean") server.promptsEnabled = hermesTools.prompts;
|
|
14754
15391
|
if (typeof hermesTools.resources === "boolean") server.resourcesEnabled = hermesTools.resources;
|
|
14755
15392
|
}
|
|
@@ -14773,11 +15410,11 @@ function convertServerToHermes(config) {
|
|
|
14773
15410
|
if (Array.isArray(command)) {
|
|
14774
15411
|
if (typeof command[0] === "string") out.command = command[0];
|
|
14775
15412
|
const rest = command.slice(1).filter((c) => typeof c === "string");
|
|
14776
|
-
const args = isStringArray(config.args) ? config.args : [];
|
|
15413
|
+
const args = isStringArray$1(config.args) ? config.args : [];
|
|
14777
15414
|
if (rest.length > 0 || args.length > 0) out.args = [...rest, ...args];
|
|
14778
15415
|
} else if (typeof command === "string") {
|
|
14779
15416
|
out.command = command;
|
|
14780
|
-
if (isStringArray(config.args)) out.args = config.args;
|
|
15417
|
+
if (isStringArray$1(config.args)) out.args = config.args;
|
|
14781
15418
|
}
|
|
14782
15419
|
if (isPlainObject$1(config.env)) out.env = omitPrototypePollutionKeys(config.env);
|
|
14783
15420
|
} else if (url !== void 0) {
|
|
@@ -14825,7 +15462,7 @@ function convertFromHermesFormat(mcpServers) {
|
|
|
14825
15462
|
if (PROTOTYPE_POLLUTION_KEYS.has(name) || !isRecord(config)) continue;
|
|
14826
15463
|
const server = {};
|
|
14827
15464
|
if (typeof config.command === "string") server.command = config.command;
|
|
14828
|
-
if (isStringArray(config.args)) server.args = config.args;
|
|
15465
|
+
if (isStringArray$1(config.args)) server.args = config.args;
|
|
14829
15466
|
if (isPlainObject$1(config.env)) server.env = omitPrototypePollutionKeys(config.env);
|
|
14830
15467
|
if (typeof config.url === "string") server.url = config.url;
|
|
14831
15468
|
if (isPlainObject$1(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
|
|
@@ -17150,7 +17787,11 @@ const VibePermissionsOverrideSchema = z.looseObject({ permission: z.optional(z.r
|
|
|
17150
17787
|
*/
|
|
17151
17788
|
const CursorPermissionsOverrideSchema = z.looseObject({
|
|
17152
17789
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17153
|
-
approvalMode: z.optional(z.
|
|
17790
|
+
approvalMode: z.optional(z.enum([
|
|
17791
|
+
"allowlist",
|
|
17792
|
+
"auto-review",
|
|
17793
|
+
"unrestricted"
|
|
17794
|
+
])),
|
|
17154
17795
|
sandbox: z.optional(z.looseObject({}))
|
|
17155
17796
|
});
|
|
17156
17797
|
/**
|
|
@@ -17238,7 +17879,11 @@ const FactorydroidPermissionsOverrideSchema = z.looseObject({
|
|
|
17238
17879
|
*/
|
|
17239
17880
|
const WarpPermissionsOverrideSchema = z.looseObject({
|
|
17240
17881
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17241
|
-
agent_mode_coding_permissions: z.optional(z.
|
|
17882
|
+
agent_mode_coding_permissions: z.optional(z.enum([
|
|
17883
|
+
"always_ask_before_reading",
|
|
17884
|
+
"always_allow_reading",
|
|
17885
|
+
"allow_reading_specific_files"
|
|
17886
|
+
])),
|
|
17242
17887
|
agent_mode_coding_file_read_allowlist: z.optional(z.array(z.string())),
|
|
17243
17888
|
agent_mode_execute_readonly_commands: z.optional(z.boolean())
|
|
17244
17889
|
});
|
|
@@ -17284,7 +17929,11 @@ const JuniePermissionsOverrideSchema = z.looseObject({
|
|
|
17284
17929
|
*/
|
|
17285
17930
|
const TaktPermissionsOverrideSchema = z.looseObject({
|
|
17286
17931
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17287
|
-
step_permission_overrides: z.optional(z.record(z.string(), z.
|
|
17932
|
+
step_permission_overrides: z.optional(z.record(z.string(), z.enum([
|
|
17933
|
+
"readonly",
|
|
17934
|
+
"edit",
|
|
17935
|
+
"full"
|
|
17936
|
+
]))),
|
|
17288
17937
|
provider_options: z.optional(z.looseObject({}))
|
|
17289
17938
|
});
|
|
17290
17939
|
/**
|
|
@@ -17314,9 +17963,15 @@ const AmpPermissionsOverrideSchema = z.looseObject({
|
|
|
17314
17963
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17315
17964
|
permissions: z.optional(z.array(z.looseObject({
|
|
17316
17965
|
tool: z.string(),
|
|
17317
|
-
action: z.
|
|
17966
|
+
action: z.enum([
|
|
17967
|
+
"allow",
|
|
17968
|
+
"ask",
|
|
17969
|
+
"reject",
|
|
17970
|
+
"delegate"
|
|
17971
|
+
]),
|
|
17972
|
+
context: z.optional(z.enum(["thread", "subagent"]))
|
|
17318
17973
|
}))),
|
|
17319
|
-
mcpPermissions: z.optional(z.array(z.looseObject({}))),
|
|
17974
|
+
mcpPermissions: z.optional(z.array(z.looseObject({ action: z.enum(["allow", "reject"]) }))),
|
|
17320
17975
|
guardedFiles: z.optional(z.looseObject({ allowlist: z.optional(z.array(z.string())) })),
|
|
17321
17976
|
dangerouslyAllowAll: z.optional(z.boolean())
|
|
17322
17977
|
});
|
|
@@ -17341,7 +17996,12 @@ const AmpPermissionsOverrideSchema = z.looseObject({
|
|
|
17341
17996
|
*/
|
|
17342
17997
|
const AntigravityCliPermissionsOverrideSchema = z.looseObject({
|
|
17343
17998
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17344
|
-
toolPermission: z.optional(z.
|
|
17999
|
+
toolPermission: z.optional(z.enum([
|
|
18000
|
+
"request-review",
|
|
18001
|
+
"proceed-in-sandbox",
|
|
18002
|
+
"always-proceed",
|
|
18003
|
+
"strict"
|
|
18004
|
+
])),
|
|
17345
18005
|
enableTerminalSandbox: z.optional(z.boolean())
|
|
17346
18006
|
});
|
|
17347
18007
|
/**
|
|
@@ -17370,7 +18030,14 @@ const AugmentcodePermissionsOverrideSchema = z.looseObject({
|
|
|
17370
18030
|
permission: z.optional(ToolScopedPermissionSchema),
|
|
17371
18031
|
toolPermissions: z.optional(z.array(z.looseObject({
|
|
17372
18032
|
toolName: z.string(),
|
|
17373
|
-
|
|
18033
|
+
eventType: z.optional(z.enum(["tool-call", "tool-response"])),
|
|
18034
|
+
permission: z.looseObject({ type: z.enum([
|
|
18035
|
+
"allow",
|
|
18036
|
+
"deny",
|
|
18037
|
+
"ask-user",
|
|
18038
|
+
"webhook-policy",
|
|
18039
|
+
"script-policy"
|
|
18040
|
+
]) })
|
|
17374
18041
|
})))
|
|
17375
18042
|
});
|
|
17376
18043
|
/**
|
|
@@ -17460,12 +18127,20 @@ const CodexApprovalsReviewerSchema = z.enum([
|
|
|
17460
18127
|
* `[permissions.rulesync]` profile may extend. Codex ships three built-in
|
|
17461
18128
|
* profiles (`:read-only`, `:workspace`, `:danger-full-access`; the leading
|
|
17462
18129
|
* colon is reserved for built-ins), but `extends` rejects
|
|
17463
|
-
* `:danger-full-access` at config load time, so only
|
|
17464
|
-
*
|
|
17465
|
-
*
|
|
18130
|
+
* `:danger-full-access` at config load time, so only these two are valid
|
|
18131
|
+
* `extends` parents. The value list is exported so the Codex CLI translator
|
|
18132
|
+
* derives its import-side baseline check from the same source.
|
|
17466
18133
|
* @see https://learn.chatgpt.com/docs/permissions
|
|
17467
18134
|
*/
|
|
17468
|
-
const
|
|
18135
|
+
const CODEX_EXTENDABLE_BASELINE_PROFILES = [":read-only", ":workspace"];
|
|
18136
|
+
/**
|
|
18137
|
+
* All accepted `codexcli.base_permission_profile` values. `:danger-full-access`
|
|
18138
|
+
* cannot be an `extends` parent, so selecting it makes rulesync emit
|
|
18139
|
+
* `default_permissions = ":danger-full-access"` directly and skip the managed
|
|
18140
|
+
* `[permissions.rulesync]` profile entirely (there is no sandbox for
|
|
18141
|
+
* filesystem/network rules to refine in that mode).
|
|
18142
|
+
*/
|
|
18143
|
+
const CODEX_BASE_PERMISSION_PROFILES = [...CODEX_EXTENDABLE_BASELINE_PROFILES, ":danger-full-access"];
|
|
17469
18144
|
const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
|
|
17470
18145
|
/**
|
|
17471
18146
|
* Codex CLI-scoped permission override.
|
|
@@ -17476,10 +18151,14 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
|
|
|
17476
18151
|
* override whose fields are written verbatim as top-level `.codex/config.toml`
|
|
17477
18152
|
* keys (the override wins per key; existing sibling keys the user set directly
|
|
17478
18153
|
* are preserved):
|
|
17479
|
-
* - `base_permission_profile` — the built-in profile
|
|
17480
|
-
*
|
|
17481
|
-
*
|
|
17482
|
-
*
|
|
18154
|
+
* - `base_permission_profile` — the built-in baseline profile (`:read-only` |
|
|
18155
|
+
* `:workspace` | `:danger-full-access`). Unlike the other keys it is not a
|
|
18156
|
+
* top-level config key: the extendable baselines are emitted as the managed
|
|
18157
|
+
* `[permissions.rulesync]` profile's `extends` value, while
|
|
18158
|
+
* `:danger-full-access` (which Codex rejects as an `extends` parent) is
|
|
18159
|
+
* selected directly via `default_permissions` and skips the managed profile
|
|
18160
|
+
* entirely — canonical filesystem/network rules are ignored in that mode.
|
|
18161
|
+
* Defaults to `:workspace` when unspecified.
|
|
17483
18162
|
* - `approval_policy` — `untrusted` | `on-request` (legacy alias `on-failure`) |
|
|
17484
18163
|
* `never`, or a `{ granular = { … } }` table (kept verbatim; the granular
|
|
17485
18164
|
* schema has required fields that are brittle to model as typed keys).
|
|
@@ -17500,13 +18179,14 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
|
|
|
17500
18179
|
* Defaults to `auto_review` when neither the override nor the existing
|
|
17501
18180
|
* config sets it.
|
|
17502
18181
|
* - `git_write_rules` — whether the managed profile's `:workspace_roots` table
|
|
17503
|
-
* emits the default `.git` carve-
|
|
17504
|
-
* `".git/config" = "read"` kept read-only as a security guard). Codex's
|
|
18182
|
+
* emits the default `.git` carve-out (`".git/**" = "write"`). Codex's
|
|
17505
18183
|
* `:workspace` baseline makes `.git` read-only, which denies basic git
|
|
17506
18184
|
* workflows (commit/stage writes to `.git/index`, `.git/objects`, refs,
|
|
17507
|
-
* logs
|
|
17508
|
-
*
|
|
17509
|
-
*
|
|
18185
|
+
* logs; everyday commands like `git remote add` or `git push -u` write to
|
|
18186
|
+
* `.git/config`), so the carve-out is emitted by default. Defaults to
|
|
18187
|
+
* `true`; only an explicit `false` suppresses it. Like
|
|
18188
|
+
* `base_permission_profile` it is consumed by the profile builder, not
|
|
18189
|
+
* written as a top-level config key.
|
|
17510
18190
|
*
|
|
17511
18191
|
* Two surfaces are deliberately NOT authorable here so the override can never
|
|
17512
18192
|
* clobber a feature-owned key: `mcp_servers.*` per-MCP gating is owned by the
|
|
@@ -17583,6 +18263,7 @@ const PermissionsConfigSchema = z.looseObject({
|
|
|
17583
18263
|
kiro: z.optional(KiroPermissionsOverrideSchema),
|
|
17584
18264
|
codexcli: z.optional(CodexcliPermissionsOverrideSchema),
|
|
17585
18265
|
"antigravity-ide": z.optional(CanonicalPermissionsOverrideSchema),
|
|
18266
|
+
copilot: z.optional(CanonicalPermissionsOverrideSchema),
|
|
17586
18267
|
devin: z.optional(CanonicalPermissionsOverrideSchema),
|
|
17587
18268
|
goose: z.optional(CanonicalPermissionsOverrideSchema),
|
|
17588
18269
|
grokcli: z.optional(CanonicalPermissionsOverrideSchema),
|
|
@@ -19503,15 +20184,13 @@ const RULESYNC_PROFILE_NAME = "rulesync";
|
|
|
19503
20184
|
const CODEX_WORKSPACE_ROOTS_KEY = ":workspace_roots";
|
|
19504
20185
|
const CODEX_WORKSPACE_BASELINE = ":workspace";
|
|
19505
20186
|
const CODEX_READ_ONLY_BASELINE = ":read-only";
|
|
19506
|
-
const
|
|
20187
|
+
const CODEX_DANGER_FULL_ACCESS_BASELINE = ":danger-full-access";
|
|
20188
|
+
const CODEX_EXTENDABLE_BASELINES = new Set(CODEX_EXTENDABLE_BASELINE_PROFILES);
|
|
19507
20189
|
const CODEX_DEFAULT_APPROVAL_POLICY = "on-request";
|
|
19508
20190
|
const CODEX_DEFAULT_APPROVALS_REVIEWER = "auto_review";
|
|
19509
20191
|
const CODEX_GLOB_SCAN_MAX_DEPTH = 8;
|
|
19510
20192
|
const CODEX_MINIMAL_KEY = ":minimal";
|
|
19511
|
-
const CODEX_GIT_WRITE_RULES = {
|
|
19512
|
-
".git/**": "write",
|
|
19513
|
-
".git/config": "read"
|
|
19514
|
-
};
|
|
20193
|
+
const CODEX_GIT_WRITE_RULES = { ".git/**": "write" };
|
|
19515
20194
|
const GLOBAL_WILDCARD_DOMAIN = "*";
|
|
19516
20195
|
var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
19517
20196
|
static getSettablePaths(_options = {}) {
|
|
@@ -19539,8 +20218,40 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
19539
20218
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
19540
20219
|
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
19541
20220
|
const existing = toMutableTable(smolToml.parse(existingContent || smolToml.stringify({})));
|
|
20221
|
+
const canonicalConfig = rulesyncPermissions.getJson();
|
|
20222
|
+
if (canonicalConfig.codexcli?.base_permission_profile === CODEX_DANGER_FULL_ACCESS_BASELINE) {
|
|
20223
|
+
const ignoredCategories = Object.entries(canonicalConfig.permission).filter(([category, rules]) => category !== "bash" && Object.keys(rules).length > 0).map(([category]) => category);
|
|
20224
|
+
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.`);
|
|
20225
|
+
const permissionsTable = toMutableTable(existing.permissions);
|
|
20226
|
+
if (permissionsTable[RULESYNC_PROFILE_NAME] !== void 0) {
|
|
20227
|
+
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.`);
|
|
20228
|
+
delete permissionsTable[RULESYNC_PROFILE_NAME];
|
|
20229
|
+
}
|
|
20230
|
+
const overridePatch = computeCodexcliOverridePatch({
|
|
20231
|
+
existing,
|
|
20232
|
+
override: canonicalConfig.codexcli,
|
|
20233
|
+
logger
|
|
20234
|
+
});
|
|
20235
|
+
return new CodexcliPermissions({
|
|
20236
|
+
outputRoot,
|
|
20237
|
+
relativeDirPath: paths.relativeDirPath,
|
|
20238
|
+
relativeFilePath: paths.relativeFilePath,
|
|
20239
|
+
fileContent: applySharedConfigPatch({
|
|
20240
|
+
fileKey: sharedConfigFileKey(paths),
|
|
20241
|
+
feature: "permissions",
|
|
20242
|
+
existingContent,
|
|
20243
|
+
patch: {
|
|
20244
|
+
permissions: Object.keys(permissionsTable).length > 0 ? permissionsTable : void 0,
|
|
20245
|
+
default_permissions: CODEX_DANGER_FULL_ACCESS_BASELINE,
|
|
20246
|
+
...overridePatch
|
|
20247
|
+
},
|
|
20248
|
+
filePath
|
|
20249
|
+
}),
|
|
20250
|
+
validate
|
|
20251
|
+
});
|
|
20252
|
+
}
|
|
19542
20253
|
const newProfile = convertRulesyncToCodexProfile({
|
|
19543
|
-
config:
|
|
20254
|
+
config: canonicalConfig,
|
|
19544
20255
|
logger
|
|
19545
20256
|
});
|
|
19546
20257
|
const permissionsTable = toMutableTable(existing.permissions);
|
|
@@ -19601,6 +20312,7 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
19601
20312
|
});
|
|
19602
20313
|
const override = extractCodexcliOverride(table);
|
|
19603
20314
|
if (typeof profile?.extends === "string" && CODEX_EXTENDABLE_BASELINES.has(profile.extends)) override.base_permission_profile = profile.extends;
|
|
20315
|
+
if (defaultProfile === CODEX_DANGER_FULL_ACCESS_BASELINE) override.base_permission_profile = CODEX_DANGER_FULL_ACCESS_BASELINE;
|
|
19604
20316
|
const result = Object.keys(override).length > 0 ? {
|
|
19605
20317
|
...config,
|
|
19606
20318
|
codexcli: override
|
|
@@ -19656,16 +20368,10 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
19656
20368
|
const filesystem = { [CODEX_MINIMAL_KEY]: "read" };
|
|
19657
20369
|
const workspaceRootFilesystem = {};
|
|
19658
20370
|
const domains = {};
|
|
20371
|
+
const filesystemCategoryRules = {};
|
|
19659
20372
|
for (const [toolName, rules] of Object.entries(config.permission)) {
|
|
19660
20373
|
if (toolName === "read" || toolName === "edit" || toolName === "write") {
|
|
19661
|
-
|
|
19662
|
-
for (const [pattern, action] of Object.entries(rules)) addFilesystemRule({
|
|
19663
|
-
filesystem,
|
|
19664
|
-
workspaceRootFilesystem,
|
|
19665
|
-
pattern,
|
|
19666
|
-
access: mapAction(action),
|
|
19667
|
-
logger
|
|
19668
|
-
});
|
|
20374
|
+
filesystemCategoryRules[toolName] = rules;
|
|
19669
20375
|
continue;
|
|
19670
20376
|
}
|
|
19671
20377
|
if (toolName === "webfetch") {
|
|
@@ -19678,6 +20384,16 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
19678
20384
|
}
|
|
19679
20385
|
logger?.warn(`Codex CLI permissions support only read/edit/write/webfetch categories. Skipping: ${toolName}`);
|
|
19680
20386
|
}
|
|
20387
|
+
for (const [pattern, access] of mergeFilesystemCategoryRules({
|
|
20388
|
+
categoryRules: filesystemCategoryRules,
|
|
20389
|
+
logger
|
|
20390
|
+
})) addFilesystemRule({
|
|
20391
|
+
filesystem,
|
|
20392
|
+
workspaceRootFilesystem,
|
|
20393
|
+
pattern,
|
|
20394
|
+
access,
|
|
20395
|
+
logger
|
|
20396
|
+
});
|
|
19681
20397
|
applyDefaultGitWriteRules({
|
|
19682
20398
|
config,
|
|
19683
20399
|
filesystem,
|
|
@@ -19958,6 +20674,67 @@ function mapReadAction(action) {
|
|
|
19958
20674
|
function mapWriteAction(action) {
|
|
19959
20675
|
return action === "allow" ? "write" : "deny";
|
|
19960
20676
|
}
|
|
20677
|
+
/**
|
|
20678
|
+
* Merge the canonical read/edit/write category rules into one Codex access
|
|
20679
|
+
* level per path pattern (Codex models a single `deny` < `read` < `write`
|
|
20680
|
+
* level, with no `ask`).
|
|
20681
|
+
*
|
|
20682
|
+
* - `edit` and `write` collapse onto Codex's write side; when both carry the
|
|
20683
|
+
* same pattern, the more restrictive action wins (`deny` > `ask` > `allow`).
|
|
20684
|
+
* - `read: allow` + write-side `allow` → `"write"`.
|
|
20685
|
+
* - `read: allow` + write-side non-allow → `"read"` (readable but not
|
|
20686
|
+
* writable — exactly what Codex's `"read"` level expresses).
|
|
20687
|
+
* - `read` non-allow → `"deny"` regardless of the write side; a contradictory
|
|
20688
|
+
* write-side `allow` (unreadable but writable is not expressible in Codex)
|
|
20689
|
+
* is warned about.
|
|
20690
|
+
* - Single-category patterns keep the existing mapReadAction/mapWriteAction
|
|
20691
|
+
* mappings.
|
|
20692
|
+
*
|
|
20693
|
+
* Iteration order is read → edit → write with first-seen pattern order, so
|
|
20694
|
+
* the emitted table is stable regardless of the authored category order.
|
|
20695
|
+
* Note the merge is one-way: `"{path}" = "read"` imports back as
|
|
20696
|
+
* `read: allow` only (the explicit write-side deny is implied by Codex's
|
|
20697
|
+
* access level and not re-materialized).
|
|
20698
|
+
*/
|
|
20699
|
+
function mergeFilesystemCategoryRules({ categoryRules, logger }) {
|
|
20700
|
+
const readRules = categoryRules.read ?? {};
|
|
20701
|
+
const writeSideRestrictiveness = {
|
|
20702
|
+
deny: 2,
|
|
20703
|
+
ask: 1,
|
|
20704
|
+
allow: 0
|
|
20705
|
+
};
|
|
20706
|
+
const writeSideRules = {};
|
|
20707
|
+
for (const category of ["edit", "write"]) for (const [pattern, action] of Object.entries(categoryRules[category] ?? {})) {
|
|
20708
|
+
const existing = writeSideRules[pattern];
|
|
20709
|
+
if (existing === void 0 || writeSideRestrictiveness[action] > writeSideRestrictiveness[existing]) writeSideRules[pattern] = action;
|
|
20710
|
+
}
|
|
20711
|
+
const patterns = [];
|
|
20712
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20713
|
+
for (const pattern of [...Object.keys(readRules), ...Object.keys(writeSideRules)]) if (!seen.has(pattern)) {
|
|
20714
|
+
seen.add(pattern);
|
|
20715
|
+
patterns.push(pattern);
|
|
20716
|
+
}
|
|
20717
|
+
const merged = [];
|
|
20718
|
+
for (const pattern of patterns) {
|
|
20719
|
+
const readAction = readRules[pattern];
|
|
20720
|
+
const writeAction = writeSideRules[pattern];
|
|
20721
|
+
if (readAction === void 0) {
|
|
20722
|
+
merged.push([pattern, mapWriteAction(writeAction)]);
|
|
20723
|
+
continue;
|
|
20724
|
+
}
|
|
20725
|
+
if (writeAction === void 0) {
|
|
20726
|
+
merged.push([pattern, mapReadAction(readAction)]);
|
|
20727
|
+
continue;
|
|
20728
|
+
}
|
|
20729
|
+
if (readAction === "allow") {
|
|
20730
|
+
merged.push([pattern, writeAction === "allow" ? "write" : "read"]);
|
|
20731
|
+
continue;
|
|
20732
|
+
}
|
|
20733
|
+
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".`);
|
|
20734
|
+
merged.push([pattern, "deny"]);
|
|
20735
|
+
}
|
|
20736
|
+
return merged;
|
|
20737
|
+
}
|
|
19961
20738
|
function buildCodexBashRulesContent(config) {
|
|
19962
20739
|
const bashRules = config.permission.bash ?? {};
|
|
19963
20740
|
const entries = Object.entries(bashRules);
|
|
@@ -19990,6 +20767,135 @@ function mapBashActionToDecision(action) {
|
|
|
19990
20767
|
return "forbidden";
|
|
19991
20768
|
}
|
|
19992
20769
|
//#endregion
|
|
20770
|
+
//#region src/features/permissions/copilot-permissions.ts
|
|
20771
|
+
/**
|
|
20772
|
+
* The flat, dotted VS Code setting key this adapter manages. VS Code stores
|
|
20773
|
+
* settings with dotted keys flat at the document top level, so this is a single
|
|
20774
|
+
* literal key — not a nested `chat.tools.terminal` path.
|
|
20775
|
+
* @see https://code.visualstudio.com/docs/agents/approvals
|
|
20776
|
+
*/
|
|
20777
|
+
const AUTO_APPROVE_KEY = "chat.tools.terminal.autoApprove";
|
|
20778
|
+
/**
|
|
20779
|
+
* The canonical permission category this adapter maps. Only shell/terminal
|
|
20780
|
+
* commands (`bash`) have a clean, high-fidelity representation in VS Code's
|
|
20781
|
+
* `chat.tools.terminal.autoApprove` map; other categories (read/edit/webfetch/
|
|
20782
|
+
* …) have no terminal-command equivalent and are intentionally not mapped.
|
|
20783
|
+
*/
|
|
20784
|
+
const TERMINAL_CATEGORY = "bash";
|
|
20785
|
+
function asAutoApproveMap(value) {
|
|
20786
|
+
if (!isPlainObject$1(value)) return {};
|
|
20787
|
+
const result = {};
|
|
20788
|
+
for (const [pattern, flag] of Object.entries(value)) if (typeof flag === "boolean") result[pattern] = flag;
|
|
20789
|
+
return result;
|
|
20790
|
+
}
|
|
20791
|
+
/**
|
|
20792
|
+
* Permissions generator for GitHub Copilot Chat in VS Code.
|
|
20793
|
+
*
|
|
20794
|
+
* VS Code has no standalone, environment-agnostic Copilot policy file (like
|
|
20795
|
+
* `.claude/settings.json`); project-level terminal auto-approvals are managed
|
|
20796
|
+
* through the workspace `chat.tools.terminal.autoApprove` map inside
|
|
20797
|
+
* `.vscode/settings.json`. That file is a general workspace settings file with
|
|
20798
|
+
* many unrelated keys, so reads and writes merge into the existing JSON
|
|
20799
|
+
* (touching only the one managed key) and the file is never deleted.
|
|
20800
|
+
*
|
|
20801
|
+
* Scope is deliberately limited to `chat.tools.terminal.autoApprove` — the one
|
|
20802
|
+
* clean, non-lossy mapping. The canonical `bash` category's per-pattern rules
|
|
20803
|
+
* map as: `allow` → `true` (auto-approve), `deny` → `false` (never approve),
|
|
20804
|
+
* and `ask` → the entry is OMITTED (VS Code then falls through to its default
|
|
20805
|
+
* in-chat approval prompt, i.e. "ask"). Only project scope is modeled: VS Code's
|
|
20806
|
+
* user-scope settings.json lives at a platform-dependent path outside rulesync's
|
|
20807
|
+
* home-relative global model.
|
|
20808
|
+
*/
|
|
20809
|
+
var CopilotPermissions = class CopilotPermissions extends ToolPermissions {
|
|
20810
|
+
constructor(params) {
|
|
20811
|
+
super({
|
|
20812
|
+
...params,
|
|
20813
|
+
fileContent: params.fileContent ?? "{}"
|
|
20814
|
+
});
|
|
20815
|
+
}
|
|
20816
|
+
/**
|
|
20817
|
+
* `.vscode/settings.json` is a user-managed workspace file with unrelated
|
|
20818
|
+
* settings, so it must not be deleted.
|
|
20819
|
+
*/
|
|
20820
|
+
isDeletable() {
|
|
20821
|
+
return false;
|
|
20822
|
+
}
|
|
20823
|
+
static getSettablePaths(_options = {}) {
|
|
20824
|
+
return {
|
|
20825
|
+
relativeDirPath: COPILOT_MCP_DIR,
|
|
20826
|
+
relativeFilePath: COPILOT_VSCODE_SETTINGS_FILE_NAME
|
|
20827
|
+
};
|
|
20828
|
+
}
|
|
20829
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true }) {
|
|
20830
|
+
const paths = CopilotPermissions.getSettablePaths();
|
|
20831
|
+
const fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{}";
|
|
20832
|
+
return new CopilotPermissions({
|
|
20833
|
+
outputRoot,
|
|
20834
|
+
relativeDirPath: paths.relativeDirPath,
|
|
20835
|
+
relativeFilePath: paths.relativeFilePath,
|
|
20836
|
+
fileContent,
|
|
20837
|
+
validate
|
|
20838
|
+
});
|
|
20839
|
+
}
|
|
20840
|
+
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions }) {
|
|
20841
|
+
const paths = CopilotPermissions.getSettablePaths();
|
|
20842
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
20843
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "{}";
|
|
20844
|
+
const rules = rulesyncPermissions.getJson().permission[TERMINAL_CATEGORY] ?? {};
|
|
20845
|
+
const autoApprove = {};
|
|
20846
|
+
for (const [pattern, action] of Object.entries(rules)) if (action === "allow") autoApprove[pattern] = true;
|
|
20847
|
+
else if (action === "deny") autoApprove[pattern] = false;
|
|
20848
|
+
const patchValue = Object.keys(autoApprove).length > 0 ? autoApprove : void 0;
|
|
20849
|
+
return new CopilotPermissions({
|
|
20850
|
+
outputRoot,
|
|
20851
|
+
relativeDirPath: paths.relativeDirPath,
|
|
20852
|
+
relativeFilePath: paths.relativeFilePath,
|
|
20853
|
+
fileContent: applySharedConfigPatch({
|
|
20854
|
+
fileKey: sharedConfigFileKey(paths),
|
|
20855
|
+
feature: "permissions",
|
|
20856
|
+
existingContent,
|
|
20857
|
+
patch: { [AUTO_APPROVE_KEY]: patchValue },
|
|
20858
|
+
filePath
|
|
20859
|
+
}),
|
|
20860
|
+
validate: true
|
|
20861
|
+
});
|
|
20862
|
+
}
|
|
20863
|
+
toRulesyncPermissions() {
|
|
20864
|
+
let settings;
|
|
20865
|
+
try {
|
|
20866
|
+
settings = parseSharedConfig({
|
|
20867
|
+
format: "jsonc",
|
|
20868
|
+
fileContent: this.getFileContent() || "{}",
|
|
20869
|
+
filePath: join(this.getRelativeDirPath(), this.getRelativeFilePath()),
|
|
20870
|
+
invalidRootPolicy: "error",
|
|
20871
|
+
jsoncParseErrors: "error"
|
|
20872
|
+
});
|
|
20873
|
+
} catch (error) {
|
|
20874
|
+
throw new Error(`Failed to parse Copilot VS Code settings in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
20875
|
+
}
|
|
20876
|
+
const autoApprove = asAutoApproveMap(settings[AUTO_APPROVE_KEY]);
|
|
20877
|
+
const rules = {};
|
|
20878
|
+
for (const [pattern, flag] of Object.entries(autoApprove)) rules[pattern] = flag ? "allow" : "deny";
|
|
20879
|
+
const permission = Object.keys(rules).length > 0 ? { [TERMINAL_CATEGORY]: rules } : {};
|
|
20880
|
+
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify({ permission }, null, 2) });
|
|
20881
|
+
}
|
|
20882
|
+
validate() {
|
|
20883
|
+
return {
|
|
20884
|
+
success: true,
|
|
20885
|
+
error: null
|
|
20886
|
+
};
|
|
20887
|
+
}
|
|
20888
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
20889
|
+
return new CopilotPermissions({
|
|
20890
|
+
outputRoot,
|
|
20891
|
+
relativeDirPath,
|
|
20892
|
+
relativeFilePath,
|
|
20893
|
+
fileContent: "{}",
|
|
20894
|
+
validate: false
|
|
20895
|
+
});
|
|
20896
|
+
}
|
|
20897
|
+
};
|
|
20898
|
+
//#endregion
|
|
19993
20899
|
//#region src/features/permissions/cursor-permissions.ts
|
|
19994
20900
|
/**
|
|
19995
20901
|
* Mapping from rulesync canonical tool category names (lowercase) to Cursor CLI
|
|
@@ -20909,7 +21815,7 @@ function convertRulesyncToGoosePermissionConfig({ config, logger }) {
|
|
|
20909
21815
|
function convertGoosePermissionConfigToRulesync(userPermission) {
|
|
20910
21816
|
const permission = {};
|
|
20911
21817
|
for (const key of GOOSE_PERMISSION_LIST_KEYS) {
|
|
20912
|
-
const toolNames = isStringArray(userPermission[key]) ? userPermission[key] : [];
|
|
21818
|
+
const toolNames = isStringArray$1(userPermission[key]) ? userPermission[key] : [];
|
|
20913
21819
|
const action = GOOSE_LIST_TO_ACTION[key];
|
|
20914
21820
|
for (const toolName of toolNames) {
|
|
20915
21821
|
const category = GOOSE_TO_RULESYNC_TOOL_NAME[toolName] ?? toolName;
|
|
@@ -21149,7 +22055,7 @@ const ACTION_RANK = {
|
|
|
21149
22055
|
* (mirrors the Cursor adapter's preservation of unmanaged types).
|
|
21150
22056
|
*/
|
|
21151
22057
|
function unmanagedEntries(existingPermission, key) {
|
|
21152
|
-
return (isStringArray(existingPermission[key]) ? existingPermission[key] : []).filter((entry) => parseGrokEntry(entry) === null);
|
|
22058
|
+
return (isStringArray$1(existingPermission[key]) ? existingPermission[key] : []).filter((entry) => parseGrokEntry(entry) === null);
|
|
21153
22059
|
}
|
|
21154
22060
|
/**
|
|
21155
22061
|
* Bucket canonical rules into Grok's `[permission]` allow/deny/ask arrays of
|
|
@@ -21190,9 +22096,9 @@ function buildGrokPermissionArrays(config, existingPermission, logger) {
|
|
|
21190
22096
|
* arrays resolves to the strictest action.
|
|
21191
22097
|
*/
|
|
21192
22098
|
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;
|
|
22099
|
+
const allow = isStringArray$1(permission.allow) ? permission.allow : void 0;
|
|
22100
|
+
const deny = isStringArray$1(permission.deny) ? permission.deny : void 0;
|
|
22101
|
+
const ask = isStringArray$1(permission.ask) ? permission.ask : void 0;
|
|
21196
22102
|
if ((allow?.length ?? 0) + (deny?.length ?? 0) + (ask?.length ?? 0) === 0) return null;
|
|
21197
22103
|
const result = {};
|
|
21198
22104
|
const apply = (entries, action) => {
|
|
@@ -22973,7 +23879,7 @@ function convertRovodevToolPermissionsToRulesync(toolPermissions) {
|
|
|
22973
23879
|
permission[category][CATCH_ALL_PATTERN$1] = value;
|
|
22974
23880
|
}
|
|
22975
23881
|
}
|
|
22976
|
-
if (isStringArray(toolPermissions.allowedExternalPaths)) for (const path of toolPermissions.allowedExternalPaths) {
|
|
23882
|
+
if (isStringArray$1(toolPermissions.allowedExternalPaths)) for (const path of toolPermissions.allowedExternalPaths) {
|
|
22977
23883
|
permission.read ??= {};
|
|
22978
23884
|
permission.read[path] = "allow";
|
|
22979
23885
|
}
|
|
@@ -23533,8 +24439,8 @@ var WarpPermissions = class WarpPermissions extends ToolPermissions {
|
|
|
23533
24439
|
const agents = isRecord(settings.agents) ? settings.agents : {};
|
|
23534
24440
|
const profiles = isRecord(agents.profiles) ? agents.profiles : {};
|
|
23535
24441
|
const config = convertWarpToRulesyncPermissions({
|
|
23536
|
-
allow: isStringArray(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
|
|
23537
|
-
deny: isStringArray(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
|
|
24442
|
+
allow: isStringArray$1(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
|
|
24443
|
+
deny: isStringArray$1(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
|
|
23538
24444
|
});
|
|
23539
24445
|
const warpOverride = {};
|
|
23540
24446
|
for (const key of WARP_OVERRIDE_KEYS) if (profiles[key] !== void 0) warpOverride[key] = profiles[key];
|
|
@@ -23880,6 +24786,14 @@ const toolPermissionsFactories = /* @__PURE__ */ new Map([
|
|
|
23880
24786
|
supportsImport: true
|
|
23881
24787
|
}
|
|
23882
24788
|
}],
|
|
24789
|
+
["copilot", {
|
|
24790
|
+
class: CopilotPermissions,
|
|
24791
|
+
meta: {
|
|
24792
|
+
supportsProject: true,
|
|
24793
|
+
supportsGlobal: false,
|
|
24794
|
+
supportsImport: true
|
|
24795
|
+
}
|
|
24796
|
+
}],
|
|
23883
24797
|
["cursor", {
|
|
23884
24798
|
class: CursorPermissions,
|
|
23885
24799
|
meta: {
|
|
@@ -24114,9 +25028,6 @@ var PermissionsProcessor = class extends FeatureProcessor {
|
|
|
24114
25028
|
}
|
|
24115
25029
|
};
|
|
24116
25030
|
//#endregion
|
|
24117
|
-
//#region src/constants/general.ts
|
|
24118
|
-
const SKILL_FILE_NAME = "SKILL.md";
|
|
24119
|
-
//#endregion
|
|
24120
25031
|
//#region src/types/ai-dir.ts
|
|
24121
25032
|
var AiDir = class {
|
|
24122
25033
|
/**
|
|
@@ -24317,10 +25228,10 @@ var ToolSkill = class extends AiDir {
|
|
|
24317
25228
|
const settablePaths = getSettablePaths({ global });
|
|
24318
25229
|
const actualRelativeDirPath = relativeDirPath ?? settablePaths.relativeDirPath;
|
|
24319
25230
|
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}`);
|
|
25231
|
+
const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
|
|
25232
|
+
if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
|
|
24322
25233
|
const { frontmatter, body: content } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
|
|
24323
|
-
const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME);
|
|
25234
|
+
const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME$1);
|
|
24324
25235
|
return {
|
|
24325
25236
|
outputRoot,
|
|
24326
25237
|
relativeDirPath: actualRelativeDirPath,
|
|
@@ -24362,7 +25273,7 @@ var SimulatedSkill = class extends ToolSkill {
|
|
|
24362
25273
|
relativeDirPath,
|
|
24363
25274
|
dirName,
|
|
24364
25275
|
mainFile: {
|
|
24365
|
-
name: SKILL_FILE_NAME,
|
|
25276
|
+
name: SKILL_FILE_NAME$1,
|
|
24366
25277
|
body,
|
|
24367
25278
|
frontmatter: { ...frontmatter }
|
|
24368
25279
|
},
|
|
@@ -24420,12 +25331,12 @@ var SimulatedSkill = class extends ToolSkill {
|
|
|
24420
25331
|
const settablePaths = this.getSettablePaths();
|
|
24421
25332
|
const actualRelativeDirPath = relativeDirPath ?? settablePaths.relativeDirPath;
|
|
24422
25333
|
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}`);
|
|
25334
|
+
const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
|
|
25335
|
+
if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
|
|
24425
25336
|
const { frontmatter, body: content } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
|
|
24426
25337
|
const result = SimulatedSkillFrontmatterSchema.safeParse(frontmatter);
|
|
24427
25338
|
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);
|
|
25339
|
+
const otherFiles = await this.collectOtherFiles(outputRoot, actualRelativeDirPath, dirName, SKILL_FILE_NAME$1);
|
|
24429
25340
|
return {
|
|
24430
25341
|
outputRoot,
|
|
24431
25342
|
relativeDirPath: actualRelativeDirPath,
|
|
@@ -24635,7 +25546,7 @@ var RulesyncSkill = class RulesyncSkill extends AiDir {
|
|
|
24635
25546
|
relativeDirPath,
|
|
24636
25547
|
dirName,
|
|
24637
25548
|
mainFile: {
|
|
24638
|
-
name: SKILL_FILE_NAME,
|
|
25549
|
+
name: SKILL_FILE_NAME$1,
|
|
24639
25550
|
body,
|
|
24640
25551
|
frontmatter: { ...frontmatter }
|
|
24641
25552
|
},
|
|
@@ -24670,13 +25581,13 @@ var RulesyncSkill = class RulesyncSkill extends AiDir {
|
|
|
24670
25581
|
}
|
|
24671
25582
|
static async fromDir({ outputRoot = process.cwd(), relativeDirPath = RULESYNC_SKILLS_RELATIVE_DIR_PATH, dirName, global = false }) {
|
|
24672
25583
|
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}`);
|
|
25584
|
+
const skillFilePath = join(skillDirPath, SKILL_FILE_NAME$1);
|
|
25585
|
+
if (!await fileExists(skillFilePath)) throw new Error(`${SKILL_FILE_NAME$1} not found in ${skillDirPath}`);
|
|
24675
25586
|
const { frontmatter, body: content, hasFrontmatter } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
|
|
24676
25587
|
if (!hasFrontmatter) throw new Error(`Missing frontmatter in ${skillFilePath}. Rulesync files must begin with a YAML frontmatter block delimited by '---'.`);
|
|
24677
25588
|
const result = RulesyncSkillFrontmatterSchema.safeParse(frontmatter);
|
|
24678
25589
|
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);
|
|
25590
|
+
const otherFiles = await this.collectOtherFiles(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME$1);
|
|
24680
25591
|
return new RulesyncSkill({
|
|
24681
25592
|
outputRoot,
|
|
24682
25593
|
relativeDirPath,
|
|
@@ -24716,7 +25627,7 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
|
|
|
24716
25627
|
relativeDirPath,
|
|
24717
25628
|
dirName,
|
|
24718
25629
|
mainFile: {
|
|
24719
|
-
name: SKILL_FILE_NAME,
|
|
25630
|
+
name: SKILL_FILE_NAME$1,
|
|
24720
25631
|
body,
|
|
24721
25632
|
frontmatter: { ...frontmatter }
|
|
24722
25633
|
},
|
|
@@ -24743,7 +25654,7 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
|
|
|
24743
25654
|
validate() {
|
|
24744
25655
|
if (!this.mainFile) return {
|
|
24745
25656
|
success: false,
|
|
24746
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
25657
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
24747
25658
|
};
|
|
24748
25659
|
const result = RovodevSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
24749
25660
|
if (!result.success) return {
|
|
@@ -24819,10 +25730,10 @@ var RovodevSkill = class RovodevSkill extends ToolSkill {
|
|
|
24819
25730
|
const result = RovodevSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
24820
25731
|
if (!result.success) {
|
|
24821
25732
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
24822
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
25733
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
24823
25734
|
}
|
|
24824
25735
|
if (result.data.name !== loaded.dirName) {
|
|
24825
|
-
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
25736
|
+
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
|
|
24826
25737
|
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
24827
25738
|
}
|
|
24828
25739
|
return new RovodevSkill({
|
|
@@ -24987,7 +25898,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
|
|
|
24987
25898
|
relativeDirPath,
|
|
24988
25899
|
dirName,
|
|
24989
25900
|
mainFile: {
|
|
24990
|
-
name: SKILL_FILE_NAME,
|
|
25901
|
+
name: SKILL_FILE_NAME$1,
|
|
24991
25902
|
body,
|
|
24992
25903
|
frontmatter: { ...frontmatter }
|
|
24993
25904
|
},
|
|
@@ -25011,7 +25922,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
|
|
|
25011
25922
|
validate() {
|
|
25012
25923
|
if (!this.mainFile) return {
|
|
25013
25924
|
success: false,
|
|
25014
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
25925
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25015
25926
|
};
|
|
25016
25927
|
const result = AgentsSkillsSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25017
25928
|
if (!result.success) return {
|
|
@@ -25083,7 +25994,7 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
|
|
|
25083
25994
|
const result = AgentsSkillsSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25084
25995
|
if (!result.success) {
|
|
25085
25996
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25086
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
25997
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25087
25998
|
}
|
|
25088
25999
|
return new this({
|
|
25089
26000
|
outputRoot: loaded.outputRoot,
|
|
@@ -25140,7 +26051,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
|
|
|
25140
26051
|
relativeDirPath,
|
|
25141
26052
|
dirName,
|
|
25142
26053
|
mainFile: {
|
|
25143
|
-
name: SKILL_FILE_NAME,
|
|
26054
|
+
name: SKILL_FILE_NAME$1,
|
|
25144
26055
|
body,
|
|
25145
26056
|
frontmatter: { ...frontmatter }
|
|
25146
26057
|
},
|
|
@@ -25165,7 +26076,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
|
|
|
25165
26076
|
validate() {
|
|
25166
26077
|
if (!this.mainFile) return {
|
|
25167
26078
|
success: false,
|
|
25168
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26079
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25169
26080
|
};
|
|
25170
26081
|
const result = AiassistantSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25171
26082
|
if (!result.success) return {
|
|
@@ -25225,7 +26136,7 @@ var AiassistantSkill = class AiassistantSkill extends ToolSkill {
|
|
|
25225
26136
|
const result = AiassistantSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25226
26137
|
if (!result.success) {
|
|
25227
26138
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25228
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26139
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25229
26140
|
}
|
|
25230
26141
|
return new AiassistantSkill({
|
|
25231
26142
|
outputRoot: loaded.outputRoot,
|
|
@@ -25276,7 +26187,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
|
|
|
25276
26187
|
relativeDirPath,
|
|
25277
26188
|
dirName,
|
|
25278
26189
|
mainFile: {
|
|
25279
|
-
name: SKILL_FILE_NAME,
|
|
26190
|
+
name: SKILL_FILE_NAME$1,
|
|
25280
26191
|
body,
|
|
25281
26192
|
frontmatter: { ...frontmatter }
|
|
25282
26193
|
},
|
|
@@ -25300,7 +26211,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
|
|
|
25300
26211
|
validate() {
|
|
25301
26212
|
if (!this.mainFile) return {
|
|
25302
26213
|
success: false,
|
|
25303
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26214
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25304
26215
|
};
|
|
25305
26216
|
const result = AmpSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25306
26217
|
if (!result.success) return {
|
|
@@ -25360,7 +26271,7 @@ var AmpSkill = class AmpSkill extends ToolSkill {
|
|
|
25360
26271
|
const result = AmpSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25361
26272
|
if (!result.success) {
|
|
25362
26273
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25363
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26274
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25364
26275
|
}
|
|
25365
26276
|
return new AmpSkill({
|
|
25366
26277
|
outputRoot: loaded.outputRoot,
|
|
@@ -25416,7 +26327,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
25416
26327
|
relativeDirPath,
|
|
25417
26328
|
dirName,
|
|
25418
26329
|
mainFile: {
|
|
25419
|
-
name: SKILL_FILE_NAME,
|
|
26330
|
+
name: SKILL_FILE_NAME$1,
|
|
25420
26331
|
body,
|
|
25421
26332
|
frontmatter: { ...frontmatter }
|
|
25422
26333
|
},
|
|
@@ -25449,7 +26360,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
25449
26360
|
validate() {
|
|
25450
26361
|
if (this.mainFile === void 0) return {
|
|
25451
26362
|
success: false,
|
|
25452
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26363
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25453
26364
|
};
|
|
25454
26365
|
const result = AntigravitySkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25455
26366
|
if (!result.success) return {
|
|
@@ -25509,7 +26420,7 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
25509
26420
|
const result = AntigravitySkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25510
26421
|
if (!result.success) {
|
|
25511
26422
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25512
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26423
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25513
26424
|
}
|
|
25514
26425
|
return new this({
|
|
25515
26426
|
outputRoot: loaded.outputRoot,
|
|
@@ -25593,7 +26504,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
25593
26504
|
relativeDirPath,
|
|
25594
26505
|
dirName,
|
|
25595
26506
|
mainFile: {
|
|
25596
|
-
name: SKILL_FILE_NAME,
|
|
26507
|
+
name: SKILL_FILE_NAME$1,
|
|
25597
26508
|
body,
|
|
25598
26509
|
frontmatter: { ...frontmatter }
|
|
25599
26510
|
},
|
|
@@ -25620,7 +26531,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
25620
26531
|
validate() {
|
|
25621
26532
|
if (this.mainFile === void 0) return {
|
|
25622
26533
|
success: false,
|
|
25623
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26534
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25624
26535
|
};
|
|
25625
26536
|
const result = AugmentcodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25626
26537
|
if (!result.success) return {
|
|
@@ -25680,7 +26591,7 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
25680
26591
|
const result = AugmentcodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25681
26592
|
if (!result.success) {
|
|
25682
26593
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25683
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26594
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25684
26595
|
}
|
|
25685
26596
|
return new AugmentcodeSkill({
|
|
25686
26597
|
outputRoot: loaded.outputRoot,
|
|
@@ -25821,7 +26732,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
|
|
|
25821
26732
|
relativeDirPath,
|
|
25822
26733
|
dirName,
|
|
25823
26734
|
mainFile: {
|
|
25824
|
-
name: SKILL_FILE_NAME,
|
|
26735
|
+
name: SKILL_FILE_NAME$1,
|
|
25825
26736
|
body,
|
|
25826
26737
|
frontmatter: { ...frontmatter }
|
|
25827
26738
|
},
|
|
@@ -25848,7 +26759,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
|
|
|
25848
26759
|
validate() {
|
|
25849
26760
|
if (this.mainFile === void 0) return {
|
|
25850
26761
|
success: false,
|
|
25851
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26762
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
25852
26763
|
};
|
|
25853
26764
|
const result = ClaudecodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
25854
26765
|
if (!result.success) return {
|
|
@@ -25936,7 +26847,7 @@ var ClaudecodeSkill = class ClaudecodeSkill extends ToolSkill {
|
|
|
25936
26847
|
const result = ClaudecodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
25937
26848
|
if (!result.success) {
|
|
25938
26849
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
25939
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26850
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
25940
26851
|
}
|
|
25941
26852
|
return new ClaudecodeSkill({
|
|
25942
26853
|
outputRoot: loaded.outputRoot,
|
|
@@ -25982,7 +26893,7 @@ var ClineSkill = class ClineSkill extends ToolSkill {
|
|
|
25982
26893
|
relativeDirPath,
|
|
25983
26894
|
dirName,
|
|
25984
26895
|
mainFile: {
|
|
25985
|
-
name: SKILL_FILE_NAME,
|
|
26896
|
+
name: SKILL_FILE_NAME$1,
|
|
25986
26897
|
body,
|
|
25987
26898
|
frontmatter: { ...frontmatter }
|
|
25988
26899
|
},
|
|
@@ -26006,7 +26917,7 @@ var ClineSkill = class ClineSkill extends ToolSkill {
|
|
|
26006
26917
|
validate() {
|
|
26007
26918
|
if (!this.mainFile) return {
|
|
26008
26919
|
success: false,
|
|
26009
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
26920
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26010
26921
|
};
|
|
26011
26922
|
const result = ClineSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26012
26923
|
if (!result.success) return {
|
|
@@ -26070,10 +26981,10 @@ var ClineSkill = class ClineSkill extends ToolSkill {
|
|
|
26070
26981
|
const result = ClineSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26071
26982
|
if (!result.success) {
|
|
26072
26983
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26073
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
26984
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26074
26985
|
}
|
|
26075
26986
|
if (result.data.name !== loaded.dirName) {
|
|
26076
|
-
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
26987
|
+
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
|
|
26077
26988
|
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
26078
26989
|
}
|
|
26079
26990
|
return new ClineSkill({
|
|
@@ -26187,7 +27098,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
|
|
|
26187
27098
|
relativeDirPath,
|
|
26188
27099
|
dirName,
|
|
26189
27100
|
mainFile: {
|
|
26190
|
-
name: SKILL_FILE_NAME,
|
|
27101
|
+
name: SKILL_FILE_NAME$1,
|
|
26191
27102
|
body,
|
|
26192
27103
|
frontmatter: { ...frontmatter }
|
|
26193
27104
|
},
|
|
@@ -26211,7 +27122,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
|
|
|
26211
27122
|
validate() {
|
|
26212
27123
|
if (!this.mainFile) return {
|
|
26213
27124
|
success: false,
|
|
26214
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27125
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26215
27126
|
};
|
|
26216
27127
|
const result = CodexCliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26217
27128
|
if (!result.success) return {
|
|
@@ -26289,7 +27200,7 @@ var CodexCliSkill = class CodexCliSkill extends ToolSkill {
|
|
|
26289
27200
|
const result = CodexCliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26290
27201
|
if (!result.success) {
|
|
26291
27202
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26292
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27203
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26293
27204
|
}
|
|
26294
27205
|
return new CodexCliSkill({
|
|
26295
27206
|
outputRoot: loaded.outputRoot,
|
|
@@ -26341,7 +27252,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
26341
27252
|
relativeDirPath,
|
|
26342
27253
|
dirName,
|
|
26343
27254
|
mainFile: {
|
|
26344
|
-
name: SKILL_FILE_NAME,
|
|
27255
|
+
name: SKILL_FILE_NAME$1,
|
|
26345
27256
|
body,
|
|
26346
27257
|
frontmatter: { ...frontmatter }
|
|
26347
27258
|
},
|
|
@@ -26366,7 +27277,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
26366
27277
|
validate() {
|
|
26367
27278
|
if (!this.mainFile) return {
|
|
26368
27279
|
success: false,
|
|
26369
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27280
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26370
27281
|
};
|
|
26371
27282
|
const result = CopilotSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26372
27283
|
if (!result.success) return {
|
|
@@ -26433,7 +27344,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
26433
27344
|
const result = CopilotSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26434
27345
|
if (!result.success) {
|
|
26435
27346
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26436
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27347
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26437
27348
|
}
|
|
26438
27349
|
return new CopilotSkill({
|
|
26439
27350
|
outputRoot: loaded.outputRoot,
|
|
@@ -26487,7 +27398,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
26487
27398
|
relativeDirPath,
|
|
26488
27399
|
dirName,
|
|
26489
27400
|
mainFile: {
|
|
26490
|
-
name: SKILL_FILE_NAME,
|
|
27401
|
+
name: SKILL_FILE_NAME$1,
|
|
26491
27402
|
body,
|
|
26492
27403
|
frontmatter: { ...frontmatter }
|
|
26493
27404
|
},
|
|
@@ -26512,7 +27423,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
26512
27423
|
validate() {
|
|
26513
27424
|
if (!this.mainFile) return {
|
|
26514
27425
|
success: false,
|
|
26515
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27426
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26516
27427
|
};
|
|
26517
27428
|
const result = CopilotcliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26518
27429
|
if (!result.success) return {
|
|
@@ -26581,7 +27492,7 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
26581
27492
|
const result = CopilotcliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26582
27493
|
if (!result.success) {
|
|
26583
27494
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26584
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27495
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26585
27496
|
}
|
|
26586
27497
|
return new CopilotcliSkill({
|
|
26587
27498
|
outputRoot: loaded.outputRoot,
|
|
@@ -26631,7 +27542,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
|
|
|
26631
27542
|
relativeDirPath,
|
|
26632
27543
|
dirName,
|
|
26633
27544
|
mainFile: {
|
|
26634
|
-
name: SKILL_FILE_NAME,
|
|
27545
|
+
name: SKILL_FILE_NAME$1,
|
|
26635
27546
|
body,
|
|
26636
27547
|
frontmatter: { ...frontmatter }
|
|
26637
27548
|
},
|
|
@@ -26655,7 +27566,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
|
|
|
26655
27566
|
validate() {
|
|
26656
27567
|
if (!this.mainFile) return {
|
|
26657
27568
|
success: false,
|
|
26658
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27569
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26659
27570
|
};
|
|
26660
27571
|
const result = CursorSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26661
27572
|
if (!result.success) return {
|
|
@@ -26729,7 +27640,7 @@ var CursorSkill = class CursorSkill extends ToolSkill {
|
|
|
26729
27640
|
const result = CursorSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26730
27641
|
if (!result.success) {
|
|
26731
27642
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26732
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27643
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26733
27644
|
}
|
|
26734
27645
|
return new CursorSkill({
|
|
26735
27646
|
outputRoot: loaded.outputRoot,
|
|
@@ -26776,7 +27687,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
|
|
|
26776
27687
|
relativeDirPath,
|
|
26777
27688
|
dirName,
|
|
26778
27689
|
mainFile: {
|
|
26779
|
-
name: SKILL_FILE_NAME,
|
|
27690
|
+
name: SKILL_FILE_NAME$1,
|
|
26780
27691
|
body,
|
|
26781
27692
|
frontmatter: { ...frontmatter }
|
|
26782
27693
|
},
|
|
@@ -26800,7 +27711,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
|
|
|
26800
27711
|
validate() {
|
|
26801
27712
|
if (!this.mainFile) return {
|
|
26802
27713
|
success: false,
|
|
26803
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27714
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26804
27715
|
};
|
|
26805
27716
|
const result = DeepagentsSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26806
27717
|
if (!result.success) return {
|
|
@@ -26876,7 +27787,7 @@ var DeepagentsSkill = class DeepagentsSkill extends ToolSkill {
|
|
|
26876
27787
|
const result = DeepagentsSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
26877
27788
|
if (!result.success) {
|
|
26878
27789
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
26879
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27790
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
26880
27791
|
}
|
|
26881
27792
|
return new DeepagentsSkill({
|
|
26882
27793
|
outputRoot: loaded.outputRoot,
|
|
@@ -26927,7 +27838,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
|
|
|
26927
27838
|
relativeDirPath,
|
|
26928
27839
|
dirName,
|
|
26929
27840
|
mainFile: {
|
|
26930
|
-
name: SKILL_FILE_NAME,
|
|
27841
|
+
name: SKILL_FILE_NAME$1,
|
|
26931
27842
|
body,
|
|
26932
27843
|
frontmatter: { ...frontmatter }
|
|
26933
27844
|
},
|
|
@@ -26952,7 +27863,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
|
|
|
26952
27863
|
validate() {
|
|
26953
27864
|
if (!this.mainFile) return {
|
|
26954
27865
|
success: false,
|
|
26955
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
27866
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
26956
27867
|
};
|
|
26957
27868
|
const result = DevinSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
26958
27869
|
if (!result.success) return {
|
|
@@ -27004,6 +27915,18 @@ var DevinSkill = class DevinSkill extends ToolSkill {
|
|
|
27004
27915
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
27005
27916
|
return targets.includes("*") || targets.includes("devin");
|
|
27006
27917
|
}
|
|
27918
|
+
/**
|
|
27919
|
+
* Commands are emitted into this same skills tree as `<slug>/SKILL.md`
|
|
27920
|
+
* (see `DevinCommand`), so a directory matching a current rulesync command
|
|
27921
|
+
* slug is owned by the commands feature: it must not be imported as a
|
|
27922
|
+
* skill nor deleted as an orphan skill.
|
|
27923
|
+
*/
|
|
27924
|
+
static async isDirOwned({ dirName, inputRoot }) {
|
|
27925
|
+
return !await rulesyncCommandSlugExists({
|
|
27926
|
+
inputRoot,
|
|
27927
|
+
dirName
|
|
27928
|
+
});
|
|
27929
|
+
}
|
|
27007
27930
|
static async fromDir(params) {
|
|
27008
27931
|
const loaded = await this.loadSkillDirContent({
|
|
27009
27932
|
...params,
|
|
@@ -27012,7 +27935,7 @@ var DevinSkill = class DevinSkill extends ToolSkill {
|
|
|
27012
27935
|
const result = DevinSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27013
27936
|
if (!result.success) {
|
|
27014
27937
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27015
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
27938
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27016
27939
|
}
|
|
27017
27940
|
return new DevinSkill({
|
|
27018
27941
|
outputRoot: loaded.outputRoot,
|
|
@@ -27064,7 +27987,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
|
|
|
27064
27987
|
relativeDirPath,
|
|
27065
27988
|
dirName,
|
|
27066
27989
|
mainFile: {
|
|
27067
|
-
name: SKILL_FILE_NAME,
|
|
27990
|
+
name: SKILL_FILE_NAME$1,
|
|
27068
27991
|
body,
|
|
27069
27992
|
frontmatter: { ...frontmatter }
|
|
27070
27993
|
},
|
|
@@ -27088,7 +28011,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
|
|
|
27088
28011
|
validate() {
|
|
27089
28012
|
if (this.mainFile === void 0) return {
|
|
27090
28013
|
success: false,
|
|
27091
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28014
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27092
28015
|
};
|
|
27093
28016
|
const result = FactorydroidSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27094
28017
|
if (!result.success) return {
|
|
@@ -27163,7 +28086,7 @@ var FactorydroidSkill = class FactorydroidSkill extends ToolSkill {
|
|
|
27163
28086
|
const result = FactorydroidSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27164
28087
|
if (!result.success) {
|
|
27165
28088
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27166
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28089
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27167
28090
|
}
|
|
27168
28091
|
return new FactorydroidSkill({
|
|
27169
28092
|
outputRoot: loaded.outputRoot,
|
|
@@ -27210,7 +28133,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
|
|
|
27210
28133
|
relativeDirPath,
|
|
27211
28134
|
dirName,
|
|
27212
28135
|
mainFile: {
|
|
27213
|
-
name: SKILL_FILE_NAME,
|
|
28136
|
+
name: SKILL_FILE_NAME$1,
|
|
27214
28137
|
body,
|
|
27215
28138
|
frontmatter: { ...frontmatter }
|
|
27216
28139
|
},
|
|
@@ -27235,7 +28158,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
|
|
|
27235
28158
|
validate() {
|
|
27236
28159
|
if (!this.mainFile) return {
|
|
27237
28160
|
success: false,
|
|
27238
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28161
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27239
28162
|
};
|
|
27240
28163
|
const result = GooseSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27241
28164
|
if (!result.success) return {
|
|
@@ -27295,7 +28218,7 @@ var GooseSkill = class GooseSkill extends ToolSkill {
|
|
|
27295
28218
|
const result = GooseSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27296
28219
|
if (!result.success) {
|
|
27297
28220
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27298
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28221
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27299
28222
|
}
|
|
27300
28223
|
return new GooseSkill({
|
|
27301
28224
|
outputRoot: loaded.outputRoot,
|
|
@@ -27348,7 +28271,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
|
|
|
27348
28271
|
relativeDirPath,
|
|
27349
28272
|
dirName,
|
|
27350
28273
|
mainFile: {
|
|
27351
|
-
name: SKILL_FILE_NAME,
|
|
28274
|
+
name: SKILL_FILE_NAME$1,
|
|
27352
28275
|
body,
|
|
27353
28276
|
frontmatter: { ...frontmatter }
|
|
27354
28277
|
},
|
|
@@ -27372,7 +28295,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
|
|
|
27372
28295
|
validate() {
|
|
27373
28296
|
if (this.mainFile === void 0) return {
|
|
27374
28297
|
success: false,
|
|
27375
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28298
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27376
28299
|
};
|
|
27377
28300
|
const result = GrokcliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27378
28301
|
if (!result.success) return {
|
|
@@ -27432,7 +28355,7 @@ var GrokcliSkill = class GrokcliSkill extends ToolSkill {
|
|
|
27432
28355
|
const result = GrokcliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27433
28356
|
if (!result.success) {
|
|
27434
28357
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27435
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28358
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27436
28359
|
}
|
|
27437
28360
|
return new GrokcliSkill({
|
|
27438
28361
|
outputRoot: loaded.outputRoot,
|
|
@@ -27467,6 +28390,18 @@ var HermesagentSkill = class extends AgentsSkillsSkill {
|
|
|
27467
28390
|
static getSettablePaths() {
|
|
27468
28391
|
return { relativeDirPath: HERMESAGENT_SKILLS_DIR_PATH };
|
|
27469
28392
|
}
|
|
28393
|
+
/**
|
|
28394
|
+
* Commands are emitted into this same skills tree as `<slug>/SKILL.md`
|
|
28395
|
+
* (see `HermesagentCommand`), so a directory matching a current rulesync
|
|
28396
|
+
* command slug is owned by the commands feature: it must not be imported
|
|
28397
|
+
* as a skill nor deleted as an orphan skill.
|
|
28398
|
+
*/
|
|
28399
|
+
static async isDirOwned({ dirName, inputRoot }) {
|
|
28400
|
+
return !await rulesyncCommandSlugExists({
|
|
28401
|
+
inputRoot,
|
|
28402
|
+
dirName
|
|
28403
|
+
});
|
|
28404
|
+
}
|
|
27470
28405
|
constructor(params) {
|
|
27471
28406
|
super({
|
|
27472
28407
|
...params,
|
|
@@ -27491,7 +28426,7 @@ var JunieSkill = class JunieSkill extends ToolSkill {
|
|
|
27491
28426
|
relativeDirPath,
|
|
27492
28427
|
dirName,
|
|
27493
28428
|
mainFile: {
|
|
27494
|
-
name: SKILL_FILE_NAME,
|
|
28429
|
+
name: SKILL_FILE_NAME$1,
|
|
27495
28430
|
body,
|
|
27496
28431
|
frontmatter: { ...frontmatter }
|
|
27497
28432
|
},
|
|
@@ -27515,7 +28450,7 @@ var JunieSkill = class JunieSkill extends ToolSkill {
|
|
|
27515
28450
|
validate() {
|
|
27516
28451
|
if (!this.mainFile) return {
|
|
27517
28452
|
success: false,
|
|
27518
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28453
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27519
28454
|
};
|
|
27520
28455
|
const result = JunieSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27521
28456
|
if (!result.success) return {
|
|
@@ -27579,10 +28514,10 @@ var JunieSkill = class JunieSkill extends ToolSkill {
|
|
|
27579
28514
|
const result = JunieSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27580
28515
|
if (!result.success) {
|
|
27581
28516
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27582
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28517
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27583
28518
|
}
|
|
27584
28519
|
if (result.data.name !== loaded.dirName) {
|
|
27585
|
-
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
28520
|
+
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
|
|
27586
28521
|
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
27587
28522
|
}
|
|
27588
28523
|
return new JunieSkill({
|
|
@@ -27630,7 +28565,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
|
|
|
27630
28565
|
relativeDirPath,
|
|
27631
28566
|
dirName,
|
|
27632
28567
|
mainFile: {
|
|
27633
|
-
name: SKILL_FILE_NAME,
|
|
28568
|
+
name: SKILL_FILE_NAME$1,
|
|
27634
28569
|
body,
|
|
27635
28570
|
frontmatter: { ...frontmatter }
|
|
27636
28571
|
},
|
|
@@ -27654,7 +28589,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
|
|
|
27654
28589
|
validate() {
|
|
27655
28590
|
if (this.mainFile === void 0) return {
|
|
27656
28591
|
success: false,
|
|
27657
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28592
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27658
28593
|
};
|
|
27659
28594
|
const result = KiloSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27660
28595
|
if (!result.success) return {
|
|
@@ -27726,7 +28661,7 @@ var KiloSkill = class KiloSkill extends ToolSkill {
|
|
|
27726
28661
|
const result = KiloSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27727
28662
|
if (!result.success) {
|
|
27728
28663
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27729
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28664
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27730
28665
|
}
|
|
27731
28666
|
return new KiloSkill({
|
|
27732
28667
|
outputRoot: loaded.outputRoot,
|
|
@@ -27772,7 +28707,7 @@ var KiroSkill = class KiroSkill extends ToolSkill {
|
|
|
27772
28707
|
relativeDirPath,
|
|
27773
28708
|
dirName,
|
|
27774
28709
|
mainFile: {
|
|
27775
|
-
name: SKILL_FILE_NAME,
|
|
28710
|
+
name: SKILL_FILE_NAME$1,
|
|
27776
28711
|
body,
|
|
27777
28712
|
frontmatter: { ...frontmatter }
|
|
27778
28713
|
},
|
|
@@ -27796,7 +28731,7 @@ var KiroSkill = class KiroSkill extends ToolSkill {
|
|
|
27796
28731
|
validate() {
|
|
27797
28732
|
if (!this.mainFile) return {
|
|
27798
28733
|
success: false,
|
|
27799
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28734
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27800
28735
|
};
|
|
27801
28736
|
const result = KiroSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27802
28737
|
if (!result.success) return {
|
|
@@ -27860,10 +28795,10 @@ var KiroSkill = class KiroSkill extends ToolSkill {
|
|
|
27860
28795
|
const result = KiroSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
27861
28796
|
if (!result.success) {
|
|
27862
28797
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
27863
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28798
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
27864
28799
|
}
|
|
27865
28800
|
if (result.data.name !== loaded.dirName) {
|
|
27866
|
-
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
28801
|
+
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
|
|
27867
28802
|
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
27868
28803
|
}
|
|
27869
28804
|
return new KiroSkill({
|
|
@@ -27946,7 +28881,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
|
|
|
27946
28881
|
relativeDirPath,
|
|
27947
28882
|
dirName,
|
|
27948
28883
|
mainFile: {
|
|
27949
|
-
name: SKILL_FILE_NAME,
|
|
28884
|
+
name: SKILL_FILE_NAME$1,
|
|
27950
28885
|
body,
|
|
27951
28886
|
frontmatter: { ...frontmatter }
|
|
27952
28887
|
},
|
|
@@ -27973,7 +28908,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
|
|
|
27973
28908
|
validate() {
|
|
27974
28909
|
if (this.mainFile === void 0) return {
|
|
27975
28910
|
success: false,
|
|
27976
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
28911
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
27977
28912
|
};
|
|
27978
28913
|
const result = OpenCodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
27979
28914
|
if (!result.success) return {
|
|
@@ -28052,7 +28987,7 @@ var OpenCodeSkill = class OpenCodeSkill extends ToolSkill {
|
|
|
28052
28987
|
const result = OpenCodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28053
28988
|
if (!result.success) {
|
|
28054
28989
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28055
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
28990
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28056
28991
|
}
|
|
28057
28992
|
return new OpenCodeSkill({
|
|
28058
28993
|
outputRoot: loaded.outputRoot,
|
|
@@ -28113,7 +29048,7 @@ var PiSkill = class PiSkill extends ToolSkill {
|
|
|
28113
29048
|
relativeDirPath: resolvedDirPath,
|
|
28114
29049
|
dirName,
|
|
28115
29050
|
mainFile: {
|
|
28116
|
-
name: SKILL_FILE_NAME,
|
|
29051
|
+
name: SKILL_FILE_NAME$1,
|
|
28117
29052
|
body,
|
|
28118
29053
|
frontmatter: { ...frontmatter }
|
|
28119
29054
|
},
|
|
@@ -28138,7 +29073,7 @@ var PiSkill = class PiSkill extends ToolSkill {
|
|
|
28138
29073
|
validate() {
|
|
28139
29074
|
if (!this.mainFile) return {
|
|
28140
29075
|
success: false,
|
|
28141
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29076
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
28142
29077
|
};
|
|
28143
29078
|
const result = PiSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
28144
29079
|
if (!result.success) return {
|
|
@@ -28213,7 +29148,7 @@ var PiSkill = class PiSkill extends ToolSkill {
|
|
|
28213
29148
|
const result = PiSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28214
29149
|
if (!result.success) {
|
|
28215
29150
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28216
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
29151
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28217
29152
|
}
|
|
28218
29153
|
return new PiSkill({
|
|
28219
29154
|
outputRoot: loaded.outputRoot,
|
|
@@ -28266,7 +29201,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
|
|
|
28266
29201
|
relativeDirPath,
|
|
28267
29202
|
dirName,
|
|
28268
29203
|
mainFile: {
|
|
28269
|
-
name: SKILL_FILE_NAME,
|
|
29204
|
+
name: SKILL_FILE_NAME$1,
|
|
28270
29205
|
body,
|
|
28271
29206
|
frontmatter: { ...frontmatter }
|
|
28272
29207
|
},
|
|
@@ -28290,7 +29225,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
|
|
|
28290
29225
|
validate() {
|
|
28291
29226
|
if (this.mainFile === void 0) return {
|
|
28292
29227
|
success: false,
|
|
28293
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29228
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
28294
29229
|
};
|
|
28295
29230
|
const result = QwencodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
28296
29231
|
if (!result.success) return {
|
|
@@ -28370,7 +29305,7 @@ var QwencodeSkill = class QwencodeSkill extends ToolSkill {
|
|
|
28370
29305
|
const result = QwencodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28371
29306
|
if (!result.success) {
|
|
28372
29307
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28373
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
29308
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28374
29309
|
}
|
|
28375
29310
|
return new QwencodeSkill({
|
|
28376
29311
|
outputRoot: loaded.outputRoot,
|
|
@@ -28420,7 +29355,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
|
|
|
28420
29355
|
relativeDirPath,
|
|
28421
29356
|
dirName,
|
|
28422
29357
|
mainFile: {
|
|
28423
|
-
name: SKILL_FILE_NAME,
|
|
29358
|
+
name: SKILL_FILE_NAME$1,
|
|
28424
29359
|
body,
|
|
28425
29360
|
frontmatter: { ...frontmatter }
|
|
28426
29361
|
},
|
|
@@ -28444,7 +29379,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
|
|
|
28444
29379
|
validate() {
|
|
28445
29380
|
if (this.mainFile === void 0) return {
|
|
28446
29381
|
success: false,
|
|
28447
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29382
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
28448
29383
|
};
|
|
28449
29384
|
const result = ReasonixSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
28450
29385
|
if (!result.success) return {
|
|
@@ -28504,7 +29439,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
|
|
|
28504
29439
|
const result = ReasonixSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28505
29440
|
if (!result.success) {
|
|
28506
29441
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28507
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
29442
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28508
29443
|
}
|
|
28509
29444
|
return new ReasonixSkill({
|
|
28510
29445
|
outputRoot: loaded.outputRoot,
|
|
@@ -28527,7 +29462,7 @@ var ReasonixSkill = class ReasonixSkill extends ToolSkill {
|
|
|
28527
29462
|
* skills-feature ownership, matching the previous behavior for such dirs.
|
|
28528
29463
|
*/
|
|
28529
29464
|
static async isDirOwned({ outputRoot, relativeDirPath, dirName }) {
|
|
28530
|
-
const skillFilePath = join(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME);
|
|
29465
|
+
const skillFilePath = join(outputRoot, relativeDirPath, dirName, SKILL_FILE_NAME$1);
|
|
28531
29466
|
try {
|
|
28532
29467
|
const { frontmatter } = parseFrontmatter(await readFileContent(skillFilePath), skillFilePath);
|
|
28533
29468
|
return frontmatter["runAs"] !== REASONIX_SUBAGENT_RUN_AS;
|
|
@@ -28577,7 +29512,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
|
|
|
28577
29512
|
relativeDirPath,
|
|
28578
29513
|
dirName,
|
|
28579
29514
|
mainFile: {
|
|
28580
|
-
name: SKILL_FILE_NAME,
|
|
29515
|
+
name: SKILL_FILE_NAME$1,
|
|
28581
29516
|
body,
|
|
28582
29517
|
frontmatter: { ...frontmatter }
|
|
28583
29518
|
},
|
|
@@ -28601,7 +29536,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
|
|
|
28601
29536
|
validate() {
|
|
28602
29537
|
if (!this.mainFile) return {
|
|
28603
29538
|
success: false,
|
|
28604
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29539
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
28605
29540
|
};
|
|
28606
29541
|
const result = ReplitSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
28607
29542
|
if (!result.success) return {
|
|
@@ -28669,7 +29604,7 @@ var ReplitSkill = class ReplitSkill extends ToolSkill {
|
|
|
28669
29604
|
const result = ReplitSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28670
29605
|
if (!result.success) {
|
|
28671
29606
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28672
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
29607
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28673
29608
|
}
|
|
28674
29609
|
return new ReplitSkill({
|
|
28675
29610
|
outputRoot: loaded.outputRoot,
|
|
@@ -28716,7 +29651,7 @@ var RooSkill = class RooSkill extends ToolSkill {
|
|
|
28716
29651
|
relativeDirPath,
|
|
28717
29652
|
dirName,
|
|
28718
29653
|
mainFile: {
|
|
28719
|
-
name: SKILL_FILE_NAME,
|
|
29654
|
+
name: SKILL_FILE_NAME$1,
|
|
28720
29655
|
body,
|
|
28721
29656
|
frontmatter: { ...frontmatter }
|
|
28722
29657
|
},
|
|
@@ -28740,7 +29675,7 @@ var RooSkill = class RooSkill extends ToolSkill {
|
|
|
28740
29675
|
validate() {
|
|
28741
29676
|
if (!this.mainFile) return {
|
|
28742
29677
|
success: false,
|
|
28743
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29678
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
28744
29679
|
};
|
|
28745
29680
|
const result = RooSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
28746
29681
|
if (!result.success) return {
|
|
@@ -28804,10 +29739,10 @@ var RooSkill = class RooSkill extends ToolSkill {
|
|
|
28804
29739
|
const result = RooSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
28805
29740
|
if (!result.success) {
|
|
28806
29741
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
28807
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
29742
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
28808
29743
|
}
|
|
28809
29744
|
if (result.data.name !== loaded.dirName) {
|
|
28810
|
-
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
29745
|
+
const skillFilePath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME$1);
|
|
28811
29746
|
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
28812
29747
|
}
|
|
28813
29748
|
return new RooSkill({
|
|
@@ -29024,7 +29959,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
|
|
|
29024
29959
|
relativeDirPath,
|
|
29025
29960
|
dirName,
|
|
29026
29961
|
mainFile: {
|
|
29027
|
-
name: SKILL_FILE_NAME,
|
|
29962
|
+
name: SKILL_FILE_NAME$1,
|
|
29028
29963
|
body,
|
|
29029
29964
|
frontmatter: { ...frontmatter }
|
|
29030
29965
|
},
|
|
@@ -29051,7 +29986,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
|
|
|
29051
29986
|
validate() {
|
|
29052
29987
|
if (!this.mainFile) return {
|
|
29053
29988
|
success: false,
|
|
29054
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
29989
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
29055
29990
|
};
|
|
29056
29991
|
const result = VibeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
29057
29992
|
if (!result.success) return {
|
|
@@ -29115,7 +30050,7 @@ var VibeSkill = class VibeSkill extends ToolSkill {
|
|
|
29115
30050
|
const result = VibeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
29116
30051
|
if (!result.success) {
|
|
29117
30052
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
29118
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
30053
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
29119
30054
|
}
|
|
29120
30055
|
return new VibeSkill({
|
|
29121
30056
|
outputRoot: loaded.outputRoot,
|
|
@@ -29171,7 +30106,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
|
|
|
29171
30106
|
relativeDirPath,
|
|
29172
30107
|
dirName,
|
|
29173
30108
|
mainFile: {
|
|
29174
|
-
name: SKILL_FILE_NAME,
|
|
30109
|
+
name: SKILL_FILE_NAME$1,
|
|
29175
30110
|
body,
|
|
29176
30111
|
frontmatter: { ...frontmatter }
|
|
29177
30112
|
},
|
|
@@ -29195,7 +30130,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
|
|
|
29195
30130
|
validate() {
|
|
29196
30131
|
if (this.mainFile === void 0) return {
|
|
29197
30132
|
success: false,
|
|
29198
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
30133
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
29199
30134
|
};
|
|
29200
30135
|
const result = WarpSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
29201
30136
|
if (!result.success) return {
|
|
@@ -29255,7 +30190,7 @@ var WarpSkill = class WarpSkill extends ToolSkill {
|
|
|
29255
30190
|
const result = WarpSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
29256
30191
|
if (!result.success) {
|
|
29257
30192
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
29258
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
30193
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
29259
30194
|
}
|
|
29260
30195
|
return new WarpSkill({
|
|
29261
30196
|
outputRoot: loaded.outputRoot,
|
|
@@ -29303,7 +30238,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
|
|
|
29303
30238
|
relativeDirPath,
|
|
29304
30239
|
dirName,
|
|
29305
30240
|
mainFile: {
|
|
29306
|
-
name: SKILL_FILE_NAME,
|
|
30241
|
+
name: SKILL_FILE_NAME$1,
|
|
29307
30242
|
body,
|
|
29308
30243
|
frontmatter: { ...frontmatter }
|
|
29309
30244
|
},
|
|
@@ -29327,7 +30262,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
|
|
|
29327
30262
|
validate() {
|
|
29328
30263
|
if (!this.mainFile) return {
|
|
29329
30264
|
success: false,
|
|
29330
|
-
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
30265
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME$1} file does not exist`)
|
|
29331
30266
|
};
|
|
29332
30267
|
const result = ZedSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
29333
30268
|
if (!result.success) return {
|
|
@@ -29396,7 +30331,7 @@ var ZedSkill = class ZedSkill extends ToolSkill {
|
|
|
29396
30331
|
const result = ZedSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
29397
30332
|
if (!result.success) {
|
|
29398
30333
|
const skillDirPath = join(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
29399
|
-
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
30334
|
+
throw new Error(`Invalid frontmatter in ${join(skillDirPath, SKILL_FILE_NAME$1)}: ${formatError(result.error)}`);
|
|
29400
30335
|
}
|
|
29401
30336
|
return new ZedSkill({
|
|
29402
30337
|
outputRoot: loaded.outputRoot,
|
|
@@ -29836,7 +30771,8 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
29836
30771
|
if (factory.class.isDirOwned && !await factory.class.isDirOwned({
|
|
29837
30772
|
outputRoot: this.outputRoot,
|
|
29838
30773
|
relativeDirPath: root,
|
|
29839
|
-
dirName
|
|
30774
|
+
dirName,
|
|
30775
|
+
inputRoot: this.inputRoot
|
|
29840
30776
|
})) continue;
|
|
29841
30777
|
seenDirNames.add(dirName);
|
|
29842
30778
|
loadEntries.push({
|
|
@@ -29867,7 +30803,8 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
29867
30803
|
if (factory.class.isDirOwned && !await factory.class.isDirOwned({
|
|
29868
30804
|
outputRoot: this.outputRoot,
|
|
29869
30805
|
relativeDirPath: root,
|
|
29870
|
-
dirName
|
|
30806
|
+
dirName,
|
|
30807
|
+
inputRoot: this.inputRoot
|
|
29871
30808
|
})) continue;
|
|
29872
30809
|
const toolSkill = factory.class.forDeletion({
|
|
29873
30810
|
outputRoot: this.outputRoot,
|
|
@@ -30970,7 +31907,6 @@ var CodexCliSubagent = class CodexCliSubagent extends ToolSubagent {
|
|
|
30970
31907
|
};
|
|
30971
31908
|
//#endregion
|
|
30972
31909
|
//#region src/features/subagents/copilot-subagent.ts
|
|
30973
|
-
const REQUIRED_TOOL = "agent/runSubagent";
|
|
30974
31910
|
const CopilotSubagentFrontmatterSchema = z.looseObject({
|
|
30975
31911
|
name: z.string(),
|
|
30976
31912
|
description: z.optional(z.string()),
|
|
@@ -30980,10 +31916,6 @@ const normalizeTools = (tools) => {
|
|
|
30980
31916
|
if (!tools) return [];
|
|
30981
31917
|
return Array.isArray(tools) ? tools : [tools];
|
|
30982
31918
|
};
|
|
30983
|
-
const ensureRequiredTool = (tools) => {
|
|
30984
|
-
const mergedTools = /* @__PURE__ */ new Set([REQUIRED_TOOL, ...tools]);
|
|
30985
|
-
return Array.from(mergedTools);
|
|
30986
|
-
};
|
|
30987
31919
|
const toCopilotAgentFilePath = (relativeFilePath) => {
|
|
30988
31920
|
if (relativeFilePath.endsWith(".agent.md")) return relativeFilePath;
|
|
30989
31921
|
if (relativeFilePath.endsWith(".md")) return relativeFilePath.replace(/\.md$/, ".agent.md");
|
|
@@ -31037,14 +31969,14 @@ var CopilotSubagent = class CopilotSubagent extends ToolSubagent {
|
|
|
31037
31969
|
static fromRulesyncSubagent({ outputRoot = process.cwd(), rulesyncSubagent, validate = true, global = false }) {
|
|
31038
31970
|
const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
|
|
31039
31971
|
const copilotSection = rulesyncFrontmatter.copilot ?? {};
|
|
31972
|
+
const { tools: _rawTools, ...copilotRest } = copilotSection;
|
|
31040
31973
|
const toolsField = copilotSection.tools;
|
|
31041
31974
|
const userTools = normalizeTools(Array.isArray(toolsField) || typeof toolsField === "string" ? toolsField : void 0);
|
|
31042
|
-
const mergedTools = ensureRequiredTool(userTools);
|
|
31043
31975
|
const copilotFrontmatter = {
|
|
31044
31976
|
name: rulesyncFrontmatter.name,
|
|
31045
31977
|
description: rulesyncFrontmatter.description,
|
|
31046
|
-
...
|
|
31047
|
-
...
|
|
31978
|
+
...copilotRest,
|
|
31979
|
+
...userTools.length > 0 && { tools: userTools }
|
|
31048
31980
|
};
|
|
31049
31981
|
const body = rulesyncSubagent.getBody();
|
|
31050
31982
|
const fileContent = stringifyFrontmatter(body, copilotFrontmatter);
|
|
@@ -33268,7 +34200,7 @@ var ReasonixSubagent = class ReasonixSubagent extends ToolSubagent {
|
|
|
33268
34200
|
frontmatter: reasonixFrontmatter,
|
|
33269
34201
|
body,
|
|
33270
34202
|
relativeDirPath: paths.relativeDirPath,
|
|
33271
|
-
relativeFilePath: join(subagentName, SKILL_FILE_NAME),
|
|
34203
|
+
relativeFilePath: join(subagentName, SKILL_FILE_NAME$1),
|
|
33272
34204
|
fileContent,
|
|
33273
34205
|
validate,
|
|
33274
34206
|
global
|
|
@@ -34274,6 +35206,7 @@ const RulesyncRuleFrontmatterSchema = z.object({
|
|
|
34274
35206
|
name: z.optional(z.string()),
|
|
34275
35207
|
description: z.optional(z.string())
|
|
34276
35208
|
})),
|
|
35209
|
+
pi: z.optional(z.looseObject({ systemPrompt: z.optional(z.enum(["append"])) })),
|
|
34277
35210
|
takt: z.optional(z.looseObject({
|
|
34278
35211
|
name: z.optional(z.string()),
|
|
34279
35212
|
extends: z.optional(z.string()),
|
|
@@ -34437,6 +35370,16 @@ var ToolRule = class extends ToolFile {
|
|
|
34437
35370
|
isRoot() {
|
|
34438
35371
|
return this.root;
|
|
34439
35372
|
}
|
|
35373
|
+
/**
|
|
35374
|
+
* Whether this rule must be left out of the root rule's reference/MCP
|
|
35375
|
+
* instruction listings even though it is a non-root survivor. Used by files
|
|
35376
|
+
* the tool loads through its own mechanism (e.g. Pi's `APPEND_SYSTEM.md`,
|
|
35377
|
+
* which Pi appends to the system prompt itself — referencing it from
|
|
35378
|
+
* `AGENTS.md` would double-load the content).
|
|
35379
|
+
*/
|
|
35380
|
+
isExcludedFromRootReferences() {
|
|
35381
|
+
return false;
|
|
35382
|
+
}
|
|
34440
35383
|
getDescription() {
|
|
34441
35384
|
return this.description;
|
|
34442
35385
|
}
|
|
@@ -36783,6 +37726,15 @@ var FactorydroidRule = class FactorydroidRule extends ToolRule {
|
|
|
36783
37726
|
* is `undefined`). This mirrors the grokcli, warp, and deepagents targets.
|
|
36784
37727
|
*
|
|
36785
37728
|
* Goose uses plain markdown files (.goosehints) without frontmatter.
|
|
37729
|
+
*
|
|
37730
|
+
* Global scope emits only `~/.config/goose/.goosehints`. Goose v1.41.0 (PR
|
|
37731
|
+
* block/goose#9736) additionally loads the vendor-neutral
|
|
37732
|
+
* `~/.agents/AGENTS.md` alongside the config-dir hints, but rulesync
|
|
37733
|
+
* deliberately does not emit that shared path from the goose target: the
|
|
37734
|
+
* config-dir hints remain fully loaded (no capability loss), and the
|
|
37735
|
+
* cross-tool `~/.agents/AGENTS.md` is already written by targets that own it
|
|
37736
|
+
* (e.g. cline in global mode) — a second writer would need cross-target
|
|
37737
|
+
* shared-file coordination for zero gain (decision recorded in issue #2207).
|
|
36786
37738
|
*/
|
|
36787
37739
|
var GooseRule = class GooseRule extends ToolRule {
|
|
36788
37740
|
static getSettablePaths({ global } = {}) {
|
|
@@ -36984,14 +37936,21 @@ var HermesagentRule = class HermesagentRule extends ToolRule {
|
|
|
36984
37936
|
/**
|
|
36985
37937
|
* Rule generator for JetBrains Junie AI coding agent
|
|
36986
37938
|
*
|
|
36987
|
-
* Generates `.junie/AGENTS.md` files based on rulesync rule content.
|
|
36988
|
-
*
|
|
36989
|
-
*
|
|
36990
|
-
*
|
|
36991
|
-
*
|
|
36992
|
-
*
|
|
36993
|
-
*
|
|
36994
|
-
*
|
|
37939
|
+
* Generates `.junie/AGENTS.md` files based on rulesync rule content. Junie CLI
|
|
37940
|
+
* resolves project guidelines **first-match-wins**: `.junie/AGENTS.md` → root
|
|
37941
|
+
* `AGENTS.md` → legacy `.junie/guidelines.md` / `.junie/guidelines/`. Only the
|
|
37942
|
+
* first match is loaded, it documents no `@`-reference or file-inclusion
|
|
37943
|
+
* mechanism, and no `.junie/memories/` read path exists — so non-root rules
|
|
37944
|
+
* are folded into the single root `.junie/AGENTS.md` by the RulesProcessor
|
|
37945
|
+
* (`nonRoot` is `undefined`, mirroring the grokcli / warp / deepagents
|
|
37946
|
+
* targets; decision recorded in issue #2211). The legacy
|
|
37947
|
+
* `.junie/guidelines.md` is still accepted as an import fallback, but
|
|
37948
|
+
* generation always targets `.junie/AGENTS.md`. Junie uses plain markdown
|
|
37949
|
+
* without frontmatter requirements.
|
|
37950
|
+
*
|
|
37951
|
+
* Global (user) scope writes a single `~/.junie/AGENTS.md` file. Junie merges
|
|
37952
|
+
* these user-scope guidelines with the project guidelines (both are included
|
|
37953
|
+
* and marked clearly).
|
|
36995
37954
|
*
|
|
36996
37955
|
* @see https://junie.jetbrains.com/docs/junie-ide-plugin.html
|
|
36997
37956
|
* @see https://junie.jetbrains.com/docs/guidelines-and-memory.html
|
|
@@ -37010,15 +37969,12 @@ var JunieRule = class JunieRule extends ToolRule {
|
|
|
37010
37969
|
alternativeRoots: [{
|
|
37011
37970
|
relativeDirPath: buildToolPath(JUNIE_DIR, ".", excludeToolDir),
|
|
37012
37971
|
relativeFilePath: JUNIE_LEGACY_RULE_FILE_NAME
|
|
37013
|
-
}]
|
|
37014
|
-
nonRoot: { relativeDirPath: buildToolPath(JUNIE_DIR, "memories", excludeToolDir) }
|
|
37972
|
+
}]
|
|
37015
37973
|
};
|
|
37016
37974
|
}
|
|
37017
37975
|
/**
|
|
37018
37976
|
* Determines whether a given relative file path refers to a root guideline file.
|
|
37019
37977
|
* 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
37978
|
*/
|
|
37023
37979
|
static isRootRelativeFilePath(relativeFilePath) {
|
|
37024
37980
|
return relativeFilePath === "AGENTS.md" || relativeFilePath === "guidelines.md";
|
|
@@ -37037,10 +37993,7 @@ var JunieRule = class JunieRule extends ToolRule {
|
|
|
37037
37993
|
root: true
|
|
37038
37994
|
});
|
|
37039
37995
|
}
|
|
37040
|
-
const
|
|
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;
|
|
37996
|
+
const relativeDirPath = this.getSettablePaths().root.relativeDirPath;
|
|
37044
37997
|
const fileContent = await readFileContent(join(outputRoot, join(relativeDirPath, relativeFilePath)));
|
|
37045
37998
|
return new JunieRule({
|
|
37046
37999
|
outputRoot,
|
|
@@ -37048,7 +38001,7 @@ var JunieRule = class JunieRule extends ToolRule {
|
|
|
37048
38001
|
relativeFilePath,
|
|
37049
38002
|
fileContent,
|
|
37050
38003
|
validate,
|
|
37051
|
-
root:
|
|
38004
|
+
root: JunieRule.isRootRelativeFilePath(relativeFilePath)
|
|
37052
38005
|
});
|
|
37053
38006
|
}
|
|
37054
38007
|
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
@@ -37063,13 +38016,15 @@ var JunieRule = class JunieRule extends ToolRule {
|
|
|
37063
38016
|
rootPath: paths.root
|
|
37064
38017
|
}));
|
|
37065
38018
|
}
|
|
37066
|
-
|
|
38019
|
+
const { root } = this.getSettablePaths();
|
|
38020
|
+
return new JunieRule({
|
|
37067
38021
|
outputRoot,
|
|
37068
|
-
|
|
38022
|
+
relativeDirPath: root.relativeDirPath,
|
|
38023
|
+
relativeFilePath: root.relativeFilePath,
|
|
38024
|
+
fileContent: rulesyncRule.getBody(),
|
|
37069
38025
|
validate,
|
|
37070
|
-
|
|
37071
|
-
|
|
37072
|
-
}));
|
|
38026
|
+
root: rulesyncRule.getFrontmatter().root ?? false
|
|
38027
|
+
});
|
|
37073
38028
|
}
|
|
37074
38029
|
toRulesyncRule() {
|
|
37075
38030
|
return this.toRulesyncRuleDefault();
|
|
@@ -37472,31 +38427,68 @@ var OpenCodeRule = class OpenCodeRule extends ToolRule {
|
|
|
37472
38427
|
* RulesProcessor (there is no separate non-root output location — `nonRoot` is
|
|
37473
38428
|
* `undefined`). This mirrors the codexcli, grokcli, warp, and deepagents targets.
|
|
37474
38429
|
*
|
|
37475
|
-
* Pi also loads two system-prompt instruction files
|
|
38430
|
+
* Pi also loads two system-prompt instruction files. `.pi/APPEND_SYSTEM.md`
|
|
38431
|
+
* (global `~/.pi/agent/APPEND_SYSTEM.md`) *appends* to the default system prompt,
|
|
38432
|
+
* and rulesync emits it from any rule that opts in via the `pi.systemPrompt:
|
|
38433
|
+
* append` frontmatter block: those bodies are routed here instead of being folded
|
|
38434
|
+
* into `AGENTS.md`, and multiple opted-in rules concatenate in source order.
|
|
37476
38435
|
* `.pi/SYSTEM.md` (global `~/.pi/agent/SYSTEM.md`) *replaces* the default system
|
|
37477
|
-
* prompt entirely
|
|
37478
|
-
*
|
|
37479
|
-
*
|
|
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.
|
|
38436
|
+
* prompt entirely — which silently disables Pi's built-in tool instructions — so
|
|
38437
|
+
* rulesync deliberately never emits it and leaves it to be authored by hand.
|
|
38438
|
+
* See docs/reference/file-formats.md.
|
|
37483
38439
|
*/
|
|
37484
38440
|
var PiRule = class PiRule extends ToolRule {
|
|
37485
|
-
|
|
38441
|
+
appendSystemPrompt;
|
|
38442
|
+
constructor({ fileContent, root, appendSystemPrompt = false, ...rest }) {
|
|
37486
38443
|
super({
|
|
37487
38444
|
...rest,
|
|
37488
38445
|
fileContent,
|
|
37489
38446
|
root: root ?? false
|
|
37490
38447
|
});
|
|
38448
|
+
this.appendSystemPrompt = appendSystemPrompt;
|
|
37491
38449
|
}
|
|
37492
38450
|
static getSettablePaths({ global = false, excludeToolDir } = {}) {
|
|
37493
|
-
return {
|
|
37494
|
-
|
|
37495
|
-
|
|
37496
|
-
|
|
38451
|
+
return {
|
|
38452
|
+
root: {
|
|
38453
|
+
relativeDirPath: global ? buildToolPath(".pi", "agent", excludeToolDir) : ".",
|
|
38454
|
+
relativeFilePath: PI_RULE_FILE_NAME
|
|
38455
|
+
},
|
|
38456
|
+
appendSystemPrompt: {
|
|
38457
|
+
relativeDirPath: global ? buildToolPath(".pi", "agent", excludeToolDir) : ".pi",
|
|
38458
|
+
relativeFilePath: PI_APPEND_SYSTEM_FILE_NAME
|
|
38459
|
+
}
|
|
38460
|
+
};
|
|
37497
38461
|
}
|
|
37498
|
-
|
|
37499
|
-
|
|
38462
|
+
/**
|
|
38463
|
+
* Extra fixed files this tool manages beyond the root rule. The
|
|
38464
|
+
* RulesProcessor enumerates these for import and deletion so a stale
|
|
38465
|
+
* `APPEND_SYSTEM.md` is cleaned up once no rule opts in anymore.
|
|
38466
|
+
*/
|
|
38467
|
+
static getExtraFixedFiles({ global = false } = {}) {
|
|
38468
|
+
return [this.getSettablePaths({ global }).appendSystemPrompt];
|
|
38469
|
+
}
|
|
38470
|
+
/**
|
|
38471
|
+
* Pi appends `APPEND_SYSTEM.md` to the system prompt itself, so listing it in
|
|
38472
|
+
* the root rule's reference section (toon/explicit discovery modes) would
|
|
38473
|
+
* double-load the content.
|
|
38474
|
+
*/
|
|
38475
|
+
isExcludedFromRootReferences() {
|
|
38476
|
+
return this.appendSystemPrompt;
|
|
38477
|
+
}
|
|
38478
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
38479
|
+
const { root, appendSystemPrompt } = this.getSettablePaths({ global });
|
|
38480
|
+
if (relativeFilePath === "APPEND_SYSTEM.md") {
|
|
38481
|
+
const fileContent = await readFileContent(join(outputRoot, join(appendSystemPrompt.relativeDirPath, appendSystemPrompt.relativeFilePath)));
|
|
38482
|
+
return new PiRule({
|
|
38483
|
+
outputRoot,
|
|
38484
|
+
relativeDirPath: appendSystemPrompt.relativeDirPath,
|
|
38485
|
+
relativeFilePath: appendSystemPrompt.relativeFilePath,
|
|
38486
|
+
fileContent,
|
|
38487
|
+
validate,
|
|
38488
|
+
root: false,
|
|
38489
|
+
appendSystemPrompt: true
|
|
38490
|
+
});
|
|
38491
|
+
}
|
|
37500
38492
|
const fileContent = await readFileContent(join(outputRoot, join(root.relativeDirPath, root.relativeFilePath)));
|
|
37501
38493
|
return new PiRule({
|
|
37502
38494
|
outputRoot,
|
|
@@ -37508,8 +38500,18 @@ var PiRule = class PiRule extends ToolRule {
|
|
|
37508
38500
|
});
|
|
37509
38501
|
}
|
|
37510
38502
|
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
37511
|
-
const { root } = this.getSettablePaths({ global });
|
|
37512
|
-
const
|
|
38503
|
+
const { root, appendSystemPrompt } = this.getSettablePaths({ global });
|
|
38504
|
+
const frontmatter = rulesyncRule.getFrontmatter();
|
|
38505
|
+
if (!frontmatter.root && frontmatter.pi?.systemPrompt === "append") return new PiRule({
|
|
38506
|
+
outputRoot,
|
|
38507
|
+
relativeDirPath: appendSystemPrompt.relativeDirPath,
|
|
38508
|
+
relativeFilePath: appendSystemPrompt.relativeFilePath,
|
|
38509
|
+
fileContent: rulesyncRule.getBody(),
|
|
38510
|
+
validate,
|
|
38511
|
+
root: false,
|
|
38512
|
+
appendSystemPrompt: true
|
|
38513
|
+
});
|
|
38514
|
+
const isRoot = frontmatter.root ?? false;
|
|
37513
38515
|
return new PiRule({
|
|
37514
38516
|
outputRoot,
|
|
37515
38517
|
relativeDirPath: root.relativeDirPath,
|
|
@@ -37520,6 +38522,17 @@ var PiRule = class PiRule extends ToolRule {
|
|
|
37520
38522
|
});
|
|
37521
38523
|
}
|
|
37522
38524
|
toRulesyncRule() {
|
|
38525
|
+
if (this.appendSystemPrompt) return new RulesyncRule({
|
|
38526
|
+
outputRoot: process.cwd(),
|
|
38527
|
+
relativeDirPath: RULESYNC_RULES_RELATIVE_DIR_PATH,
|
|
38528
|
+
relativeFilePath: PI_APPEND_SYSTEM_FILE_NAME,
|
|
38529
|
+
frontmatter: {
|
|
38530
|
+
root: false,
|
|
38531
|
+
targets: ["pi"],
|
|
38532
|
+
pi: { systemPrompt: "append" }
|
|
38533
|
+
},
|
|
38534
|
+
body: this.getFileContent()
|
|
38535
|
+
});
|
|
37523
38536
|
return this.toRulesyncRuleDefault();
|
|
37524
38537
|
}
|
|
37525
38538
|
validate() {
|
|
@@ -37530,6 +38543,15 @@ var PiRule = class PiRule extends ToolRule {
|
|
|
37530
38543
|
}
|
|
37531
38544
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
37532
38545
|
const { root } = this.getSettablePaths({ global });
|
|
38546
|
+
if (relativeFilePath === "APPEND_SYSTEM.md") return new PiRule({
|
|
38547
|
+
outputRoot,
|
|
38548
|
+
relativeDirPath,
|
|
38549
|
+
relativeFilePath,
|
|
38550
|
+
fileContent: "",
|
|
38551
|
+
validate: false,
|
|
38552
|
+
root: false,
|
|
38553
|
+
appendSystemPrompt: true
|
|
38554
|
+
});
|
|
37533
38555
|
const isRoot = relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === root.relativeDirPath);
|
|
37534
38556
|
return new PiRule({
|
|
37535
38557
|
outputRoot,
|
|
@@ -38689,7 +39711,8 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
38689
39711
|
meta: {
|
|
38690
39712
|
extension: "md",
|
|
38691
39713
|
supportsGlobal: true,
|
|
38692
|
-
ruleDiscoveryMode: "
|
|
39714
|
+
ruleDiscoveryMode: "auto",
|
|
39715
|
+
foldsNonRootIntoRoot: true
|
|
38693
39716
|
}
|
|
38694
39717
|
}],
|
|
38695
39718
|
["kilo", {
|
|
@@ -38955,7 +39978,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
38955
39978
|
*/
|
|
38956
39979
|
async buildMcpInstructionFiles({ toolRules, meta }) {
|
|
38957
39980
|
if (!meta.mcpInstructionsRegistrar || this.global) return [];
|
|
38958
|
-
const instructionPaths = toolRules.filter((rule) => !rule.isRoot()).map((rule) => toPosixPath(join(rule.getRelativeDirPath(), rule.getRelativeFilePath())));
|
|
39981
|
+
const instructionPaths = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences()).map((rule) => toPosixPath(join(rule.getRelativeDirPath(), rule.getRelativeFilePath())));
|
|
38959
39982
|
if (instructionPaths.length === 0) return [];
|
|
38960
39983
|
return [await meta.mcpInstructionsRegistrar.fromInstructions({
|
|
38961
39984
|
outputRoot: this.outputRoot,
|
|
@@ -38987,7 +40010,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
38987
40010
|
const toolRelativeDirPath = skillClass.getSettablePaths({ global: this.global }).relativeDirPath;
|
|
38988
40011
|
return this.skills.filter((skill) => skillClass.isTargetedByRulesyncSkill(skill)).map((skill) => {
|
|
38989
40012
|
const frontmatter = skill.getFrontmatter();
|
|
38990
|
-
const relativePath = join(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME);
|
|
40013
|
+
const relativePath = join(toolRelativeDirPath, skill.getDirName(), SKILL_FILE_NAME$1);
|
|
38991
40014
|
return {
|
|
38992
40015
|
name: frontmatter.name,
|
|
38993
40016
|
description: frontmatter.description,
|
|
@@ -39011,11 +40034,25 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
39011
40034
|
*/
|
|
39012
40035
|
foldNonRootRulesIntoRootRule(toolRules) {
|
|
39013
40036
|
if (toolRules.length <= 1) return;
|
|
39014
|
-
const
|
|
39015
|
-
|
|
39016
|
-
|
|
39017
|
-
|
|
39018
|
-
|
|
40037
|
+
const groups = /* @__PURE__ */ new Map();
|
|
40038
|
+
for (const rule of toolRules) {
|
|
40039
|
+
const path = join(rule.getRelativeDirPath(), rule.getRelativeFilePath());
|
|
40040
|
+
const group = groups.get(path);
|
|
40041
|
+
if (group) group.push(rule);
|
|
40042
|
+
else groups.set(path, [rule]);
|
|
40043
|
+
}
|
|
40044
|
+
const survivors = /* @__PURE__ */ new Set();
|
|
40045
|
+
for (const group of groups.values()) {
|
|
40046
|
+
const target = group.find((rule) => rule.isRoot()) ?? group[0];
|
|
40047
|
+
if (!target) continue;
|
|
40048
|
+
const mergedContent = [target, ...group.filter((rule) => rule !== target)].map((rule) => rule.getFileContent().trim()).filter((content) => content.length > 0).join("\n\n");
|
|
40049
|
+
target.setFileContent(mergedContent);
|
|
40050
|
+
survivors.add(target);
|
|
40051
|
+
}
|
|
40052
|
+
for (let i = toolRules.length - 1; i >= 0; i--) {
|
|
40053
|
+
const rule = toolRules[i];
|
|
40054
|
+
if (rule && !survivors.has(rule)) toolRules.splice(i, 1);
|
|
40055
|
+
}
|
|
39019
40056
|
}
|
|
39020
40057
|
/**
|
|
39021
40058
|
* Handle localRoot rule generation based on tool target.
|
|
@@ -39225,6 +40262,27 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
39225
40262
|
const mirrorPaths = await findFilesByGlobs(mirrorGlob);
|
|
39226
40263
|
return buildDeletionRulesFromPaths(mirrorPaths);
|
|
39227
40264
|
})();
|
|
40265
|
+
const extraFixedToolRules = await (async () => {
|
|
40266
|
+
const extraFiles = factory.class.getExtraFixedFiles?.({ global: this.global });
|
|
40267
|
+
if (!extraFiles || extraFiles.length === 0) return [];
|
|
40268
|
+
const filePaths = await findFilesByGlobs(extraFiles.map((file) => join(this.outputRoot, file.relativeDirPath, file.relativeFilePath)));
|
|
40269
|
+
if (filePaths.length === 0) return [];
|
|
40270
|
+
if (forDeletion) return buildDeletionRulesFromPaths(filePaths);
|
|
40271
|
+
return await Promise.all(filePaths.map((filePath) => {
|
|
40272
|
+
const relativeDirPath = resolveRelativeDirPath(filePath);
|
|
40273
|
+
checkPathTraversal({
|
|
40274
|
+
relativePath: relativeDirPath,
|
|
40275
|
+
intendedRootDir: this.outputRoot
|
|
40276
|
+
});
|
|
40277
|
+
return factory.class.fromFile({
|
|
40278
|
+
outputRoot: this.outputRoot,
|
|
40279
|
+
relativeDirPath,
|
|
40280
|
+
relativeFilePath: basename(filePath),
|
|
40281
|
+
global: this.global
|
|
40282
|
+
});
|
|
40283
|
+
}));
|
|
40284
|
+
})();
|
|
40285
|
+
this.logger.debug(`Found ${extraFixedToolRules.length} extra fixed tool rule files`);
|
|
39228
40286
|
const nonRootToolRules = await (async () => {
|
|
39229
40287
|
if (!settablePaths.nonRoot) return [];
|
|
39230
40288
|
const nonRootOutputRoot = join(this.outputRoot, settablePaths.nonRoot.relativeDirPath);
|
|
@@ -39260,6 +40318,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
39260
40318
|
...rootToolRules,
|
|
39261
40319
|
...localRootToolRules,
|
|
39262
40320
|
...rootMirrorDeletionRules,
|
|
40321
|
+
...extraFixedToolRules,
|
|
39263
40322
|
...nonRootToolRules
|
|
39264
40323
|
];
|
|
39265
40324
|
} catch (error) {
|
|
@@ -39287,7 +40346,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
39287
40346
|
return toolRuleFactories.get(result.data);
|
|
39288
40347
|
}
|
|
39289
40348
|
generateToonReferencesSection(toolRules) {
|
|
39290
|
-
const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
|
|
40349
|
+
const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences());
|
|
39291
40350
|
if (toolRulesWithoutRoot.length === 0) return "";
|
|
39292
40351
|
const lines = [];
|
|
39293
40352
|
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 +40362,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
39303
40362
|
return lines.join("\n") + "\n\n";
|
|
39304
40363
|
}
|
|
39305
40364
|
generateReferencesSection(toolRules) {
|
|
39306
|
-
const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot());
|
|
40365
|
+
const toolRulesWithoutRoot = toolRules.filter((rule) => !rule.isRoot() && !rule.isExcludedFromRootReferences());
|
|
39307
40366
|
if (toolRulesWithoutRoot.length === 0) return "";
|
|
39308
40367
|
const lines = [];
|
|
39309
40368
|
lines.push("Please also reference the following rules as needed:");
|
|
@@ -39324,7 +40383,7 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
39324
40383
|
*/
|
|
39325
40384
|
async function convertFromTool(params) {
|
|
39326
40385
|
const ctx = params;
|
|
39327
|
-
const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount] = [
|
|
40386
|
+
const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount, checksCount] = [
|
|
39328
40387
|
await runFeatureConvert(ctx, buildRulesStrategy(ctx)),
|
|
39329
40388
|
await runFeatureConvert(ctx, buildIgnoreStrategy(ctx)),
|
|
39330
40389
|
await runFeatureConvert(ctx, buildMcpStrategy(ctx)),
|
|
@@ -39332,7 +40391,8 @@ async function convertFromTool(params) {
|
|
|
39332
40391
|
await runFeatureConvert(ctx, buildSubagentsStrategy(ctx)),
|
|
39333
40392
|
await runFeatureConvert(ctx, buildSkillsStrategy(ctx)),
|
|
39334
40393
|
await runFeatureConvert(ctx, buildHooksStrategy(ctx)),
|
|
39335
|
-
await runFeatureConvert(ctx, buildPermissionsStrategy(ctx))
|
|
40394
|
+
await runFeatureConvert(ctx, buildPermissionsStrategy(ctx)),
|
|
40395
|
+
await runFeatureConvert(ctx, buildChecksStrategy(ctx))
|
|
39336
40396
|
];
|
|
39337
40397
|
return {
|
|
39338
40398
|
rulesCount,
|
|
@@ -39342,7 +40402,8 @@ async function convertFromTool(params) {
|
|
|
39342
40402
|
subagentsCount,
|
|
39343
40403
|
skillsCount,
|
|
39344
40404
|
hooksCount,
|
|
39345
|
-
permissionsCount
|
|
40405
|
+
permissionsCount,
|
|
40406
|
+
checksCount
|
|
39346
40407
|
};
|
|
39347
40408
|
}
|
|
39348
40409
|
async function runFeatureConvert(ctx, strategy) {
|
|
@@ -39575,6 +40636,27 @@ function buildPermissionsStrategy(ctx) {
|
|
|
39575
40636
|
write: (p, files) => p.writeAiFiles(files)
|
|
39576
40637
|
};
|
|
39577
40638
|
}
|
|
40639
|
+
function buildChecksStrategy(ctx) {
|
|
40640
|
+
const { config, logger } = ctx;
|
|
40641
|
+
const global = config.getGlobal();
|
|
40642
|
+
const outputRoot = getOutputRoot(config);
|
|
40643
|
+
return {
|
|
40644
|
+
feature: "checks",
|
|
40645
|
+
itemLabel: "check file(s)",
|
|
40646
|
+
allTargets: ChecksProcessor.getToolTargets({ global }),
|
|
40647
|
+
createProcessor: ({ toolTarget, dryRun }) => new ChecksProcessor({
|
|
40648
|
+
outputRoot,
|
|
40649
|
+
toolTarget,
|
|
40650
|
+
global,
|
|
40651
|
+
dryRun,
|
|
40652
|
+
logger
|
|
40653
|
+
}),
|
|
40654
|
+
loadSource: (p) => p.loadToolFiles(),
|
|
40655
|
+
toRulesync: (p, files) => p.convertToolFilesToRulesyncFiles(files),
|
|
40656
|
+
fromRulesync: (p, files) => p.convertRulesyncFilesToToolFiles(files),
|
|
40657
|
+
write: (p, files) => p.writeAiFiles(files)
|
|
40658
|
+
};
|
|
40659
|
+
}
|
|
39578
40660
|
//#endregion
|
|
39579
40661
|
//#region src/types/processor-registry.ts
|
|
39580
40662
|
const PROCESSOR_REGISTRY = [
|
|
@@ -39625,6 +40707,12 @@ const PROCESSOR_REGISTRY = [
|
|
|
39625
40707
|
processor: PermissionsProcessor,
|
|
39626
40708
|
schema: PermissionsProcessorToolTargetSchema,
|
|
39627
40709
|
factory: toolPermissionsFactories
|
|
40710
|
+
},
|
|
40711
|
+
{
|
|
40712
|
+
feature: "checks",
|
|
40713
|
+
processor: ChecksProcessor,
|
|
40714
|
+
schema: ChecksProcessorToolTargetSchema,
|
|
40715
|
+
factory: toolCheckFactories
|
|
39628
40716
|
}
|
|
39629
40717
|
];
|
|
39630
40718
|
const getProcessorRegistryEntry = (feature) => {
|
|
@@ -39974,6 +41062,7 @@ const GENERATION_STEP_GRAPH = [
|
|
|
39974
41062
|
id: "permissions",
|
|
39975
41063
|
...sharedWriteMeta("permissions")
|
|
39976
41064
|
},
|
|
41065
|
+
{ id: "checks" },
|
|
39977
41066
|
{
|
|
39978
41067
|
id: "rules",
|
|
39979
41068
|
...sharedWriteMeta("rules"),
|
|
@@ -40059,6 +41148,10 @@ async function generate(params) {
|
|
|
40059
41148
|
config,
|
|
40060
41149
|
logger
|
|
40061
41150
|
}),
|
|
41151
|
+
checks: () => generateChecksCore({
|
|
41152
|
+
config,
|
|
41153
|
+
logger
|
|
41154
|
+
}),
|
|
40062
41155
|
rules: () => generateRulesCore({
|
|
40063
41156
|
config,
|
|
40064
41157
|
logger,
|
|
@@ -40095,6 +41188,8 @@ async function generate(params) {
|
|
|
40095
41188
|
hooksPaths: get("hooks").paths,
|
|
40096
41189
|
permissionsCount: get("permissions").count,
|
|
40097
41190
|
permissionsPaths: get("permissions").paths,
|
|
41191
|
+
checksCount: get("checks").count,
|
|
41192
|
+
checksPaths: get("checks").paths,
|
|
40098
41193
|
skills: skillsResult.skills,
|
|
40099
41194
|
hasDiff
|
|
40100
41195
|
};
|
|
@@ -40463,6 +41558,44 @@ async function generatePermissionsCore(params) {
|
|
|
40463
41558
|
hasDiff
|
|
40464
41559
|
};
|
|
40465
41560
|
}
|
|
41561
|
+
async function generateChecksCore(params) {
|
|
41562
|
+
const { config, logger } = params;
|
|
41563
|
+
let totalCount = 0;
|
|
41564
|
+
const allPaths = [];
|
|
41565
|
+
let hasDiff = false;
|
|
41566
|
+
const supportedChecksTargets = ChecksProcessor.getToolTargets({ global: config.getGlobal() });
|
|
41567
|
+
const toolTargets = intersection(config.getTargets(), supportedChecksTargets);
|
|
41568
|
+
warnUnsupportedTargets({
|
|
41569
|
+
config,
|
|
41570
|
+
supportedTargets: supportedChecksTargets,
|
|
41571
|
+
featureName: "checks",
|
|
41572
|
+
logger
|
|
41573
|
+
});
|
|
41574
|
+
for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
|
|
41575
|
+
if (!config.getFeatures(toolTarget).includes("checks")) continue;
|
|
41576
|
+
const processor = new ChecksProcessor({
|
|
41577
|
+
outputRoot,
|
|
41578
|
+
inputRoot: config.getInputRoot(),
|
|
41579
|
+
toolTarget,
|
|
41580
|
+
global: config.getGlobal(),
|
|
41581
|
+
dryRun: config.isPreviewMode(),
|
|
41582
|
+
logger
|
|
41583
|
+
});
|
|
41584
|
+
const result = await processFeatureWithRulesyncFiles({
|
|
41585
|
+
config,
|
|
41586
|
+
processor,
|
|
41587
|
+
rulesyncFiles: await processor.loadRulesyncFiles()
|
|
41588
|
+
});
|
|
41589
|
+
totalCount += result.count;
|
|
41590
|
+
allPaths.push(...result.paths);
|
|
41591
|
+
if (result.hasDiff) hasDiff = true;
|
|
41592
|
+
}
|
|
41593
|
+
return {
|
|
41594
|
+
count: totalCount,
|
|
41595
|
+
paths: allPaths,
|
|
41596
|
+
hasDiff
|
|
41597
|
+
};
|
|
41598
|
+
}
|
|
40466
41599
|
//#endregion
|
|
40467
41600
|
//#region src/lib/import.ts
|
|
40468
41601
|
/**
|
|
@@ -40520,6 +41653,11 @@ async function importFromTool(params) {
|
|
|
40520
41653
|
config,
|
|
40521
41654
|
tool,
|
|
40522
41655
|
logger
|
|
41656
|
+
}),
|
|
41657
|
+
checksCount: await importChecksCore({
|
|
41658
|
+
config,
|
|
41659
|
+
tool,
|
|
41660
|
+
logger
|
|
40523
41661
|
})
|
|
40524
41662
|
};
|
|
40525
41663
|
}
|
|
@@ -40736,7 +41874,28 @@ async function importPermissionsCore(params) {
|
|
|
40736
41874
|
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} permissions file(s)`);
|
|
40737
41875
|
return writtenCount;
|
|
40738
41876
|
}
|
|
41877
|
+
async function importChecksCore(params) {
|
|
41878
|
+
const { config, tool, logger } = params;
|
|
41879
|
+
if (!config.getFeatures(tool).includes("checks")) return 0;
|
|
41880
|
+
const global = config.getGlobal();
|
|
41881
|
+
if (!ChecksProcessor.getToolTargets({ global }).includes(tool)) return 0;
|
|
41882
|
+
const checksProcessor = new ChecksProcessor({
|
|
41883
|
+
outputRoot: config.getOutputRoots()[0] ?? ".",
|
|
41884
|
+
toolTarget: tool,
|
|
41885
|
+
global,
|
|
41886
|
+
logger
|
|
41887
|
+
});
|
|
41888
|
+
const toolFiles = await checksProcessor.loadToolFiles();
|
|
41889
|
+
if (toolFiles.length === 0) {
|
|
41890
|
+
logger.warn(`No check files found for ${tool}. Skipping import.`);
|
|
41891
|
+
return 0;
|
|
41892
|
+
}
|
|
41893
|
+
const rulesyncFiles = await checksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
|
|
41894
|
+
const { count: writtenCount } = await checksProcessor.writeAiFiles(rulesyncFiles);
|
|
41895
|
+
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} check files`);
|
|
41896
|
+
return writtenCount;
|
|
41897
|
+
}
|
|
40739
41898
|
//#endregion
|
|
40740
|
-
export {
|
|
41899
|
+
export { isSymlink as $, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as A, RULESYNC_PERMISSIONS_JSONC_FILE_NAME as At, findControlCharacter as B, ALL_FEATURES_WITH_WILDCARD as Bt, CommandsProcessor as C, RULESYNC_MCP_FILE_NAME as Ct, CLAUDECODE_DIR as D, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Dt, CODEXCLI_DIR as E, RULESYNC_MCP_SCHEMA_URL as Et, RulesyncCheck as F, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Ft, checkPathTraversal as G, JsonLogger as H, RulesyncCheckFrontmatterSchema as I, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as It, ensureDir as J, createTempDirectory as K, stringifyFrontmatter as L, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Lt, RulesyncCommand as M, RULESYNC_PERMISSIONS_SCHEMA_URL as Mt, RulesyncCommandFrontmatterSchema as N, RULESYNC_RELATIVE_DIR_PATH as Nt, CLAUDECODE_LOCAL_RULE_FILE_NAME as O, RULESYNC_OVERVIEW_FILE_NAME as Ot, ChecksProcessor as P, RULESYNC_RULES_RELATIVE_DIR_PATH as Pt, getHomeDirectory as Q, loadYaml as R, formatError 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_RELATIVE_FILE_PATH as jt, CLAUDECODE_MEMORIES_DIR_NAME as k, RULESYNC_PERMISSIONS_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 as zt };
|
|
40741
41900
|
|
|
40742
|
-
//# sourceMappingURL=import-
|
|
41901
|
+
//# sourceMappingURL=import-CSnC5vl7.js.map
|