rulesync 9.6.3 → 9.7.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 +11 -1
- package/dist/cli/index.cjs +10 -21
- package/dist/cli/index.js +10 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-DnpMhZOY.cjs → import-D5f_X4-A.cjs} +684 -244
- package/dist/{import-A1yGuzwv.js → import-DC9T1JlQ.js} +686 -245
- package/dist/import-DC9T1JlQ.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-A1yGuzwv.js.map +0 -1
|
@@ -8,6 +8,7 @@ import { intersection, kebabCase, uniq } from "es-toolkit";
|
|
|
8
8
|
import { globbySync } from "globby";
|
|
9
9
|
import { isDeepStrictEqual } from "node:util";
|
|
10
10
|
import * as smolToml from "smol-toml";
|
|
11
|
+
import { parse as parse$1, stringify } from "smol-toml";
|
|
11
12
|
import matter from "gray-matter";
|
|
12
13
|
import { YAMLException, dump, load } from "js-yaml";
|
|
13
14
|
import { omit } from "es-toolkit/object";
|
|
@@ -2677,6 +2678,13 @@ const CODEXCLI_MCP_FILE_NAME = "config.toml";
|
|
|
2677
2678
|
const CODEXCLI_RULE_FILE_NAME = "AGENTS.md";
|
|
2678
2679
|
const CODEXCLI_BASH_RULES_FILE_NAME = "rulesync.rules";
|
|
2679
2680
|
const CODEXCLI_OPENAI_YAML_RELATIVE_PATH = join("agents", "openai.yaml");
|
|
2681
|
+
const CODEXCLI_OVERRIDE_KEYS = [
|
|
2682
|
+
"approval_policy",
|
|
2683
|
+
"sandbox_mode",
|
|
2684
|
+
"sandbox_workspace_write",
|
|
2685
|
+
"apps",
|
|
2686
|
+
"approvals_reviewer"
|
|
2687
|
+
];
|
|
2680
2688
|
//#endregion
|
|
2681
2689
|
//#region src/features/commands/codexcli-command.ts
|
|
2682
2690
|
const CodexcliCommandFrontmatterSchema = z.looseObject({
|
|
@@ -4055,14 +4063,22 @@ function sanitizeSharedConfigValue(value) {
|
|
|
4055
4063
|
* root follows `invalidRootPolicy`. Syntax errors are wrapped with the file
|
|
4056
4064
|
* path when one is given.
|
|
4057
4065
|
*/
|
|
4058
|
-
function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy = "coerce-empty" }) {
|
|
4066
|
+
function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy = "coerce-empty", jsoncParseErrors = "tolerate" }) {
|
|
4059
4067
|
if (fileContent.trim() === "") return {};
|
|
4060
4068
|
const at = filePath === void 0 ? "" : ` at ${filePath}`;
|
|
4061
4069
|
let parsed;
|
|
4062
4070
|
try {
|
|
4063
4071
|
if (format === "yaml") parsed = loadYaml(fileContent);
|
|
4072
|
+
else if (format === "toml") parsed = parse$1(fileContent);
|
|
4064
4073
|
else if (format === "json") parsed = JSON.parse(fileContent);
|
|
4065
|
-
else
|
|
4074
|
+
else if (jsoncParseErrors === "error") {
|
|
4075
|
+
const errors = [];
|
|
4076
|
+
parsed = parse(fileContent, errors, { allowTrailingComma: true });
|
|
4077
|
+
if (errors.length > 0) {
|
|
4078
|
+
const details = errors.map((error) => `${printParseErrorCode(error.error)} at offset ${error.offset}`).join(", ");
|
|
4079
|
+
throw new Error(details);
|
|
4080
|
+
}
|
|
4081
|
+
} else parsed = parse(fileContent);
|
|
4066
4082
|
} catch (error) {
|
|
4067
4083
|
throw new Error(`Failed to parse shared config${at}: ${formatError(error)}`, { cause: error });
|
|
4068
4084
|
}
|
|
@@ -4076,13 +4092,15 @@ function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy =
|
|
|
4076
4092
|
/**
|
|
4077
4093
|
* Serialize a shared config document. YAML output always ends with exactly one
|
|
4078
4094
|
* newline; JSON output matches the 2-space `JSON.stringify` shape the JSON
|
|
4079
|
-
* writers have always emitted (no trailing newline)
|
|
4095
|
+
* writers have always emitted (no trailing newline); TOML output matches the
|
|
4096
|
+
* `smol-toml` `stringify` shape the TOML writers have always emitted.
|
|
4080
4097
|
*/
|
|
4081
4098
|
function stringifySharedConfig({ format, document }) {
|
|
4082
4099
|
if (format === "yaml") return dump(document, {
|
|
4083
4100
|
noRefs: true,
|
|
4084
4101
|
sortKeys: false
|
|
4085
4102
|
}).trimEnd() + "\n";
|
|
4103
|
+
if (format === "toml") return stringify(document);
|
|
4086
4104
|
return JSON.stringify(document, null, 2);
|
|
4087
4105
|
}
|
|
4088
4106
|
/**
|
|
@@ -4121,6 +4139,25 @@ function mergeSharedConfigDeep({ base, patch }) {
|
|
|
4121
4139
|
const CLAUDE_SETTINGS_SHARED_FILE_KEY = ".claude/settings.json";
|
|
4122
4140
|
const HERMES_CONFIG_SHARED_FILE_KEY = ".hermes/config.yaml";
|
|
4123
4141
|
const TAKT_CONFIG_SHARED_FILE_KEY = ".takt/config.yaml";
|
|
4142
|
+
const CODEXCLI_CONFIG_SHARED_FILE_KEY = ".codex/config.toml";
|
|
4143
|
+
const GROKCLI_CONFIG_SHARED_FILE_KEY = ".grok/config.toml";
|
|
4144
|
+
const VIBE_CONFIG_SHARED_FILE_KEY = ".vibe/config.toml";
|
|
4145
|
+
const REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY = "reasonix.toml";
|
|
4146
|
+
const REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY = ".reasonix/config.toml";
|
|
4147
|
+
/**
|
|
4148
|
+
* Build the `SHARED_CONFIG_OWNERSHIP` lookup key from a tool's settable paths.
|
|
4149
|
+
* Mirrors `sharedFileKey` in `src/lib/shared-file-derive.ts` (kept separate so
|
|
4150
|
+
* feature classes don't pull the processor registry through this module and
|
|
4151
|
+
* create an import cycle); the ownership lock-step test keeps the two aligned.
|
|
4152
|
+
* Lets a tool whose file lives at a scope-dependent path (`.zed/settings.json`
|
|
4153
|
+
* vs `.config/zed/settings.json`) resolve its declaration from the settable
|
|
4154
|
+
* paths it already holds.
|
|
4155
|
+
*/
|
|
4156
|
+
const sharedConfigFileKey = ({ relativeDirPath, relativeFilePath }) => {
|
|
4157
|
+
const dir = relativeDirPath.replace(/\\/g, "/").replace(/\/$/, "");
|
|
4158
|
+
const file = relativeFilePath.replace(/\\/g, "/");
|
|
4159
|
+
return dir === "" || dir === "." ? file : `${dir}/${file}`;
|
|
4160
|
+
};
|
|
4124
4161
|
/**
|
|
4125
4162
|
* Who owns what in each gateway-managed shared config file, and which policy
|
|
4126
4163
|
* resolves conflicts. Keys are `dir/file` tokens matching
|
|
@@ -4177,6 +4214,298 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
4177
4214
|
},
|
|
4178
4215
|
permissions: { kind: "deep-merge" }
|
|
4179
4216
|
}
|
|
4217
|
+
},
|
|
4218
|
+
".zed/settings.json": {
|
|
4219
|
+
format: "json",
|
|
4220
|
+
features: {
|
|
4221
|
+
ignore: {
|
|
4222
|
+
kind: "replace-owned-keys",
|
|
4223
|
+
ownedKeys: ["private_files"]
|
|
4224
|
+
},
|
|
4225
|
+
mcp: {
|
|
4226
|
+
kind: "replace-owned-keys",
|
|
4227
|
+
ownedKeys: ["context_servers"]
|
|
4228
|
+
},
|
|
4229
|
+
permissions: {
|
|
4230
|
+
kind: "replace-owned-keys",
|
|
4231
|
+
ownedKeys: ["agent"]
|
|
4232
|
+
}
|
|
4233
|
+
}
|
|
4234
|
+
},
|
|
4235
|
+
".config/zed/settings.json": {
|
|
4236
|
+
format: "json",
|
|
4237
|
+
features: {
|
|
4238
|
+
mcp: {
|
|
4239
|
+
kind: "replace-owned-keys",
|
|
4240
|
+
ownedKeys: ["context_servers"]
|
|
4241
|
+
},
|
|
4242
|
+
permissions: {
|
|
4243
|
+
kind: "replace-owned-keys",
|
|
4244
|
+
ownedKeys: ["agent"]
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
},
|
|
4248
|
+
".qwen/settings.json": {
|
|
4249
|
+
format: "json",
|
|
4250
|
+
features: {
|
|
4251
|
+
mcp: {
|
|
4252
|
+
kind: "replace-owned-keys",
|
|
4253
|
+
ownedKeys: ["mcpServers"]
|
|
4254
|
+
},
|
|
4255
|
+
hooks: {
|
|
4256
|
+
kind: "replace-owned-keys",
|
|
4257
|
+
ownedKeys: ["hooks", "disableAllHooks"]
|
|
4258
|
+
},
|
|
4259
|
+
permissions: {
|
|
4260
|
+
kind: "replace-owned-keys",
|
|
4261
|
+
ownedKeys: [
|
|
4262
|
+
"permissions",
|
|
4263
|
+
"tools",
|
|
4264
|
+
"security"
|
|
4265
|
+
]
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
},
|
|
4269
|
+
".augment/settings.json": {
|
|
4270
|
+
format: "json",
|
|
4271
|
+
features: {
|
|
4272
|
+
mcp: {
|
|
4273
|
+
kind: "replace-owned-keys",
|
|
4274
|
+
ownedKeys: ["mcpServers"]
|
|
4275
|
+
},
|
|
4276
|
+
hooks: {
|
|
4277
|
+
kind: "replace-owned-keys",
|
|
4278
|
+
ownedKeys: ["hooks"]
|
|
4279
|
+
},
|
|
4280
|
+
permissions: {
|
|
4281
|
+
kind: "replace-owned-keys",
|
|
4282
|
+
ownedKeys: ["toolPermissions"]
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
},
|
|
4286
|
+
".devin/config.json": {
|
|
4287
|
+
format: "json",
|
|
4288
|
+
features: {
|
|
4289
|
+
mcp: {
|
|
4290
|
+
kind: "replace-owned-keys",
|
|
4291
|
+
ownedKeys: ["mcpServers"]
|
|
4292
|
+
},
|
|
4293
|
+
permissions: {
|
|
4294
|
+
kind: "replace-owned-keys",
|
|
4295
|
+
ownedKeys: ["permissions"]
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
},
|
|
4299
|
+
".config/devin/config.json": {
|
|
4300
|
+
format: "json",
|
|
4301
|
+
features: {
|
|
4302
|
+
mcp: {
|
|
4303
|
+
kind: "replace-owned-keys",
|
|
4304
|
+
ownedKeys: ["mcpServers"]
|
|
4305
|
+
},
|
|
4306
|
+
hooks: {
|
|
4307
|
+
kind: "replace-owned-keys",
|
|
4308
|
+
ownedKeys: ["hooks"]
|
|
4309
|
+
},
|
|
4310
|
+
permissions: {
|
|
4311
|
+
kind: "replace-owned-keys",
|
|
4312
|
+
ownedKeys: ["permissions"]
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
},
|
|
4316
|
+
".kiro/agents/default.json": {
|
|
4317
|
+
format: "json",
|
|
4318
|
+
features: {
|
|
4319
|
+
hooks: {
|
|
4320
|
+
kind: "replace-owned-keys",
|
|
4321
|
+
ownedKeys: ["hooks"]
|
|
4322
|
+
},
|
|
4323
|
+
permissions: {
|
|
4324
|
+
kind: "replace-owned-keys",
|
|
4325
|
+
ownedKeys: ["allowedTools", "toolsSettings"]
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
},
|
|
4329
|
+
".amp/settings.json": {
|
|
4330
|
+
format: "jsonc",
|
|
4331
|
+
invalidRootPolicy: "error",
|
|
4332
|
+
jsoncParseErrors: "error",
|
|
4333
|
+
features: {
|
|
4334
|
+
mcp: {
|
|
4335
|
+
kind: "replace-owned-keys",
|
|
4336
|
+
ownedKeys: ["amp.mcpServers"]
|
|
4337
|
+
},
|
|
4338
|
+
permissions: {
|
|
4339
|
+
kind: "replace-owned-keys",
|
|
4340
|
+
ownedKeys: [
|
|
4341
|
+
"amp.tools.disable",
|
|
4342
|
+
"amp.permissions",
|
|
4343
|
+
"amp.guardedFiles.allowlist",
|
|
4344
|
+
"amp.dangerouslyAllowAll",
|
|
4345
|
+
"amp.mcpPermissions"
|
|
4346
|
+
]
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
},
|
|
4350
|
+
".config/amp/settings.json": {
|
|
4351
|
+
format: "jsonc",
|
|
4352
|
+
invalidRootPolicy: "error",
|
|
4353
|
+
jsoncParseErrors: "error",
|
|
4354
|
+
features: {
|
|
4355
|
+
mcp: {
|
|
4356
|
+
kind: "replace-owned-keys",
|
|
4357
|
+
ownedKeys: ["amp.mcpServers"]
|
|
4358
|
+
},
|
|
4359
|
+
permissions: {
|
|
4360
|
+
kind: "replace-owned-keys",
|
|
4361
|
+
ownedKeys: [
|
|
4362
|
+
"amp.tools.disable",
|
|
4363
|
+
"amp.permissions",
|
|
4364
|
+
"amp.guardedFiles.allowlist",
|
|
4365
|
+
"amp.dangerouslyAllowAll",
|
|
4366
|
+
"amp.mcpPermissions"
|
|
4367
|
+
]
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
},
|
|
4371
|
+
"opencode.json": {
|
|
4372
|
+
format: "jsonc",
|
|
4373
|
+
features: {
|
|
4374
|
+
mcp: {
|
|
4375
|
+
kind: "replace-owned-keys",
|
|
4376
|
+
ownedKeys: ["mcp", "tools"]
|
|
4377
|
+
},
|
|
4378
|
+
permissions: {
|
|
4379
|
+
kind: "replace-owned-keys",
|
|
4380
|
+
ownedKeys: ["permission"]
|
|
4381
|
+
},
|
|
4382
|
+
rules: {
|
|
4383
|
+
kind: "replace-owned-keys",
|
|
4384
|
+
ownedKeys: ["instructions"]
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
},
|
|
4388
|
+
".config/opencode/opencode.json": {
|
|
4389
|
+
format: "jsonc",
|
|
4390
|
+
features: {
|
|
4391
|
+
mcp: {
|
|
4392
|
+
kind: "replace-owned-keys",
|
|
4393
|
+
ownedKeys: ["mcp", "tools"]
|
|
4394
|
+
},
|
|
4395
|
+
permissions: {
|
|
4396
|
+
kind: "replace-owned-keys",
|
|
4397
|
+
ownedKeys: ["permission"]
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
},
|
|
4401
|
+
"kilo.json": {
|
|
4402
|
+
format: "jsonc",
|
|
4403
|
+
features: {
|
|
4404
|
+
mcp: {
|
|
4405
|
+
kind: "replace-owned-keys",
|
|
4406
|
+
ownedKeys: ["mcp", "tools"]
|
|
4407
|
+
},
|
|
4408
|
+
rules: {
|
|
4409
|
+
kind: "replace-owned-keys",
|
|
4410
|
+
ownedKeys: ["instructions"]
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
},
|
|
4414
|
+
".config/kilo/kilo.json": {
|
|
4415
|
+
format: "jsonc",
|
|
4416
|
+
features: { mcp: {
|
|
4417
|
+
kind: "replace-owned-keys",
|
|
4418
|
+
ownedKeys: ["mcp", "tools"]
|
|
4419
|
+
} }
|
|
4420
|
+
},
|
|
4421
|
+
[CODEXCLI_CONFIG_SHARED_FILE_KEY]: {
|
|
4422
|
+
format: "toml",
|
|
4423
|
+
features: {
|
|
4424
|
+
hooks: {
|
|
4425
|
+
kind: "replace-owned-keys",
|
|
4426
|
+
ownedKeys: ["features"]
|
|
4427
|
+
},
|
|
4428
|
+
mcp: {
|
|
4429
|
+
kind: "replace-owned-keys",
|
|
4430
|
+
ownedKeys: ["mcp_servers"]
|
|
4431
|
+
},
|
|
4432
|
+
permissions: {
|
|
4433
|
+
kind: "replace-owned-keys",
|
|
4434
|
+
ownedKeys: [
|
|
4435
|
+
"permissions",
|
|
4436
|
+
"default_permissions",
|
|
4437
|
+
...CODEXCLI_OVERRIDE_KEYS
|
|
4438
|
+
]
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
},
|
|
4442
|
+
[GROKCLI_CONFIG_SHARED_FILE_KEY]: {
|
|
4443
|
+
format: "toml",
|
|
4444
|
+
features: {
|
|
4445
|
+
mcp: {
|
|
4446
|
+
kind: "replace-owned-keys",
|
|
4447
|
+
ownedKeys: ["mcp_servers"]
|
|
4448
|
+
},
|
|
4449
|
+
permissions: {
|
|
4450
|
+
kind: "replace-owned-keys",
|
|
4451
|
+
ownedKeys: ["permission", "ui"]
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
},
|
|
4455
|
+
[VIBE_CONFIG_SHARED_FILE_KEY]: {
|
|
4456
|
+
format: "toml",
|
|
4457
|
+
features: {
|
|
4458
|
+
hooks: {
|
|
4459
|
+
kind: "replace-owned-keys",
|
|
4460
|
+
ownedKeys: ["enable_experimental_hooks"]
|
|
4461
|
+
},
|
|
4462
|
+
mcp: {
|
|
4463
|
+
kind: "replace-owned-keys",
|
|
4464
|
+
ownedKeys: ["mcp_servers"]
|
|
4465
|
+
},
|
|
4466
|
+
permissions: {
|
|
4467
|
+
kind: "replace-owned-keys",
|
|
4468
|
+
ownedKeys: [
|
|
4469
|
+
"tools",
|
|
4470
|
+
"enabled_tools",
|
|
4471
|
+
"disabled_tools"
|
|
4472
|
+
]
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
},
|
|
4476
|
+
[REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY]: {
|
|
4477
|
+
format: "toml",
|
|
4478
|
+
features: {
|
|
4479
|
+
mcp: {
|
|
4480
|
+
kind: "replace-owned-keys",
|
|
4481
|
+
ownedKeys: ["plugins"]
|
|
4482
|
+
},
|
|
4483
|
+
permissions: {
|
|
4484
|
+
kind: "replace-owned-keys",
|
|
4485
|
+
ownedKeys: [
|
|
4486
|
+
"permissions",
|
|
4487
|
+
"sandbox",
|
|
4488
|
+
"agent"
|
|
4489
|
+
]
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
},
|
|
4493
|
+
[REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY]: {
|
|
4494
|
+
format: "toml",
|
|
4495
|
+
features: {
|
|
4496
|
+
mcp: {
|
|
4497
|
+
kind: "replace-owned-keys",
|
|
4498
|
+
ownedKeys: ["plugins"]
|
|
4499
|
+
},
|
|
4500
|
+
permissions: {
|
|
4501
|
+
kind: "replace-owned-keys",
|
|
4502
|
+
ownedKeys: [
|
|
4503
|
+
"permissions",
|
|
4504
|
+
"sandbox",
|
|
4505
|
+
"agent"
|
|
4506
|
+
]
|
|
4507
|
+
}
|
|
4508
|
+
}
|
|
4180
4509
|
}
|
|
4181
4510
|
};
|
|
4182
4511
|
/**
|
|
@@ -4197,17 +4526,20 @@ function applySharedConfigPatch({ fileKey, feature, existingContent, patch, file
|
|
|
4197
4526
|
format: declaration.format,
|
|
4198
4527
|
fileContent: existingContent,
|
|
4199
4528
|
filePath,
|
|
4200
|
-
...declaration.invalidRootPolicy !== void 0 && { invalidRootPolicy: declaration.invalidRootPolicy }
|
|
4529
|
+
...declaration.invalidRootPolicy !== void 0 && { invalidRootPolicy: declaration.invalidRootPolicy },
|
|
4530
|
+
...declaration.jsoncParseErrors !== void 0 && { jsoncParseErrors: declaration.jsoncParseErrors }
|
|
4201
4531
|
});
|
|
4202
4532
|
if (policy.kind === "replace-owned-keys") {
|
|
4203
4533
|
const unowned = Object.keys(patch).filter((key) => !policy.ownedKeys.includes(key));
|
|
4204
4534
|
if (unowned.length > 0) throw new Error(`Feature '${feature}' tried to write undeclared keys [${unowned.join(", ")}] to '${fileKey}'; extend its ownedKeys declaration if that ownership is intended.`);
|
|
4535
|
+
const document = mergeSharedConfigShallow({
|
|
4536
|
+
base,
|
|
4537
|
+
patch
|
|
4538
|
+
});
|
|
4539
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0) delete document[key];
|
|
4205
4540
|
return stringifySharedConfig({
|
|
4206
4541
|
format: declaration.format,
|
|
4207
|
-
document
|
|
4208
|
-
base,
|
|
4209
|
-
patch
|
|
4210
|
-
})
|
|
4542
|
+
document
|
|
4211
4543
|
});
|
|
4212
4544
|
}
|
|
4213
4545
|
const merged = mergeSharedConfigDeep({
|
|
@@ -7280,12 +7612,6 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
7280
7612
|
const paths = AugmentcodeHooks.getSettablePaths({ global });
|
|
7281
7613
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
7282
7614
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
7283
|
-
let settings;
|
|
7284
|
-
try {
|
|
7285
|
-
settings = JSON.parse(existingContent);
|
|
7286
|
-
} catch (error) {
|
|
7287
|
-
throw new Error(`Failed to parse existing AugmentCode settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
7288
|
-
}
|
|
7289
7615
|
const config = rulesyncHooks.getJson();
|
|
7290
7616
|
const augmentHooks = canonicalToToolHooks({
|
|
7291
7617
|
config,
|
|
@@ -7293,11 +7619,13 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
7293
7619
|
converterConfig: AUGMENTCODE_CONVERTER_CONFIG,
|
|
7294
7620
|
logger
|
|
7295
7621
|
});
|
|
7296
|
-
const
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7622
|
+
const fileContent = applySharedConfigPatch({
|
|
7623
|
+
fileKey: sharedConfigFileKey(paths),
|
|
7624
|
+
feature: "hooks",
|
|
7625
|
+
existingContent,
|
|
7626
|
+
patch: { hooks: augmentHooks },
|
|
7627
|
+
filePath
|
|
7628
|
+
});
|
|
7301
7629
|
return new AugmentcodeHooks({
|
|
7302
7630
|
outputRoot,
|
|
7303
7631
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -7464,15 +7792,28 @@ const CODEXCLI_CONVERTER_CONFIG = {
|
|
|
7464
7792
|
*/
|
|
7465
7793
|
async function buildCodexConfigTomlContent({ outputRoot }) {
|
|
7466
7794
|
const configPath = join(outputRoot, CODEXCLI_DIR, CODEXCLI_MCP_FILE_NAME);
|
|
7467
|
-
const existingContent = await readFileContentOrNull(configPath) ??
|
|
7795
|
+
const existingContent = await readFileContentOrNull(configPath) ?? "";
|
|
7468
7796
|
let configToml;
|
|
7469
7797
|
try {
|
|
7470
|
-
configToml = smolToml.parse(existingContent);
|
|
7798
|
+
configToml = smolToml.parse(existingContent || smolToml.stringify({}));
|
|
7471
7799
|
} catch (error) {
|
|
7472
7800
|
throw new Error(`Failed to parse existing Codex CLI config at ${configPath}: ${formatError(error)}`, { cause: error });
|
|
7473
7801
|
}
|
|
7474
|
-
|
|
7475
|
-
|
|
7802
|
+
let features;
|
|
7803
|
+
if (typeof configToml.features === "object" && configToml.features !== null) {
|
|
7804
|
+
features = { ...configToml.features };
|
|
7805
|
+
delete features.codex_hooks;
|
|
7806
|
+
}
|
|
7807
|
+
return applySharedConfigPatch({
|
|
7808
|
+
fileKey: sharedConfigFileKey({
|
|
7809
|
+
relativeDirPath: CODEXCLI_DIR,
|
|
7810
|
+
relativeFilePath: CODEXCLI_MCP_FILE_NAME
|
|
7811
|
+
}),
|
|
7812
|
+
feature: "hooks",
|
|
7813
|
+
existingContent,
|
|
7814
|
+
patch: { features },
|
|
7815
|
+
filePath: configPath
|
|
7816
|
+
});
|
|
7476
7817
|
}
|
|
7477
7818
|
/**
|
|
7478
7819
|
* Represents the `.codex/config.toml` file as a generated ToolFile,
|
|
@@ -8388,17 +8729,13 @@ var DevinHooks = class DevinHooks extends ToolHooks {
|
|
|
8388
8729
|
let fileContent;
|
|
8389
8730
|
if (global) {
|
|
8390
8731
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
...isRecord(parsedSettings) ? parsedSettings : {},
|
|
8399
|
-
hooks: devinHooks
|
|
8400
|
-
};
|
|
8401
|
-
fileContent = JSON.stringify(merged, null, 2);
|
|
8732
|
+
fileContent = applySharedConfigPatch({
|
|
8733
|
+
fileKey: sharedConfigFileKey(paths),
|
|
8734
|
+
feature: "hooks",
|
|
8735
|
+
existingContent,
|
|
8736
|
+
patch: { hooks: devinHooks },
|
|
8737
|
+
filePath
|
|
8738
|
+
});
|
|
8402
8739
|
} else {
|
|
8403
8740
|
await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
8404
8741
|
fileContent = JSON.stringify(devinHooks, null, 2);
|
|
@@ -9210,18 +9547,14 @@ var KiroHooks = class KiroHooks extends ToolHooks {
|
|
|
9210
9547
|
const paths = KiroHooks.getSettablePaths({ global });
|
|
9211
9548
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
9212
9549
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
9213
|
-
let agentConfig;
|
|
9214
|
-
try {
|
|
9215
|
-
agentConfig = JSON.parse(existingContent);
|
|
9216
|
-
} catch (error) {
|
|
9217
|
-
throw new Error(`Failed to parse existing Kiro agent config at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
9218
|
-
}
|
|
9219
9550
|
const kiroHooks = canonicalToKiroHooks(rulesyncHooks.getJson(), this.getOverrideKey());
|
|
9220
|
-
const
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9551
|
+
const fileContent = applySharedConfigPatch({
|
|
9552
|
+
fileKey: sharedConfigFileKey(paths),
|
|
9553
|
+
feature: "hooks",
|
|
9554
|
+
existingContent,
|
|
9555
|
+
patch: { hooks: kiroHooks },
|
|
9556
|
+
filePath
|
|
9557
|
+
});
|
|
9225
9558
|
return new KiroHooks({
|
|
9226
9559
|
outputRoot,
|
|
9227
9560
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -9716,21 +10049,17 @@ var QwencodeHooks = class QwencodeHooks extends ToolHooks {
|
|
|
9716
10049
|
const paths = QwencodeHooks.getSettablePaths({ global });
|
|
9717
10050
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
9718
10051
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
9719
|
-
let settings;
|
|
9720
|
-
try {
|
|
9721
|
-
settings = JSON.parse(existingContent);
|
|
9722
|
-
} catch (error) {
|
|
9723
|
-
throw new Error(`Failed to parse existing Qwen Code settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
9724
|
-
}
|
|
9725
10052
|
const config = rulesyncHooks.getJson();
|
|
9726
|
-
const
|
|
9727
|
-
const merged = {
|
|
9728
|
-
...settings,
|
|
9729
|
-
hooks: qwencodeHooks
|
|
9730
|
-
};
|
|
10053
|
+
const patch = { hooks: canonicalToQwencodeHooks(config) };
|
|
9731
10054
|
const disableAllHooks = config.qwencode?.disableAllHooks;
|
|
9732
|
-
if (typeof disableAllHooks === "boolean")
|
|
9733
|
-
const fileContent =
|
|
10055
|
+
if (typeof disableAllHooks === "boolean") patch.disableAllHooks = disableAllHooks;
|
|
10056
|
+
const fileContent = applySharedConfigPatch({
|
|
10057
|
+
fileKey: sharedConfigFileKey(paths),
|
|
10058
|
+
feature: "hooks",
|
|
10059
|
+
existingContent,
|
|
10060
|
+
patch,
|
|
10061
|
+
filePath
|
|
10062
|
+
});
|
|
9734
10063
|
return new QwencodeHooks({
|
|
9735
10064
|
outputRoot,
|
|
9736
10065
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -9989,10 +10318,6 @@ function canonicalToVibeHooks(config, toolOverride) {
|
|
|
9989
10318
|
}
|
|
9990
10319
|
return { hooks };
|
|
9991
10320
|
}
|
|
9992
|
-
/**
|
|
9993
|
-
* Reverse {@link canonicalToVibeHooks}: parse the flat `[[hooks]]` array back
|
|
9994
|
-
* into a canonical event → definition[] record.
|
|
9995
|
-
*/
|
|
9996
10321
|
/** Convert one raw `[[hooks]]` entry to a canonical definition, or null to skip. */
|
|
9997
10322
|
function vibeEntryToCanonicalDef(raw) {
|
|
9998
10323
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -10012,6 +10337,10 @@ function vibeEntryToCanonicalDef(raw) {
|
|
|
10012
10337
|
def
|
|
10013
10338
|
};
|
|
10014
10339
|
}
|
|
10340
|
+
/**
|
|
10341
|
+
* Reverse {@link canonicalToVibeHooks}: parse the flat `[[hooks]]` array back
|
|
10342
|
+
* into a canonical event → definition[] record.
|
|
10343
|
+
*/
|
|
10015
10344
|
function vibeHooksToCanonical(parsed) {
|
|
10016
10345
|
const canonical = {};
|
|
10017
10346
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return canonical;
|
|
@@ -10040,15 +10369,22 @@ function parseVibeToml(fileContent) {
|
|
|
10040
10369
|
*/
|
|
10041
10370
|
async function buildVibeConfigTomlContent({ outputRoot }) {
|
|
10042
10371
|
const configPath = join(outputRoot, VIBE_DIR, VIBE_CONFIG_FILE_NAME);
|
|
10043
|
-
const existingContent = await readFileContentOrNull(configPath) ??
|
|
10044
|
-
let config;
|
|
10372
|
+
const existingContent = await readFileContentOrNull(configPath) ?? "";
|
|
10045
10373
|
try {
|
|
10046
|
-
|
|
10374
|
+
parseVibeToml(existingContent);
|
|
10047
10375
|
} catch (error) {
|
|
10048
10376
|
throw new Error(`Failed to parse existing Vibe config at ${configPath}: ${formatError(error)}`, { cause: error });
|
|
10049
10377
|
}
|
|
10050
|
-
|
|
10051
|
-
|
|
10378
|
+
return applySharedConfigPatch({
|
|
10379
|
+
fileKey: sharedConfigFileKey({
|
|
10380
|
+
relativeDirPath: VIBE_DIR,
|
|
10381
|
+
relativeFilePath: VIBE_CONFIG_FILE_NAME
|
|
10382
|
+
}),
|
|
10383
|
+
feature: "hooks",
|
|
10384
|
+
existingContent,
|
|
10385
|
+
patch: { enable_experimental_hooks: true },
|
|
10386
|
+
filePath: configPath
|
|
10387
|
+
});
|
|
10052
10388
|
}
|
|
10053
10389
|
/**
|
|
10054
10390
|
* Represents the `.vibe/config.toml` file as a generated ToolFile so it goes
|
|
@@ -11548,17 +11884,18 @@ var ZedIgnore = class ZedIgnore extends ToolIgnore {
|
|
|
11548
11884
|
const patterns = rulesyncIgnore.getFileContent().split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
11549
11885
|
const filePath = join(outputRoot, this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath);
|
|
11550
11886
|
const existingFileContent = await fileExists(filePath) ? await readFileContent(filePath) : "{}";
|
|
11551
|
-
const
|
|
11552
|
-
const mergedPatterns = uniq([...existingJsonValue.private_files ?? [], ...patterns].toSorted());
|
|
11553
|
-
const jsonValue = {
|
|
11554
|
-
...existingJsonValue,
|
|
11555
|
-
private_files: mergedPatterns
|
|
11556
|
-
};
|
|
11887
|
+
const mergedPatterns = uniq([...JSON.parse(existingFileContent).private_files ?? [], ...patterns].toSorted());
|
|
11557
11888
|
return new ZedIgnore({
|
|
11558
11889
|
outputRoot,
|
|
11559
11890
|
relativeDirPath: this.getSettablePaths().relativeDirPath,
|
|
11560
11891
|
relativeFilePath: this.getSettablePaths().relativeFilePath,
|
|
11561
|
-
fileContent:
|
|
11892
|
+
fileContent: applySharedConfigPatch({
|
|
11893
|
+
fileKey: sharedConfigFileKey(this.getSettablePaths()),
|
|
11894
|
+
feature: "ignore",
|
|
11895
|
+
existingContent: existingFileContent,
|
|
11896
|
+
patch: { private_files: mergedPatterns },
|
|
11897
|
+
filePath
|
|
11898
|
+
}),
|
|
11562
11899
|
validate: true
|
|
11563
11900
|
});
|
|
11564
11901
|
}
|
|
@@ -12015,17 +12352,17 @@ var AmpMcp = class AmpMcp extends ToolMcp {
|
|
|
12015
12352
|
const basePaths = this.getSettablePaths({ global });
|
|
12016
12353
|
const jsonDir = join(outputRoot, basePaths.relativeDirPath);
|
|
12017
12354
|
const { fileContent, relativeFilePath } = await this.resolveSettingsFile(jsonDir);
|
|
12018
|
-
const json = fileContent ? parseAmpSettingsJsonc(fileContent) : { [AMP_MCP_SERVERS_KEY]: {} };
|
|
12019
|
-
const filteredMcpServers = filterMcpServers(rulesyncMcp.getMcpServers());
|
|
12020
|
-
const newJson = {
|
|
12021
|
-
...json,
|
|
12022
|
-
[AMP_MCP_SERVERS_KEY]: filteredMcpServers
|
|
12023
|
-
};
|
|
12024
12355
|
return new AmpMcp({
|
|
12025
12356
|
outputRoot,
|
|
12026
12357
|
relativeDirPath: basePaths.relativeDirPath,
|
|
12027
12358
|
relativeFilePath,
|
|
12028
|
-
fileContent:
|
|
12359
|
+
fileContent: applySharedConfigPatch({
|
|
12360
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
12361
|
+
feature: "mcp",
|
|
12362
|
+
existingContent: fileContent ?? "",
|
|
12363
|
+
patch: { [AMP_MCP_SERVERS_KEY]: filterMcpServers(rulesyncMcp.getMcpServers()) },
|
|
12364
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
12365
|
+
}),
|
|
12029
12366
|
validate,
|
|
12030
12367
|
global
|
|
12031
12368
|
});
|
|
@@ -12312,15 +12649,19 @@ var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
|
12312
12649
|
}
|
|
12313
12650
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12314
12651
|
const paths = this.getSettablePaths({ global });
|
|
12315
|
-
const
|
|
12316
|
-
|
|
12317
|
-
mcpServers: rulesyncMcp.getMcpServers()
|
|
12318
|
-
};
|
|
12652
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
12653
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
12319
12654
|
return new AugmentcodeMcp({
|
|
12320
12655
|
outputRoot,
|
|
12321
12656
|
relativeDirPath: paths.relativeDirPath,
|
|
12322
12657
|
relativeFilePath: paths.relativeFilePath,
|
|
12323
|
-
fileContent:
|
|
12658
|
+
fileContent: applySharedConfigPatch({
|
|
12659
|
+
fileKey: sharedConfigFileKey(paths),
|
|
12660
|
+
feature: "mcp",
|
|
12661
|
+
existingContent,
|
|
12662
|
+
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
12663
|
+
filePath
|
|
12664
|
+
}),
|
|
12324
12665
|
validate,
|
|
12325
12666
|
global
|
|
12326
12667
|
});
|
|
@@ -12714,8 +13055,9 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12714
13055
|
}
|
|
12715
13056
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12716
13057
|
const paths = this.getSettablePaths({ global });
|
|
12717
|
-
const
|
|
12718
|
-
const
|
|
13058
|
+
const configTomlFilePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13059
|
+
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13060
|
+
const configToml = smolToml.parse(configTomlFileContent || smolToml.stringify({}));
|
|
12719
13061
|
const strippedMcpServers = rulesyncMcp.getMcpServers();
|
|
12720
13062
|
const rawMcpServers = rulesyncMcp.getJson().mcpServers;
|
|
12721
13063
|
const converted = convertToCodexFormat(Object.fromEntries(Object.entries(strippedMcpServers).map(([serverName, serverConfig]) => {
|
|
@@ -12728,7 +13070,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12728
13070
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
12729
13071
|
for (const name of Object.keys(converted)) if (!Object.hasOwn(filteredMcpServers, name)) warnWithFallback(void 0, `MCP server "${name}" had no non-empty configuration and was dropped from the codex CLI config`);
|
|
12730
13072
|
const existingMcpServers = isRecord(configToml["mcp_servers"]) ? configToml["mcp_servers"] : {};
|
|
12731
|
-
|
|
13073
|
+
const mergedMcpServers = Object.fromEntries(Object.entries(filteredMcpServers).map(([name, serverConfig]) => {
|
|
12732
13074
|
const existingServer = isRecord(existingMcpServers[name]) ? existingMcpServers[name] : void 0;
|
|
12733
13075
|
const serverRecord = serverConfig;
|
|
12734
13076
|
if (existingServer && isRecord(existingServer["tools"]) && !("tools" in serverRecord)) return [name, {
|
|
@@ -12741,7 +13083,13 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12741
13083
|
outputRoot,
|
|
12742
13084
|
relativeDirPath: paths.relativeDirPath,
|
|
12743
13085
|
relativeFilePath: paths.relativeFilePath,
|
|
12744
|
-
fileContent:
|
|
13086
|
+
fileContent: applySharedConfigPatch({
|
|
13087
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13088
|
+
feature: "mcp",
|
|
13089
|
+
existingContent: configTomlFileContent,
|
|
13090
|
+
patch: { mcp_servers: mergedMcpServers },
|
|
13091
|
+
filePath: configTomlFilePath
|
|
13092
|
+
}),
|
|
12745
13093
|
validate
|
|
12746
13094
|
});
|
|
12747
13095
|
}
|
|
@@ -13308,16 +13656,19 @@ var DevinMcp = class DevinMcp extends ToolMcp {
|
|
|
13308
13656
|
}
|
|
13309
13657
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13310
13658
|
const paths = this.getSettablePaths({ global });
|
|
13311
|
-
const
|
|
13312
|
-
const
|
|
13313
|
-
...this.parseJsonOrThrow(fileContent, paths.relativeDirPath, paths.relativeFilePath),
|
|
13314
|
-
mcpServers: rulesyncMcp.getMcpServers()
|
|
13315
|
-
};
|
|
13659
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13660
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
13316
13661
|
return new DevinMcp({
|
|
13317
13662
|
outputRoot,
|
|
13318
13663
|
relativeDirPath: paths.relativeDirPath,
|
|
13319
13664
|
relativeFilePath: paths.relativeFilePath,
|
|
13320
|
-
fileContent:
|
|
13665
|
+
fileContent: applySharedConfigPatch({
|
|
13666
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13667
|
+
feature: "mcp",
|
|
13668
|
+
existingContent,
|
|
13669
|
+
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
13670
|
+
filePath
|
|
13671
|
+
}),
|
|
13321
13672
|
validate,
|
|
13322
13673
|
global
|
|
13323
13674
|
});
|
|
@@ -13804,17 +14155,22 @@ var GrokcliMcp = class GrokcliMcp extends ToolMcp {
|
|
|
13804
14155
|
}
|
|
13805
14156
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13806
14157
|
const paths = this.getSettablePaths({ global });
|
|
13807
|
-
const
|
|
13808
|
-
const
|
|
14158
|
+
const configTomlFilePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
14159
|
+
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13809
14160
|
const converted = convertToGrokFormat(rulesyncMcp.getMcpServers());
|
|
13810
14161
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
13811
14162
|
for (const name of Object.keys(converted)) if (!Object.hasOwn(filteredMcpServers, name)) warnWithFallback(void 0, `MCP server "${name}" had no non-empty configuration and was dropped from the grok CLI config`);
|
|
13812
|
-
configToml["mcp_servers"] = filteredMcpServers;
|
|
13813
14163
|
return new GrokcliMcp({
|
|
13814
14164
|
outputRoot,
|
|
13815
14165
|
relativeDirPath: paths.relativeDirPath,
|
|
13816
14166
|
relativeFilePath: paths.relativeFilePath,
|
|
13817
|
-
fileContent:
|
|
14167
|
+
fileContent: applySharedConfigPatch({
|
|
14168
|
+
fileKey: sharedConfigFileKey(paths),
|
|
14169
|
+
feature: "mcp",
|
|
14170
|
+
existingContent: configTomlFileContent,
|
|
14171
|
+
patch: { mcp_servers: filteredMcpServers },
|
|
14172
|
+
filePath: configTomlFilePath
|
|
14173
|
+
}),
|
|
13818
14174
|
validate
|
|
13819
14175
|
});
|
|
13820
14176
|
}
|
|
@@ -14347,20 +14703,21 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14347
14703
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14348
14704
|
if (fileContent) relativeFilePath = KILO_JSON_FILE_NAME;
|
|
14349
14705
|
}
|
|
14350
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14351
|
-
const json = parse(fileContent);
|
|
14352
14706
|
const { mcp: convertedMcp, tools: mcpTools } = convertToKiloFormat(rulesyncMcp.getMcpServers());
|
|
14353
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14354
|
-
const newJson = {
|
|
14355
|
-
...jsonWithoutTools,
|
|
14356
|
-
mcp: convertedMcp,
|
|
14357
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14358
|
-
};
|
|
14359
14707
|
return new KiloMcp({
|
|
14360
14708
|
outputRoot,
|
|
14361
14709
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14362
14710
|
relativeFilePath,
|
|
14363
|
-
fileContent:
|
|
14711
|
+
fileContent: applySharedConfigPatch({
|
|
14712
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
14713
|
+
feature: "mcp",
|
|
14714
|
+
existingContent: fileContent ?? "",
|
|
14715
|
+
patch: {
|
|
14716
|
+
mcp: convertedMcp,
|
|
14717
|
+
tools: Object.keys(mcpTools).length > 0 ? mcpTools : void 0
|
|
14718
|
+
},
|
|
14719
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
14720
|
+
}),
|
|
14364
14721
|
validate
|
|
14365
14722
|
});
|
|
14366
14723
|
}
|
|
@@ -14389,15 +14746,17 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14389
14746
|
const json = fileContent ? parse(fileContent) : {};
|
|
14390
14747
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14391
14748
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14392
|
-
const newJson = {
|
|
14393
|
-
...json,
|
|
14394
|
-
instructions: mergedInstructions
|
|
14395
|
-
};
|
|
14396
14749
|
return new KiloMcp({
|
|
14397
14750
|
outputRoot,
|
|
14398
14751
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14399
14752
|
relativeFilePath,
|
|
14400
|
-
fileContent:
|
|
14753
|
+
fileContent: applySharedConfigPatch({
|
|
14754
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
14755
|
+
feature: "rules",
|
|
14756
|
+
existingContent: fileContent ?? "",
|
|
14757
|
+
patch: { instructions: mergedInstructions },
|
|
14758
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
14759
|
+
}),
|
|
14401
14760
|
validate
|
|
14402
14761
|
});
|
|
14403
14762
|
}
|
|
@@ -14669,23 +15028,24 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14669
15028
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14670
15029
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
14671
15030
|
}
|
|
14672
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14673
|
-
const json = parse(fileContent);
|
|
14674
15031
|
const { mcp: convertedMcp, tools: mcpTools } = convertToOpencodeFormat(convertEnvVarRefsToToolFormat({
|
|
14675
15032
|
mcpServers: rulesyncMcp.getMcpServers(),
|
|
14676
15033
|
replacement: "{env:$1}"
|
|
14677
15034
|
}));
|
|
14678
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14679
|
-
const newJson = {
|
|
14680
|
-
...jsonWithoutTools,
|
|
14681
|
-
mcp: convertedMcp,
|
|
14682
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14683
|
-
};
|
|
14684
15035
|
return new OpencodeMcp({
|
|
14685
15036
|
outputRoot,
|
|
14686
15037
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14687
15038
|
relativeFilePath,
|
|
14688
|
-
fileContent:
|
|
15039
|
+
fileContent: applySharedConfigPatch({
|
|
15040
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
15041
|
+
feature: "mcp",
|
|
15042
|
+
existingContent: fileContent ?? "",
|
|
15043
|
+
patch: {
|
|
15044
|
+
mcp: convertedMcp,
|
|
15045
|
+
tools: Object.keys(mcpTools).length > 0 ? mcpTools : void 0
|
|
15046
|
+
},
|
|
15047
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
15048
|
+
}),
|
|
14689
15049
|
validate
|
|
14690
15050
|
});
|
|
14691
15051
|
}
|
|
@@ -14720,15 +15080,17 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14720
15080
|
const json = fileContent ? parse(fileContent) : {};
|
|
14721
15081
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14722
15082
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14723
|
-
const newJson = {
|
|
14724
|
-
...json,
|
|
14725
|
-
instructions: mergedInstructions
|
|
14726
|
-
};
|
|
14727
15083
|
return new OpencodeMcp({
|
|
14728
15084
|
outputRoot,
|
|
14729
15085
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14730
15086
|
relativeFilePath,
|
|
14731
|
-
fileContent:
|
|
15087
|
+
fileContent: applySharedConfigPatch({
|
|
15088
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
15089
|
+
feature: "rules",
|
|
15090
|
+
existingContent: fileContent ?? "",
|
|
15091
|
+
patch: { instructions: mergedInstructions },
|
|
15092
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
15093
|
+
}),
|
|
14732
15094
|
validate
|
|
14733
15095
|
});
|
|
14734
15096
|
}
|
|
@@ -14838,16 +15200,19 @@ var QwencodeMcp = class QwencodeMcp extends ToolMcp {
|
|
|
14838
15200
|
}
|
|
14839
15201
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14840
15202
|
const paths = this.getSettablePaths({ global });
|
|
14841
|
-
const
|
|
14842
|
-
const
|
|
14843
|
-
...JSON.parse(fileContent),
|
|
14844
|
-
mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers())
|
|
14845
|
-
};
|
|
15203
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15204
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
14846
15205
|
return new QwencodeMcp({
|
|
14847
15206
|
outputRoot,
|
|
14848
15207
|
relativeDirPath: paths.relativeDirPath,
|
|
14849
15208
|
relativeFilePath: paths.relativeFilePath,
|
|
14850
|
-
fileContent:
|
|
15209
|
+
fileContent: applySharedConfigPatch({
|
|
15210
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15211
|
+
feature: "mcp",
|
|
15212
|
+
existingContent,
|
|
15213
|
+
patch: { mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers()) },
|
|
15214
|
+
filePath
|
|
15215
|
+
}),
|
|
14851
15216
|
validate
|
|
14852
15217
|
});
|
|
14853
15218
|
}
|
|
@@ -14932,13 +15297,20 @@ var ReasonixMcp = class ReasonixMcp extends ToolMcp {
|
|
|
14932
15297
|
}
|
|
14933
15298
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14934
15299
|
const paths = this.getSettablePaths({ global });
|
|
14935
|
-
const
|
|
14936
|
-
|
|
15300
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15301
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
15302
|
+
const plugins = Object.entries(rulesyncMcp.getMcpServers()).map(([name, server]) => rulesyncMcpServerToReasonix(name, server));
|
|
14937
15303
|
return new ReasonixMcp({
|
|
14938
15304
|
outputRoot,
|
|
14939
15305
|
relativeDirPath: paths.relativeDirPath,
|
|
14940
15306
|
relativeFilePath: paths.relativeFilePath,
|
|
14941
|
-
fileContent:
|
|
15307
|
+
fileContent: applySharedConfigPatch({
|
|
15308
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15309
|
+
feature: "mcp",
|
|
15310
|
+
existingContent,
|
|
15311
|
+
patch: { plugins },
|
|
15312
|
+
filePath
|
|
15313
|
+
}),
|
|
14942
15314
|
validate,
|
|
14943
15315
|
global
|
|
14944
15316
|
});
|
|
@@ -15413,13 +15785,20 @@ var VibeMcp = class VibeMcp extends ToolMcp {
|
|
|
15413
15785
|
}
|
|
15414
15786
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15415
15787
|
const paths = this.getSettablePaths({ global });
|
|
15416
|
-
const
|
|
15417
|
-
|
|
15788
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15789
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
15790
|
+
const mcpServers = Object.entries(rulesyncMcp.getMcpServers()).map(([name, server]) => rulesyncMcpServerToVibe(name, server));
|
|
15418
15791
|
return new VibeMcp({
|
|
15419
15792
|
outputRoot,
|
|
15420
15793
|
relativeDirPath: paths.relativeDirPath,
|
|
15421
15794
|
relativeFilePath: paths.relativeFilePath,
|
|
15422
|
-
fileContent:
|
|
15795
|
+
fileContent: applySharedConfigPatch({
|
|
15796
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15797
|
+
feature: "mcp",
|
|
15798
|
+
existingContent,
|
|
15799
|
+
patch: { mcp_servers: mcpServers },
|
|
15800
|
+
filePath
|
|
15801
|
+
}),
|
|
15423
15802
|
validate,
|
|
15424
15803
|
global
|
|
15425
15804
|
});
|
|
@@ -15650,16 +16029,19 @@ var ZedMcp = class ZedMcp extends ToolMcp {
|
|
|
15650
16029
|
}
|
|
15651
16030
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15652
16031
|
const paths = this.getSettablePaths({ global });
|
|
15653
|
-
const
|
|
15654
|
-
const
|
|
15655
|
-
...JSON.parse(fileContent),
|
|
15656
|
-
context_servers: rulesyncMcp.getMcpServers()
|
|
15657
|
-
};
|
|
16032
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
16033
|
+
const existingContent = await readOrInitializeFileContent(filePath, "{}");
|
|
15658
16034
|
return new ZedMcp({
|
|
15659
16035
|
outputRoot,
|
|
15660
16036
|
relativeDirPath: paths.relativeDirPath,
|
|
15661
16037
|
relativeFilePath: paths.relativeFilePath,
|
|
15662
|
-
fileContent:
|
|
16038
|
+
fileContent: applySharedConfigPatch({
|
|
16039
|
+
fileKey: sharedConfigFileKey(paths),
|
|
16040
|
+
feature: "mcp",
|
|
16041
|
+
existingContent,
|
|
16042
|
+
patch: { context_servers: rulesyncMcp.getMcpServers() },
|
|
16043
|
+
filePath
|
|
16044
|
+
}),
|
|
15663
16045
|
validate
|
|
15664
16046
|
});
|
|
15665
16047
|
}
|
|
@@ -16828,25 +17210,29 @@ var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
|
16828
17210
|
const override = config.amp;
|
|
16829
17211
|
const authoredExtras = override?.permissions ? toPermissionsList(override.permissions) : [];
|
|
16830
17212
|
const preservedDelegates = override?.permissions ? [] : toPermissionsList(json[AMP_PERMISSIONS_KEY]).filter((entry) => entry.action === "delegate");
|
|
16831
|
-
const newJson = {
|
|
16832
|
-
...json,
|
|
16833
|
-
[AMP_TOOLS_DISABLE_KEY]: disable
|
|
16834
|
-
};
|
|
16835
17213
|
const mergedPermissions = mergeAmpPermissions([
|
|
16836
17214
|
...permissions,
|
|
16837
17215
|
...authoredExtras,
|
|
16838
17216
|
...preservedDelegates
|
|
16839
17217
|
]);
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
if (override?.
|
|
17218
|
+
const patch = {
|
|
17219
|
+
[AMP_TOOLS_DISABLE_KEY]: disable,
|
|
17220
|
+
[AMP_PERMISSIONS_KEY]: mergedPermissions.length > 0 ? mergedPermissions : void 0
|
|
17221
|
+
};
|
|
17222
|
+
if (override?.guardedFiles?.allowlist !== void 0) patch[AMP_GUARDED_FILES_ALLOWLIST_KEY] = override.guardedFiles.allowlist;
|
|
17223
|
+
if (override?.dangerouslyAllowAll !== void 0) patch[AMP_DANGEROUSLY_ALLOW_ALL_KEY] = override.dangerouslyAllowAll;
|
|
17224
|
+
if (override?.mcpPermissions !== void 0) patch[AMP_MCP_PERMISSIONS_KEY] = override.mcpPermissions;
|
|
16845
17225
|
return new AmpPermissions({
|
|
16846
17226
|
outputRoot,
|
|
16847
17227
|
relativeDirPath: basePaths.relativeDirPath,
|
|
16848
17228
|
relativeFilePath,
|
|
16849
|
-
fileContent:
|
|
17229
|
+
fileContent: applySharedConfigPatch({
|
|
17230
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
17231
|
+
feature: "permissions",
|
|
17232
|
+
existingContent: fileContent ?? "",
|
|
17233
|
+
patch,
|
|
17234
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
17235
|
+
}),
|
|
16850
17236
|
validate: true
|
|
16851
17237
|
});
|
|
16852
17238
|
}
|
|
@@ -17788,11 +18174,13 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
|
|
|
17788
18174
|
...preservedBasicEntries,
|
|
17789
18175
|
...authoredBasics
|
|
17790
18176
|
]);
|
|
17791
|
-
const
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
18177
|
+
const fileContent = applySharedConfigPatch({
|
|
18178
|
+
fileKey: sharedConfigFileKey(paths),
|
|
18179
|
+
feature: "permissions",
|
|
18180
|
+
existingContent,
|
|
18181
|
+
patch: { toolPermissions: [...specialEntries, ...sortedBasic] },
|
|
18182
|
+
filePath
|
|
18183
|
+
});
|
|
17796
18184
|
return new AugmentcodePermissions({
|
|
17797
18185
|
outputRoot,
|
|
17798
18186
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -18384,13 +18772,6 @@ const WORKSPACE_WIDE_WRITE_PATTERNS = /* @__PURE__ */ new Set([
|
|
|
18384
18772
|
]);
|
|
18385
18773
|
const CODEX_MINIMAL_KEY = ":minimal";
|
|
18386
18774
|
const GLOBAL_WILDCARD_DOMAIN = "*";
|
|
18387
|
-
const CODEXCLI_OVERRIDE_KEYS = [
|
|
18388
|
-
"approval_policy",
|
|
18389
|
-
"sandbox_mode",
|
|
18390
|
-
"sandbox_workspace_write",
|
|
18391
|
-
"apps",
|
|
18392
|
-
"approvals_reviewer"
|
|
18393
|
-
];
|
|
18394
18775
|
var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
18395
18776
|
static getSettablePaths(_options = {}) {
|
|
18396
18777
|
return {
|
|
@@ -18414,26 +18795,27 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18414
18795
|
}
|
|
18415
18796
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
18416
18797
|
const paths = this.getSettablePaths({ global });
|
|
18417
|
-
const
|
|
18418
|
-
const
|
|
18798
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
18799
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
18800
|
+
const existing = toMutableTable(smolToml.parse(existingContent || smolToml.stringify({})));
|
|
18419
18801
|
const newProfile = convertRulesyncToCodexProfile({
|
|
18420
18802
|
config: rulesyncPermissions.getJson(),
|
|
18421
18803
|
logger
|
|
18422
18804
|
});
|
|
18423
|
-
const permissionsTable = toMutableTable(
|
|
18805
|
+
const permissionsTable = toMutableTable(existing.permissions);
|
|
18424
18806
|
const { profile: existingProfile, domainsHadUnknown: existingDomainsHadUnknown } = toCodexProfile(permissionsTable[RULESYNC_PROFILE_NAME]);
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18807
|
+
warnAboutPreservedProfileState({
|
|
18808
|
+
existingProfile,
|
|
18809
|
+
newProfile,
|
|
18810
|
+
existingDomainsHadUnknown,
|
|
18811
|
+
logger
|
|
18812
|
+
});
|
|
18429
18813
|
permissionsTable[RULESYNC_PROFILE_NAME] = mergeWithExistingProfile({
|
|
18430
18814
|
newProfile,
|
|
18431
18815
|
existingProfile
|
|
18432
18816
|
});
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
applyCodexcliOverride({
|
|
18436
|
-
parsed,
|
|
18817
|
+
const overridePatch = computeCodexcliOverridePatch({
|
|
18818
|
+
existing,
|
|
18437
18819
|
override: rulesyncPermissions.getJson().codexcli,
|
|
18438
18820
|
logger
|
|
18439
18821
|
});
|
|
@@ -18441,7 +18823,17 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18441
18823
|
outputRoot,
|
|
18442
18824
|
relativeDirPath: paths.relativeDirPath,
|
|
18443
18825
|
relativeFilePath: paths.relativeFilePath,
|
|
18444
|
-
fileContent:
|
|
18826
|
+
fileContent: applySharedConfigPatch({
|
|
18827
|
+
fileKey: sharedConfigFileKey(paths),
|
|
18828
|
+
feature: "permissions",
|
|
18829
|
+
existingContent,
|
|
18830
|
+
patch: {
|
|
18831
|
+
permissions: permissionsTable,
|
|
18832
|
+
default_permissions: RULESYNC_PROFILE_NAME,
|
|
18833
|
+
...overridePatch
|
|
18834
|
+
},
|
|
18835
|
+
filePath
|
|
18836
|
+
}),
|
|
18445
18837
|
validate
|
|
18446
18838
|
});
|
|
18447
18839
|
}
|
|
@@ -18611,6 +19003,12 @@ function toCodexProfile(value) {
|
|
|
18611
19003
|
domainsHadUnknown
|
|
18612
19004
|
};
|
|
18613
19005
|
}
|
|
19006
|
+
function warnAboutPreservedProfileState({ existingProfile, newProfile, existingDomainsHadUnknown, logger }) {
|
|
19007
|
+
if (existingProfile?.extends !== void 0 && existingProfile.extends !== newProfile.extends) logger?.warn(`Existing "extends" value "${existingProfile.extends}" will be replaced by Rulesync-managed "${newProfile.extends ?? "(none)"}".`);
|
|
19008
|
+
if (existingProfile?.network?.unix_sockets !== void 0) logger?.warn(`Preserving existing "network.unix_sockets" from config. Review these entries manually as they may grant broad system access.`);
|
|
19009
|
+
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.`);
|
|
19010
|
+
if (existingDomainsHadUnknown) logger?.warn(`Existing "network.domains" contained unrecognized values. These entries were skipped and will not be imported.`);
|
|
19011
|
+
}
|
|
18614
19012
|
function mergeWithExistingProfile({ newProfile, existingProfile }) {
|
|
18615
19013
|
if (!existingProfile) return newProfile;
|
|
18616
19014
|
const mergedNetwork = { ...newProfile.network };
|
|
@@ -18661,8 +19059,9 @@ function toMutableTable(value) {
|
|
|
18661
19059
|
function isPlainObject(value) {
|
|
18662
19060
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18663
19061
|
}
|
|
18664
|
-
function
|
|
18665
|
-
|
|
19062
|
+
function computeCodexcliOverridePatch({ existing, override, logger }) {
|
|
19063
|
+
const patch = {};
|
|
19064
|
+
if (!override) return patch;
|
|
18666
19065
|
const allowed = new Set(CODEXCLI_OVERRIDE_KEYS);
|
|
18667
19066
|
for (const [key, value] of Object.entries(override)) {
|
|
18668
19067
|
if (!allowed.has(key)) {
|
|
@@ -18670,12 +19069,13 @@ function applyCodexcliOverride({ parsed, override, logger }) {
|
|
|
18670
19069
|
continue;
|
|
18671
19070
|
}
|
|
18672
19071
|
if (value === void 0) continue;
|
|
18673
|
-
const
|
|
18674
|
-
|
|
18675
|
-
...
|
|
19072
|
+
const existingValue = existing[key];
|
|
19073
|
+
patch[key] = isPlainObject(existingValue) && isPlainObject(value) ? {
|
|
19074
|
+
...existingValue,
|
|
18676
19075
|
...value
|
|
18677
19076
|
} : value;
|
|
18678
19077
|
}
|
|
19078
|
+
return patch;
|
|
18679
19079
|
}
|
|
18680
19080
|
function extractCodexcliOverride(table) {
|
|
18681
19081
|
const override = {};
|
|
@@ -19236,15 +19636,17 @@ var DevinPermissions = class DevinPermissions extends ToolPermissions {
|
|
|
19236
19636
|
else delete mergedPermissions.ask;
|
|
19237
19637
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
19238
19638
|
else delete mergedPermissions.deny;
|
|
19239
|
-
const merged = {
|
|
19240
|
-
...settings,
|
|
19241
|
-
permissions: mergedPermissions
|
|
19242
|
-
};
|
|
19243
19639
|
return new DevinPermissions({
|
|
19244
19640
|
outputRoot,
|
|
19245
19641
|
relativeDirPath: paths.relativeDirPath,
|
|
19246
19642
|
relativeFilePath: paths.relativeFilePath,
|
|
19247
|
-
fileContent:
|
|
19643
|
+
fileContent: applySharedConfigPatch({
|
|
19644
|
+
fileKey: sharedConfigFileKey(paths),
|
|
19645
|
+
feature: "permissions",
|
|
19646
|
+
existingContent,
|
|
19647
|
+
patch: { permissions: mergedPermissions },
|
|
19648
|
+
filePath
|
|
19649
|
+
}),
|
|
19248
19650
|
validate
|
|
19249
19651
|
});
|
|
19250
19652
|
}
|
|
@@ -19853,23 +20255,31 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
19853
20255
|
const config = rulesyncPermissions.getJson();
|
|
19854
20256
|
const existingPermission = isRecord(parsed[GROKCLI_PERMISSION_KEY]) ? parsed[GROKCLI_PERMISSION_KEY] : {};
|
|
19855
20257
|
const buckets = buildGrokPermissionArrays(config, existingPermission, logger);
|
|
19856
|
-
|
|
20258
|
+
const permission = {
|
|
19857
20259
|
...existingPermission,
|
|
19858
20260
|
allow: buckets.allow,
|
|
19859
20261
|
deny: buckets.deny,
|
|
19860
20262
|
ask: buckets.ask
|
|
19861
20263
|
};
|
|
19862
20264
|
const mode = deriveGrokPermissionMode(config);
|
|
19863
|
-
const
|
|
19864
|
-
|
|
19865
|
-
...existingUi,
|
|
20265
|
+
const ui = {
|
|
20266
|
+
...isRecord(parsed[GROKCLI_UI_KEY]) ? parsed[GROKCLI_UI_KEY] : {},
|
|
19866
20267
|
[GROKCLI_PERMISSION_MODE_KEY]: mode
|
|
19867
20268
|
};
|
|
19868
20269
|
return new GrokcliPermissions({
|
|
19869
20270
|
outputRoot,
|
|
19870
20271
|
relativeDirPath: paths.relativeDirPath,
|
|
19871
20272
|
relativeFilePath: paths.relativeFilePath,
|
|
19872
|
-
fileContent:
|
|
20273
|
+
fileContent: applySharedConfigPatch({
|
|
20274
|
+
fileKey: sharedConfigFileKey(paths),
|
|
20275
|
+
feature: "permissions",
|
|
20276
|
+
existingContent,
|
|
20277
|
+
patch: {
|
|
20278
|
+
[GROKCLI_PERMISSION_KEY]: permission,
|
|
20279
|
+
[GROKCLI_UI_KEY]: ui
|
|
20280
|
+
},
|
|
20281
|
+
filePath
|
|
20282
|
+
}),
|
|
19873
20283
|
validate: true,
|
|
19874
20284
|
global: true
|
|
19875
20285
|
});
|
|
@@ -20572,7 +20982,16 @@ var KiroPermissions = class KiroPermissions extends ToolPermissions {
|
|
|
20572
20982
|
outputRoot,
|
|
20573
20983
|
relativeDirPath: paths.relativeDirPath,
|
|
20574
20984
|
relativeFilePath: paths.relativeFilePath,
|
|
20575
|
-
fileContent:
|
|
20985
|
+
fileContent: applySharedConfigPatch({
|
|
20986
|
+
fileKey: sharedConfigFileKey(paths),
|
|
20987
|
+
feature: "permissions",
|
|
20988
|
+
existingContent,
|
|
20989
|
+
patch: {
|
|
20990
|
+
allowedTools: next.allowedTools,
|
|
20991
|
+
toolsSettings: next.toolsSettings
|
|
20992
|
+
},
|
|
20993
|
+
filePath
|
|
20994
|
+
}),
|
|
20576
20995
|
validate
|
|
20577
20996
|
});
|
|
20578
20997
|
}
|
|
@@ -20869,21 +21288,22 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
20869
21288
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
20870
21289
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
20871
21290
|
}
|
|
20872
|
-
const parsed = parse(fileContent ?? "{}");
|
|
20873
21291
|
const rulesyncJson = rulesyncPermissions.getJson();
|
|
20874
21292
|
const overridePermission = rulesyncJson.opencode?.permission ?? {};
|
|
20875
|
-
const nextJson = {
|
|
20876
|
-
...parsed,
|
|
20877
|
-
permission: {
|
|
20878
|
-
...rulesyncJson.permission,
|
|
20879
|
-
...overridePermission
|
|
20880
|
-
}
|
|
20881
|
-
};
|
|
20882
21293
|
return new OpencodePermissions({
|
|
20883
21294
|
outputRoot,
|
|
20884
21295
|
relativeDirPath: basePaths.relativeDirPath,
|
|
20885
21296
|
relativeFilePath,
|
|
20886
|
-
fileContent:
|
|
21297
|
+
fileContent: applySharedConfigPatch({
|
|
21298
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
21299
|
+
feature: "permissions",
|
|
21300
|
+
existingContent: fileContent ?? "",
|
|
21301
|
+
patch: { permission: {
|
|
21302
|
+
...rulesyncJson.permission,
|
|
21303
|
+
...overridePermission
|
|
21304
|
+
} },
|
|
21305
|
+
filePath: join(jsonDir, relativeFilePath)
|
|
21306
|
+
}),
|
|
20887
21307
|
validate: true
|
|
20888
21308
|
});
|
|
20889
21309
|
}
|
|
@@ -21092,20 +21512,23 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
21092
21512
|
else delete mergedPermissions.ask;
|
|
21093
21513
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21094
21514
|
else delete mergedPermissions.deny;
|
|
21095
|
-
const
|
|
21096
|
-
...settings,
|
|
21097
|
-
permissions: mergedPermissions
|
|
21098
|
-
};
|
|
21515
|
+
const patch = { permissions: mergedPermissions };
|
|
21099
21516
|
const override = config.qwencode;
|
|
21100
|
-
if (override?.tools !== void 0)
|
|
21517
|
+
if (override?.tools !== void 0) patch.tools = {
|
|
21101
21518
|
...asPlainRecord(settings.tools),
|
|
21102
21519
|
...asPlainRecord(override.tools)
|
|
21103
21520
|
};
|
|
21104
|
-
if (override?.security !== void 0)
|
|
21521
|
+
if (override?.security !== void 0) patch.security = {
|
|
21105
21522
|
...asPlainRecord(settings.security),
|
|
21106
21523
|
...asPlainRecord(override.security)
|
|
21107
21524
|
};
|
|
21108
|
-
const fileContent =
|
|
21525
|
+
const fileContent = applySharedConfigPatch({
|
|
21526
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21527
|
+
feature: "permissions",
|
|
21528
|
+
existingContent,
|
|
21529
|
+
patch,
|
|
21530
|
+
filePath
|
|
21531
|
+
});
|
|
21109
21532
|
return new QwencodePermissions({
|
|
21110
21533
|
outputRoot,
|
|
21111
21534
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -21340,7 +21763,9 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21340
21763
|
}
|
|
21341
21764
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21342
21765
|
const paths = this.getSettablePaths({ global });
|
|
21343
|
-
const
|
|
21766
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
21767
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
21768
|
+
const parsed = parseReasonixConfig(existingContent);
|
|
21344
21769
|
const config = rulesyncPermissions.getJson();
|
|
21345
21770
|
const { allow, ask, deny } = convertRulesyncToReasonixPermissions(config);
|
|
21346
21771
|
const managedToolNames = new Set(Object.keys(config.permission).map((category) => toReasonixToolName(category)));
|
|
@@ -21365,25 +21790,27 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21365
21790
|
else delete mergedPermissions.ask;
|
|
21366
21791
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21367
21792
|
else delete mergedPermissions.deny;
|
|
21368
|
-
const
|
|
21369
|
-
...parsed,
|
|
21370
|
-
permissions: mergedPermissions
|
|
21371
|
-
};
|
|
21793
|
+
const patch = { permissions: mergedPermissions };
|
|
21372
21794
|
const override = config.reasonix;
|
|
21373
|
-
if (override?.sandbox !== void 0)
|
|
21795
|
+
if (override?.sandbox !== void 0) patch.sandbox = {
|
|
21374
21796
|
...asReasonixRecord(parsed.sandbox),
|
|
21375
21797
|
...asReasonixRecord(override.sandbox)
|
|
21376
21798
|
};
|
|
21377
|
-
if (override?.agent !== void 0)
|
|
21799
|
+
if (override?.agent !== void 0) patch.agent = {
|
|
21378
21800
|
...asReasonixRecord(parsed.agent),
|
|
21379
21801
|
...asReasonixRecord(override.agent)
|
|
21380
21802
|
};
|
|
21381
|
-
const fileContent = smolToml.stringify(merged);
|
|
21382
21803
|
return new ReasonixPermissions({
|
|
21383
21804
|
outputRoot,
|
|
21384
21805
|
relativeDirPath: paths.relativeDirPath,
|
|
21385
21806
|
relativeFilePath: paths.relativeFilePath,
|
|
21386
|
-
fileContent
|
|
21807
|
+
fileContent: applySharedConfigPatch({
|
|
21808
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21809
|
+
feature: "permissions",
|
|
21810
|
+
existingContent,
|
|
21811
|
+
patch,
|
|
21812
|
+
filePath
|
|
21813
|
+
}),
|
|
21387
21814
|
validate
|
|
21388
21815
|
});
|
|
21389
21816
|
}
|
|
@@ -21954,7 +22381,9 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
21954
22381
|
}
|
|
21955
22382
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21956
22383
|
const paths = this.getSettablePaths({ global });
|
|
21957
|
-
const
|
|
22384
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
22385
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
22386
|
+
const config = parseVibeConfig(existingContent);
|
|
21958
22387
|
const permission = rulesyncPermissions.getJson().permission;
|
|
21959
22388
|
const tools = toVibeToolsRecord(config.tools);
|
|
21960
22389
|
const enabledTools = new Set(toStringArray(config.enabled_tools));
|
|
@@ -21999,16 +22428,21 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
21999
22428
|
tools[vibeToolName] = nextTool;
|
|
22000
22429
|
}
|
|
22001
22430
|
applyVibeSensitivePatterns(tools, rulesyncPermissions.getJson().vibe);
|
|
22002
|
-
config.tools = tools;
|
|
22003
|
-
if (enabledTools.size > 0) config.enabled_tools = [...enabledTools].toSorted();
|
|
22004
|
-
else delete config.enabled_tools;
|
|
22005
|
-
if (disabledTools.size > 0) config.disabled_tools = [...disabledTools].toSorted();
|
|
22006
|
-
else delete config.disabled_tools;
|
|
22007
22431
|
return new VibePermissions({
|
|
22008
22432
|
outputRoot,
|
|
22009
22433
|
relativeDirPath: paths.relativeDirPath,
|
|
22010
22434
|
relativeFilePath: paths.relativeFilePath,
|
|
22011
|
-
fileContent:
|
|
22435
|
+
fileContent: applySharedConfigPatch({
|
|
22436
|
+
fileKey: sharedConfigFileKey(paths),
|
|
22437
|
+
feature: "permissions",
|
|
22438
|
+
existingContent,
|
|
22439
|
+
patch: {
|
|
22440
|
+
tools,
|
|
22441
|
+
enabled_tools: enabledTools.size > 0 ? [...enabledTools].toSorted() : void 0,
|
|
22442
|
+
disabled_tools: disabledTools.size > 0 ? [...disabledTools].toSorted() : void 0
|
|
22443
|
+
},
|
|
22444
|
+
filePath
|
|
22445
|
+
}),
|
|
22012
22446
|
validate,
|
|
22013
22447
|
global
|
|
22014
22448
|
});
|
|
@@ -22471,24 +22905,26 @@ var ZedPermissions = class ZedPermissions extends ToolPermissions {
|
|
|
22471
22905
|
}
|
|
22472
22906
|
const managedToolNames = new Set(Object.keys(managedTools));
|
|
22473
22907
|
const preservedTools = Object.fromEntries(Object.entries(existingTools).filter(([toolName]) => !managedToolNames.has(toolName)));
|
|
22474
|
-
const mergedSettings = {
|
|
22475
|
-
...settings,
|
|
22476
|
-
agent: {
|
|
22477
|
-
...agent,
|
|
22478
|
-
tool_permissions: {
|
|
22479
|
-
...toolPermissions,
|
|
22480
|
-
tools: {
|
|
22481
|
-
...preservedTools,
|
|
22482
|
-
...managedTools
|
|
22483
|
-
}
|
|
22484
|
-
}
|
|
22485
|
-
}
|
|
22486
|
-
};
|
|
22487
22908
|
return new ZedPermissions({
|
|
22488
22909
|
outputRoot,
|
|
22489
22910
|
relativeDirPath: paths.relativeDirPath,
|
|
22490
22911
|
relativeFilePath: paths.relativeFilePath,
|
|
22491
|
-
fileContent:
|
|
22912
|
+
fileContent: applySharedConfigPatch({
|
|
22913
|
+
fileKey: sharedConfigFileKey(paths),
|
|
22914
|
+
feature: "permissions",
|
|
22915
|
+
existingContent,
|
|
22916
|
+
patch: { agent: {
|
|
22917
|
+
...agent,
|
|
22918
|
+
tool_permissions: {
|
|
22919
|
+
...toolPermissions,
|
|
22920
|
+
tools: {
|
|
22921
|
+
...preservedTools,
|
|
22922
|
+
...managedTools
|
|
22923
|
+
}
|
|
22924
|
+
}
|
|
22925
|
+
} },
|
|
22926
|
+
filePath
|
|
22927
|
+
}),
|
|
22492
22928
|
validate: true
|
|
22493
22929
|
});
|
|
22494
22930
|
}
|
|
@@ -38178,8 +38614,13 @@ const collectFactoryPaths = (factory) => [...settablePathsForScope({
|
|
|
38178
38614
|
* Derive, from the processor registry, every on-disk file that two or more
|
|
38179
38615
|
* features read-modify-write. Source of truth the generation step graph's
|
|
38180
38616
|
* `writesSharedFile` declarations must match.
|
|
38617
|
+
*
|
|
38618
|
+
* `minWriters: 1` widens the result to single-feature files as well — used to
|
|
38619
|
+
* validate `SHARED_CONFIG_OWNERSHIP` declarations for files that route through
|
|
38620
|
+
* the gateway without being cross-feature shared (e.g. a global-scope twin
|
|
38621
|
+
* only one feature writes).
|
|
38181
38622
|
*/
|
|
38182
|
-
const deriveSharedFileWriters = () => {
|
|
38623
|
+
const deriveSharedFileWriters = ({ minWriters = 2 } = {}) => {
|
|
38183
38624
|
const byKey = /* @__PURE__ */ new Map();
|
|
38184
38625
|
const pathByKey = /* @__PURE__ */ new Map();
|
|
38185
38626
|
for (const entry of PROCESSOR_REGISTRY) {
|
|
@@ -38205,7 +38646,7 @@ const deriveSharedFileWriters = () => {
|
|
|
38205
38646
|
}
|
|
38206
38647
|
const writers = [];
|
|
38207
38648
|
for (const [key, features] of byKey) {
|
|
38208
|
-
if (features.size <
|
|
38649
|
+
if (features.size < minWriters) continue;
|
|
38209
38650
|
const path = pathByKey.get(key);
|
|
38210
38651
|
const toolsByFeature = /* @__PURE__ */ new Map();
|
|
38211
38652
|
for (const [feature, tools] of features) toolsByFeature.set(feature, [...tools].toSorted());
|
|
@@ -39150,4 +39591,4 @@ async function importPermissionsCore(params) {
|
|
|
39150
39591
|
//#endregion
|
|
39151
39592
|
export { removeTempDirectory as $, RulesyncCommand as A, checkPathTraversal as B, RulesyncHooks as C, RULESYNC_RULES_RELATIVE_DIR_PATH as Ct, CLAUDECODE_MEMORIES_DIR_NAME as D, formatError as Dt, CLAUDECODE_LOCAL_RULE_FILE_NAME as E, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Et, findControlCharacter as F, findFilesByGlobs as G, directoryExists as H, ConsoleLogger as I, isSymlink as J, getFileSize as K, JsonLogger as L, stringifyFrontmatter as M, loadYaml as N, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as O, ALL_FEATURES as Ot, ConfigResolver as P, removeFile as Q, CLIError as R, HooksProcessor as S, RULESYNC_RELATIVE_DIR_PATH as St, CLAUDECODE_DIR as T, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Tt, ensureDir as U, createTempDirectory as V, fileExists as W, readFileContent as X, listDirectoryFiles as Y, removeDirectory as Z, RulesyncPermissions as _, RULESYNC_MCP_RELATIVE_FILE_PATH as _t, convertFromTool as a, MAX_FILE_SIZE as at, IgnoreProcessor as b, RULESYNC_PERMISSIONS_FILE_NAME as bt, RulesyncRuleFrontmatterSchema as c, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as ct, RulesyncSubagentFrontmatterSchema as d, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as dt, toPosixPath as et, SkillsProcessor as f, RULESYNC_HOOKS_FILE_NAME as ft, SKILL_FILE_NAME as g, RULESYNC_MCP_FILE_NAME as gt, RulesyncSkillFrontmatterSchema as h, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as ht, getProcessorRegistryEntry as i, ToolTargetSchema as it, RulesyncCommandFrontmatterSchema as j, CLAUDECODE_SKILLS_DIR_PATH as k, ALL_FEATURES_WITH_WILDCARD as kt, SubagentsProcessor as l, RULESYNC_CONFIG_RELATIVE_FILE_PATH as lt, RulesyncSkill as m, RULESYNC_IGNORE_RELATIVE_FILE_PATH as mt, checkRulesyncDirExists as n, ALL_TOOL_TARGETS as nt, RulesProcessor as o, RULESYNC_AIIGNORE_FILE_NAME as ot, getLocalSkillDirNames as p, RULESYNC_HOOKS_RELATIVE_FILE_PATH as pt, getHomeDirectory as q, generate as r, ALL_TOOL_TARGETS_WITH_WILDCARD as rt, RulesyncRule as s, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as st, importFromTool as t, writeFileContent as tt, RulesyncSubagent as u, RULESYNC_CONFIG_SCHEMA_URL as ut, McpProcessor as v, RULESYNC_MCP_SCHEMA_URL as vt, CommandsProcessor as w, RULESYNC_SKILLS_RELATIVE_DIR_PATH as wt, RulesyncIgnore as x, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as xt, RulesyncMcp as y, RULESYNC_OVERVIEW_FILE_NAME as yt, ErrorCodes as z };
|
|
39152
39593
|
|
|
39153
|
-
//# sourceMappingURL=import-
|
|
39594
|
+
//# sourceMappingURL=import-DC9T1JlQ.js.map
|