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
|
@@ -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
|
});
|
|
@@ -12741,8 +13081,9 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12741
13081
|
}
|
|
12742
13082
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12743
13083
|
const paths = this.getSettablePaths({ global });
|
|
12744
|
-
const
|
|
12745
|
-
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({}));
|
|
12746
13087
|
const strippedMcpServers = rulesyncMcp.getMcpServers();
|
|
12747
13088
|
const rawMcpServers = rulesyncMcp.getJson().mcpServers;
|
|
12748
13089
|
const converted = convertToCodexFormat(Object.fromEntries(Object.entries(strippedMcpServers).map(([serverName, serverConfig]) => {
|
|
@@ -12755,7 +13096,7 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12755
13096
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
12756
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`);
|
|
12757
13098
|
const existingMcpServers = isRecord(configToml["mcp_servers"]) ? configToml["mcp_servers"] : {};
|
|
12758
|
-
|
|
13099
|
+
const mergedMcpServers = Object.fromEntries(Object.entries(filteredMcpServers).map(([name, serverConfig]) => {
|
|
12759
13100
|
const existingServer = isRecord(existingMcpServers[name]) ? existingMcpServers[name] : void 0;
|
|
12760
13101
|
const serverRecord = serverConfig;
|
|
12761
13102
|
if (existingServer && isRecord(existingServer["tools"]) && !("tools" in serverRecord)) return [name, {
|
|
@@ -12768,7 +13109,13 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
12768
13109
|
outputRoot,
|
|
12769
13110
|
relativeDirPath: paths.relativeDirPath,
|
|
12770
13111
|
relativeFilePath: paths.relativeFilePath,
|
|
12771
|
-
fileContent:
|
|
13112
|
+
fileContent: applySharedConfigPatch({
|
|
13113
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13114
|
+
feature: "mcp",
|
|
13115
|
+
existingContent: configTomlFileContent,
|
|
13116
|
+
patch: { mcp_servers: mergedMcpServers },
|
|
13117
|
+
filePath: configTomlFilePath
|
|
13118
|
+
}),
|
|
12772
13119
|
validate
|
|
12773
13120
|
});
|
|
12774
13121
|
}
|
|
@@ -13335,16 +13682,19 @@ var DevinMcp = class DevinMcp extends ToolMcp {
|
|
|
13335
13682
|
}
|
|
13336
13683
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13337
13684
|
const paths = this.getSettablePaths({ global });
|
|
13338
|
-
const
|
|
13339
|
-
const
|
|
13340
|
-
...this.parseJsonOrThrow(fileContent, paths.relativeDirPath, paths.relativeFilePath),
|
|
13341
|
-
mcpServers: rulesyncMcp.getMcpServers()
|
|
13342
|
-
};
|
|
13685
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13686
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
13343
13687
|
return new DevinMcp({
|
|
13344
13688
|
outputRoot,
|
|
13345
13689
|
relativeDirPath: paths.relativeDirPath,
|
|
13346
13690
|
relativeFilePath: paths.relativeFilePath,
|
|
13347
|
-
fileContent:
|
|
13691
|
+
fileContent: applySharedConfigPatch({
|
|
13692
|
+
fileKey: sharedConfigFileKey(paths),
|
|
13693
|
+
feature: "mcp",
|
|
13694
|
+
existingContent,
|
|
13695
|
+
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
13696
|
+
filePath
|
|
13697
|
+
}),
|
|
13348
13698
|
validate,
|
|
13349
13699
|
global
|
|
13350
13700
|
});
|
|
@@ -13831,17 +14181,22 @@ var GrokcliMcp = class GrokcliMcp extends ToolMcp {
|
|
|
13831
14181
|
}
|
|
13832
14182
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13833
14183
|
const paths = this.getSettablePaths({ global });
|
|
13834
|
-
const
|
|
13835
|
-
const
|
|
14184
|
+
const configTomlFilePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
14185
|
+
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13836
14186
|
const converted = convertToGrokFormat(rulesyncMcp.getMcpServers());
|
|
13837
14187
|
const filteredMcpServers = this.removeEmptyEntries(converted);
|
|
13838
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`);
|
|
13839
|
-
configToml["mcp_servers"] = filteredMcpServers;
|
|
13840
14189
|
return new GrokcliMcp({
|
|
13841
14190
|
outputRoot,
|
|
13842
14191
|
relativeDirPath: paths.relativeDirPath,
|
|
13843
14192
|
relativeFilePath: paths.relativeFilePath,
|
|
13844
|
-
fileContent:
|
|
14193
|
+
fileContent: applySharedConfigPatch({
|
|
14194
|
+
fileKey: sharedConfigFileKey(paths),
|
|
14195
|
+
feature: "mcp",
|
|
14196
|
+
existingContent: configTomlFileContent,
|
|
14197
|
+
patch: { mcp_servers: filteredMcpServers },
|
|
14198
|
+
filePath: configTomlFilePath
|
|
14199
|
+
}),
|
|
13845
14200
|
validate
|
|
13846
14201
|
});
|
|
13847
14202
|
}
|
|
@@ -14374,20 +14729,21 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14374
14729
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14375
14730
|
if (fileContent) relativeFilePath = KILO_JSON_FILE_NAME;
|
|
14376
14731
|
}
|
|
14377
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14378
|
-
const json = (0, jsonc_parser.parse)(fileContent);
|
|
14379
14732
|
const { mcp: convertedMcp, tools: mcpTools } = convertToKiloFormat(rulesyncMcp.getMcpServers());
|
|
14380
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14381
|
-
const newJson = {
|
|
14382
|
-
...jsonWithoutTools,
|
|
14383
|
-
mcp: convertedMcp,
|
|
14384
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14385
|
-
};
|
|
14386
14733
|
return new KiloMcp({
|
|
14387
14734
|
outputRoot,
|
|
14388
14735
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14389
14736
|
relativeFilePath,
|
|
14390
|
-
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
|
+
}),
|
|
14391
14747
|
validate
|
|
14392
14748
|
});
|
|
14393
14749
|
}
|
|
@@ -14416,15 +14772,17 @@ var KiloMcp = class KiloMcp extends ToolMcp {
|
|
|
14416
14772
|
const json = fileContent ? (0, jsonc_parser.parse)(fileContent) : {};
|
|
14417
14773
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14418
14774
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14419
|
-
const newJson = {
|
|
14420
|
-
...json,
|
|
14421
|
-
instructions: mergedInstructions
|
|
14422
|
-
};
|
|
14423
14775
|
return new KiloMcp({
|
|
14424
14776
|
outputRoot,
|
|
14425
14777
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14426
14778
|
relativeFilePath,
|
|
14427
|
-
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
|
+
}),
|
|
14428
14786
|
validate
|
|
14429
14787
|
});
|
|
14430
14788
|
}
|
|
@@ -14696,23 +15054,24 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14696
15054
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
14697
15055
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
14698
15056
|
}
|
|
14699
|
-
if (!fileContent) fileContent = JSON.stringify({ mcp: {} }, null, 2);
|
|
14700
|
-
const json = (0, jsonc_parser.parse)(fileContent);
|
|
14701
15057
|
const { mcp: convertedMcp, tools: mcpTools } = convertToOpencodeFormat(convertEnvVarRefsToToolFormat({
|
|
14702
15058
|
mcpServers: rulesyncMcp.getMcpServers(),
|
|
14703
15059
|
replacement: "{env:$1}"
|
|
14704
15060
|
}));
|
|
14705
|
-
const { tools: _existingTools, ...jsonWithoutTools } = json;
|
|
14706
|
-
const newJson = {
|
|
14707
|
-
...jsonWithoutTools,
|
|
14708
|
-
mcp: convertedMcp,
|
|
14709
|
-
...Object.keys(mcpTools).length > 0 && { tools: mcpTools }
|
|
14710
|
-
};
|
|
14711
15061
|
return new OpencodeMcp({
|
|
14712
15062
|
outputRoot,
|
|
14713
15063
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14714
15064
|
relativeFilePath,
|
|
14715
|
-
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
|
+
}),
|
|
14716
15075
|
validate
|
|
14717
15076
|
});
|
|
14718
15077
|
}
|
|
@@ -14747,15 +15106,17 @@ var OpencodeMcp = class OpencodeMcp extends ToolMcp {
|
|
|
14747
15106
|
const json = fileContent ? (0, jsonc_parser.parse)(fileContent) : {};
|
|
14748
15107
|
const existingInstructions = Array.isArray(json.instructions) ? json.instructions.filter((entry) => typeof entry === "string") : [];
|
|
14749
15108
|
const mergedInstructions = Array.from(/* @__PURE__ */ new Set([...existingInstructions, ...instructions])).toSorted();
|
|
14750
|
-
const newJson = {
|
|
14751
|
-
...json,
|
|
14752
|
-
instructions: mergedInstructions
|
|
14753
|
-
};
|
|
14754
15109
|
return new OpencodeMcp({
|
|
14755
15110
|
outputRoot,
|
|
14756
15111
|
relativeDirPath: basePaths.relativeDirPath,
|
|
14757
15112
|
relativeFilePath,
|
|
14758
|
-
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
|
+
}),
|
|
14759
15120
|
validate
|
|
14760
15121
|
});
|
|
14761
15122
|
}
|
|
@@ -14865,16 +15226,19 @@ var QwencodeMcp = class QwencodeMcp extends ToolMcp {
|
|
|
14865
15226
|
}
|
|
14866
15227
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14867
15228
|
const paths = this.getSettablePaths({ global });
|
|
14868
|
-
const
|
|
14869
|
-
const
|
|
14870
|
-
...JSON.parse(fileContent),
|
|
14871
|
-
mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers())
|
|
14872
|
-
};
|
|
15229
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15230
|
+
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({ mcpServers: {} }, null, 2));
|
|
14873
15231
|
return new QwencodeMcp({
|
|
14874
15232
|
outputRoot,
|
|
14875
15233
|
relativeDirPath: paths.relativeDirPath,
|
|
14876
15234
|
relativeFilePath: paths.relativeFilePath,
|
|
14877
|
-
fileContent:
|
|
15235
|
+
fileContent: applySharedConfigPatch({
|
|
15236
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15237
|
+
feature: "mcp",
|
|
15238
|
+
existingContent,
|
|
15239
|
+
patch: { mcpServers: convertToQwencodeFormat(rulesyncMcp.getMcpServers()) },
|
|
15240
|
+
filePath
|
|
15241
|
+
}),
|
|
14878
15242
|
validate
|
|
14879
15243
|
});
|
|
14880
15244
|
}
|
|
@@ -14959,13 +15323,20 @@ var ReasonixMcp = class ReasonixMcp extends ToolMcp {
|
|
|
14959
15323
|
}
|
|
14960
15324
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
14961
15325
|
const paths = this.getSettablePaths({ global });
|
|
14962
|
-
const
|
|
14963
|
-
|
|
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));
|
|
14964
15329
|
return new ReasonixMcp({
|
|
14965
15330
|
outputRoot,
|
|
14966
15331
|
relativeDirPath: paths.relativeDirPath,
|
|
14967
15332
|
relativeFilePath: paths.relativeFilePath,
|
|
14968
|
-
fileContent:
|
|
15333
|
+
fileContent: applySharedConfigPatch({
|
|
15334
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15335
|
+
feature: "mcp",
|
|
15336
|
+
existingContent,
|
|
15337
|
+
patch: { plugins },
|
|
15338
|
+
filePath
|
|
15339
|
+
}),
|
|
14969
15340
|
validate,
|
|
14970
15341
|
global
|
|
14971
15342
|
});
|
|
@@ -15440,13 +15811,20 @@ var VibeMcp = class VibeMcp extends ToolMcp {
|
|
|
15440
15811
|
}
|
|
15441
15812
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15442
15813
|
const paths = this.getSettablePaths({ global });
|
|
15443
|
-
const
|
|
15444
|
-
|
|
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));
|
|
15445
15817
|
return new VibeMcp({
|
|
15446
15818
|
outputRoot,
|
|
15447
15819
|
relativeDirPath: paths.relativeDirPath,
|
|
15448
15820
|
relativeFilePath: paths.relativeFilePath,
|
|
15449
|
-
fileContent:
|
|
15821
|
+
fileContent: applySharedConfigPatch({
|
|
15822
|
+
fileKey: sharedConfigFileKey(paths),
|
|
15823
|
+
feature: "mcp",
|
|
15824
|
+
existingContent,
|
|
15825
|
+
patch: { mcp_servers: mcpServers },
|
|
15826
|
+
filePath
|
|
15827
|
+
}),
|
|
15450
15828
|
validate,
|
|
15451
15829
|
global
|
|
15452
15830
|
});
|
|
@@ -15677,16 +16055,19 @@ var ZedMcp = class ZedMcp extends ToolMcp {
|
|
|
15677
16055
|
}
|
|
15678
16056
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15679
16057
|
const paths = this.getSettablePaths({ global });
|
|
15680
|
-
const
|
|
15681
|
-
const
|
|
15682
|
-
...JSON.parse(fileContent),
|
|
15683
|
-
context_servers: rulesyncMcp.getMcpServers()
|
|
15684
|
-
};
|
|
16058
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
16059
|
+
const existingContent = await readOrInitializeFileContent(filePath, "{}");
|
|
15685
16060
|
return new ZedMcp({
|
|
15686
16061
|
outputRoot,
|
|
15687
16062
|
relativeDirPath: paths.relativeDirPath,
|
|
15688
16063
|
relativeFilePath: paths.relativeFilePath,
|
|
15689
|
-
fileContent:
|
|
16064
|
+
fileContent: applySharedConfigPatch({
|
|
16065
|
+
fileKey: sharedConfigFileKey(paths),
|
|
16066
|
+
feature: "mcp",
|
|
16067
|
+
existingContent,
|
|
16068
|
+
patch: { context_servers: rulesyncMcp.getMcpServers() },
|
|
16069
|
+
filePath
|
|
16070
|
+
}),
|
|
15690
16071
|
validate
|
|
15691
16072
|
});
|
|
15692
16073
|
}
|
|
@@ -16855,25 +17236,29 @@ var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
|
16855
17236
|
const override = config.amp;
|
|
16856
17237
|
const authoredExtras = override?.permissions ? toPermissionsList(override.permissions) : [];
|
|
16857
17238
|
const preservedDelegates = override?.permissions ? [] : toPermissionsList(json[AMP_PERMISSIONS_KEY]).filter((entry) => entry.action === "delegate");
|
|
16858
|
-
const newJson = {
|
|
16859
|
-
...json,
|
|
16860
|
-
[AMP_TOOLS_DISABLE_KEY]: disable
|
|
16861
|
-
};
|
|
16862
17239
|
const mergedPermissions = mergeAmpPermissions([
|
|
16863
17240
|
...permissions,
|
|
16864
17241
|
...authoredExtras,
|
|
16865
17242
|
...preservedDelegates
|
|
16866
17243
|
]);
|
|
16867
|
-
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
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;
|
|
16872
17251
|
return new AmpPermissions({
|
|
16873
17252
|
outputRoot,
|
|
16874
17253
|
relativeDirPath: basePaths.relativeDirPath,
|
|
16875
17254
|
relativeFilePath,
|
|
16876
|
-
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
|
+
}),
|
|
16877
17262
|
validate: true
|
|
16878
17263
|
});
|
|
16879
17264
|
}
|
|
@@ -17815,11 +18200,13 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
|
|
|
17815
18200
|
...preservedBasicEntries,
|
|
17816
18201
|
...authoredBasics
|
|
17817
18202
|
]);
|
|
17818
|
-
const
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
18203
|
+
const fileContent = applySharedConfigPatch({
|
|
18204
|
+
fileKey: sharedConfigFileKey(paths),
|
|
18205
|
+
feature: "permissions",
|
|
18206
|
+
existingContent,
|
|
18207
|
+
patch: { toolPermissions: [...specialEntries, ...sortedBasic] },
|
|
18208
|
+
filePath
|
|
18209
|
+
});
|
|
17823
18210
|
return new AugmentcodePermissions({
|
|
17824
18211
|
outputRoot,
|
|
17825
18212
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -18411,13 +18798,6 @@ const WORKSPACE_WIDE_WRITE_PATTERNS = /* @__PURE__ */ new Set([
|
|
|
18411
18798
|
]);
|
|
18412
18799
|
const CODEX_MINIMAL_KEY = ":minimal";
|
|
18413
18800
|
const GLOBAL_WILDCARD_DOMAIN = "*";
|
|
18414
|
-
const CODEXCLI_OVERRIDE_KEYS = [
|
|
18415
|
-
"approval_policy",
|
|
18416
|
-
"sandbox_mode",
|
|
18417
|
-
"sandbox_workspace_write",
|
|
18418
|
-
"apps",
|
|
18419
|
-
"approvals_reviewer"
|
|
18420
|
-
];
|
|
18421
18801
|
var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
18422
18802
|
static getSettablePaths(_options = {}) {
|
|
18423
18803
|
return {
|
|
@@ -18441,26 +18821,27 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18441
18821
|
}
|
|
18442
18822
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
18443
18823
|
const paths = this.getSettablePaths({ global });
|
|
18444
|
-
const
|
|
18445
|
-
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({})));
|
|
18446
18827
|
const newProfile = convertRulesyncToCodexProfile({
|
|
18447
18828
|
config: rulesyncPermissions.getJson(),
|
|
18448
18829
|
logger
|
|
18449
18830
|
});
|
|
18450
|
-
const permissionsTable = toMutableTable(
|
|
18831
|
+
const permissionsTable = toMutableTable(existing.permissions);
|
|
18451
18832
|
const { profile: existingProfile, domainsHadUnknown: existingDomainsHadUnknown } = toCodexProfile(permissionsTable[RULESYNC_PROFILE_NAME]);
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
|
|
18833
|
+
warnAboutPreservedProfileState({
|
|
18834
|
+
existingProfile,
|
|
18835
|
+
newProfile,
|
|
18836
|
+
existingDomainsHadUnknown,
|
|
18837
|
+
logger
|
|
18838
|
+
});
|
|
18456
18839
|
permissionsTable[RULESYNC_PROFILE_NAME] = mergeWithExistingProfile({
|
|
18457
18840
|
newProfile,
|
|
18458
18841
|
existingProfile
|
|
18459
18842
|
});
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
applyCodexcliOverride({
|
|
18463
|
-
parsed,
|
|
18843
|
+
const overridePatch = computeCodexcliOverridePatch({
|
|
18844
|
+
existing,
|
|
18464
18845
|
override: rulesyncPermissions.getJson().codexcli,
|
|
18465
18846
|
logger
|
|
18466
18847
|
});
|
|
@@ -18468,7 +18849,17 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
|
|
|
18468
18849
|
outputRoot,
|
|
18469
18850
|
relativeDirPath: paths.relativeDirPath,
|
|
18470
18851
|
relativeFilePath: paths.relativeFilePath,
|
|
18471
|
-
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
|
+
}),
|
|
18472
18863
|
validate
|
|
18473
18864
|
});
|
|
18474
18865
|
}
|
|
@@ -18638,6 +19029,12 @@ function toCodexProfile(value) {
|
|
|
18638
19029
|
domainsHadUnknown
|
|
18639
19030
|
};
|
|
18640
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
|
+
}
|
|
18641
19038
|
function mergeWithExistingProfile({ newProfile, existingProfile }) {
|
|
18642
19039
|
if (!existingProfile) return newProfile;
|
|
18643
19040
|
const mergedNetwork = { ...newProfile.network };
|
|
@@ -18688,8 +19085,9 @@ function toMutableTable(value) {
|
|
|
18688
19085
|
function isPlainObject(value) {
|
|
18689
19086
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18690
19087
|
}
|
|
18691
|
-
function
|
|
18692
|
-
|
|
19088
|
+
function computeCodexcliOverridePatch({ existing, override, logger }) {
|
|
19089
|
+
const patch = {};
|
|
19090
|
+
if (!override) return patch;
|
|
18693
19091
|
const allowed = new Set(CODEXCLI_OVERRIDE_KEYS);
|
|
18694
19092
|
for (const [key, value] of Object.entries(override)) {
|
|
18695
19093
|
if (!allowed.has(key)) {
|
|
@@ -18697,12 +19095,13 @@ function applyCodexcliOverride({ parsed, override, logger }) {
|
|
|
18697
19095
|
continue;
|
|
18698
19096
|
}
|
|
18699
19097
|
if (value === void 0) continue;
|
|
18700
|
-
const
|
|
18701
|
-
|
|
18702
|
-
...
|
|
19098
|
+
const existingValue = existing[key];
|
|
19099
|
+
patch[key] = isPlainObject(existingValue) && isPlainObject(value) ? {
|
|
19100
|
+
...existingValue,
|
|
18703
19101
|
...value
|
|
18704
19102
|
} : value;
|
|
18705
19103
|
}
|
|
19104
|
+
return patch;
|
|
18706
19105
|
}
|
|
18707
19106
|
function extractCodexcliOverride(table) {
|
|
18708
19107
|
const override = {};
|
|
@@ -19263,15 +19662,17 @@ var DevinPermissions = class DevinPermissions extends ToolPermissions {
|
|
|
19263
19662
|
else delete mergedPermissions.ask;
|
|
19264
19663
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
19265
19664
|
else delete mergedPermissions.deny;
|
|
19266
|
-
const merged = {
|
|
19267
|
-
...settings,
|
|
19268
|
-
permissions: mergedPermissions
|
|
19269
|
-
};
|
|
19270
19665
|
return new DevinPermissions({
|
|
19271
19666
|
outputRoot,
|
|
19272
19667
|
relativeDirPath: paths.relativeDirPath,
|
|
19273
19668
|
relativeFilePath: paths.relativeFilePath,
|
|
19274
|
-
fileContent:
|
|
19669
|
+
fileContent: applySharedConfigPatch({
|
|
19670
|
+
fileKey: sharedConfigFileKey(paths),
|
|
19671
|
+
feature: "permissions",
|
|
19672
|
+
existingContent,
|
|
19673
|
+
patch: { permissions: mergedPermissions },
|
|
19674
|
+
filePath
|
|
19675
|
+
}),
|
|
19275
19676
|
validate
|
|
19276
19677
|
});
|
|
19277
19678
|
}
|
|
@@ -19880,23 +20281,31 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
19880
20281
|
const config = rulesyncPermissions.getJson();
|
|
19881
20282
|
const existingPermission = isRecord(parsed[GROKCLI_PERMISSION_KEY]) ? parsed[GROKCLI_PERMISSION_KEY] : {};
|
|
19882
20283
|
const buckets = buildGrokPermissionArrays(config, existingPermission, logger);
|
|
19883
|
-
|
|
20284
|
+
const permission = {
|
|
19884
20285
|
...existingPermission,
|
|
19885
20286
|
allow: buckets.allow,
|
|
19886
20287
|
deny: buckets.deny,
|
|
19887
20288
|
ask: buckets.ask
|
|
19888
20289
|
};
|
|
19889
20290
|
const mode = deriveGrokPermissionMode(config);
|
|
19890
|
-
const
|
|
19891
|
-
|
|
19892
|
-
...existingUi,
|
|
20291
|
+
const ui = {
|
|
20292
|
+
...isRecord(parsed[GROKCLI_UI_KEY]) ? parsed[GROKCLI_UI_KEY] : {},
|
|
19893
20293
|
[GROKCLI_PERMISSION_MODE_KEY]: mode
|
|
19894
20294
|
};
|
|
19895
20295
|
return new GrokcliPermissions({
|
|
19896
20296
|
outputRoot,
|
|
19897
20297
|
relativeDirPath: paths.relativeDirPath,
|
|
19898
20298
|
relativeFilePath: paths.relativeFilePath,
|
|
19899
|
-
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
|
+
}),
|
|
19900
20309
|
validate: true,
|
|
19901
20310
|
global: true
|
|
19902
20311
|
});
|
|
@@ -20599,7 +21008,16 @@ var KiroPermissions = class KiroPermissions extends ToolPermissions {
|
|
|
20599
21008
|
outputRoot,
|
|
20600
21009
|
relativeDirPath: paths.relativeDirPath,
|
|
20601
21010
|
relativeFilePath: paths.relativeFilePath,
|
|
20602
|
-
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
|
+
}),
|
|
20603
21021
|
validate
|
|
20604
21022
|
});
|
|
20605
21023
|
}
|
|
@@ -20896,21 +21314,22 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
20896
21314
|
fileContent = await readFileContentOrNull(jsonPath);
|
|
20897
21315
|
if (fileContent) relativeFilePath = OPENCODE_JSON_FILE_NAME;
|
|
20898
21316
|
}
|
|
20899
|
-
const parsed = (0, jsonc_parser.parse)(fileContent ?? "{}");
|
|
20900
21317
|
const rulesyncJson = rulesyncPermissions.getJson();
|
|
20901
21318
|
const overridePermission = rulesyncJson.opencode?.permission ?? {};
|
|
20902
|
-
const nextJson = {
|
|
20903
|
-
...parsed,
|
|
20904
|
-
permission: {
|
|
20905
|
-
...rulesyncJson.permission,
|
|
20906
|
-
...overridePermission
|
|
20907
|
-
}
|
|
20908
|
-
};
|
|
20909
21319
|
return new OpencodePermissions({
|
|
20910
21320
|
outputRoot,
|
|
20911
21321
|
relativeDirPath: basePaths.relativeDirPath,
|
|
20912
21322
|
relativeFilePath,
|
|
20913
|
-
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
|
+
}),
|
|
20914
21333
|
validate: true
|
|
20915
21334
|
});
|
|
20916
21335
|
}
|
|
@@ -21119,20 +21538,23 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
21119
21538
|
else delete mergedPermissions.ask;
|
|
21120
21539
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21121
21540
|
else delete mergedPermissions.deny;
|
|
21122
|
-
const
|
|
21123
|
-
...settings,
|
|
21124
|
-
permissions: mergedPermissions
|
|
21125
|
-
};
|
|
21541
|
+
const patch = { permissions: mergedPermissions };
|
|
21126
21542
|
const override = config.qwencode;
|
|
21127
|
-
if (override?.tools !== void 0)
|
|
21543
|
+
if (override?.tools !== void 0) patch.tools = {
|
|
21128
21544
|
...asPlainRecord(settings.tools),
|
|
21129
21545
|
...asPlainRecord(override.tools)
|
|
21130
21546
|
};
|
|
21131
|
-
if (override?.security !== void 0)
|
|
21547
|
+
if (override?.security !== void 0) patch.security = {
|
|
21132
21548
|
...asPlainRecord(settings.security),
|
|
21133
21549
|
...asPlainRecord(override.security)
|
|
21134
21550
|
};
|
|
21135
|
-
const fileContent =
|
|
21551
|
+
const fileContent = applySharedConfigPatch({
|
|
21552
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21553
|
+
feature: "permissions",
|
|
21554
|
+
existingContent,
|
|
21555
|
+
patch,
|
|
21556
|
+
filePath
|
|
21557
|
+
});
|
|
21136
21558
|
return new QwencodePermissions({
|
|
21137
21559
|
outputRoot,
|
|
21138
21560
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -21367,7 +21789,9 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21367
21789
|
}
|
|
21368
21790
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21369
21791
|
const paths = this.getSettablePaths({ global });
|
|
21370
|
-
const
|
|
21792
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
21793
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
21794
|
+
const parsed = parseReasonixConfig(existingContent);
|
|
21371
21795
|
const config = rulesyncPermissions.getJson();
|
|
21372
21796
|
const { allow, ask, deny } = convertRulesyncToReasonixPermissions(config);
|
|
21373
21797
|
const managedToolNames = new Set(Object.keys(config.permission).map((category) => toReasonixToolName(category)));
|
|
@@ -21392,25 +21816,27 @@ var ReasonixPermissions = class ReasonixPermissions extends ToolPermissions {
|
|
|
21392
21816
|
else delete mergedPermissions.ask;
|
|
21393
21817
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21394
21818
|
else delete mergedPermissions.deny;
|
|
21395
|
-
const
|
|
21396
|
-
...parsed,
|
|
21397
|
-
permissions: mergedPermissions
|
|
21398
|
-
};
|
|
21819
|
+
const patch = { permissions: mergedPermissions };
|
|
21399
21820
|
const override = config.reasonix;
|
|
21400
|
-
if (override?.sandbox !== void 0)
|
|
21821
|
+
if (override?.sandbox !== void 0) patch.sandbox = {
|
|
21401
21822
|
...asReasonixRecord(parsed.sandbox),
|
|
21402
21823
|
...asReasonixRecord(override.sandbox)
|
|
21403
21824
|
};
|
|
21404
|
-
if (override?.agent !== void 0)
|
|
21825
|
+
if (override?.agent !== void 0) patch.agent = {
|
|
21405
21826
|
...asReasonixRecord(parsed.agent),
|
|
21406
21827
|
...asReasonixRecord(override.agent)
|
|
21407
21828
|
};
|
|
21408
|
-
const fileContent = smol_toml.stringify(merged);
|
|
21409
21829
|
return new ReasonixPermissions({
|
|
21410
21830
|
outputRoot,
|
|
21411
21831
|
relativeDirPath: paths.relativeDirPath,
|
|
21412
21832
|
relativeFilePath: paths.relativeFilePath,
|
|
21413
|
-
fileContent
|
|
21833
|
+
fileContent: applySharedConfigPatch({
|
|
21834
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21835
|
+
feature: "permissions",
|
|
21836
|
+
existingContent,
|
|
21837
|
+
patch,
|
|
21838
|
+
filePath
|
|
21839
|
+
}),
|
|
21414
21840
|
validate
|
|
21415
21841
|
});
|
|
21416
21842
|
}
|
|
@@ -21981,7 +22407,9 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
21981
22407
|
}
|
|
21982
22408
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, validate = true, logger, global = false }) {
|
|
21983
22409
|
const paths = this.getSettablePaths({ global });
|
|
21984
|
-
const
|
|
22410
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
22411
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
22412
|
+
const config = parseVibeConfig(existingContent);
|
|
21985
22413
|
const permission = rulesyncPermissions.getJson().permission;
|
|
21986
22414
|
const tools = toVibeToolsRecord(config.tools);
|
|
21987
22415
|
const enabledTools = new Set(toStringArray(config.enabled_tools));
|
|
@@ -22026,16 +22454,21 @@ var VibePermissions = class VibePermissions extends ToolPermissions {
|
|
|
22026
22454
|
tools[vibeToolName] = nextTool;
|
|
22027
22455
|
}
|
|
22028
22456
|
applyVibeSensitivePatterns(tools, rulesyncPermissions.getJson().vibe);
|
|
22029
|
-
config.tools = tools;
|
|
22030
|
-
if (enabledTools.size > 0) config.enabled_tools = [...enabledTools].toSorted();
|
|
22031
|
-
else delete config.enabled_tools;
|
|
22032
|
-
if (disabledTools.size > 0) config.disabled_tools = [...disabledTools].toSorted();
|
|
22033
|
-
else delete config.disabled_tools;
|
|
22034
22457
|
return new VibePermissions({
|
|
22035
22458
|
outputRoot,
|
|
22036
22459
|
relativeDirPath: paths.relativeDirPath,
|
|
22037
22460
|
relativeFilePath: paths.relativeFilePath,
|
|
22038
|
-
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
|
+
}),
|
|
22039
22472
|
validate,
|
|
22040
22473
|
global
|
|
22041
22474
|
});
|
|
@@ -22498,24 +22931,26 @@ var ZedPermissions = class ZedPermissions extends ToolPermissions {
|
|
|
22498
22931
|
}
|
|
22499
22932
|
const managedToolNames = new Set(Object.keys(managedTools));
|
|
22500
22933
|
const preservedTools = Object.fromEntries(Object.entries(existingTools).filter(([toolName]) => !managedToolNames.has(toolName)));
|
|
22501
|
-
const mergedSettings = {
|
|
22502
|
-
...settings,
|
|
22503
|
-
agent: {
|
|
22504
|
-
...agent,
|
|
22505
|
-
tool_permissions: {
|
|
22506
|
-
...toolPermissions,
|
|
22507
|
-
tools: {
|
|
22508
|
-
...preservedTools,
|
|
22509
|
-
...managedTools
|
|
22510
|
-
}
|
|
22511
|
-
}
|
|
22512
|
-
}
|
|
22513
|
-
};
|
|
22514
22934
|
return new ZedPermissions({
|
|
22515
22935
|
outputRoot,
|
|
22516
22936
|
relativeDirPath: paths.relativeDirPath,
|
|
22517
22937
|
relativeFilePath: paths.relativeFilePath,
|
|
22518
|
-
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
|
+
}),
|
|
22519
22954
|
validate: true
|
|
22520
22955
|
});
|
|
22521
22956
|
}
|
|
@@ -38205,8 +38640,13 @@ const collectFactoryPaths = (factory) => [...settablePathsForScope({
|
|
|
38205
38640
|
* Derive, from the processor registry, every on-disk file that two or more
|
|
38206
38641
|
* features read-modify-write. Source of truth the generation step graph's
|
|
38207
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).
|
|
38208
38648
|
*/
|
|
38209
|
-
const deriveSharedFileWriters = () => {
|
|
38649
|
+
const deriveSharedFileWriters = ({ minWriters = 2 } = {}) => {
|
|
38210
38650
|
const byKey = /* @__PURE__ */ new Map();
|
|
38211
38651
|
const pathByKey = /* @__PURE__ */ new Map();
|
|
38212
38652
|
for (const entry of PROCESSOR_REGISTRY) {
|
|
@@ -38232,7 +38672,7 @@ const deriveSharedFileWriters = () => {
|
|
|
38232
38672
|
}
|
|
38233
38673
|
const writers = [];
|
|
38234
38674
|
for (const [key, features] of byKey) {
|
|
38235
|
-
if (features.size <
|
|
38675
|
+
if (features.size < minWriters) continue;
|
|
38236
38676
|
const path = pathByKey.get(key);
|
|
38237
38677
|
const toolsByFeature = /* @__PURE__ */ new Map();
|
|
38238
38678
|
for (const [feature, tools] of features) toolsByFeature.set(feature, [...tools].toSorted());
|