rulesync 9.6.2 → 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-rMBf0tf2.cjs → import-D5f_X4-A.cjs} +701 -246
- package/dist/{import-CUHHL2_P.js → import-DC9T1JlQ.js} +703 -247
- 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-CUHHL2_P.js.map +0 -1
|
@@ -2703,6 +2703,13 @@ const CODEXCLI_MCP_FILE_NAME = "config.toml";
|
|
|
2703
2703
|
const CODEXCLI_RULE_FILE_NAME = "AGENTS.md";
|
|
2704
2704
|
const CODEXCLI_BASH_RULES_FILE_NAME = "rulesync.rules";
|
|
2705
2705
|
const CODEXCLI_OPENAI_YAML_RELATIVE_PATH = (0, node_path.join)("agents", "openai.yaml");
|
|
2706
|
+
const CODEXCLI_OVERRIDE_KEYS = [
|
|
2707
|
+
"approval_policy",
|
|
2708
|
+
"sandbox_mode",
|
|
2709
|
+
"sandbox_workspace_write",
|
|
2710
|
+
"apps",
|
|
2711
|
+
"approvals_reviewer"
|
|
2712
|
+
];
|
|
2706
2713
|
//#endregion
|
|
2707
2714
|
//#region src/features/commands/codexcli-command.ts
|
|
2708
2715
|
const CodexcliCommandFrontmatterSchema = zod_mini.z.looseObject({
|
|
@@ -4082,14 +4089,22 @@ function sanitizeSharedConfigValue(value) {
|
|
|
4082
4089
|
* root follows `invalidRootPolicy`. Syntax errors are wrapped with the file
|
|
4083
4090
|
* path when one is given.
|
|
4084
4091
|
*/
|
|
4085
|
-
function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy = "coerce-empty" }) {
|
|
4092
|
+
function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy = "coerce-empty", jsoncParseErrors = "tolerate" }) {
|
|
4086
4093
|
if (fileContent.trim() === "") return {};
|
|
4087
4094
|
const at = filePath === void 0 ? "" : ` at ${filePath}`;
|
|
4088
4095
|
let parsed;
|
|
4089
4096
|
try {
|
|
4090
4097
|
if (format === "yaml") parsed = loadYaml(fileContent);
|
|
4098
|
+
else if (format === "toml") parsed = (0, smol_toml.parse)(fileContent);
|
|
4091
4099
|
else if (format === "json") parsed = JSON.parse(fileContent);
|
|
4092
|
-
else
|
|
4100
|
+
else if (jsoncParseErrors === "error") {
|
|
4101
|
+
const errors = [];
|
|
4102
|
+
parsed = (0, jsonc_parser.parse)(fileContent, errors, { allowTrailingComma: true });
|
|
4103
|
+
if (errors.length > 0) {
|
|
4104
|
+
const details = errors.map((error) => `${(0, jsonc_parser.printParseErrorCode)(error.error)} at offset ${error.offset}`).join(", ");
|
|
4105
|
+
throw new Error(details);
|
|
4106
|
+
}
|
|
4107
|
+
} else parsed = (0, jsonc_parser.parse)(fileContent);
|
|
4093
4108
|
} catch (error) {
|
|
4094
4109
|
throw new Error(`Failed to parse shared config${at}: ${formatError(error)}`, { cause: error });
|
|
4095
4110
|
}
|
|
@@ -4103,13 +4118,15 @@ function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy =
|
|
|
4103
4118
|
/**
|
|
4104
4119
|
* Serialize a shared config document. YAML output always ends with exactly one
|
|
4105
4120
|
* newline; JSON output matches the 2-space `JSON.stringify` shape the JSON
|
|
4106
|
-
* writers have always emitted (no trailing newline)
|
|
4121
|
+
* writers have always emitted (no trailing newline); TOML output matches the
|
|
4122
|
+
* `smol-toml` `stringify` shape the TOML writers have always emitted.
|
|
4107
4123
|
*/
|
|
4108
4124
|
function stringifySharedConfig({ format, document }) {
|
|
4109
4125
|
if (format === "yaml") return (0, js_yaml.dump)(document, {
|
|
4110
4126
|
noRefs: true,
|
|
4111
4127
|
sortKeys: false
|
|
4112
4128
|
}).trimEnd() + "\n";
|
|
4129
|
+
if (format === "toml") return (0, smol_toml.stringify)(document);
|
|
4113
4130
|
return JSON.stringify(document, null, 2);
|
|
4114
4131
|
}
|
|
4115
4132
|
/**
|
|
@@ -4148,6 +4165,25 @@ function mergeSharedConfigDeep({ base, patch }) {
|
|
|
4148
4165
|
const CLAUDE_SETTINGS_SHARED_FILE_KEY = ".claude/settings.json";
|
|
4149
4166
|
const HERMES_CONFIG_SHARED_FILE_KEY = ".hermes/config.yaml";
|
|
4150
4167
|
const TAKT_CONFIG_SHARED_FILE_KEY = ".takt/config.yaml";
|
|
4168
|
+
const CODEXCLI_CONFIG_SHARED_FILE_KEY = ".codex/config.toml";
|
|
4169
|
+
const GROKCLI_CONFIG_SHARED_FILE_KEY = ".grok/config.toml";
|
|
4170
|
+
const VIBE_CONFIG_SHARED_FILE_KEY = ".vibe/config.toml";
|
|
4171
|
+
const REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY = "reasonix.toml";
|
|
4172
|
+
const REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY = ".reasonix/config.toml";
|
|
4173
|
+
/**
|
|
4174
|
+
* Build the `SHARED_CONFIG_OWNERSHIP` lookup key from a tool's settable paths.
|
|
4175
|
+
* Mirrors `sharedFileKey` in `src/lib/shared-file-derive.ts` (kept separate so
|
|
4176
|
+
* feature classes don't pull the processor registry through this module and
|
|
4177
|
+
* create an import cycle); the ownership lock-step test keeps the two aligned.
|
|
4178
|
+
* Lets a tool whose file lives at a scope-dependent path (`.zed/settings.json`
|
|
4179
|
+
* vs `.config/zed/settings.json`) resolve its declaration from the settable
|
|
4180
|
+
* paths it already holds.
|
|
4181
|
+
*/
|
|
4182
|
+
const sharedConfigFileKey = ({ relativeDirPath, relativeFilePath }) => {
|
|
4183
|
+
const dir = relativeDirPath.replace(/\\/g, "/").replace(/\/$/, "");
|
|
4184
|
+
const file = relativeFilePath.replace(/\\/g, "/");
|
|
4185
|
+
return dir === "" || dir === "." ? file : `${dir}/${file}`;
|
|
4186
|
+
};
|
|
4151
4187
|
/**
|
|
4152
4188
|
* Who owns what in each gateway-managed shared config file, and which policy
|
|
4153
4189
|
* resolves conflicts. Keys are `dir/file` tokens matching
|
|
@@ -4204,6 +4240,298 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
4204
4240
|
},
|
|
4205
4241
|
permissions: { kind: "deep-merge" }
|
|
4206
4242
|
}
|
|
4243
|
+
},
|
|
4244
|
+
".zed/settings.json": {
|
|
4245
|
+
format: "json",
|
|
4246
|
+
features: {
|
|
4247
|
+
ignore: {
|
|
4248
|
+
kind: "replace-owned-keys",
|
|
4249
|
+
ownedKeys: ["private_files"]
|
|
4250
|
+
},
|
|
4251
|
+
mcp: {
|
|
4252
|
+
kind: "replace-owned-keys",
|
|
4253
|
+
ownedKeys: ["context_servers"]
|
|
4254
|
+
},
|
|
4255
|
+
permissions: {
|
|
4256
|
+
kind: "replace-owned-keys",
|
|
4257
|
+
ownedKeys: ["agent"]
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
},
|
|
4261
|
+
".config/zed/settings.json": {
|
|
4262
|
+
format: "json",
|
|
4263
|
+
features: {
|
|
4264
|
+
mcp: {
|
|
4265
|
+
kind: "replace-owned-keys",
|
|
4266
|
+
ownedKeys: ["context_servers"]
|
|
4267
|
+
},
|
|
4268
|
+
permissions: {
|
|
4269
|
+
kind: "replace-owned-keys",
|
|
4270
|
+
ownedKeys: ["agent"]
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
},
|
|
4274
|
+
".qwen/settings.json": {
|
|
4275
|
+
format: "json",
|
|
4276
|
+
features: {
|
|
4277
|
+
mcp: {
|
|
4278
|
+
kind: "replace-owned-keys",
|
|
4279
|
+
ownedKeys: ["mcpServers"]
|
|
4280
|
+
},
|
|
4281
|
+
hooks: {
|
|
4282
|
+
kind: "replace-owned-keys",
|
|
4283
|
+
ownedKeys: ["hooks", "disableAllHooks"]
|
|
4284
|
+
},
|
|
4285
|
+
permissions: {
|
|
4286
|
+
kind: "replace-owned-keys",
|
|
4287
|
+
ownedKeys: [
|
|
4288
|
+
"permissions",
|
|
4289
|
+
"tools",
|
|
4290
|
+
"security"
|
|
4291
|
+
]
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
},
|
|
4295
|
+
".augment/settings.json": {
|
|
4296
|
+
format: "json",
|
|
4297
|
+
features: {
|
|
4298
|
+
mcp: {
|
|
4299
|
+
kind: "replace-owned-keys",
|
|
4300
|
+
ownedKeys: ["mcpServers"]
|
|
4301
|
+
},
|
|
4302
|
+
hooks: {
|
|
4303
|
+
kind: "replace-owned-keys",
|
|
4304
|
+
ownedKeys: ["hooks"]
|
|
4305
|
+
},
|
|
4306
|
+
permissions: {
|
|
4307
|
+
kind: "replace-owned-keys",
|
|
4308
|
+
ownedKeys: ["toolPermissions"]
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
},
|
|
4312
|
+
".devin/config.json": {
|
|
4313
|
+
format: "json",
|
|
4314
|
+
features: {
|
|
4315
|
+
mcp: {
|
|
4316
|
+
kind: "replace-owned-keys",
|
|
4317
|
+
ownedKeys: ["mcpServers"]
|
|
4318
|
+
},
|
|
4319
|
+
permissions: {
|
|
4320
|
+
kind: "replace-owned-keys",
|
|
4321
|
+
ownedKeys: ["permissions"]
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
},
|
|
4325
|
+
".config/devin/config.json": {
|
|
4326
|
+
format: "json",
|
|
4327
|
+
features: {
|
|
4328
|
+
mcp: {
|
|
4329
|
+
kind: "replace-owned-keys",
|
|
4330
|
+
ownedKeys: ["mcpServers"]
|
|
4331
|
+
},
|
|
4332
|
+
hooks: {
|
|
4333
|
+
kind: "replace-owned-keys",
|
|
4334
|
+
ownedKeys: ["hooks"]
|
|
4335
|
+
},
|
|
4336
|
+
permissions: {
|
|
4337
|
+
kind: "replace-owned-keys",
|
|
4338
|
+
ownedKeys: ["permissions"]
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
},
|
|
4342
|
+
".kiro/agents/default.json": {
|
|
4343
|
+
format: "json",
|
|
4344
|
+
features: {
|
|
4345
|
+
hooks: {
|
|
4346
|
+
kind: "replace-owned-keys",
|
|
4347
|
+
ownedKeys: ["hooks"]
|
|
4348
|
+
},
|
|
4349
|
+
permissions: {
|
|
4350
|
+
kind: "replace-owned-keys",
|
|
4351
|
+
ownedKeys: ["allowedTools", "toolsSettings"]
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
},
|
|
4355
|
+
".amp/settings.json": {
|
|
4356
|
+
format: "jsonc",
|
|
4357
|
+
invalidRootPolicy: "error",
|
|
4358
|
+
jsoncParseErrors: "error",
|
|
4359
|
+
features: {
|
|
4360
|
+
mcp: {
|
|
4361
|
+
kind: "replace-owned-keys",
|
|
4362
|
+
ownedKeys: ["amp.mcpServers"]
|
|
4363
|
+
},
|
|
4364
|
+
permissions: {
|
|
4365
|
+
kind: "replace-owned-keys",
|
|
4366
|
+
ownedKeys: [
|
|
4367
|
+
"amp.tools.disable",
|
|
4368
|
+
"amp.permissions",
|
|
4369
|
+
"amp.guardedFiles.allowlist",
|
|
4370
|
+
"amp.dangerouslyAllowAll",
|
|
4371
|
+
"amp.mcpPermissions"
|
|
4372
|
+
]
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
},
|
|
4376
|
+
".config/amp/settings.json": {
|
|
4377
|
+
format: "jsonc",
|
|
4378
|
+
invalidRootPolicy: "error",
|
|
4379
|
+
jsoncParseErrors: "error",
|
|
4380
|
+
features: {
|
|
4381
|
+
mcp: {
|
|
4382
|
+
kind: "replace-owned-keys",
|
|
4383
|
+
ownedKeys: ["amp.mcpServers"]
|
|
4384
|
+
},
|
|
4385
|
+
permissions: {
|
|
4386
|
+
kind: "replace-owned-keys",
|
|
4387
|
+
ownedKeys: [
|
|
4388
|
+
"amp.tools.disable",
|
|
4389
|
+
"amp.permissions",
|
|
4390
|
+
"amp.guardedFiles.allowlist",
|
|
4391
|
+
"amp.dangerouslyAllowAll",
|
|
4392
|
+
"amp.mcpPermissions"
|
|
4393
|
+
]
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
},
|
|
4397
|
+
"opencode.json": {
|
|
4398
|
+
format: "jsonc",
|
|
4399
|
+
features: {
|
|
4400
|
+
mcp: {
|
|
4401
|
+
kind: "replace-owned-keys",
|
|
4402
|
+
ownedKeys: ["mcp", "tools"]
|
|
4403
|
+
},
|
|
4404
|
+
permissions: {
|
|
4405
|
+
kind: "replace-owned-keys",
|
|
4406
|
+
ownedKeys: ["permission"]
|
|
4407
|
+
},
|
|
4408
|
+
rules: {
|
|
4409
|
+
kind: "replace-owned-keys",
|
|
4410
|
+
ownedKeys: ["instructions"]
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
},
|
|
4414
|
+
".config/opencode/opencode.json": {
|
|
4415
|
+
format: "jsonc",
|
|
4416
|
+
features: {
|
|
4417
|
+
mcp: {
|
|
4418
|
+
kind: "replace-owned-keys",
|
|
4419
|
+
ownedKeys: ["mcp", "tools"]
|
|
4420
|
+
},
|
|
4421
|
+
permissions: {
|
|
4422
|
+
kind: "replace-owned-keys",
|
|
4423
|
+
ownedKeys: ["permission"]
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
},
|
|
4427
|
+
"kilo.json": {
|
|
4428
|
+
format: "jsonc",
|
|
4429
|
+
features: {
|
|
4430
|
+
mcp: {
|
|
4431
|
+
kind: "replace-owned-keys",
|
|
4432
|
+
ownedKeys: ["mcp", "tools"]
|
|
4433
|
+
},
|
|
4434
|
+
rules: {
|
|
4435
|
+
kind: "replace-owned-keys",
|
|
4436
|
+
ownedKeys: ["instructions"]
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
},
|
|
4440
|
+
".config/kilo/kilo.json": {
|
|
4441
|
+
format: "jsonc",
|
|
4442
|
+
features: { mcp: {
|
|
4443
|
+
kind: "replace-owned-keys",
|
|
4444
|
+
ownedKeys: ["mcp", "tools"]
|
|
4445
|
+
} }
|
|
4446
|
+
},
|
|
4447
|
+
[CODEXCLI_CONFIG_SHARED_FILE_KEY]: {
|
|
4448
|
+
format: "toml",
|
|
4449
|
+
features: {
|
|
4450
|
+
hooks: {
|
|
4451
|
+
kind: "replace-owned-keys",
|
|
4452
|
+
ownedKeys: ["features"]
|
|
4453
|
+
},
|
|
4454
|
+
mcp: {
|
|
4455
|
+
kind: "replace-owned-keys",
|
|
4456
|
+
ownedKeys: ["mcp_servers"]
|
|
4457
|
+
},
|
|
4458
|
+
permissions: {
|
|
4459
|
+
kind: "replace-owned-keys",
|
|
4460
|
+
ownedKeys: [
|
|
4461
|
+
"permissions",
|
|
4462
|
+
"default_permissions",
|
|
4463
|
+
...CODEXCLI_OVERRIDE_KEYS
|
|
4464
|
+
]
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
},
|
|
4468
|
+
[GROKCLI_CONFIG_SHARED_FILE_KEY]: {
|
|
4469
|
+
format: "toml",
|
|
4470
|
+
features: {
|
|
4471
|
+
mcp: {
|
|
4472
|
+
kind: "replace-owned-keys",
|
|
4473
|
+
ownedKeys: ["mcp_servers"]
|
|
4474
|
+
},
|
|
4475
|
+
permissions: {
|
|
4476
|
+
kind: "replace-owned-keys",
|
|
4477
|
+
ownedKeys: ["permission", "ui"]
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
},
|
|
4481
|
+
[VIBE_CONFIG_SHARED_FILE_KEY]: {
|
|
4482
|
+
format: "toml",
|
|
4483
|
+
features: {
|
|
4484
|
+
hooks: {
|
|
4485
|
+
kind: "replace-owned-keys",
|
|
4486
|
+
ownedKeys: ["enable_experimental_hooks"]
|
|
4487
|
+
},
|
|
4488
|
+
mcp: {
|
|
4489
|
+
kind: "replace-owned-keys",
|
|
4490
|
+
ownedKeys: ["mcp_servers"]
|
|
4491
|
+
},
|
|
4492
|
+
permissions: {
|
|
4493
|
+
kind: "replace-owned-keys",
|
|
4494
|
+
ownedKeys: [
|
|
4495
|
+
"tools",
|
|
4496
|
+
"enabled_tools",
|
|
4497
|
+
"disabled_tools"
|
|
4498
|
+
]
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
},
|
|
4502
|
+
[REASONIX_PROJECT_CONFIG_SHARED_FILE_KEY]: {
|
|
4503
|
+
format: "toml",
|
|
4504
|
+
features: {
|
|
4505
|
+
mcp: {
|
|
4506
|
+
kind: "replace-owned-keys",
|
|
4507
|
+
ownedKeys: ["plugins"]
|
|
4508
|
+
},
|
|
4509
|
+
permissions: {
|
|
4510
|
+
kind: "replace-owned-keys",
|
|
4511
|
+
ownedKeys: [
|
|
4512
|
+
"permissions",
|
|
4513
|
+
"sandbox",
|
|
4514
|
+
"agent"
|
|
4515
|
+
]
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
},
|
|
4519
|
+
[REASONIX_GLOBAL_CONFIG_SHARED_FILE_KEY]: {
|
|
4520
|
+
format: "toml",
|
|
4521
|
+
features: {
|
|
4522
|
+
mcp: {
|
|
4523
|
+
kind: "replace-owned-keys",
|
|
4524
|
+
ownedKeys: ["plugins"]
|
|
4525
|
+
},
|
|
4526
|
+
permissions: {
|
|
4527
|
+
kind: "replace-owned-keys",
|
|
4528
|
+
ownedKeys: [
|
|
4529
|
+
"permissions",
|
|
4530
|
+
"sandbox",
|
|
4531
|
+
"agent"
|
|
4532
|
+
]
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4207
4535
|
}
|
|
4208
4536
|
};
|
|
4209
4537
|
/**
|
|
@@ -4224,17 +4552,20 @@ function applySharedConfigPatch({ fileKey, feature, existingContent, patch, file
|
|
|
4224
4552
|
format: declaration.format,
|
|
4225
4553
|
fileContent: existingContent,
|
|
4226
4554
|
filePath,
|
|
4227
|
-
...declaration.invalidRootPolicy !== void 0 && { invalidRootPolicy: declaration.invalidRootPolicy }
|
|
4555
|
+
...declaration.invalidRootPolicy !== void 0 && { invalidRootPolicy: declaration.invalidRootPolicy },
|
|
4556
|
+
...declaration.jsoncParseErrors !== void 0 && { jsoncParseErrors: declaration.jsoncParseErrors }
|
|
4228
4557
|
});
|
|
4229
4558
|
if (policy.kind === "replace-owned-keys") {
|
|
4230
4559
|
const unowned = Object.keys(patch).filter((key) => !policy.ownedKeys.includes(key));
|
|
4231
4560
|
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.`);
|
|
4561
|
+
const document = mergeSharedConfigShallow({
|
|
4562
|
+
base,
|
|
4563
|
+
patch
|
|
4564
|
+
});
|
|
4565
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0) delete document[key];
|
|
4232
4566
|
return stringifySharedConfig({
|
|
4233
4567
|
format: declaration.format,
|
|
4234
|
-
document
|
|
4235
|
-
base,
|
|
4236
|
-
patch
|
|
4237
|
-
})
|
|
4568
|
+
document
|
|
4238
4569
|
});
|
|
4239
4570
|
}
|
|
4240
4571
|
const merged = mergeSharedConfigDeep({
|
|
@@ -7307,12 +7638,6 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
7307
7638
|
const paths = AugmentcodeHooks.getSettablePaths({ global });
|
|
7308
7639
|
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
7309
7640
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
7310
|
-
let settings;
|
|
7311
|
-
try {
|
|
7312
|
-
settings = JSON.parse(existingContent);
|
|
7313
|
-
} catch (error) {
|
|
7314
|
-
throw new Error(`Failed to parse existing AugmentCode settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
7315
|
-
}
|
|
7316
7641
|
const config = rulesyncHooks.getJson();
|
|
7317
7642
|
const augmentHooks = canonicalToToolHooks({
|
|
7318
7643
|
config,
|
|
@@ -7320,11 +7645,13 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
7320
7645
|
converterConfig: AUGMENTCODE_CONVERTER_CONFIG,
|
|
7321
7646
|
logger
|
|
7322
7647
|
});
|
|
7323
|
-
const
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7648
|
+
const fileContent = applySharedConfigPatch({
|
|
7649
|
+
fileKey: sharedConfigFileKey(paths),
|
|
7650
|
+
feature: "hooks",
|
|
7651
|
+
existingContent,
|
|
7652
|
+
patch: { hooks: augmentHooks },
|
|
7653
|
+
filePath
|
|
7654
|
+
});
|
|
7328
7655
|
return new AugmentcodeHooks({
|
|
7329
7656
|
outputRoot,
|
|
7330
7657
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -7491,15 +7818,28 @@ const CODEXCLI_CONVERTER_CONFIG = {
|
|
|
7491
7818
|
*/
|
|
7492
7819
|
async function buildCodexConfigTomlContent({ outputRoot }) {
|
|
7493
7820
|
const configPath = (0, node_path.join)(outputRoot, CODEXCLI_DIR, CODEXCLI_MCP_FILE_NAME);
|
|
7494
|
-
const existingContent = await readFileContentOrNull(configPath) ??
|
|
7821
|
+
const existingContent = await readFileContentOrNull(configPath) ?? "";
|
|
7495
7822
|
let configToml;
|
|
7496
7823
|
try {
|
|
7497
|
-
configToml = smol_toml.parse(existingContent);
|
|
7824
|
+
configToml = smol_toml.parse(existingContent || smol_toml.stringify({}));
|
|
7498
7825
|
} catch (error) {
|
|
7499
7826
|
throw new Error(`Failed to parse existing Codex CLI config at ${configPath}: ${formatError(error)}`, { cause: error });
|
|
7500
7827
|
}
|
|
7501
|
-
|
|
7502
|
-
|
|
7828
|
+
let features;
|
|
7829
|
+
if (typeof configToml.features === "object" && configToml.features !== null) {
|
|
7830
|
+
features = { ...configToml.features };
|
|
7831
|
+
delete features.codex_hooks;
|
|
7832
|
+
}
|
|
7833
|
+
return applySharedConfigPatch({
|
|
7834
|
+
fileKey: sharedConfigFileKey({
|
|
7835
|
+
relativeDirPath: CODEXCLI_DIR,
|
|
7836
|
+
relativeFilePath: CODEXCLI_MCP_FILE_NAME
|
|
7837
|
+
}),
|
|
7838
|
+
feature: "hooks",
|
|
7839
|
+
existingContent,
|
|
7840
|
+
patch: { features },
|
|
7841
|
+
filePath: configPath
|
|
7842
|
+
});
|
|
7503
7843
|
}
|
|
7504
7844
|
/**
|
|
7505
7845
|
* Represents the `.codex/config.toml` file as a generated ToolFile,
|
|
@@ -8415,17 +8755,13 @@ var DevinHooks = class DevinHooks extends ToolHooks {
|
|
|
8415
8755
|
let fileContent;
|
|
8416
8756
|
if (global) {
|
|
8417
8757
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
...isRecord(parsedSettings) ? parsedSettings : {},
|
|
8426
|
-
hooks: devinHooks
|
|
8427
|
-
};
|
|
8428
|
-
fileContent = JSON.stringify(merged, null, 2);
|
|
8758
|
+
fileContent = applySharedConfigPatch({
|
|
8759
|
+
fileKey: sharedConfigFileKey(paths),
|
|
8760
|
+
feature: "hooks",
|
|
8761
|
+
existingContent,
|
|
8762
|
+
patch: { hooks: devinHooks },
|
|
8763
|
+
filePath
|
|
8764
|
+
});
|
|
8429
8765
|
} else {
|
|
8430
8766
|
await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
8431
8767
|
fileContent = JSON.stringify(devinHooks, null, 2);
|
|
@@ -9237,18 +9573,14 @@ var KiroHooks = class KiroHooks extends ToolHooks {
|
|
|
9237
9573
|
const paths = KiroHooks.getSettablePaths({ global });
|
|
9238
9574
|
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
9239
9575
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
9240
|
-
let agentConfig;
|
|
9241
|
-
try {
|
|
9242
|
-
agentConfig = JSON.parse(existingContent);
|
|
9243
|
-
} catch (error) {
|
|
9244
|
-
throw new Error(`Failed to parse existing Kiro agent config at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
9245
|
-
}
|
|
9246
9576
|
const kiroHooks = canonicalToKiroHooks(rulesyncHooks.getJson(), this.getOverrideKey());
|
|
9247
|
-
const
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9577
|
+
const fileContent = applySharedConfigPatch({
|
|
9578
|
+
fileKey: sharedConfigFileKey(paths),
|
|
9579
|
+
feature: "hooks",
|
|
9580
|
+
existingContent,
|
|
9581
|
+
patch: { hooks: kiroHooks },
|
|
9582
|
+
filePath
|
|
9583
|
+
});
|
|
9252
9584
|
return new KiroHooks({
|
|
9253
9585
|
outputRoot,
|
|
9254
9586
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -9743,21 +10075,17 @@ var QwencodeHooks = class QwencodeHooks extends ToolHooks {
|
|
|
9743
10075
|
const paths = QwencodeHooks.getSettablePaths({ global });
|
|
9744
10076
|
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
9745
10077
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
9746
|
-
let settings;
|
|
9747
|
-
try {
|
|
9748
|
-
settings = JSON.parse(existingContent);
|
|
9749
|
-
} catch (error) {
|
|
9750
|
-
throw new Error(`Failed to parse existing Qwen Code settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
9751
|
-
}
|
|
9752
10078
|
const config = rulesyncHooks.getJson();
|
|
9753
|
-
const
|
|
9754
|
-
const merged = {
|
|
9755
|
-
...settings,
|
|
9756
|
-
hooks: qwencodeHooks
|
|
9757
|
-
};
|
|
10079
|
+
const patch = { hooks: canonicalToQwencodeHooks(config) };
|
|
9758
10080
|
const disableAllHooks = config.qwencode?.disableAllHooks;
|
|
9759
|
-
if (typeof disableAllHooks === "boolean")
|
|
9760
|
-
const fileContent =
|
|
10081
|
+
if (typeof disableAllHooks === "boolean") patch.disableAllHooks = disableAllHooks;
|
|
10082
|
+
const fileContent = applySharedConfigPatch({
|
|
10083
|
+
fileKey: sharedConfigFileKey(paths),
|
|
10084
|
+
feature: "hooks",
|
|
10085
|
+
existingContent,
|
|
10086
|
+
patch,
|
|
10087
|
+
filePath
|
|
10088
|
+
});
|
|
9761
10089
|
return new QwencodeHooks({
|
|
9762
10090
|
outputRoot,
|
|
9763
10091
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -10016,10 +10344,6 @@ function canonicalToVibeHooks(config, toolOverride) {
|
|
|
10016
10344
|
}
|
|
10017
10345
|
return { hooks };
|
|
10018
10346
|
}
|
|
10019
|
-
/**
|
|
10020
|
-
* Reverse {@link canonicalToVibeHooks}: parse the flat `[[hooks]]` array back
|
|
10021
|
-
* into a canonical event → definition[] record.
|
|
10022
|
-
*/
|
|
10023
10347
|
/** Convert one raw `[[hooks]]` entry to a canonical definition, or null to skip. */
|
|
10024
10348
|
function vibeEntryToCanonicalDef(raw) {
|
|
10025
10349
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -10039,6 +10363,10 @@ function vibeEntryToCanonicalDef(raw) {
|
|
|
10039
10363
|
def
|
|
10040
10364
|
};
|
|
10041
10365
|
}
|
|
10366
|
+
/**
|
|
10367
|
+
* Reverse {@link canonicalToVibeHooks}: parse the flat `[[hooks]]` array back
|
|
10368
|
+
* into a canonical event → definition[] record.
|
|
10369
|
+
*/
|
|
10042
10370
|
function vibeHooksToCanonical(parsed) {
|
|
10043
10371
|
const canonical = {};
|
|
10044
10372
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return canonical;
|
|
@@ -10067,15 +10395,22 @@ function parseVibeToml(fileContent) {
|
|
|
10067
10395
|
*/
|
|
10068
10396
|
async function buildVibeConfigTomlContent({ outputRoot }) {
|
|
10069
10397
|
const configPath = (0, node_path.join)(outputRoot, VIBE_DIR, VIBE_CONFIG_FILE_NAME);
|
|
10070
|
-
const existingContent = await readFileContentOrNull(configPath) ??
|
|
10071
|
-
let config;
|
|
10398
|
+
const existingContent = await readFileContentOrNull(configPath) ?? "";
|
|
10072
10399
|
try {
|
|
10073
|
-
|
|
10400
|
+
parseVibeToml(existingContent);
|
|
10074
10401
|
} catch (error) {
|
|
10075
10402
|
throw new Error(`Failed to parse existing Vibe config at ${configPath}: ${formatError(error)}`, { cause: error });
|
|
10076
10403
|
}
|
|
10077
|
-
|
|
10078
|
-
|
|
10404
|
+
return applySharedConfigPatch({
|
|
10405
|
+
fileKey: sharedConfigFileKey({
|
|
10406
|
+
relativeDirPath: VIBE_DIR,
|
|
10407
|
+
relativeFilePath: VIBE_CONFIG_FILE_NAME
|
|
10408
|
+
}),
|
|
10409
|
+
feature: "hooks",
|
|
10410
|
+
existingContent,
|
|
10411
|
+
patch: { enable_experimental_hooks: true },
|
|
10412
|
+
filePath: configPath
|
|
10413
|
+
});
|
|
10079
10414
|
}
|
|
10080
10415
|
/**
|
|
10081
10416
|
* Represents the `.vibe/config.toml` file as a generated ToolFile so it goes
|
|
@@ -11575,17 +11910,18 @@ var ZedIgnore = class ZedIgnore extends ToolIgnore {
|
|
|
11575
11910
|
const patterns = rulesyncIgnore.getFileContent().split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
11576
11911
|
const filePath = (0, node_path.join)(outputRoot, this.getSettablePaths().relativeDirPath, this.getSettablePaths().relativeFilePath);
|
|
11577
11912
|
const existingFileContent = await fileExists(filePath) ? await readFileContent(filePath) : "{}";
|
|
11578
|
-
const
|
|
11579
|
-
const mergedPatterns = (0, es_toolkit.uniq)([...existingJsonValue.private_files ?? [], ...patterns].toSorted());
|
|
11580
|
-
const jsonValue = {
|
|
11581
|
-
...existingJsonValue,
|
|
11582
|
-
private_files: mergedPatterns
|
|
11583
|
-
};
|
|
11913
|
+
const mergedPatterns = (0, es_toolkit.uniq)([...JSON.parse(existingFileContent).private_files ?? [], ...patterns].toSorted());
|
|
11584
11914
|
return new ZedIgnore({
|
|
11585
11915
|
outputRoot,
|
|
11586
11916
|
relativeDirPath: this.getSettablePaths().relativeDirPath,
|
|
11587
11917
|
relativeFilePath: this.getSettablePaths().relativeFilePath,
|
|
11588
|
-
fileContent:
|
|
11918
|
+
fileContent: applySharedConfigPatch({
|
|
11919
|
+
fileKey: sharedConfigFileKey(this.getSettablePaths()),
|
|
11920
|
+
feature: "ignore",
|
|
11921
|
+
existingContent: existingFileContent,
|
|
11922
|
+
patch: { private_files: mergedPatterns },
|
|
11923
|
+
filePath
|
|
11924
|
+
}),
|
|
11589
11925
|
validate: true
|
|
11590
11926
|
});
|
|
11591
11927
|
}
|
|
@@ -12042,17 +12378,17 @@ var AmpMcp = class AmpMcp extends ToolMcp {
|
|
|
12042
12378
|
const basePaths = this.getSettablePaths({ global });
|
|
12043
12379
|
const jsonDir = (0, node_path.join)(outputRoot, basePaths.relativeDirPath);
|
|
12044
12380
|
const { fileContent, relativeFilePath } = await this.resolveSettingsFile(jsonDir);
|
|
12045
|
-
const json = fileContent ? parseAmpSettingsJsonc(fileContent) : { [AMP_MCP_SERVERS_KEY]: {} };
|
|
12046
|
-
const filteredMcpServers = filterMcpServers(rulesyncMcp.getMcpServers());
|
|
12047
|
-
const newJson = {
|
|
12048
|
-
...json,
|
|
12049
|
-
[AMP_MCP_SERVERS_KEY]: filteredMcpServers
|
|
12050
|
-
};
|
|
12051
12381
|
return new AmpMcp({
|
|
12052
12382
|
outputRoot,
|
|
12053
12383
|
relativeDirPath: basePaths.relativeDirPath,
|
|
12054
12384
|
relativeFilePath,
|
|
12055
|
-
fileContent:
|
|
12385
|
+
fileContent: applySharedConfigPatch({
|
|
12386
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
12387
|
+
feature: "mcp",
|
|
12388
|
+
existingContent: fileContent ?? "",
|
|
12389
|
+
patch: { [AMP_MCP_SERVERS_KEY]: filterMcpServers(rulesyncMcp.getMcpServers()) },
|
|
12390
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
12391
|
+
}),
|
|
12056
12392
|
validate,
|
|
12057
12393
|
global
|
|
12058
12394
|
});
|
|
@@ -12339,15 +12675,19 @@ var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
|
12339
12675
|
}
|
|
12340
12676
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12341
12677
|
const paths = this.getSettablePaths({ global });
|
|
12342
|
-
const
|
|
12343
|
-
|
|
12344
|
-
mcpServers: rulesyncMcp.getMcpServers()
|
|
12345
|
-
};
|
|
12678
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
12679
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
12346
12680
|
return new AugmentcodeMcp({
|
|
12347
12681
|
outputRoot,
|
|
12348
12682
|
relativeDirPath: paths.relativeDirPath,
|
|
12349
12683
|
relativeFilePath: paths.relativeFilePath,
|
|
12350
|
-
fileContent:
|
|
12684
|
+
fileContent: applySharedConfigPatch({
|
|
12685
|
+
fileKey: sharedConfigFileKey(paths),
|
|
12686
|
+
feature: "mcp",
|
|
12687
|
+
existingContent,
|
|
12688
|
+
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
12689
|
+
filePath
|
|
12690
|
+
}),
|
|
12351
12691
|
validate,
|
|
12352
12692
|
global
|
|
12353
12693
|
});
|
|
@@ -12644,6 +12984,13 @@ function mapOauthFromCodex(oauth) {
|
|
|
12644
12984
|
}
|
|
12645
12985
|
return result;
|
|
12646
12986
|
}
|
|
12987
|
+
const CODEX_MCP_SERVER_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
12988
|
+
function normalizeCodexMcpServerName(name) {
|
|
12989
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(name)) return null;
|
|
12990
|
+
if (CODEX_MCP_SERVER_NAME_PATTERN.test(name)) return name;
|
|
12991
|
+
const normalizedName = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
12992
|
+
return normalizedName && !PROTOTYPE_POLLUTION_KEYS.has(normalizedName) ? normalizedName : null;
|
|
12993
|
+
}
|
|
12647
12994
|
function convertFromCodexFormat(codexMcp) {
|
|
12648
12995
|
const result = {};
|
|
12649
12996
|
for (const [name, config] of Object.entries(codexMcp)) {
|
|
@@ -12666,8 +13013,13 @@ function convertFromCodexFormat(codexMcp) {
|
|
|
12666
13013
|
}
|
|
12667
13014
|
function convertToCodexFormat(mcpServers) {
|
|
12668
13015
|
const result = {};
|
|
13016
|
+
const originalNames = /* @__PURE__ */ new Map();
|
|
12669
13017
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
12670
|
-
|
|
13018
|
+
const codexName = normalizeCodexMcpServerName(name);
|
|
13019
|
+
if (codexName === null) {
|
|
13020
|
+
warnWithFallback(void 0, `MCP server "${name}" could not be normalized to a valid Codex MCP server name and was skipped.`);
|
|
13021
|
+
continue;
|
|
13022
|
+
}
|
|
12671
13023
|
if (!isRecord(config)) continue;
|
|
12672
13024
|
const converted = {};
|
|
12673
13025
|
for (const [key, value] of Object.entries(config)) {
|
|
@@ -12681,7 +13033,10 @@ function convertToCodexFormat(mcpServers) {
|
|
|
12681
13033
|
else warnWithFallback(void 0, `[CodexCliMcp] Skipping invalid value type for mapped key '${key}': expected string array, got ${typeof value}`);
|
|
12682
13034
|
} else converted[key] = value;
|
|
12683
13035
|
}
|
|
12684
|
-
|
|
13036
|
+
const previousName = originalNames.get(codexName);
|
|
13037
|
+
if (previousName !== void 0) warnWithFallback(void 0, `Codex MCP server name collision: "${previousName}" and "${name}" both normalize to "${codexName}". Only the last processed server will be used.`);
|
|
13038
|
+
originalNames.set(codexName, name);
|
|
13039
|
+
result[codexName] = converted;
|
|
12685
13040
|
}
|
|
12686
13041
|
return result;
|
|
12687
13042
|
}
|
|
@@ -12726,8 +13081,9 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12726
13081
|
}
|
|
12727
13082
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12728
13083
|
const paths = this.getSettablePaths({ global });
|
|
12729
|
-
const
|
|
12730
|
-
const
|
|
13084
|
+
const configTomlFilePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13085
|
+
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13086
|
+
const configToml = smol_toml.parse(configTomlFileContent || smol_toml.stringify({}));
|
|
12731
13087
|
const strippedMcpServers = rulesyncMcp.getMcpServers();
|
|
12732
13088
|
const rawMcpServers = rulesyncMcp.getJson().mcpServers;
|
|
12733
13089
|
const converted = convertToCodexFormat(Object.fromEntries(Object.entries(strippedMcpServers).map(([serverName, serverConfig]) => {
|
|
@@ -12740,7 +13096,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12740
13096
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
12741
13097
|
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`);
|
|
12742
13098
|
const existingMcpServers = isRecord(configToml["mcp_servers"]) ? configToml["mcp_servers"] : {};
|
|
12743
|
-
|
|
13099
|
+
const mergedMcpServers = Object.fromEntries(Object.entries(filteredMcpServers).map(([name, serverConfig]) => {
|
|
12744
13100
|
const existingServer = isRecord(existingMcpServers[name]) ? existingMcpServers[name] : void 0;
|
|
12745
13101
|
const serverRecord = serverConfig;
|
|
12746
13102
|
if (existingServer && isRecord(existingServer["tools"]) && !("tools" in serverRecord)) return [name, {
|
|
@@ -12753,7 +13109,13 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12753
13109
|
outputRoot,
|
|
12754
13110
|
relativeDirPath: paths.relativeDirPath,
|
|
12755
13111
|
relativeFilePath: paths.relativeFilePath,
|
|
12756
|
-
fileContent:
|
|
13112
|
+
fileContent: applySharedConfigPatch({
|
|
13113
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13114
|
+
feature: "mcp",
|
|
13115
|
+
existingContent: configTomlFileContent,
|
|
13116
|
+
patch: { mcp_servers: mergedMcpServers },
|
|
13117
|
+
filePath: configTomlFilePath
|
|
13118
|
+
}),
|
|
12757
13119
|
validate
|
|
12758
13120
|
});
|
|
12759
13121
|
}
|
|
@@ -13320,16 +13682,19 @@ var DevinMcp = class DevinMcp extends ToolMcp {
|
|
|
13320
13682
|
}
|
|
13321
13683
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13322
13684
|
const paths = this.getSettablePaths({ global });
|
|
13323
|
-
const
|
|
13324
|
-
const
|
|
13325
|
-
...this.parseJsonOrThrow(fileContent, paths.relativeDirPath, paths.relativeFilePath),
|
|
13326
|
-
mcpServers: rulesyncMcp.getMcpServers()
|
|
13327
|
-
};
|
|
13685
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13686
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
13328
13687
|
return new DevinMcp({
|
|
13329
13688
|
outputRoot,
|
|
13330
13689
|
relativeDirPath: paths.relativeDirPath,
|
|
13331
13690
|
relativeFilePath: paths.relativeFilePath,
|
|
13332
|
-
fileContent:
|
|
13691
|
+
fileContent: applySharedConfigPatch({
|
|
13692
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13693
|
+
feature: "mcp",
|
|
13694
|
+
existingContent,
|
|
13695
|
+
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
13696
|
+
filePath
|
|
13697
|
+
}),
|
|
13333
13698
|
validate,
|
|
13334
13699
|
global
|
|
13335
13700
|
});
|
|
@@ -13816,17 +14181,22 @@ var GrokcliMcp = class GrokcliMcp extends ToolMcp {
|
|
|
13816
14181
|
}
|
|
13817
14182
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13818
14183
|
const paths = this.getSettablePaths({ global });
|
|
13819
|
-
const
|
|
13820
|
-
const
|
|
14184
|
+
const configTomlFilePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
14185
|
+
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13821
14186
|
const converted = convertToGrokFormat(rulesyncMcp.getMcpServers());
|
|
13822
14187
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
13823
14188
|
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`);
|
|
13824
|
-
configToml["mcp_servers"] = filteredMcpServers;
|
|
13825
14189
|
return new GrokcliMcp({
|
|
13826
14190
|
outputRoot,
|
|
13827
14191
|
relativeDirPath: paths.relativeDirPath,
|
|
13828
14192
|
relativeFilePath: paths.relativeFilePath,
|
|
13829
|
-
fileContent:
|
|
14193
|
+
fileContent: applySharedConfigPatch({
|
|
14194
|
+
fileKey: sharedConfigFileKey(paths),
|
|
14195
|
+
feature: "mcp",
|
|
14196
|
+
existingContent: configTomlFileContent,
|
|
14197
|
+
patch: { mcp_servers: filteredMcpServers },
|
|
14198
|
+
filePath: configTomlFilePath
|
|
14199
|
+
}),
|
|
13830
14200
|
validate
|
|
13831
14201
|
});
|
|
13832
14202
|
}
|
|
@@ -14359,20 +14729,21 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14359
14729
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14360
14730
|
if (fileContent) relativeFilePath = KILO_JSON_FILE_NAME;
|
|
14361
14731
|
}
|
|
14362
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14363
|
-
const json = (0, jsonc_parser.parse)(fileContent);
|
|
14364
14732
|
const { mcp: convertedMcp, tools: mcpTools } = convertToKiloFormat(rulesyncMcp.getMcpServers());
|
|
14365
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14366
|
-
const newJson = {
|
|
14367
|
-
...jsonWithoutTools,
|
|
14368
|
-
mcp: convertedMcp,
|
|
14369
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14370
|
-
};
|
|
14371
14733
|
return new KiloMcp({
|
|
14372
14734
|
outputRoot,
|
|
14373
14735
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14374
14736
|
relativeFilePath,
|
|
14375
|
-
fileContent:
|
|
14737
|
+
fileContent: applySharedConfigPatch({
|
|
14738
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
14739
|
+
feature: "mcp",
|
|
14740
|
+
existingContent: fileContent ?? "",
|
|
14741
|
+
patch: {
|
|
14742
|
+
mcp: convertedMcp,
|
|
14743
|
+
tools: Object.keys(mcpTools).length > 0 ? mcpTools : void 0
|
|
14744
|
+
},
|
|
14745
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
14746
|
+
}),
|
|
14376
14747
|
validate
|
|
14377
14748
|
});
|
|
14378
14749
|
}
|
|
@@ -14401,15 +14772,17 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14401
14772
|
const json = fileContent ? (0, jsonc_parser.parse)(fileContent) : {};
|
|
14402
14773
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14403
14774
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14404
|
-
const newJson = {
|
|
14405
|
-
...json,
|
|
14406
|
-
instructions: mergedInstructions
|
|
14407
|
-
};
|
|
14408
14775
|
return new KiloMcp({
|
|
14409
14776
|
outputRoot,
|
|
14410
14777
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14411
14778
|
relativeFilePath,
|
|
14412
|
-
fileContent:
|
|
14779
|
+
fileContent: applySharedConfigPatch({
|
|
14780
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
14781
|
+
feature: "rules",
|
|
14782
|
+
existingContent: fileContent ?? "",
|
|
14783
|
+
patch: { instructions: mergedInstructions },
|
|
14784
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
14785
|
+
}),
|
|
14413
14786
|
validate
|
|
14414
14787
|
});
|
|
14415
14788
|
}
|
|
@@ -14681,23 +15054,24 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14681
15054
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14682
15055
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
14683
15056
|
}
|
|
14684
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14685
|
-
const json = (0, jsonc_parser.parse)(fileContent);
|
|
14686
15057
|
const { mcp: convertedMcp, tools: mcpTools } = convertToOpencodeFormat(convertEnvVarRefsToToolFormat({
|
|
14687
15058
|
mcpServers: rulesyncMcp.getMcpServers(),
|
|
14688
15059
|
replacement: "{env:$1}"
|
|
14689
15060
|
}));
|
|
14690
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14691
|
-
const newJson = {
|
|
14692
|
-
...jsonWithoutTools,
|
|
14693
|
-
mcp: convertedMcp,
|
|
14694
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14695
|
-
};
|
|
14696
15061
|
return new OpencodeMcp({
|
|
14697
15062
|
outputRoot,
|
|
14698
15063
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14699
15064
|
relativeFilePath,
|
|
14700
|
-
fileContent:
|
|
15065
|
+
fileContent: applySharedConfigPatch({
|
|
15066
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
15067
|
+
feature: "mcp",
|
|
15068
|
+
existingContent: fileContent ?? "",
|
|
15069
|
+
patch: {
|
|
15070
|
+
mcp: convertedMcp,
|
|
15071
|
+
tools: Object.keys(mcpTools).length > 0 ? mcpTools : void 0
|
|
15072
|
+
},
|
|
15073
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
15074
|
+
}),
|
|
14701
15075
|
validate
|
|
14702
15076
|
});
|
|
14703
15077
|
}
|
|
@@ -14732,15 +15106,17 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14732
15106
|
const json = fileContent ? (0, jsonc_parser.parse)(fileContent) : {};
|
|
14733
15107
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14734
15108
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14735
|
-
const newJson = {
|
|
14736
|
-
...json,
|
|
14737
|
-
instructions: mergedInstructions
|
|
14738
|
-
};
|
|
14739
15109
|
return new OpencodeMcp({
|
|
14740
15110
|
outputRoot,
|
|
14741
15111
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14742
15112
|
relativeFilePath,
|
|
14743
|
-
fileContent:
|
|
15113
|
+
fileContent: applySharedConfigPatch({
|
|
15114
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
15115
|
+
feature: "rules",
|
|
15116
|
+
existingContent: fileContent ?? "",
|
|
15117
|
+
patch: { instructions: mergedInstructions },
|
|
15118
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
15119
|
+
}),
|
|
14744
15120
|
validate
|
|
14745
15121
|
});
|
|
14746
15122
|
}
|
|
@@ -14850,16 +15226,19 @@ var QwencodeMcp = class QwencodeMcp extends ToolMcp {
|
|
|
14850
15226
|
}
|
|
14851
15227
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14852
15228
|
const paths = this.getSettablePaths({ global });
|
|
14853
|
-
const
|
|
14854
|
-
const
|
|
14855
|
-
...JSON.parse(fileContent),
|
|
14856
|
-
mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers())
|
|
14857
|
-
};
|
|
15229
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15230
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
14858
15231
|
return new QwencodeMcp({
|
|
14859
15232
|
outputRoot,
|
|
14860
15233
|
relativeDirPath: paths.relativeDirPath,
|
|
14861
15234
|
relativeFilePath: paths.relativeFilePath,
|
|
14862
|
-
fileContent:
|
|
15235
|
+
fileContent: applySharedConfigPatch({
|
|
15236
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15237
|
+
feature: "mcp",
|
|
15238
|
+
existingContent,
|
|
15239
|
+
patch: { mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers()) },
|
|
15240
|
+
filePath
|
|
15241
|
+
}),
|
|
14863
15242
|
validate
|
|
14864
15243
|
});
|
|
14865
15244
|
}
|
|
@@ -14944,13 +15323,20 @@ var ReasonixMcp = class ReasonixMcp extends ToolMcp {
|
|
|
14944
15323
|
}
|
|
14945
15324
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14946
15325
|
const paths = this.getSettablePaths({ global });
|
|
14947
|
-
const
|
|
14948
|
-
|
|
15326
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15327
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
15328
|
+
const plugins = Object.entries(rulesyncMcp.getMcpServers()).map(([name, server]) => rulesyncMcpServerToReasonix(name, server));
|
|
14949
15329
|
return new ReasonixMcp({
|
|
14950
15330
|
outputRoot,
|
|
14951
15331
|
relativeDirPath: paths.relativeDirPath,
|
|
14952
15332
|
relativeFilePath: paths.relativeFilePath,
|
|
14953
|
-
fileContent:
|
|
15333
|
+
fileContent: applySharedConfigPatch({
|
|
15334
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15335
|
+
feature: "mcp",
|
|
15336
|
+
existingContent,
|
|
15337
|
+
patch: { plugins },
|
|
15338
|
+
filePath
|
|
15339
|
+
}),
|
|
14954
15340
|
validate,
|
|
14955
15341
|
global
|
|
14956
15342
|
});
|
|
@@ -15425,13 +15811,20 @@ var VibeMcp = class VibeMcp extends ToolMcp {
|
|
|
15425
15811
|
}
|
|
15426
15812
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15427
15813
|
const paths = this.getSettablePaths({ global });
|
|
15428
|
-
const
|
|
15429
|
-
|
|
15814
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15815
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
15816
|
+
const mcpServers = Object.entries(rulesyncMcp.getMcpServers()).map(([name, server]) => rulesyncMcpServerToVibe(name, server));
|
|
15430
15817
|
return new VibeMcp({
|
|
15431
15818
|
outputRoot,
|
|
15432
15819
|
relativeDirPath: paths.relativeDirPath,
|
|
15433
15820
|
relativeFilePath: paths.relativeFilePath,
|
|
15434
|
-
fileContent:
|
|
15821
|
+
fileContent: applySharedConfigPatch({
|
|
15822
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15823
|
+
feature: "mcp",
|
|
15824
|
+
existingContent,
|
|
15825
|
+
patch: { mcp_servers: mcpServers },
|
|
15826
|
+
filePath
|
|
15827
|
+
}),
|
|
15435
15828
|
validate,
|
|
15436
15829
|
global
|
|
15437
15830
|
});
|
|
@@ -15662,16 +16055,19 @@ var ZedMcp = class ZedMcp extends ToolMcp {
|
|
|
15662
16055
|
}
|
|
15663
16056
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15664
16057
|
const paths = this.getSettablePaths({ global });
|
|
15665
|
-
const
|
|
15666
|
-
const
|
|
15667
|
-
...JSON.parse(fileContent),
|
|
15668
|
-
context_servers: rulesyncMcp.getMcpServers()
|
|
15669
|
-
};
|
|
16058
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
16059
|
+
const existingContent = await readOrInitializeFileContent(filePath, "{}");
|
|
15670
16060
|
return new ZedMcp({
|
|
15671
16061
|
outputRoot,
|
|
15672
16062
|
relativeDirPath: paths.relativeDirPath,
|
|
15673
16063
|
relativeFilePath: paths.relativeFilePath,
|
|
15674
|
-
fileContent:
|
|
16064
|
+
fileContent: applySharedConfigPatch({
|
|
16065
|
+
fileKey: sharedConfigFileKey(paths),
|
|
16066
|
+
feature: "mcp",
|
|
16067
|
+
existingContent,
|
|
16068
|
+
patch: { context_servers: rulesyncMcp.getMcpServers() },
|
|
16069
|
+
filePath
|
|
16070
|
+
}),
|
|
15675
16071
|
validate
|
|
15676
16072
|
});
|
|
15677
16073
|
}
|
|
@@ -16840,25 +17236,29 @@ var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
|
16840
17236
|
const override = config.amp;
|
|
16841
17237
|
const authoredExtras = override?.permissions ? toPermissionsList(override.permissions) : [];
|
|
16842
17238
|
const preservedDelegates = override?.permissions ? [] : toPermissionsList(json[AMP_PERMISSIONS_KEY]).filter((entry) => entry.action === "delegate");
|
|
16843
|
-
const newJson = {
|
|
16844
|
-
...json,
|
|
16845
|
-
[AMP_TOOLS_DISABLE_KEY]: disable
|
|
16846
|
-
};
|
|
16847
17239
|
const mergedPermissions = mergeAmpPermissions([
|
|
16848
17240
|
...permissions,
|
|
16849
17241
|
...authoredExtras,
|
|
16850
17242
|
...preservedDelegates
|
|
16851
17243
|
]);
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
if (override?.
|
|
17244
|
+
const patch = {
|
|
17245
|
+
[AMP_TOOLS_DISABLE_KEY]: disable,
|
|
17246
|
+
[AMP_PERMISSIONS_KEY]: mergedPermissions.length > 0 ? mergedPermissions : void 0
|
|
17247
|
+
};
|
|
17248
|
+
if (override?.guardedFiles?.allowlist !== void 0) patch[AMP_GUARDED_FILES_ALLOWLIST_KEY] = override.guardedFiles.allowlist;
|
|
17249
|
+
if (override?.dangerouslyAllowAll !== void 0) patch[AMP_DANGEROUSLY_ALLOW_ALL_KEY] = override.dangerouslyAllowAll;
|
|
17250
|
+
if (override?.mcpPermissions !== void 0) patch[AMP_MCP_PERMISSIONS_KEY] = override.mcpPermissions;
|
|
16857
17251
|
return new AmpPermissions({
|
|
16858
17252
|
outputRoot,
|
|
16859
17253
|
relativeDirPath: basePaths.relativeDirPath,
|
|
16860
17254
|
relativeFilePath,
|
|
16861
|
-
fileContent:
|
|
17255
|
+
fileContent: applySharedConfigPatch({
|
|
17256
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
17257
|
+
feature: "permissions",
|
|
17258
|
+
existingContent: fileContent ?? "",
|
|
17259
|
+
patch,
|
|
17260
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
17261
|
+
}),
|
|
16862
17262
|
validate: true
|
|
16863
17263
|
});
|
|
16864
17264
|
}
|
|
@@ -17800,11 +18200,13 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
|
|
|
17800
18200
|
...preservedBasicEntries,
|
|
17801
18201
|
...authoredBasics
|
|
17802
18202
|
]);
|
|
17803
|
-
const
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
18203
|
+
const fileContent = applySharedConfigPatch({
|
|
18204
|
+
fileKey: sharedConfigFileKey(paths),
|
|
18205
|
+
feature: "permissions",
|
|
18206
|
+
existingContent,
|
|
18207
|
+
patch: { toolPermissions: [...specialEntries, ...sortedBasic] },
|
|
18208
|
+
filePath
|
|
18209
|
+
});
|
|
17808
18210
|
return new AugmentcodePermissions({
|
|
17809
18211
|
outputRoot,
|
|
17810
18212
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -18396,13 +18798,6 @@ const WORKSPACE_WIDE_WRITE_PATTERNS = /* @__PURE__ */ new Set([
|
|
|
18396
18798
|
]);
|
|
18397
18799
|
const CODEX_MINIMAL_KEY = ":minimal";
|
|
18398
18800
|
const GLOBAL_WILDCARD_DOMAIN = "*";
|
|
18399
|
-
const CODEXCLI_OVERRIDE_KEYS = [
|
|
18400
|
-
"approval_policy",
|
|
18401
|
-
"sandbox_mode",
|
|
18402
|
-
"sandbox_workspace_write",
|
|
18403
|
-
"apps",
|
|
18404
|
-
"approvals_reviewer"
|
|
18405
|
-
];
|
|
18406
18801
|
var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
18407
18802
|
static getSettablePaths(_options = {}) {
|
|
18408
18803
|
return {
|
|
@@ -18426,26 +18821,27 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18426
18821
|
}
|
|
18427
18822
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
18428
18823
|
const paths = this.getSettablePaths({ global });
|
|
18429
|
-
const
|
|
18430
|
-
const
|
|
18824
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
18825
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
18826
|
+
const existing = toMutableTable(smol_toml.parse(existingContent || smol_toml.stringify({})));
|
|
18431
18827
|
const newProfile = convertRulesyncToCodexProfile({
|
|
18432
18828
|
config: rulesyncPermissions.getJson(),
|
|
18433
18829
|
logger
|
|
18434
18830
|
});
|
|
18435
|
-
const permissionsTable = toMutableTable(
|
|
18831
|
+
const permissionsTable = toMutableTable(existing.permissions);
|
|
18436
18832
|
const { profile: existingProfile, domainsHadUnknown: existingDomainsHadUnknown } = toCodexProfile(permissionsTable[RULESYNC_PROFILE_NAME]);
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18833
|
+
warnAboutPreservedProfileState({
|
|
18834
|
+
existingProfile,
|
|
18835
|
+
newProfile,
|
|
18836
|
+
existingDomainsHadUnknown,
|
|
18837
|
+
logger
|
|
18838
|
+
});
|
|
18441
18839
|
permissionsTable[RULESYNC_PROFILE_NAME] = mergeWithExistingProfile({
|
|
18442
18840
|
newProfile,
|
|
18443
18841
|
existingProfile
|
|
18444
18842
|
});
|
|
18445
|
-
|
|
18446
|
-
|
|
18447
|
-
applyCodexcliOverride({
|
|
18448
|
-
parsed,
|
|
18843
|
+
const overridePatch = computeCodexcliOverridePatch({
|
|
18844
|
+
existing,
|
|
18449
18845
|
override: rulesyncPermissions.getJson().codexcli,
|
|
18450
18846
|
logger
|
|
18451
18847
|
});
|
|
@@ -18453,7 +18849,17 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18453
18849
|
outputRoot,
|
|
18454
18850
|
relativeDirPath: paths.relativeDirPath,
|
|
18455
18851
|
relativeFilePath: paths.relativeFilePath,
|
|
18456
|
-
fileContent:
|
|
18852
|
+
fileContent: applySharedConfigPatch({
|
|
18853
|
+
fileKey: sharedConfigFileKey(paths),
|
|
18854
|
+
feature: "permissions",
|
|
18855
|
+
existingContent,
|
|
18856
|
+
patch: {
|
|
18857
|
+
permissions: permissionsTable,
|
|
18858
|
+
default_permissions: RULESYNC_PROFILE_NAME,
|
|
18859
|
+
...overridePatch
|
|
18860
|
+
},
|
|
18861
|
+
filePath
|
|
18862
|
+
}),
|
|
18457
18863
|
validate
|
|
18458
18864
|
});
|
|
18459
18865
|
}
|
|
@@ -18623,6 +19029,12 @@ function toCodexProfile(value) {
|
|
|
18623
19029
|
domainsHadUnknown
|
|
18624
19030
|
};
|
|
18625
19031
|
}
|
|
19032
|
+
function warnAboutPreservedProfileState({ existingProfile, newProfile, existingDomainsHadUnknown, logger }) {
|
|
19033
|
+
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)"}".`);
|
|
19034
|
+
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.`);
|
|
19035
|
+
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.`);
|
|
19036
|
+
if (existingDomainsHadUnknown) logger?.warn(`Existing "network.domains" contained unrecognized values. These entries were skipped and will not be imported.`);
|
|
19037
|
+
}
|
|
18626
19038
|
function mergeWithExistingProfile({ newProfile, existingProfile }) {
|
|
18627
19039
|
if (!existingProfile) return newProfile;
|
|
18628
19040
|
const mergedNetwork = { ...newProfile.network };
|
|
@@ -18673,8 +19085,9 @@ function toMutableTable(value) {
|
|
|
18673
19085
|
function isPlainObject(value) {
|
|
18674
19086
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18675
19087
|
}
|
|
18676
|
-
function
|
|
18677
|
-
|
|
19088
|
+
function computeCodexcliOverridePatch({ existing, override, logger }) {
|
|
19089
|
+
const patch = {};
|
|
19090
|
+
if (!override) return patch;
|
|
18678
19091
|
const allowed = new Set(CODEXCLI_OVERRIDE_KEYS);
|
|
18679
19092
|
for (const [key, value] of Object.entries(override)) {
|
|
18680
19093
|
if (!allowed.has(key)) {
|
|
@@ -18682,12 +19095,13 @@ function applyCodexcliOverride({ parsed, override, logger }) {
|
|
|
18682
19095
|
continue;
|
|
18683
19096
|
}
|
|
18684
19097
|
if (value === void 0) continue;
|
|
18685
|
-
const
|
|
18686
|
-
|
|
18687
|
-
...
|
|
19098
|
+
const existingValue = existing[key];
|
|
19099
|
+
patch[key] = isPlainObject(existingValue) && isPlainObject(value) ? {
|
|
19100
|
+
...existingValue,
|
|
18688
19101
|
...value
|
|
18689
19102
|
} : value;
|
|
18690
19103
|
}
|
|
19104
|
+
return patch;
|
|
18691
19105
|
}
|
|
18692
19106
|
function extractCodexcliOverride(table) {
|
|
18693
19107
|
const override = {};
|
|
@@ -19248,15 +19662,17 @@ var DevinPermissions = class DevinPermissions extends ToolPermissions {
|
|
|
19248
19662
|
else delete mergedPermissions.ask;
|
|
19249
19663
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
19250
19664
|
else delete mergedPermissions.deny;
|
|
19251
|
-
const merged = {
|
|
19252
|
-
...settings,
|
|
19253
|
-
permissions: mergedPermissions
|
|
19254
|
-
};
|
|
19255
19665
|
return new DevinPermissions({
|
|
19256
19666
|
outputRoot,
|
|
19257
19667
|
relativeDirPath: paths.relativeDirPath,
|
|
19258
19668
|
relativeFilePath: paths.relativeFilePath,
|
|
19259
|
-
fileContent:
|
|
19669
|
+
fileContent: applySharedConfigPatch({
|
|
19670
|
+
fileKey: sharedConfigFileKey(paths),
|
|
19671
|
+
feature: "permissions",
|
|
19672
|
+
existingContent,
|
|
19673
|
+
patch: { permissions: mergedPermissions },
|
|
19674
|
+
filePath
|
|
19675
|
+
}),
|
|
19260
19676
|
validate
|
|
19261
19677
|
});
|
|
19262
19678
|
}
|
|
@@ -19865,23 +20281,31 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
19865
20281
|
const config = rulesyncPermissions.getJson();
|
|
19866
20282
|
const existingPermission = isRecord(parsed[GROKCLI_PERMISSION_KEY]) ? parsed[GROKCLI_PERMISSION_KEY] : {};
|
|
19867
20283
|
const buckets = buildGrokPermissionArrays(config, existingPermission, logger);
|
|
19868
|
-
|
|
20284
|
+
const permission = {
|
|
19869
20285
|
...existingPermission,
|
|
19870
20286
|
allow: buckets.allow,
|
|
19871
20287
|
deny: buckets.deny,
|
|
19872
20288
|
ask: buckets.ask
|
|
19873
20289
|
};
|
|
19874
20290
|
const mode = deriveGrokPermissionMode(config);
|
|
19875
|
-
const
|
|
19876
|
-
|
|
19877
|
-
...existingUi,
|
|
20291
|
+
const ui = {
|
|
20292
|
+
...isRecord(parsed[GROKCLI_UI_KEY]) ? parsed[GROKCLI_UI_KEY] : {},
|
|
19878
20293
|
[GROKCLI_PERMISSION_MODE_KEY]: mode
|
|
19879
20294
|
};
|
|
19880
20295
|
return new GrokcliPermissions({
|
|
19881
20296
|
outputRoot,
|
|
19882
20297
|
relativeDirPath: paths.relativeDirPath,
|
|
19883
20298
|
relativeFilePath: paths.relativeFilePath,
|
|
19884
|
-
fileContent:
|
|
20299
|
+
fileContent: applySharedConfigPatch({
|
|
20300
|
+
fileKey: sharedConfigFileKey(paths),
|
|
20301
|
+
feature: "permissions",
|
|
20302
|
+
existingContent,
|
|
20303
|
+
patch: {
|
|
20304
|
+
[GROKCLI_PERMISSION_KEY]: permission,
|
|
20305
|
+
[GROKCLI_UI_KEY]: ui
|
|
20306
|
+
},
|
|
20307
|
+
filePath
|
|
20308
|
+
}),
|
|
19885
20309
|
validate: true,
|
|
19886
20310
|
global: true
|
|
19887
20311
|
});
|
|
@@ -20584,7 +21008,16 @@ var KiroPermissions = class KiroPermissions extends ToolPermissions {
|
|
|
20584
21008
|
outputRoot,
|
|
20585
21009
|
relativeDirPath: paths.relativeDirPath,
|
|
20586
21010
|
relativeFilePath: paths.relativeFilePath,
|
|
20587
|
-
fileContent:
|
|
21011
|
+
fileContent: applySharedConfigPatch({
|
|
21012
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21013
|
+
feature: "permissions",
|
|
21014
|
+
existingContent,
|
|
21015
|
+
patch: {
|
|
21016
|
+
allowedTools: next.allowedTools,
|
|
21017
|
+
toolsSettings: next.toolsSettings
|
|
21018
|
+
},
|
|
21019
|
+
filePath
|
|
21020
|
+
}),
|
|
20588
21021
|
validate
|
|
20589
21022
|
});
|
|
20590
21023
|
}
|
|
@@ -20881,21 +21314,22 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
20881
21314
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
20882
21315
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
20883
21316
|
}
|
|
20884
|
-
const parsed = (0, jsonc_parser.parse)(fileContent ?? "{}");
|
|
20885
21317
|
const rulesyncJson = rulesyncPermissions.getJson();
|
|
20886
21318
|
const overridePermission = rulesyncJson.opencode?.permission ?? {};
|
|
20887
|
-
const nextJson = {
|
|
20888
|
-
...parsed,
|
|
20889
|
-
permission: {
|
|
20890
|
-
...rulesyncJson.permission,
|
|
20891
|
-
...overridePermission
|
|
20892
|
-
}
|
|
20893
|
-
};
|
|
20894
21319
|
return new OpencodePermissions({
|
|
20895
21320
|
outputRoot,
|
|
20896
21321
|
relativeDirPath: basePaths.relativeDirPath,
|
|
20897
21322
|
relativeFilePath,
|
|
20898
|
-
fileContent:
|
|
21323
|
+
fileContent: applySharedConfigPatch({
|
|
21324
|
+
fileKey: sharedConfigFileKey(basePaths),
|
|
21325
|
+
feature: "permissions",
|
|
21326
|
+
existingContent: fileContent ?? "",
|
|
21327
|
+
patch: { permission: {
|
|
21328
|
+
...rulesyncJson.permission,
|
|
21329
|
+
...overridePermission
|
|
21330
|
+
} },
|
|
21331
|
+
filePath: (0, node_path.join)(jsonDir, relativeFilePath)
|
|
21332
|
+
}),
|
|
20899
21333
|
validate: true
|
|
20900
21334
|
});
|
|
20901
21335
|
}
|
|
@@ -21104,20 +21538,23 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
21104
21538
|
else delete mergedPermissions.ask;
|
|
21105
21539
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21106
21540
|
else delete mergedPermissions.deny;
|
|
21107
|
-
const
|
|
21108
|
-
...settings,
|
|
21109
|
-
permissions: mergedPermissions
|
|
21110
|
-
};
|
|
21541
|
+
const patch = { permissions: mergedPermissions };
|
|
21111
21542
|
const override = config.qwencode;
|
|
21112
|
-
if (override?.tools !== void 0)
|
|
21543
|
+
if (override?.tools !== void 0) patch.tools = {
|
|
21113
21544
|
...asPlainRecord(settings.tools),
|
|
21114
21545
|
...asPlainRecord(override.tools)
|
|
21115
21546
|
};
|
|
21116
|
-
if (override?.security !== void 0)
|
|
21547
|
+
if (override?.security !== void 0) patch.security = {
|
|
21117
21548
|
...asPlainRecord(settings.security),
|
|
21118
21549
|
...asPlainRecord(override.security)
|
|
21119
21550
|
};
|
|
21120
|
-
const fileContent =
|
|
21551
|
+
const fileContent = applySharedConfigPatch({
|
|
21552
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21553
|
+
feature: "permissions",
|
|
21554
|
+
existingContent,
|
|
21555
|
+
patch,
|
|
21556
|
+
filePath
|
|
21557
|
+
});
|
|
21121
21558
|
return new QwencodePermissions({
|
|
21122
21559
|
outputRoot,
|
|
21123
21560
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -21352,7 +21789,9 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21352
21789
|
}
|
|
21353
21790
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21354
21791
|
const paths = this.getSettablePaths({ global });
|
|
21355
|
-
const
|
|
21792
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
21793
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
21794
|
+
const parsed = parseReasonixConfig(existingContent);
|
|
21356
21795
|
const config = rulesyncPermissions.getJson();
|
|
21357
21796
|
const { allow, ask, deny } = convertRulesyncToReasonixPermissions(config);
|
|
21358
21797
|
const managedToolNames = new Set(Object.keys(config.permission).map((category) => toReasonixToolName(category)));
|
|
@@ -21377,25 +21816,27 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21377
21816
|
else delete mergedPermissions.ask;
|
|
21378
21817
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21379
21818
|
else delete mergedPermissions.deny;
|
|
21380
|
-
const
|
|
21381
|
-
...parsed,
|
|
21382
|
-
permissions: mergedPermissions
|
|
21383
|
-
};
|
|
21819
|
+
const patch = { permissions: mergedPermissions };
|
|
21384
21820
|
const override = config.reasonix;
|
|
21385
|
-
if (override?.sandbox !== void 0)
|
|
21821
|
+
if (override?.sandbox !== void 0) patch.sandbox = {
|
|
21386
21822
|
...asReasonixRecord(parsed.sandbox),
|
|
21387
21823
|
...asReasonixRecord(override.sandbox)
|
|
21388
21824
|
};
|
|
21389
|
-
if (override?.agent !== void 0)
|
|
21825
|
+
if (override?.agent !== void 0) patch.agent = {
|
|
21390
21826
|
...asReasonixRecord(parsed.agent),
|
|
21391
21827
|
...asReasonixRecord(override.agent)
|
|
21392
21828
|
};
|
|
21393
|
-
const fileContent = smol_toml.stringify(merged);
|
|
21394
21829
|
return new ReasonixPermissions({
|
|
21395
21830
|
outputRoot,
|
|
21396
21831
|
relativeDirPath: paths.relativeDirPath,
|
|
21397
21832
|
relativeFilePath: paths.relativeFilePath,
|
|
21398
|
-
fileContent
|
|
21833
|
+
fileContent: applySharedConfigPatch({
|
|
21834
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21835
|
+
feature: "permissions",
|
|
21836
|
+
existingContent,
|
|
21837
|
+
patch,
|
|
21838
|
+
filePath
|
|
21839
|
+
}),
|
|
21399
21840
|
validate
|
|
21400
21841
|
});
|
|
21401
21842
|
}
|
|
@@ -21966,7 +22407,9 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
21966
22407
|
}
|
|
21967
22408
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21968
22409
|
const paths = this.getSettablePaths({ global });
|
|
21969
|
-
const
|
|
22410
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
22411
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
22412
|
+
const config = parseVibeConfig(existingContent);
|
|
21970
22413
|
const permission = rulesyncPermissions.getJson().permission;
|
|
21971
22414
|
const tools = toVibeToolsRecord(config.tools);
|
|
21972
22415
|
const enabledTools = new Set(toStringArray(config.enabled_tools));
|
|
@@ -22011,16 +22454,21 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
22011
22454
|
tools[vibeToolName] = nextTool;
|
|
22012
22455
|
}
|
|
22013
22456
|
applyVibeSensitivePatterns(tools, rulesyncPermissions.getJson().vibe);
|
|
22014
|
-
config.tools = tools;
|
|
22015
|
-
if (enabledTools.size > 0) config.enabled_tools = [...enabledTools].toSorted();
|
|
22016
|
-
else delete config.enabled_tools;
|
|
22017
|
-
if (disabledTools.size > 0) config.disabled_tools = [...disabledTools].toSorted();
|
|
22018
|
-
else delete config.disabled_tools;
|
|
22019
22457
|
return new VibePermissions({
|
|
22020
22458
|
outputRoot,
|
|
22021
22459
|
relativeDirPath: paths.relativeDirPath,
|
|
22022
22460
|
relativeFilePath: paths.relativeFilePath,
|
|
22023
|
-
fileContent:
|
|
22461
|
+
fileContent: applySharedConfigPatch({
|
|
22462
|
+
fileKey: sharedConfigFileKey(paths),
|
|
22463
|
+
feature: "permissions",
|
|
22464
|
+
existingContent,
|
|
22465
|
+
patch: {
|
|
22466
|
+
tools,
|
|
22467
|
+
enabled_tools: enabledTools.size > 0 ? [...enabledTools].toSorted() : void 0,
|
|
22468
|
+
disabled_tools: disabledTools.size > 0 ? [...disabledTools].toSorted() : void 0
|
|
22469
|
+
},
|
|
22470
|
+
filePath
|
|
22471
|
+
}),
|
|
22024
22472
|
validate,
|
|
22025
22473
|
global
|
|
22026
22474
|
});
|
|
@@ -22483,24 +22931,26 @@ var ZedPermissions = class ZedPermissions extends ToolPermissions {
|
|
|
22483
22931
|
}
|
|
22484
22932
|
const managedToolNames = new Set(Object.keys(managedTools));
|
|
22485
22933
|
const preservedTools = Object.fromEntries(Object.entries(existingTools).filter(([toolName]) => !managedToolNames.has(toolName)));
|
|
22486
|
-
const mergedSettings = {
|
|
22487
|
-
...settings,
|
|
22488
|
-
agent: {
|
|
22489
|
-
...agent,
|
|
22490
|
-
tool_permissions: {
|
|
22491
|
-
...toolPermissions,
|
|
22492
|
-
tools: {
|
|
22493
|
-
...preservedTools,
|
|
22494
|
-
...managedTools
|
|
22495
|
-
}
|
|
22496
|
-
}
|
|
22497
|
-
}
|
|
22498
|
-
};
|
|
22499
22934
|
return new ZedPermissions({
|
|
22500
22935
|
outputRoot,
|
|
22501
22936
|
relativeDirPath: paths.relativeDirPath,
|
|
22502
22937
|
relativeFilePath: paths.relativeFilePath,
|
|
22503
|
-
fileContent:
|
|
22938
|
+
fileContent: applySharedConfigPatch({
|
|
22939
|
+
fileKey: sharedConfigFileKey(paths),
|
|
22940
|
+
feature: "permissions",
|
|
22941
|
+
existingContent,
|
|
22942
|
+
patch: { agent: {
|
|
22943
|
+
...agent,
|
|
22944
|
+
tool_permissions: {
|
|
22945
|
+
...toolPermissions,
|
|
22946
|
+
tools: {
|
|
22947
|
+
...preservedTools,
|
|
22948
|
+
...managedTools
|
|
22949
|
+
}
|
|
22950
|
+
}
|
|
22951
|
+
} },
|
|
22952
|
+
filePath
|
|
22953
|
+
}),
|
|
22504
22954
|
validate: true
|
|
22505
22955
|
});
|
|
22506
22956
|
}
|
|
@@ -38190,8 +38640,13 @@ const collectFactoryPaths = (factory) => [...settablePathsForScope({
|
|
|
38190
38640
|
* Derive, from the processor registry, every on-disk file that two or more
|
|
38191
38641
|
* features read-modify-write. Source of truth the generation step graph's
|
|
38192
38642
|
* `writesSharedFile` declarations must match.
|
|
38643
|
+
*
|
|
38644
|
+
* `minWriters: 1` widens the result to single-feature files as well — used to
|
|
38645
|
+
* validate `SHARED_CONFIG_OWNERSHIP` declarations for files that route through
|
|
38646
|
+
* the gateway without being cross-feature shared (e.g. a global-scope twin
|
|
38647
|
+
* only one feature writes).
|
|
38193
38648
|
*/
|
|
38194
|
-
const deriveSharedFileWriters = () => {
|
|
38649
|
+
const deriveSharedFileWriters = ({ minWriters = 2 } = {}) => {
|
|
38195
38650
|
const byKey = /* @__PURE__ */ new Map();
|
|
38196
38651
|
const pathByKey = /* @__PURE__ */ new Map();
|
|
38197
38652
|
for (const entry of PROCESSOR_REGISTRY) {
|
|
@@ -38217,7 +38672,7 @@ const deriveSharedFileWriters = () => {
|
|
|
38217
38672
|
}
|
|
38218
38673
|
const writers = [];
|
|
38219
38674
|
for (const [key, features] of byKey) {
|
|
38220
|
-
if (features.size <
|
|
38675
|
+
if (features.size < minWriters) continue;
|
|
38221
38676
|
const path = pathByKey.get(key);
|
|
38222
38677
|
const toolsByFeature = /* @__PURE__ */ new Map();
|
|
38223
38678
|
for (const [feature, tools] of features) toolsByFeature.set(feature, [...tools].toSorted());
|