rulesync 9.8.0 → 10.1.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/dist/cli/index.cjs +143 -37
- package/dist/cli/index.js +143 -37
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-Dioh9ca8.js → import-B02AyWkQ.js} +506 -55
- package/dist/import-B02AyWkQ.js.map +1 -0
- package/dist/{import-l0o1jVdc.cjs → import-Dcj5HiOE.cjs} +544 -63
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-Dioh9ca8.js.map +0 -1
|
@@ -114,28 +114,35 @@ function formatError(error) {
|
|
|
114
114
|
}
|
|
115
115
|
//#endregion
|
|
116
116
|
//#region src/constants/rulesync-paths.ts
|
|
117
|
-
const { join: join$
|
|
117
|
+
const { join: join$251 } = node_path.posix;
|
|
118
118
|
const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
119
119
|
const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
|
|
120
120
|
const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
121
|
-
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$
|
|
122
|
-
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$
|
|
123
|
-
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$
|
|
124
|
-
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$
|
|
125
|
-
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$
|
|
126
|
-
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$
|
|
121
|
+
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "rules");
|
|
122
|
+
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "commands");
|
|
123
|
+
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "subagents");
|
|
124
|
+
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
125
|
+
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
|
|
126
|
+
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
|
|
127
|
+
const RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
|
|
128
|
+
const RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
|
|
129
|
+
const RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
|
|
127
130
|
const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
128
|
-
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$
|
|
131
|
+
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
129
132
|
const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
130
133
|
const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
131
|
-
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$
|
|
132
|
-
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$
|
|
134
|
+
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$251(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
135
|
+
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$251(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
|
|
133
136
|
const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
|
|
134
137
|
const RULESYNC_MCP_FILE_NAME = "mcp.json";
|
|
135
138
|
const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
|
|
136
139
|
const RULESYNC_PERMISSIONS_FILE_NAME = "permissions.json";
|
|
140
|
+
const RULESYNC_MCP_JSONC_FILE_NAME = "mcp.jsonc";
|
|
141
|
+
const RULESYNC_HOOKS_JSONC_FILE_NAME = "hooks.jsonc";
|
|
142
|
+
const RULESYNC_PERMISSIONS_JSONC_FILE_NAME = "permissions.jsonc";
|
|
137
143
|
const RULESYNC_CONFIG_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/config-schema.json";
|
|
138
144
|
const RULESYNC_MCP_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/mcp-schema.json";
|
|
145
|
+
const RULESYNC_PERMISSIONS_SCHEMA_URL = "https://github.com/dyoshikawa/rulesync/releases/latest/download/permissions-schema.json";
|
|
139
146
|
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
140
147
|
//#endregion
|
|
141
148
|
//#region src/types/tool-target-tuples.ts
|
|
@@ -7343,12 +7350,55 @@ function toolHooksToCanonical({ hooks, converterConfig }) {
|
|
|
7343
7350
|
return canonical;
|
|
7344
7351
|
}
|
|
7345
7352
|
//#endregion
|
|
7353
|
+
//#region src/utils/jsonc.ts
|
|
7354
|
+
/**
|
|
7355
|
+
* Rebuild the parsed value from its own enumerable entries, dropping
|
|
7356
|
+
* prototype-pollution keys (`__proto__`, `constructor`, `prototype`).
|
|
7357
|
+
* `jsonc-parser` assigns keys with plain `obj[key] = value` semantics, so a
|
|
7358
|
+
* literal `__proto__` key would replace the containing object's prototype
|
|
7359
|
+
* instead of becoming an own property; rebuilding gives every object a clean
|
|
7360
|
+
* `Object.prototype` again and severs that path.
|
|
7361
|
+
*/
|
|
7362
|
+
function deepSanitize(value) {
|
|
7363
|
+
if (Array.isArray(value)) return value.map((item) => deepSanitize(item));
|
|
7364
|
+
if (value !== null && typeof value === "object") {
|
|
7365
|
+
const sanitized = {};
|
|
7366
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
7367
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
7368
|
+
sanitized[key] = deepSanitize(entry);
|
|
7369
|
+
}
|
|
7370
|
+
return sanitized;
|
|
7371
|
+
}
|
|
7372
|
+
return value;
|
|
7373
|
+
}
|
|
7374
|
+
/**
|
|
7375
|
+
* Parse a JSONC (JSON with Comments) document strictly.
|
|
7376
|
+
*
|
|
7377
|
+
* Unlike `jsonc-parser`'s bare `parse` (which silently tolerates syntax
|
|
7378
|
+
* errors and returns a best-effort value), this throws on any parse error so
|
|
7379
|
+
* a malformed source file fails loudly instead of generating half-empty tool
|
|
7380
|
+
* configs. Plain JSON is valid JSONC, so this is a drop-in replacement for
|
|
7381
|
+
* `JSON.parse` on files that may contain comments or trailing commas.
|
|
7382
|
+
*/
|
|
7383
|
+
function parseJsonc$6(content) {
|
|
7384
|
+
const errors = [];
|
|
7385
|
+
const result = (0, jsonc_parser.parse)(content, errors, {
|
|
7386
|
+
allowTrailingComma: true,
|
|
7387
|
+
disallowComments: false
|
|
7388
|
+
});
|
|
7389
|
+
if (errors.length > 0) {
|
|
7390
|
+
const details = errors.map((e) => `${(0, jsonc_parser.printParseErrorCode)(e.error)} at offset ${e.offset}`).join(", ");
|
|
7391
|
+
throw new SyntaxError(`Failed to parse JSONC content: ${details}`);
|
|
7392
|
+
}
|
|
7393
|
+
return deepSanitize(result);
|
|
7394
|
+
}
|
|
7395
|
+
//#endregion
|
|
7346
7396
|
//#region src/features/hooks/rulesync-hooks.ts
|
|
7347
7397
|
var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
|
|
7348
7398
|
json;
|
|
7349
7399
|
constructor(params) {
|
|
7350
7400
|
super({ ...params });
|
|
7351
|
-
this.json =
|
|
7401
|
+
this.json = parseJsonc$6(this.fileContent);
|
|
7352
7402
|
if (params.validate) {
|
|
7353
7403
|
const result = this.validate();
|
|
7354
7404
|
if (!result.success) throw result.error;
|
|
@@ -7357,7 +7407,11 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
|
|
|
7357
7407
|
static getSettablePaths() {
|
|
7358
7408
|
return {
|
|
7359
7409
|
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
7360
|
-
relativeFilePath:
|
|
7410
|
+
relativeFilePath: RULESYNC_HOOKS_FILE_NAME,
|
|
7411
|
+
jsonc: {
|
|
7412
|
+
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
7413
|
+
relativeFilePath: RULESYNC_HOOKS_JSONC_FILE_NAME
|
|
7414
|
+
}
|
|
7361
7415
|
};
|
|
7362
7416
|
}
|
|
7363
7417
|
validate() {
|
|
@@ -7373,16 +7427,23 @@ var RulesyncHooks = class RulesyncHooks extends RulesyncFile {
|
|
|
7373
7427
|
}
|
|
7374
7428
|
static async fromFile({ outputRoot = process.cwd(), validate = true }) {
|
|
7375
7429
|
const paths = RulesyncHooks.getSettablePaths();
|
|
7376
|
-
const
|
|
7377
|
-
if (!await fileExists(filePath)) throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} found.`);
|
|
7378
|
-
const fileContent = await readFileContent(filePath);
|
|
7379
|
-
return new RulesyncHooks({
|
|
7380
|
-
outputRoot,
|
|
7430
|
+
const candidates = [paths.jsonc, {
|
|
7381
7431
|
relativeDirPath: paths.relativeDirPath,
|
|
7382
|
-
relativeFilePath: paths.relativeFilePath
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7432
|
+
relativeFilePath: paths.relativeFilePath
|
|
7433
|
+
}];
|
|
7434
|
+
for (const candidate of candidates) {
|
|
7435
|
+
const filePath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
|
|
7436
|
+
if (!await fileExists(filePath)) continue;
|
|
7437
|
+
const fileContent = await readFileContent(filePath);
|
|
7438
|
+
return new RulesyncHooks({
|
|
7439
|
+
outputRoot,
|
|
7440
|
+
relativeDirPath: candidate.relativeDirPath,
|
|
7441
|
+
relativeFilePath: candidate.relativeFilePath,
|
|
7442
|
+
fileContent,
|
|
7443
|
+
validate
|
|
7444
|
+
});
|
|
7445
|
+
}
|
|
7446
|
+
throw new Error(`No ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} or ${RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH} found.`);
|
|
7386
7447
|
}
|
|
7387
7448
|
getJson() {
|
|
7388
7449
|
return this.json;
|
|
@@ -12390,15 +12451,51 @@ const RulesyncMcpServerSchema = zod_mini.z.extend(McpServerSchema, {
|
|
|
12390
12451
|
exposed: zod_mini.z.optional(zod_mini.z.boolean())
|
|
12391
12452
|
});
|
|
12392
12453
|
const RulesyncMcpConfigSchema = zod_mini.z.object({ mcpServers: zod_mini.z.record(zod_mini.z.string(), RulesyncMcpServerSchema) });
|
|
12454
|
+
/**
|
|
12455
|
+
* Tool-scoped MCP block: servers that apply only to one tool. A named entry
|
|
12456
|
+
* replaces/adds the same-named shared server wholesale for that tool; `null`
|
|
12457
|
+
* removes the shared server for that tool. Mirrors `{toolname}.hooks` in
|
|
12458
|
+
* `.rulesync/hooks.json` and `{toolname}.permission` in
|
|
12459
|
+
* `.rulesync/permissions.json`.
|
|
12460
|
+
*/
|
|
12461
|
+
const toolScopedMcpSchema = zod_mini.z.looseObject({ mcpServers: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.nullable(RulesyncMcpServerSchema))) });
|
|
12393
12462
|
const RulesyncMcpFileSchema = zod_mini.z.looseObject({
|
|
12394
12463
|
$schema: zod_mini.z.optional(zod_mini.z.string()),
|
|
12395
|
-
...RulesyncMcpConfigSchema.shape
|
|
12464
|
+
...RulesyncMcpConfigSchema.shape,
|
|
12465
|
+
amp: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12466
|
+
"antigravity-cli": zod_mini.z.optional(toolScopedMcpSchema),
|
|
12467
|
+
"antigravity-ide": zod_mini.z.optional(toolScopedMcpSchema),
|
|
12468
|
+
augmentcode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12469
|
+
claudecode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12470
|
+
cline: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12471
|
+
codexcli: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12472
|
+
copilot: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12473
|
+
copilotcli: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12474
|
+
cursor: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12475
|
+
deepagents: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12476
|
+
devin: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12477
|
+
factorydroid: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12478
|
+
goose: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12479
|
+
grokcli: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12480
|
+
hermesagent: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12481
|
+
junie: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12482
|
+
kilo: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12483
|
+
kiro: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12484
|
+
opencode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12485
|
+
qwencode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12486
|
+
reasonix: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12487
|
+
roo: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12488
|
+
rovodev: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12489
|
+
takt: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12490
|
+
vibe: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12491
|
+
warp: zod_mini.z.optional(toolScopedMcpSchema),
|
|
12492
|
+
zed: zod_mini.z.optional(toolScopedMcpSchema)
|
|
12396
12493
|
});
|
|
12397
12494
|
var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
|
|
12398
12495
|
json;
|
|
12399
12496
|
constructor(params) {
|
|
12400
12497
|
super(params);
|
|
12401
|
-
this.json =
|
|
12498
|
+
this.json = parseJsonc$6(this.fileContent);
|
|
12402
12499
|
if (params.validate) {
|
|
12403
12500
|
const result = this.validate();
|
|
12404
12501
|
if (!result.success) throw result.error;
|
|
@@ -12408,7 +12505,11 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
|
|
|
12408
12505
|
return {
|
|
12409
12506
|
recommended: {
|
|
12410
12507
|
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
12411
|
-
relativeFilePath:
|
|
12508
|
+
relativeFilePath: RULESYNC_MCP_FILE_NAME
|
|
12509
|
+
},
|
|
12510
|
+
jsonc: {
|
|
12511
|
+
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
12512
|
+
relativeFilePath: RULESYNC_MCP_JSONC_FILE_NAME
|
|
12412
12513
|
},
|
|
12413
12514
|
legacy: {
|
|
12414
12515
|
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
@@ -12430,7 +12531,18 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
|
|
|
12430
12531
|
static async fromFile({ outputRoot = process.cwd(), validate = true, logger }) {
|
|
12431
12532
|
const paths = this.getSettablePaths();
|
|
12432
12533
|
const recommendedPath = (0, node_path.join)(outputRoot, paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
|
|
12534
|
+
const jsoncPath = (0, node_path.join)(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath);
|
|
12433
12535
|
const legacyPath = (0, node_path.join)(outputRoot, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
|
|
12536
|
+
if (await fileExists(jsoncPath)) {
|
|
12537
|
+
const fileContent = await readFileContent(jsoncPath);
|
|
12538
|
+
return new RulesyncMcp({
|
|
12539
|
+
outputRoot,
|
|
12540
|
+
relativeDirPath: paths.jsonc.relativeDirPath,
|
|
12541
|
+
relativeFilePath: paths.jsonc.relativeFilePath,
|
|
12542
|
+
fileContent,
|
|
12543
|
+
validate
|
|
12544
|
+
});
|
|
12545
|
+
}
|
|
12434
12546
|
if (await fileExists(recommendedPath)) {
|
|
12435
12547
|
const fileContent = await readFileContent(recommendedPath);
|
|
12436
12548
|
return new RulesyncMcp({
|
|
@@ -12490,7 +12602,141 @@ var RulesyncMcp = class RulesyncMcp extends RulesyncFile {
|
|
|
12490
12602
|
getJson() {
|
|
12491
12603
|
return this.json;
|
|
12492
12604
|
}
|
|
12493
|
-
|
|
12605
|
+
/**
|
|
12606
|
+
* Build the effective MCP config for one tool target:
|
|
12607
|
+
*
|
|
12608
|
+
* 1. Filter shared servers by the DEPRECATED per-server `targets` field
|
|
12609
|
+
* (missing/`["*"]` means every tool). A deprecation warning points at
|
|
12610
|
+
* the tool-scoped blocks that replace it.
|
|
12611
|
+
* 2. Overlay the tool-scoped `{toolname}.mcpServers` block(s): a named
|
|
12612
|
+
* entry replaces/adds the shared server wholesale for this tool; `null`
|
|
12613
|
+
* removes it.
|
|
12614
|
+
*
|
|
12615
|
+
* Targets that share one output file resolve identically so the shared
|
|
12616
|
+
* file's content never depends on which of them generates last — see
|
|
12617
|
+
* `resolveMcpTarget` for the alias groups (kiro trio, claudecode/-legacy,
|
|
12618
|
+
* and the Antigravity pair).
|
|
12619
|
+
*
|
|
12620
|
+
* Returns the same instance when neither mechanism is used.
|
|
12621
|
+
*/
|
|
12622
|
+
forTarget({ toolTarget, logger }) {
|
|
12623
|
+
const { blockKeys, acceptedTargetNames } = resolveMcpTarget({ toolTarget });
|
|
12624
|
+
const json = this.json;
|
|
12625
|
+
const sharedServers = this.json.mcpServers ?? {};
|
|
12626
|
+
const serverNamesWithTargets = Object.entries(sharedServers).filter(([, serverConfig]) => serverConfig.targets !== void 0).map(([serverName]) => serverName);
|
|
12627
|
+
if (serverNamesWithTargets.length > 0) this.warnTargetsDeprecationOnce({
|
|
12628
|
+
serverNamesWithTargets,
|
|
12629
|
+
logger
|
|
12630
|
+
});
|
|
12631
|
+
for (const ignoredKey of MCP_IGNORED_ALIAS_SOURCE_KEYS) {
|
|
12632
|
+
if (!isRecord(json[ignoredKey])) continue;
|
|
12633
|
+
this.warnOncePerFile(`alias:${ignoredKey}`, `The "${ignoredKey}" block in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)} is ignored. Author it under the "${MCP_BLOCK_KEY_ALIASES[ignoredKey]}" key instead.`, logger);
|
|
12634
|
+
}
|
|
12635
|
+
const toolBlockKeys = Object.keys(json).filter((key) => MCP_TOOL_BLOCK_KEYS.has(key));
|
|
12636
|
+
if (serverNamesWithTargets.length === 0 && toolBlockKeys.length === 0) return this;
|
|
12637
|
+
const effectiveServers = Object.fromEntries(Object.entries(sharedServers).filter(([, serverConfig]) => {
|
|
12638
|
+
const targets = serverConfig.targets;
|
|
12639
|
+
if (targets === void 0) return true;
|
|
12640
|
+
return targets.some((target) => target === "*" || acceptedTargetNames.has(target));
|
|
12641
|
+
}));
|
|
12642
|
+
for (const blockKey of blockKeys) {
|
|
12643
|
+
const toolBlock = json[blockKey];
|
|
12644
|
+
const toolServers = isRecord(toolBlock) && isRecord(toolBlock.mcpServers) ? toolBlock.mcpServers : void 0;
|
|
12645
|
+
for (const [serverName, serverConfig] of Object.entries(toolServers ?? {})) {
|
|
12646
|
+
if (isPrototypePollutionKey(serverName)) continue;
|
|
12647
|
+
if (serverConfig === null) delete effectiveServers[serverName];
|
|
12648
|
+
else effectiveServers[serverName] = serverConfig;
|
|
12649
|
+
}
|
|
12650
|
+
}
|
|
12651
|
+
const rest = Object.fromEntries(Object.entries(json).filter(([key]) => !MCP_TOOL_BLOCK_KEYS.has(key)));
|
|
12652
|
+
return new RulesyncMcp({
|
|
12653
|
+
outputRoot: this.outputRoot,
|
|
12654
|
+
relativeDirPath: this.relativeDirPath,
|
|
12655
|
+
relativeFilePath: this.relativeFilePath,
|
|
12656
|
+
fileContent: JSON.stringify({
|
|
12657
|
+
...rest,
|
|
12658
|
+
mcpServers: effectiveServers
|
|
12659
|
+
}, null, 2)
|
|
12660
|
+
});
|
|
12661
|
+
}
|
|
12662
|
+
/**
|
|
12663
|
+
* The deprecation warning would otherwise repeat once per generated tool
|
|
12664
|
+
* target (a full `--targets "*"` run creates one RulesyncMcp per target),
|
|
12665
|
+
* so it is deduplicated per source file path.
|
|
12666
|
+
*/
|
|
12667
|
+
warnTargetsDeprecationOnce({ serverNamesWithTargets, logger }) {
|
|
12668
|
+
this.warnOncePerFile("targets-deprecation", `The per-server "targets" field in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)} is deprecated (servers: ${serverNamesWithTargets.join(", ")}). Author tool-scoped "{toolname}.mcpServers" blocks instead.`, logger);
|
|
12669
|
+
}
|
|
12670
|
+
warnOncePerFile(kind, message, logger) {
|
|
12671
|
+
const dedupeKey = `${this.getFilePath()}#${kind}`;
|
|
12672
|
+
if (warnedOnceKeys.has(dedupeKey)) return;
|
|
12673
|
+
warnedOnceKeys.add(dedupeKey);
|
|
12674
|
+
logger?.warn(message);
|
|
12675
|
+
}
|
|
12676
|
+
};
|
|
12677
|
+
/**
|
|
12678
|
+
* All keys that may hold a tool-scoped `{toolname}.mcpServers` block. Derived
|
|
12679
|
+
* from the MCP processor's target tuple so a newly added MCP-capable tool is
|
|
12680
|
+
* covered automatically.
|
|
12681
|
+
*/
|
|
12682
|
+
const MCP_TOOL_BLOCK_KEYS = new Set(mcpProcessorToolTargetTuple);
|
|
12683
|
+
/**
|
|
12684
|
+
* Targets whose `{toolname}.mcpServers` block key is ALWAYS another target's
|
|
12685
|
+
* key (at every scope): `claudecode-legacy` is a deprecated alias of
|
|
12686
|
+
* `claudecode`, and the Kiro IDE/CLI targets share the `kiro` block because
|
|
12687
|
+
* all three write the same `.kiro/settings/mcp.json` at both scopes. Blocks
|
|
12688
|
+
* authored under these source names are never read (a warning is emitted).
|
|
12689
|
+
*/
|
|
12690
|
+
const MCP_BLOCK_KEY_ALIASES = {
|
|
12691
|
+
"claudecode-legacy": "claudecode",
|
|
12692
|
+
"kiro-cli": "kiro",
|
|
12693
|
+
"kiro-ide": "kiro"
|
|
12694
|
+
};
|
|
12695
|
+
const MCP_IGNORED_ALIAS_SOURCE_KEYS = Object.keys(MCP_BLOCK_KEY_ALIASES);
|
|
12696
|
+
/**
|
|
12697
|
+
* Resolve which tool-scoped blocks a target reads and which deprecated
|
|
12698
|
+
* `targets` names match it. Targets that share one output file must resolve
|
|
12699
|
+
* identically, otherwise the shared file's content would depend on which
|
|
12700
|
+
* target happened to generate last:
|
|
12701
|
+
*
|
|
12702
|
+
* - `claudecode-legacy` aliases `claudecode`; the Kiro trio shares `kiro`
|
|
12703
|
+
* (same output file at both scopes).
|
|
12704
|
+
* - `antigravity-ide` / `antigravity-cli` share their output file at BOTH
|
|
12705
|
+
* scopes — `.agents/mcp_config.json` (project) and
|
|
12706
|
+
* `~/.gemini/config/mcp_config.json` (global; both global subdirs are
|
|
12707
|
+
* `config`) — so both targets always apply both blocks in a fixed order
|
|
12708
|
+
* (`antigravity-ide` first, `antigravity-cli` second — the CLI block wins
|
|
12709
|
+
* per server on conflict).
|
|
12710
|
+
*/
|
|
12711
|
+
function resolveMcpTarget({ toolTarget }) {
|
|
12712
|
+
if (toolTarget === "claudecode" || toolTarget === "claudecode-legacy") return {
|
|
12713
|
+
blockKeys: ["claudecode"],
|
|
12714
|
+
acceptedTargetNames: /* @__PURE__ */ new Set(["claudecode", "claudecode-legacy"])
|
|
12715
|
+
};
|
|
12716
|
+
if (toolTarget === "kiro" || toolTarget === "kiro-cli" || toolTarget === "kiro-ide") return {
|
|
12717
|
+
blockKeys: ["kiro"],
|
|
12718
|
+
acceptedTargetNames: /* @__PURE__ */ new Set([
|
|
12719
|
+
"kiro",
|
|
12720
|
+
"kiro-cli",
|
|
12721
|
+
"kiro-ide"
|
|
12722
|
+
])
|
|
12723
|
+
};
|
|
12724
|
+
if (toolTarget === "antigravity-ide" || toolTarget === "antigravity-cli") return {
|
|
12725
|
+
blockKeys: ["antigravity-ide", "antigravity-cli"],
|
|
12726
|
+
acceptedTargetNames: /* @__PURE__ */ new Set(["antigravity-ide", "antigravity-cli"])
|
|
12727
|
+
};
|
|
12728
|
+
return {
|
|
12729
|
+
blockKeys: [toolTarget],
|
|
12730
|
+
acceptedTargetNames: /* @__PURE__ */ new Set([toolTarget])
|
|
12731
|
+
};
|
|
12732
|
+
}
|
|
12733
|
+
/**
|
|
12734
|
+
* Deduplication set for once-per-source-file warnings, keyed by
|
|
12735
|
+
* `<absolute file path>#<warning kind>`. Never cleared: rulesync CLI runs
|
|
12736
|
+
* are one-shot processes, and in a long-lived embedding (the rulesync MCP
|
|
12737
|
+
* server) repeating the same warning per generate would only add noise.
|
|
12738
|
+
*/
|
|
12739
|
+
const warnedOnceKeys = /* @__PURE__ */ new Set();
|
|
12494
12740
|
//#endregion
|
|
12495
12741
|
//#region src/features/mcp/tool-mcp.ts
|
|
12496
12742
|
var ToolMcp = class extends ToolFile {
|
|
@@ -16740,10 +16986,14 @@ var McpProcessor = class extends FeatureProcessor {
|
|
|
16740
16986
|
if (!rulesyncMcp) throw new Error(`No ${RULESYNC_MCP_RELATIVE_FILE_PATH} found.`);
|
|
16741
16987
|
const factory = this.getFactory(this.toolTarget);
|
|
16742
16988
|
return await Promise.all([rulesyncMcp].map(async (mcp) => {
|
|
16989
|
+
const targetedRulesyncMcp = mcp.forTarget({
|
|
16990
|
+
toolTarget: this.toolTarget,
|
|
16991
|
+
logger: this.logger
|
|
16992
|
+
});
|
|
16743
16993
|
const fieldsToStrip = [];
|
|
16744
16994
|
if (!factory.meta.supportsEnabledTools) fieldsToStrip.push("enabledTools");
|
|
16745
16995
|
if (!factory.meta.supportsDisabledTools) fieldsToStrip.push("disabledTools");
|
|
16746
|
-
const filteredRulesyncMcp =
|
|
16996
|
+
const filteredRulesyncMcp = targetedRulesyncMcp.stripMcpServerFields(fieldsToStrip);
|
|
16747
16997
|
return await factory.class.fromRulesyncMcp({
|
|
16748
16998
|
outputRoot: this.outputRoot,
|
|
16749
16999
|
rulesyncMcp: filteredRulesyncMcp,
|
|
@@ -16793,6 +17043,25 @@ const PermissionActionSchema = zod_mini.z.enum([
|
|
|
16793
17043
|
*/
|
|
16794
17044
|
const PermissionRulesSchema = zod_mini.z.record(zod_mini.z.string(), PermissionActionSchema);
|
|
16795
17045
|
/**
|
|
17046
|
+
* Tool-scoped canonical `permission` block: the same shape as the shared
|
|
17047
|
+
* top-level `permission` record, but applied only to the tool whose override
|
|
17048
|
+
* key it appears under. During generation the categories placed here are
|
|
17049
|
+
* merged over the shared `permission` block per category (the tool-scoped
|
|
17050
|
+
* category replaces the shared one wholesale), mirroring how
|
|
17051
|
+
* `.rulesync/hooks.json` merges `{toolname}.hooks` per event.
|
|
17052
|
+
*
|
|
17053
|
+
* @example
|
|
17054
|
+
* { "claudecode": { "permission": { "bash": { "git push *": "deny" } } } }
|
|
17055
|
+
*/
|
|
17056
|
+
const ToolScopedPermissionSchema = zod_mini.z.record(zod_mini.z.string(), PermissionRulesSchema);
|
|
17057
|
+
/**
|
|
17058
|
+
* Generic tool-scoped override block for tools that have no tool-specific
|
|
17059
|
+
* override keys of their own; it carries only the canonical tool-scoped
|
|
17060
|
+
* `permission` block. Kept `looseObject` so future tool-specific keys can be
|
|
17061
|
+
* added without a schema break.
|
|
17062
|
+
*/
|
|
17063
|
+
const CanonicalPermissionsOverrideSchema = zod_mini.z.looseObject({ permission: zod_mini.z.optional(ToolScopedPermissionSchema) });
|
|
17064
|
+
/**
|
|
16796
17065
|
* OpenCode-specific permission value. Unlike the shared canonical block, which
|
|
16797
17066
|
* only accepts a pattern-to-action map, OpenCode also allows a bare action
|
|
16798
17067
|
* string that applies to the whole category (e.g. `"external_directory": "deny"`).
|
|
@@ -16822,7 +17091,7 @@ const OpencodePermissionsOverrideSchema = zod_mini.z.looseObject({ permission: z
|
|
|
16822
17091
|
* @example
|
|
16823
17092
|
* { "approvals": { "mode": "smart" }, "security": { "allow_private_urls": false } }
|
|
16824
17093
|
*/
|
|
16825
|
-
const HermesPermissionsOverrideSchema = zod_mini.z.looseObject({});
|
|
17094
|
+
const HermesPermissionsOverrideSchema = zod_mini.z.looseObject({ permission: zod_mini.z.optional(ToolScopedPermissionSchema) });
|
|
16826
17095
|
/**
|
|
16827
17096
|
* Tool-scoped override block for Cline. Cline's `command-permissions.json`
|
|
16828
17097
|
* carries a single global `allowRedirects` boolean (gates shell redirection
|
|
@@ -16834,7 +17103,10 @@ const HermesPermissionsOverrideSchema = zod_mini.z.looseObject({});
|
|
|
16834
17103
|
* @example
|
|
16835
17104
|
* { "allowRedirects": true }
|
|
16836
17105
|
*/
|
|
16837
|
-
const ClinePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17106
|
+
const ClinePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17107
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17108
|
+
allowRedirects: zod_mini.z.optional(zod_mini.z.boolean())
|
|
17109
|
+
});
|
|
16838
17110
|
/**
|
|
16839
17111
|
* Tool-scoped override block for Kilo Code (an OpenCode fork). Kilo's permission
|
|
16840
17112
|
* object is a free-form record with tool-specific keys that have no canonical
|
|
@@ -16864,7 +17136,10 @@ const KiloPermissionsOverrideSchema = zod_mini.z.looseObject({ permission: zod_m
|
|
|
16864
17136
|
* @example
|
|
16865
17137
|
* { "permissions": { "defaultMode": "acceptEdits", "additionalDirectories": ["../shared"] } }
|
|
16866
17138
|
*/
|
|
16867
|
-
const ClaudecodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17139
|
+
const ClaudecodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17140
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17141
|
+
permissions: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
17142
|
+
});
|
|
16868
17143
|
/**
|
|
16869
17144
|
* Tool-scoped override block for Mistral Vibe. Vibe's per-tool `BaseToolConfig`
|
|
16870
17145
|
* carries a `sensitive_patterns` list — patterns that escalate to ASK even when
|
|
@@ -16896,6 +17171,7 @@ const VibePermissionsOverrideSchema = zod_mini.z.looseObject({ permission: zod_m
|
|
|
16896
17171
|
* { "approvalMode": "auto-review" }
|
|
16897
17172
|
*/
|
|
16898
17173
|
const CursorPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17174
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
16899
17175
|
approvalMode: zod_mini.z.optional(zod_mini.z.string()),
|
|
16900
17176
|
sandbox: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
16901
17177
|
});
|
|
@@ -16921,6 +17197,7 @@ const CursorPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
16921
17197
|
* }
|
|
16922
17198
|
*/
|
|
16923
17199
|
const QwencodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17200
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
16924
17201
|
tools: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
16925
17202
|
security: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
16926
17203
|
autoMode: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
@@ -16942,6 +17219,7 @@ const QwencodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
16942
17219
|
* { "sandbox": { "bash": "enforce", "network": false }, "agent": { "plan_mode_read_only_commands": ["gh pr diff"] } }
|
|
16943
17220
|
*/
|
|
16944
17221
|
const ReasonixPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17222
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
16945
17223
|
sandbox: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
16946
17224
|
agent: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
16947
17225
|
});
|
|
@@ -16961,7 +17239,10 @@ const ReasonixPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
16961
17239
|
* @example
|
|
16962
17240
|
* { "commandBlocklist": ["rm -rf /*"], "sandbox": { "enabled": true } }
|
|
16963
17241
|
*/
|
|
16964
|
-
const FactorydroidPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17242
|
+
const FactorydroidPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17243
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17244
|
+
commandBlocklist: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string()))
|
|
17245
|
+
});
|
|
16965
17246
|
/**
|
|
16966
17247
|
* Tool-scoped override block for Warp. Warp's `[agents.profiles]` table exposes
|
|
16967
17248
|
* file-read/read-only autonomy keys with no canonical per-command allow/ask/deny
|
|
@@ -16978,6 +17259,7 @@ const FactorydroidPermissionsOverrideSchema = zod_mini.z.looseObject({ commandBl
|
|
|
16978
17259
|
* { "agent_mode_coding_permissions": "always_allow_reading", "agent_mode_execute_readonly_commands": true }
|
|
16979
17260
|
*/
|
|
16980
17261
|
const WarpPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17262
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
16981
17263
|
agent_mode_coding_permissions: zod_mini.z.optional(zod_mini.z.string()),
|
|
16982
17264
|
agent_mode_coding_file_read_allowlist: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
16983
17265
|
agent_mode_execute_readonly_commands: zod_mini.z.optional(zod_mini.z.boolean())
|
|
@@ -16995,6 +17277,7 @@ const WarpPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
16995
17277
|
* { "allowReadonlyCommands": true, "defaultBehavior": "ask" }
|
|
16996
17278
|
*/
|
|
16997
17279
|
const JuniePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17280
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
16998
17281
|
allowReadonlyCommands: zod_mini.z.optional(zod_mini.z.boolean()),
|
|
16999
17282
|
defaultBehavior: zod_mini.z.optional(zod_mini.z.string())
|
|
17000
17283
|
});
|
|
@@ -17022,6 +17305,7 @@ const JuniePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
17022
17305
|
* { "step_permission_overrides": { "ai_review": "readonly" }, "provider_options": { "codex": { "network_access": true } } }
|
|
17023
17306
|
*/
|
|
17024
17307
|
const TaktPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17308
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17025
17309
|
step_permission_overrides: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.string())),
|
|
17026
17310
|
provider_options: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
17027
17311
|
});
|
|
@@ -17049,6 +17333,7 @@ const TaktPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
17049
17333
|
* "permissions": [{ "tool": "Bash", "action": "delegate", "to": "approve.sh" }] }
|
|
17050
17334
|
*/
|
|
17051
17335
|
const AmpPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17336
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17052
17337
|
permissions: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({
|
|
17053
17338
|
tool: zod_mini.z.string(),
|
|
17054
17339
|
action: zod_mini.z.string()
|
|
@@ -17077,6 +17362,7 @@ const AmpPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
17077
17362
|
* { "toolPermission": "strict", "enableTerminalSandbox": true }
|
|
17078
17363
|
*/
|
|
17079
17364
|
const AntigravityCliPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17365
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17080
17366
|
toolPermission: zod_mini.z.optional(zod_mini.z.string()),
|
|
17081
17367
|
enableTerminalSandbox: zod_mini.z.optional(zod_mini.z.boolean())
|
|
17082
17368
|
});
|
|
@@ -17102,10 +17388,13 @@ const AntigravityCliPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
17102
17388
|
* "permission": { "type": "webhook-policy", "webhookUrl": "https://api.example.com/validate" } },
|
|
17103
17389
|
* { "toolName": "view", "eventType": "tool-response", "permission": { "type": "allow" } } ] }
|
|
17104
17390
|
*/
|
|
17105
|
-
const AugmentcodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17391
|
+
const AugmentcodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17392
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17393
|
+
toolPermissions: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({
|
|
17394
|
+
toolName: zod_mini.z.string(),
|
|
17395
|
+
permission: zod_mini.z.looseObject({ type: zod_mini.z.string() })
|
|
17396
|
+
})))
|
|
17397
|
+
});
|
|
17109
17398
|
/**
|
|
17110
17399
|
* Tool-scoped override block for Kiro. Kiro's agent config (`.kiro/agents/<name>.json`)
|
|
17111
17400
|
* exposes per-tool `toolsSettings` knobs with no canonical allow/ask/deny
|
|
@@ -17131,21 +17420,24 @@ const AugmentcodePermissionsOverrideSchema = zod_mini.z.looseObject({ toolPermis
|
|
|
17131
17420
|
* "aws": { "allowedServices": ["s3"], "deniedServices": ["eks"] },
|
|
17132
17421
|
* "web_fetch": { "trusted": [".*github\\.com.*"] } } }
|
|
17133
17422
|
*/
|
|
17134
|
-
const KiroPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17423
|
+
const KiroPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17424
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17425
|
+
toolsSettings: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
17426
|
+
shell: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
17427
|
+
autoAllowReadonly: zod_mini.z.optional(zod_mini.z.boolean()),
|
|
17428
|
+
denyByDefault: zod_mini.z.optional(zod_mini.z.boolean())
|
|
17429
|
+
})),
|
|
17430
|
+
aws: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
17431
|
+
allowedServices: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
17432
|
+
deniedServices: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
17433
|
+
autoAllowReadonly: zod_mini.z.optional(zod_mini.z.boolean())
|
|
17434
|
+
})),
|
|
17435
|
+
web_fetch: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
17436
|
+
trusted: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
17437
|
+
blocked: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string()))
|
|
17438
|
+
}))
|
|
17147
17439
|
}))
|
|
17148
|
-
})
|
|
17440
|
+
});
|
|
17149
17441
|
/**
|
|
17150
17442
|
* Codex CLI's approval-workflow policy. Serialized as a kebab-case string in
|
|
17151
17443
|
* `.codex/config.toml`. `on-failure` is a legacy alias for `on-request` that
|
|
@@ -17217,6 +17509,7 @@ const CodexApprovalsReviewerSchema = zod_mini.z.enum([
|
|
|
17217
17509
|
* "sandbox_workspace_write": { "network_access": true } }
|
|
17218
17510
|
*/
|
|
17219
17511
|
const CodexcliPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
17512
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
17220
17513
|
approval_policy: zod_mini.z.optional(zod_mini.z.union([CodexApprovalPolicySchema, zod_mini.z.looseObject({})])),
|
|
17221
17514
|
sandbox_mode: zod_mini.z.optional(CodexSandboxModeSchema),
|
|
17222
17515
|
sandbox_workspace_write: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
@@ -17235,6 +17528,15 @@ const CodexcliPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
17235
17528
|
* `*PermissionsOverrideSchema`); every other tool reads the shared `permission`
|
|
17236
17529
|
* block and ignores them.
|
|
17237
17530
|
*
|
|
17531
|
+
* Additionally, every permissions-capable tool accepts a canonical tool-scoped
|
|
17532
|
+
* `permission` block under its override key (`{toolname}.permission`, same
|
|
17533
|
+
* shape as the shared `permission` record). Its categories apply only to that
|
|
17534
|
+
* tool, merged over the shared block per category — see
|
|
17535
|
+
* `RulesyncPermissions.forTarget`. `kiro-cli`/`kiro-ide` alias to the `kiro`
|
|
17536
|
+
* key and `hermesagent` to `hermes` (matching the shared output file each
|
|
17537
|
+
* writes). OpenCode/Kilo/Vibe keep their existing tool-native `permission`
|
|
17538
|
+
* override semantics (handled by their translators, not the central merge).
|
|
17539
|
+
*
|
|
17238
17540
|
* @example
|
|
17239
17541
|
* {
|
|
17240
17542
|
* "bash": { "*": "ask", "git *": "allow", "rm *": "deny" },
|
|
@@ -17260,7 +17562,13 @@ const PermissionsConfigSchema = zod_mini.z.looseObject({
|
|
|
17260
17562
|
"antigravity-cli": zod_mini.z.optional(AntigravityCliPermissionsOverrideSchema),
|
|
17261
17563
|
augmentcode: zod_mini.z.optional(AugmentcodePermissionsOverrideSchema),
|
|
17262
17564
|
kiro: zod_mini.z.optional(KiroPermissionsOverrideSchema),
|
|
17263
|
-
codexcli: zod_mini.z.optional(CodexcliPermissionsOverrideSchema)
|
|
17565
|
+
codexcli: zod_mini.z.optional(CodexcliPermissionsOverrideSchema),
|
|
17566
|
+
"antigravity-ide": zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
|
|
17567
|
+
devin: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
|
|
17568
|
+
goose: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
|
|
17569
|
+
grokcli: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
|
|
17570
|
+
rovodev: zod_mini.z.optional(CanonicalPermissionsOverrideSchema),
|
|
17571
|
+
zed: zod_mini.z.optional(CanonicalPermissionsOverrideSchema)
|
|
17264
17572
|
});
|
|
17265
17573
|
/**
|
|
17266
17574
|
* Full permissions file schema including optional $schema field.
|
|
@@ -17275,7 +17583,7 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
|
|
|
17275
17583
|
json;
|
|
17276
17584
|
constructor(params) {
|
|
17277
17585
|
super({ ...params });
|
|
17278
|
-
this.json =
|
|
17586
|
+
this.json = parseJsonc$6(this.fileContent);
|
|
17279
17587
|
if (params.validate) {
|
|
17280
17588
|
const result = this.validate();
|
|
17281
17589
|
if (!result.success) throw result.error;
|
|
@@ -17284,7 +17592,11 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
|
|
|
17284
17592
|
static getSettablePaths() {
|
|
17285
17593
|
return {
|
|
17286
17594
|
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
17287
|
-
relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME
|
|
17595
|
+
relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
|
|
17596
|
+
jsonc: {
|
|
17597
|
+
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
17598
|
+
relativeFilePath: RULESYNC_PERMISSIONS_JSONC_FILE_NAME
|
|
17599
|
+
}
|
|
17288
17600
|
};
|
|
17289
17601
|
}
|
|
17290
17602
|
validate() {
|
|
@@ -17300,20 +17612,85 @@ var RulesyncPermissions = class RulesyncPermissions extends RulesyncFile {
|
|
|
17300
17612
|
}
|
|
17301
17613
|
static async fromFile({ outputRoot = process.cwd(), validate = true }) {
|
|
17302
17614
|
const paths = RulesyncPermissions.getSettablePaths();
|
|
17303
|
-
const
|
|
17304
|
-
if (!await fileExists(filePath)) throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} found.`);
|
|
17305
|
-
const fileContent = await readFileContent(filePath);
|
|
17306
|
-
return new RulesyncPermissions({
|
|
17307
|
-
outputRoot,
|
|
17615
|
+
const candidates = [paths.jsonc, {
|
|
17308
17616
|
relativeDirPath: paths.relativeDirPath,
|
|
17309
|
-
relativeFilePath: paths.relativeFilePath
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17617
|
+
relativeFilePath: paths.relativeFilePath
|
|
17618
|
+
}];
|
|
17619
|
+
for (const candidate of candidates) {
|
|
17620
|
+
const filePath = (0, node_path.join)(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath);
|
|
17621
|
+
if (!await fileExists(filePath)) continue;
|
|
17622
|
+
const fileContent = await readFileContent(filePath);
|
|
17623
|
+
return new RulesyncPermissions({
|
|
17624
|
+
outputRoot,
|
|
17625
|
+
relativeDirPath: candidate.relativeDirPath,
|
|
17626
|
+
relativeFilePath: candidate.relativeFilePath,
|
|
17627
|
+
fileContent,
|
|
17628
|
+
validate
|
|
17629
|
+
});
|
|
17630
|
+
}
|
|
17631
|
+
throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} or ${RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH} found.`);
|
|
17313
17632
|
}
|
|
17314
17633
|
getJson() {
|
|
17315
17634
|
return this.json;
|
|
17316
17635
|
}
|
|
17636
|
+
/**
|
|
17637
|
+
* Build the effective permissions config for one tool target by merging the
|
|
17638
|
+
* tool-scoped `{toolname}.permission` block over the shared `permission`
|
|
17639
|
+
* block, per category (the tool-scoped category replaces the shared one
|
|
17640
|
+
* wholesale — mirroring how `{toolname}.hooks` merges per event in
|
|
17641
|
+
* `.rulesync/hooks.json`). The consumed `permission` key is stripped from
|
|
17642
|
+
* the override block so verbatim-passthrough translators (e.g. the Hermes
|
|
17643
|
+
* deep merge or the Codex CLI top-level key whitelist) never see it.
|
|
17644
|
+
*
|
|
17645
|
+
* Returns the same instance when the target has no tool-scoped canonical
|
|
17646
|
+
* `permission` block, or when the target's translator natively consumes its
|
|
17647
|
+
* own `permission` override shape (OpenCode / Kilo / Vibe).
|
|
17648
|
+
*/
|
|
17649
|
+
forTarget({ toolTarget, logger }) {
|
|
17650
|
+
if (NATIVE_PERMISSION_OVERRIDE_TARGETS.has(toolTarget)) return this;
|
|
17651
|
+
const overrideKey = PERMISSION_OVERRIDE_KEY_ALIASES[toolTarget] ?? toolTarget;
|
|
17652
|
+
const json = this.json;
|
|
17653
|
+
if (overrideKey !== toolTarget && isRecord(json[toolTarget])) logger?.warn(`The "${toolTarget}" block in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)} is ignored. Author it under the "${overrideKey}" key instead (the ${toolTarget} target reads that block).`);
|
|
17654
|
+
const overrideBlock = json[overrideKey];
|
|
17655
|
+
if (!isRecord(overrideBlock) || !isRecord(overrideBlock.permission)) return this;
|
|
17656
|
+
const { permission: toolScopedPermission, ...restOverride } = overrideBlock;
|
|
17657
|
+
const merged = {
|
|
17658
|
+
...json,
|
|
17659
|
+
permission: {
|
|
17660
|
+
...this.json.permission,
|
|
17661
|
+
...toolScopedPermission
|
|
17662
|
+
}
|
|
17663
|
+
};
|
|
17664
|
+
if (Object.keys(restOverride).length > 0) merged[overrideKey] = restOverride;
|
|
17665
|
+
else delete merged[overrideKey];
|
|
17666
|
+
return new RulesyncPermissions({
|
|
17667
|
+
outputRoot: this.outputRoot,
|
|
17668
|
+
relativeDirPath: this.relativeDirPath,
|
|
17669
|
+
relativeFilePath: this.relativeFilePath,
|
|
17670
|
+
fileContent: JSON.stringify(merged, null, 2)
|
|
17671
|
+
});
|
|
17672
|
+
}
|
|
17673
|
+
};
|
|
17674
|
+
/**
|
|
17675
|
+
* Targets whose tool-scoped `permission` override uses tool-native semantics
|
|
17676
|
+
* consumed directly by their translator (bare action strings / tool-only
|
|
17677
|
+
* categories for OpenCode and Kilo, `sensitive_patterns` objects for Vibe).
|
|
17678
|
+
* The central canonical merge must not touch those blocks.
|
|
17679
|
+
*/
|
|
17680
|
+
const NATIVE_PERMISSION_OVERRIDE_TARGETS = /* @__PURE__ */ new Set([
|
|
17681
|
+
"opencode",
|
|
17682
|
+
"kilo",
|
|
17683
|
+
"vibe"
|
|
17684
|
+
]);
|
|
17685
|
+
/**
|
|
17686
|
+
* Targets that read their tool-scoped override from a differently named key:
|
|
17687
|
+
* Kiro IDE/CLI share the `kiro` block (they write the same agent config) and
|
|
17688
|
+
* Hermes Agent's established override key is `hermes`.
|
|
17689
|
+
*/
|
|
17690
|
+
const PERMISSION_OVERRIDE_KEY_ALIASES = {
|
|
17691
|
+
"kiro-cli": "kiro",
|
|
17692
|
+
"kiro-ide": "kiro",
|
|
17693
|
+
hermesagent: "hermes"
|
|
17317
17694
|
};
|
|
17318
17695
|
//#endregion
|
|
17319
17696
|
//#region src/features/permissions/tool-permissions.ts
|
|
@@ -19153,10 +19530,15 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
19153
19530
|
existingDomainsHadUnknown,
|
|
19154
19531
|
logger
|
|
19155
19532
|
});
|
|
19156
|
-
|
|
19533
|
+
const profile = mergeWithExistingProfile({
|
|
19157
19534
|
newProfile,
|
|
19158
19535
|
existingProfile
|
|
19159
19536
|
});
|
|
19537
|
+
permissionsTable[RULESYNC_PROFILE_NAME] = preserveUnmanagedProfileKeys({
|
|
19538
|
+
rawExistingProfile: permissionsTable[RULESYNC_PROFILE_NAME],
|
|
19539
|
+
profile,
|
|
19540
|
+
logger
|
|
19541
|
+
});
|
|
19160
19542
|
const overridePatch = computeCodexcliOverridePatch({
|
|
19161
19543
|
existing,
|
|
19162
19544
|
override: rulesyncPermissions.getJson().codexcli,
|
|
@@ -19352,6 +19734,43 @@ function warnAboutPreservedProfileState({ existingProfile, newProfile, existingD
|
|
|
19352
19734
|
if (existingProfile?.network?.mode !== void 0) logger?.warn(`Preserving existing "network.mode" from config. Review this value manually as it may grant broader network access than the Rulesync-managed domain rules.`);
|
|
19353
19735
|
if (existingDomainsHadUnknown) logger?.warn(`Existing "network.domains" contained unrecognized values. These entries were skipped and will not be imported.`);
|
|
19354
19736
|
}
|
|
19737
|
+
const MANAGED_PROFILE_KEYS = /* @__PURE__ */ new Set([
|
|
19738
|
+
"description",
|
|
19739
|
+
"extends",
|
|
19740
|
+
"filesystem",
|
|
19741
|
+
"network"
|
|
19742
|
+
]);
|
|
19743
|
+
const MANAGED_NETWORK_KEYS = /* @__PURE__ */ new Set([
|
|
19744
|
+
"enabled",
|
|
19745
|
+
"mode",
|
|
19746
|
+
"domains",
|
|
19747
|
+
"unix_sockets"
|
|
19748
|
+
]);
|
|
19749
|
+
/**
|
|
19750
|
+
* Re-attach the keys of the existing rulesync profile that rulesync does not
|
|
19751
|
+
* manage. The managed keys always come from `profile` (the freshly computed
|
|
19752
|
+
* merge result); unmanaged siblings — at the profile level and inside the
|
|
19753
|
+
* `network` table — are preserved verbatim from the existing config so a
|
|
19754
|
+
* regeneration never deletes user-authored Codex settings.
|
|
19755
|
+
*/
|
|
19756
|
+
function preserveUnmanagedProfileKeys({ rawExistingProfile, profile, logger }) {
|
|
19757
|
+
const rawProfileTable = toMutableTable(rawExistingProfile);
|
|
19758
|
+
const profileExtras = Object.fromEntries(Object.entries(rawProfileTable).filter(([key]) => !MANAGED_PROFILE_KEYS.has(key)));
|
|
19759
|
+
const rawNetworkTable = toMutableTable(rawProfileTable.network);
|
|
19760
|
+
const networkExtras = Object.fromEntries(Object.entries(rawNetworkTable).filter(([key]) => !MANAGED_NETWORK_KEYS.has(key)));
|
|
19761
|
+
const preservedKeyNames = [...Object.keys(profileExtras), ...Object.keys(networkExtras).map((key) => `network.${key}`)];
|
|
19762
|
+
if (preservedKeyNames.length > 0) logger?.warn(`Preserving unmanaged keys in the "${RULESYNC_PROFILE_NAME}" permissions profile: ${preservedKeyNames.join(", ")}. Review them manually; rulesync carries them forward verbatim.`);
|
|
19763
|
+
const result = {
|
|
19764
|
+
...profileExtras,
|
|
19765
|
+
...profile
|
|
19766
|
+
};
|
|
19767
|
+
const mergedNetwork = {
|
|
19768
|
+
...networkExtras,
|
|
19769
|
+
...profile.network
|
|
19770
|
+
};
|
|
19771
|
+
if (Object.keys(mergedNetwork).length > 0) result.network = mergedNetwork;
|
|
19772
|
+
return result;
|
|
19773
|
+
}
|
|
19355
19774
|
function mergeWithExistingProfile({ newProfile, existingProfile }) {
|
|
19356
19775
|
if (!existingProfile) return newProfile;
|
|
19357
19776
|
const mergedNetwork = { ...newProfile.network };
|
|
@@ -23613,16 +24032,20 @@ var PermissionsProcessor = class extends FeatureProcessor {
|
|
|
23613
24032
|
if (!rulesyncPermissions) throw new Error(`No ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH} found.`);
|
|
23614
24033
|
const factory = toolPermissionsFactories.get(this.toolTarget);
|
|
23615
24034
|
if (!factory) throw new Error(`Unsupported tool target: ${this.toolTarget}`);
|
|
24035
|
+
const effectivePermissions = rulesyncPermissions.forTarget({
|
|
24036
|
+
toolTarget: this.toolTarget,
|
|
24037
|
+
logger: this.logger
|
|
24038
|
+
});
|
|
23616
24039
|
const toolPermissions = await factory.class.fromRulesyncPermissions({
|
|
23617
24040
|
outputRoot: this.outputRoot,
|
|
23618
|
-
rulesyncPermissions,
|
|
24041
|
+
rulesyncPermissions: effectivePermissions,
|
|
23619
24042
|
logger: this.logger,
|
|
23620
24043
|
global: this.global
|
|
23621
24044
|
});
|
|
23622
24045
|
if (this.toolTarget !== "codexcli") return [toolPermissions];
|
|
23623
24046
|
return [toolPermissions, createCodexcliBashRulesFile({
|
|
23624
24047
|
outputRoot: this.outputRoot,
|
|
23625
|
-
config:
|
|
24048
|
+
config: effectivePermissions.getJson()
|
|
23626
24049
|
})];
|
|
23627
24050
|
}
|
|
23628
24051
|
async convertToolFilesToRulesyncFiles(toolFiles) {
|
|
@@ -39718,6 +40141,16 @@ async function generatePermissionsCore(params) {
|
|
|
39718
40141
|
//#endregion
|
|
39719
40142
|
//#region src/lib/import.ts
|
|
39720
40143
|
/**
|
|
40144
|
+
* Import always writes the `.json` variant of a fixed-path source file, but a
|
|
40145
|
+
* sibling `.jsonc` variant takes precedence at read time — so an import into a
|
|
40146
|
+
* project that authors the `.jsonc` variant would be silently shadowed. Warn
|
|
40147
|
+
* so the user merges (or removes) one of the two by hand.
|
|
40148
|
+
*/
|
|
40149
|
+
async function warnIfShadowedByJsonc(params) {
|
|
40150
|
+
const { outputRoot, jsonRelativePath, jsoncRelativePath, logger } = params;
|
|
40151
|
+
if (await fileExists((0, node_path.join)(outputRoot, jsoncRelativePath))) logger.warn(`${jsoncRelativePath} exists and takes precedence over the imported ${jsonRelativePath}. Merge the imported content into ${jsoncRelativePath} (or remove it) so the import takes effect.`);
|
|
40152
|
+
}
|
|
40153
|
+
/**
|
|
39721
40154
|
* Import configuration files from AI tools.
|
|
39722
40155
|
*/
|
|
39723
40156
|
async function importFromTool(params) {
|
|
@@ -39829,6 +40262,12 @@ async function importMcpCore(params) {
|
|
|
39829
40262
|
}
|
|
39830
40263
|
const rulesyncFiles = await mcpProcessor.convertToolFilesToRulesyncFiles(toolFiles);
|
|
39831
40264
|
const { count: writtenCount } = await mcpProcessor.writeAiFiles(rulesyncFiles);
|
|
40265
|
+
if (writtenCount > 0) await warnIfShadowedByJsonc({
|
|
40266
|
+
outputRoot: config.getOutputRoots()[0] ?? ".",
|
|
40267
|
+
jsonRelativePath: RULESYNC_MCP_RELATIVE_FILE_PATH,
|
|
40268
|
+
jsoncRelativePath: RULESYNC_MCP_JSONC_RELATIVE_FILE_PATH,
|
|
40269
|
+
logger
|
|
40270
|
+
});
|
|
39832
40271
|
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} MCP files`);
|
|
39833
40272
|
return writtenCount;
|
|
39834
40273
|
}
|
|
@@ -39928,6 +40367,12 @@ async function importHooksCore(params) {
|
|
|
39928
40367
|
}
|
|
39929
40368
|
const rulesyncFiles = await hooksProcessor.convertToolFilesToRulesyncFiles(toolFiles);
|
|
39930
40369
|
const { count: writtenCount } = await hooksProcessor.writeAiFiles(rulesyncFiles);
|
|
40370
|
+
if (writtenCount > 0) await warnIfShadowedByJsonc({
|
|
40371
|
+
outputRoot: config.getOutputRoots()[0] ?? ".",
|
|
40372
|
+
jsonRelativePath: RULESYNC_HOOKS_RELATIVE_FILE_PATH,
|
|
40373
|
+
jsoncRelativePath: RULESYNC_HOOKS_JSONC_RELATIVE_FILE_PATH,
|
|
40374
|
+
logger
|
|
40375
|
+
});
|
|
39931
40376
|
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} hooks file(s)`);
|
|
39932
40377
|
return writtenCount;
|
|
39933
40378
|
}
|
|
@@ -39957,6 +40402,12 @@ async function importPermissionsCore(params) {
|
|
|
39957
40402
|
}
|
|
39958
40403
|
const rulesyncFiles = await permissionsProcessor.convertToolFilesToRulesyncFiles(toolFiles);
|
|
39959
40404
|
const { count: writtenCount } = await permissionsProcessor.writeAiFiles(rulesyncFiles);
|
|
40405
|
+
if (writtenCount > 0) await warnIfShadowedByJsonc({
|
|
40406
|
+
outputRoot: config.getOutputRoots()[0] ?? ".",
|
|
40407
|
+
jsonRelativePath: RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH,
|
|
40408
|
+
jsoncRelativePath: RULESYNC_PERMISSIONS_JSONC_RELATIVE_FILE_PATH,
|
|
40409
|
+
logger
|
|
40410
|
+
});
|
|
39960
40411
|
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} permissions file(s)`);
|
|
39961
40412
|
return writtenCount;
|
|
39962
40413
|
}
|
|
@@ -40021,6 +40472,12 @@ Object.defineProperty(exports, "CLIError", {
|
|
|
40021
40472
|
return CLIError;
|
|
40022
40473
|
}
|
|
40023
40474
|
});
|
|
40475
|
+
Object.defineProperty(exports, "CODEXCLI_DIR", {
|
|
40476
|
+
enumerable: true,
|
|
40477
|
+
get: function() {
|
|
40478
|
+
return CODEXCLI_DIR;
|
|
40479
|
+
}
|
|
40480
|
+
});
|
|
40024
40481
|
Object.defineProperty(exports, "CommandsProcessor", {
|
|
40025
40482
|
enumerable: true,
|
|
40026
40483
|
get: function() {
|
|
@@ -40117,6 +40574,12 @@ Object.defineProperty(exports, "RULESYNC_HOOKS_FILE_NAME", {
|
|
|
40117
40574
|
return RULESYNC_HOOKS_FILE_NAME;
|
|
40118
40575
|
}
|
|
40119
40576
|
});
|
|
40577
|
+
Object.defineProperty(exports, "RULESYNC_HOOKS_JSONC_FILE_NAME", {
|
|
40578
|
+
enumerable: true,
|
|
40579
|
+
get: function() {
|
|
40580
|
+
return RULESYNC_HOOKS_JSONC_FILE_NAME;
|
|
40581
|
+
}
|
|
40582
|
+
});
|
|
40120
40583
|
Object.defineProperty(exports, "RULESYNC_HOOKS_RELATIVE_FILE_PATH", {
|
|
40121
40584
|
enumerable: true,
|
|
40122
40585
|
get: function() {
|
|
@@ -40141,6 +40604,12 @@ Object.defineProperty(exports, "RULESYNC_MCP_FILE_NAME", {
|
|
|
40141
40604
|
return RULESYNC_MCP_FILE_NAME;
|
|
40142
40605
|
}
|
|
40143
40606
|
});
|
|
40607
|
+
Object.defineProperty(exports, "RULESYNC_MCP_JSONC_FILE_NAME", {
|
|
40608
|
+
enumerable: true,
|
|
40609
|
+
get: function() {
|
|
40610
|
+
return RULESYNC_MCP_JSONC_FILE_NAME;
|
|
40611
|
+
}
|
|
40612
|
+
});
|
|
40144
40613
|
Object.defineProperty(exports, "RULESYNC_MCP_RELATIVE_FILE_PATH", {
|
|
40145
40614
|
enumerable: true,
|
|
40146
40615
|
get: function() {
|
|
@@ -40165,12 +40634,24 @@ Object.defineProperty(exports, "RULESYNC_PERMISSIONS_FILE_NAME", {
|
|
|
40165
40634
|
return RULESYNC_PERMISSIONS_FILE_NAME;
|
|
40166
40635
|
}
|
|
40167
40636
|
});
|
|
40637
|
+
Object.defineProperty(exports, "RULESYNC_PERMISSIONS_JSONC_FILE_NAME", {
|
|
40638
|
+
enumerable: true,
|
|
40639
|
+
get: function() {
|
|
40640
|
+
return RULESYNC_PERMISSIONS_JSONC_FILE_NAME;
|
|
40641
|
+
}
|
|
40642
|
+
});
|
|
40168
40643
|
Object.defineProperty(exports, "RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH", {
|
|
40169
40644
|
enumerable: true,
|
|
40170
40645
|
get: function() {
|
|
40171
40646
|
return RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH;
|
|
40172
40647
|
}
|
|
40173
40648
|
});
|
|
40649
|
+
Object.defineProperty(exports, "RULESYNC_PERMISSIONS_SCHEMA_URL", {
|
|
40650
|
+
enumerable: true,
|
|
40651
|
+
get: function() {
|
|
40652
|
+
return RULESYNC_PERMISSIONS_SCHEMA_URL;
|
|
40653
|
+
}
|
|
40654
|
+
});
|
|
40174
40655
|
Object.defineProperty(exports, "RULESYNC_RELATIVE_DIR_PATH", {
|
|
40175
40656
|
enumerable: true,
|
|
40176
40657
|
get: function() {
|