rulesync 8.15.0 → 8.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-UMJWBQ2X.js → chunk-3DM6NLND.js} +135 -18
- package/dist/cli/index.cjs +140 -20
- package/dist/cli/index.js +6 -3
- package/dist/index.cjs +135 -18
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -473,7 +473,8 @@ function validateOutputRoot(outputRoot) {
|
|
|
473
473
|
throw new Error("outputRoot cannot be an empty string");
|
|
474
474
|
}
|
|
475
475
|
if (isAbsolute(outputRoot)) {
|
|
476
|
-
const
|
|
476
|
+
const separatorRegex = process.platform === "win32" ? /[/\\]/ : /\//;
|
|
477
|
+
const segments = outputRoot.split(separatorRegex);
|
|
477
478
|
if (segments.includes("..")) {
|
|
478
479
|
throw new Error(`Path traversal detected: ${outputRoot}`);
|
|
479
480
|
}
|
|
@@ -10092,6 +10093,7 @@ var ToolPermissions = class extends ToolFile {
|
|
|
10092
10093
|
};
|
|
10093
10094
|
|
|
10094
10095
|
// src/features/permissions/augmentcode-permissions.ts
|
|
10096
|
+
var moduleLogger = new ConsoleLogger();
|
|
10095
10097
|
var AugmentPermissionTypeSchema = z30.enum(["allow", "deny", "ask-user"]);
|
|
10096
10098
|
var AugmentToolPermissionSchema = z30.looseObject({
|
|
10097
10099
|
toolName: z30.string(),
|
|
@@ -10183,6 +10185,33 @@ function shellRegexToGlob(regex) {
|
|
|
10183
10185
|
}
|
|
10184
10186
|
return glob;
|
|
10185
10187
|
}
|
|
10188
|
+
function isShellRegexRoundtrippable(regex) {
|
|
10189
|
+
if (!regex.startsWith("^") || !regex.endsWith("$")) {
|
|
10190
|
+
return false;
|
|
10191
|
+
}
|
|
10192
|
+
const body = regex.slice(1, -1);
|
|
10193
|
+
let i = 0;
|
|
10194
|
+
while (i < body.length) {
|
|
10195
|
+
const ch = body[i];
|
|
10196
|
+
if (ch === "\\" && i + 1 < body.length) {
|
|
10197
|
+
i += 2;
|
|
10198
|
+
continue;
|
|
10199
|
+
}
|
|
10200
|
+
if (ch === "." && body[i + 1] === "*") {
|
|
10201
|
+
i += 2;
|
|
10202
|
+
continue;
|
|
10203
|
+
}
|
|
10204
|
+
if (ch === ".") {
|
|
10205
|
+
i += 1;
|
|
10206
|
+
continue;
|
|
10207
|
+
}
|
|
10208
|
+
if (/[$^|+?*(){}[\]]/.test(ch ?? "")) {
|
|
10209
|
+
return false;
|
|
10210
|
+
}
|
|
10211
|
+
i += 1;
|
|
10212
|
+
}
|
|
10213
|
+
return true;
|
|
10214
|
+
}
|
|
10186
10215
|
var MANAGED_AUGMENT_TOOL_NAMES = new Set(Object.values(CANONICAL_TO_AUGMENT_TOOL_NAMES));
|
|
10187
10216
|
var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissions {
|
|
10188
10217
|
constructor(params) {
|
|
@@ -10190,6 +10219,12 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10190
10219
|
...params,
|
|
10191
10220
|
fileContent: params.fileContent ?? "{}"
|
|
10192
10221
|
});
|
|
10222
|
+
if (params.validate) {
|
|
10223
|
+
const result = this.validate();
|
|
10224
|
+
if (!result.success) {
|
|
10225
|
+
throw result.error;
|
|
10226
|
+
}
|
|
10227
|
+
}
|
|
10193
10228
|
}
|
|
10194
10229
|
isDeletable() {
|
|
10195
10230
|
return false;
|
|
@@ -10283,14 +10318,27 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10283
10318
|
);
|
|
10284
10319
|
}
|
|
10285
10320
|
const config = convertAugmentToRulesyncPermissions({
|
|
10286
|
-
entries: settings.toolPermissions ?? []
|
|
10321
|
+
entries: settings.toolPermissions ?? [],
|
|
10322
|
+
logger: moduleLogger
|
|
10287
10323
|
});
|
|
10288
10324
|
return this.toRulesyncPermissionsDefault({
|
|
10289
10325
|
fileContent: JSON.stringify(config, null, 2)
|
|
10290
10326
|
});
|
|
10291
10327
|
}
|
|
10292
10328
|
validate() {
|
|
10293
|
-
|
|
10329
|
+
try {
|
|
10330
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10331
|
+
const result = AugmentSettingsSchema.safeParse(parsed);
|
|
10332
|
+
if (!result.success) {
|
|
10333
|
+
return { success: false, error: result.error };
|
|
10334
|
+
}
|
|
10335
|
+
return { success: true, error: null };
|
|
10336
|
+
} catch (error) {
|
|
10337
|
+
return {
|
|
10338
|
+
success: false,
|
|
10339
|
+
error: new Error(`Failed to parse AugmentCode permissions JSON: ${formatError(error)}`)
|
|
10340
|
+
};
|
|
10341
|
+
}
|
|
10294
10342
|
}
|
|
10295
10343
|
static forDeletion({
|
|
10296
10344
|
outputRoot = process.cwd(),
|
|
@@ -10388,7 +10436,8 @@ function sortAugmentEntries(entries) {
|
|
|
10388
10436
|
return decorated.map((d) => d.entry);
|
|
10389
10437
|
}
|
|
10390
10438
|
function convertAugmentToRulesyncPermissions({
|
|
10391
|
-
entries
|
|
10439
|
+
entries,
|
|
10440
|
+
logger
|
|
10392
10441
|
}) {
|
|
10393
10442
|
const actionPriority = {
|
|
10394
10443
|
deny: 2,
|
|
@@ -10399,7 +10448,27 @@ function convertAugmentToRulesyncPermissions({
|
|
|
10399
10448
|
for (const entry of entries) {
|
|
10400
10449
|
const canonical = toCanonicalToolName(entry.toolName);
|
|
10401
10450
|
const action = augmentTypeToAction(entry.permission.type);
|
|
10402
|
-
|
|
10451
|
+
let pattern;
|
|
10452
|
+
if (entry.toolName === "launch-process" && entry.shellInputRegex) {
|
|
10453
|
+
const regex = entry.shellInputRegex;
|
|
10454
|
+
if (isShellRegexRoundtrippable(regex)) {
|
|
10455
|
+
pattern = shellRegexToGlob(regex);
|
|
10456
|
+
} else {
|
|
10457
|
+
if (action === "deny") {
|
|
10458
|
+
logger?.warn(
|
|
10459
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as the catch-all '*' pattern (fail-closed) so the deny rule cannot be silently narrowed on regenerate.`
|
|
10460
|
+
);
|
|
10461
|
+
pattern = "*";
|
|
10462
|
+
} else {
|
|
10463
|
+
pattern = shellRegexToGlob(regex);
|
|
10464
|
+
logger?.warn(
|
|
10465
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as glob '${pattern}'; the rule may match a different set of inputs after regenerate.`
|
|
10466
|
+
);
|
|
10467
|
+
}
|
|
10468
|
+
}
|
|
10469
|
+
} else {
|
|
10470
|
+
pattern = "*";
|
|
10471
|
+
}
|
|
10403
10472
|
if (!permission[canonical]) {
|
|
10404
10473
|
permission[canonical] = {};
|
|
10405
10474
|
}
|
|
@@ -10654,6 +10723,12 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10654
10723
|
...params,
|
|
10655
10724
|
fileContent: params.fileContent ?? "{}"
|
|
10656
10725
|
});
|
|
10726
|
+
if (params.validate) {
|
|
10727
|
+
const result = this.validate();
|
|
10728
|
+
if (!result.success) {
|
|
10729
|
+
throw result.error;
|
|
10730
|
+
}
|
|
10731
|
+
}
|
|
10657
10732
|
}
|
|
10658
10733
|
isDeletable() {
|
|
10659
10734
|
return false;
|
|
@@ -10792,7 +10867,19 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10792
10867
|
});
|
|
10793
10868
|
}
|
|
10794
10869
|
validate() {
|
|
10795
|
-
|
|
10870
|
+
try {
|
|
10871
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10872
|
+
const result = ClineCommandPermissionsSchema.safeParse(parsed);
|
|
10873
|
+
if (!result.success) {
|
|
10874
|
+
return { success: false, error: result.error };
|
|
10875
|
+
}
|
|
10876
|
+
return { success: true, error: null };
|
|
10877
|
+
} catch (error) {
|
|
10878
|
+
return {
|
|
10879
|
+
success: false,
|
|
10880
|
+
error: new Error(`Failed to parse Cline permissions JSON: ${formatError(error)}`)
|
|
10881
|
+
};
|
|
10882
|
+
}
|
|
10796
10883
|
}
|
|
10797
10884
|
static forDeletion({
|
|
10798
10885
|
outputRoot = process.cwd(),
|
|
@@ -11385,7 +11472,7 @@ var RESERVED_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
|
11385
11472
|
"constructor",
|
|
11386
11473
|
"prototype"
|
|
11387
11474
|
]);
|
|
11388
|
-
var
|
|
11475
|
+
var moduleLogger2 = new ConsoleLogger();
|
|
11389
11476
|
var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
11390
11477
|
static getSettablePaths(_options = {}) {
|
|
11391
11478
|
return {
|
|
@@ -11414,7 +11501,7 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11414
11501
|
rulesyncPermissions,
|
|
11415
11502
|
validate = true,
|
|
11416
11503
|
global = false,
|
|
11417
|
-
logger =
|
|
11504
|
+
logger = moduleLogger2
|
|
11418
11505
|
}) {
|
|
11419
11506
|
const paths = this.getSettablePaths({ global });
|
|
11420
11507
|
const fileContent = buildGeminicliPolicyContent(rulesyncPermissions.getJson(), logger);
|
|
@@ -11439,31 +11526,31 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11439
11526
|
{ cause: error }
|
|
11440
11527
|
);
|
|
11441
11528
|
}
|
|
11442
|
-
const rules = extractRules(parsed,
|
|
11529
|
+
const rules = extractRules(parsed, moduleLogger2);
|
|
11443
11530
|
for (const [index, rule] of rules.entries()) {
|
|
11444
11531
|
const mappedCategory = Object.hasOwn(GEMINICLI_TO_RULESYNC_TOOL_NAME, rule.toolName) ? GEMINICLI_TO_RULESYNC_TOOL_NAME[rule.toolName] : void 0;
|
|
11445
11532
|
const category = mappedCategory ?? rule.toolName;
|
|
11446
11533
|
if (RESERVED_OBJECT_KEYS.has(category)) {
|
|
11447
|
-
|
|
11534
|
+
moduleLogger2.warn(
|
|
11448
11535
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: toolName "${rule.toolName}" maps to a reserved object key ("${category}") and would risk prototype pollution.`
|
|
11449
11536
|
);
|
|
11450
11537
|
continue;
|
|
11451
11538
|
}
|
|
11452
11539
|
const action = mapFromGeminicliDecision(rule.decision);
|
|
11453
11540
|
if (!action) {
|
|
11454
|
-
|
|
11541
|
+
moduleLogger2.warn(
|
|
11455
11542
|
`Skipping rule #${index} (toolName="${rule.toolName}", commandPrefix=${JSON.stringify(rule.commandPrefix)}, argsPattern=${JSON.stringify(rule.argsPattern)}) in ${this.getRelativeFilePath()}: unknown decision ${JSON.stringify(rule.decision)}`
|
|
11456
11543
|
);
|
|
11457
11544
|
continue;
|
|
11458
11545
|
}
|
|
11459
11546
|
if (rule.toolName === "run_shell_command" && rule.commandPrefix !== void 0 && rule.argsPattern !== void 0) {
|
|
11460
|
-
|
|
11547
|
+
moduleLogger2.warn(
|
|
11461
11548
|
`Rule #${index} in ${this.getRelativeFilePath()} sets both commandPrefix and argsPattern; rulesync will honor argsPattern and ignore commandPrefix=${JSON.stringify(rule.commandPrefix)}.`
|
|
11462
11549
|
);
|
|
11463
11550
|
}
|
|
11464
11551
|
const pattern = extractPattern(rule);
|
|
11465
11552
|
if (RESERVED_OBJECT_KEYS.has(pattern)) {
|
|
11466
|
-
|
|
11553
|
+
moduleLogger2.warn(
|
|
11467
11554
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: pattern "${pattern}" is a reserved object key.`
|
|
11468
11555
|
);
|
|
11469
11556
|
continue;
|
|
@@ -12232,7 +12319,7 @@ var QwenSettingsPermissionsSchema = z36.looseObject({
|
|
|
12232
12319
|
var QwenSettingsSchema = z36.looseObject({
|
|
12233
12320
|
permissions: z36.optional(QwenSettingsPermissionsSchema)
|
|
12234
12321
|
});
|
|
12235
|
-
var
|
|
12322
|
+
var moduleLogger3 = new ConsoleLogger();
|
|
12236
12323
|
var CANONICAL_TO_QWEN_TOOL_NAMES = {
|
|
12237
12324
|
bash: "Bash",
|
|
12238
12325
|
read: "Read",
|
|
@@ -12287,6 +12374,12 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12287
12374
|
...params,
|
|
12288
12375
|
fileContent: params.fileContent ?? "{}"
|
|
12289
12376
|
});
|
|
12377
|
+
if (params.validate) {
|
|
12378
|
+
const result = this.validate();
|
|
12379
|
+
if (!result.success) {
|
|
12380
|
+
throw result.error;
|
|
12381
|
+
}
|
|
12382
|
+
}
|
|
12290
12383
|
}
|
|
12291
12384
|
isDeletable() {
|
|
12292
12385
|
return false;
|
|
@@ -12408,7 +12501,19 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12408
12501
|
});
|
|
12409
12502
|
}
|
|
12410
12503
|
validate() {
|
|
12411
|
-
|
|
12504
|
+
try {
|
|
12505
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
12506
|
+
const result = QwenSettingsSchema.safeParse(parsed);
|
|
12507
|
+
if (!result.success) {
|
|
12508
|
+
return { success: false, error: result.error };
|
|
12509
|
+
}
|
|
12510
|
+
return { success: true, error: null };
|
|
12511
|
+
} catch (error) {
|
|
12512
|
+
return {
|
|
12513
|
+
success: false,
|
|
12514
|
+
error: new Error(`Failed to parse Qwen permissions JSON: ${formatError(error)}`)
|
|
12515
|
+
};
|
|
12516
|
+
}
|
|
12412
12517
|
}
|
|
12413
12518
|
static forDeletion({
|
|
12414
12519
|
outputRoot = process.cwd(),
|
|
@@ -12449,7 +12554,7 @@ function convertRulesyncToQwenPermissions(config) {
|
|
|
12449
12554
|
}
|
|
12450
12555
|
function convertQwenToRulesyncPermissions(params) {
|
|
12451
12556
|
const permission = {};
|
|
12452
|
-
const logger = params.logger ??
|
|
12557
|
+
const logger = params.logger ?? moduleLogger3;
|
|
12453
12558
|
const processEntries = (entries, action) => {
|
|
12454
12559
|
for (const entry of entries) {
|
|
12455
12560
|
const parsed = parseQwenPermissionEntry(entry, { logger });
|
|
@@ -21030,6 +21135,8 @@ var CopilotRuleFrontmatterSchema = z77.object({
|
|
|
21030
21135
|
applyTo: z77.optional(z77.string()),
|
|
21031
21136
|
excludeAgent: z77.optional(z77.union([z77.literal("code-review"), z77.literal("coding-agent")]))
|
|
21032
21137
|
});
|
|
21138
|
+
var normalizeRelativePath = (path4) => path4.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
21139
|
+
var sameRelativePath = (leftDir, leftFile, rightDir, rightFile) => normalizeRelativePath(join133(leftDir, leftFile)) === normalizeRelativePath(join133(rightDir, rightFile));
|
|
21033
21140
|
var CopilotRule = class _CopilotRule extends ToolRule {
|
|
21034
21141
|
frontmatter;
|
|
21035
21142
|
body;
|
|
@@ -21147,7 +21254,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21147
21254
|
global = false
|
|
21148
21255
|
}) {
|
|
21149
21256
|
const paths = this.getSettablePaths({ global });
|
|
21150
|
-
const isRoot = relativeDirPath ?
|
|
21257
|
+
const isRoot = relativeDirPath ? sameRelativePath(
|
|
21258
|
+
relativeDirPath,
|
|
21259
|
+
relativeFilePath,
|
|
21260
|
+
paths.root.relativeDirPath,
|
|
21261
|
+
paths.root.relativeFilePath
|
|
21262
|
+
) : relativeFilePath === paths.root.relativeFilePath;
|
|
21151
21263
|
const resolvedRelativeDirPath = relativeDirPath ?? (isRoot ? paths.root.relativeDirPath : paths.nonRoot?.relativeDirPath ?? paths.root.relativeDirPath);
|
|
21152
21264
|
if (isRoot) {
|
|
21153
21265
|
const relativePath2 = join133(paths.root.relativeDirPath, paths.root.relativeFilePath);
|
|
@@ -21191,7 +21303,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21191
21303
|
global = false
|
|
21192
21304
|
}) {
|
|
21193
21305
|
const paths = this.getSettablePaths({ global });
|
|
21194
|
-
const isRoot =
|
|
21306
|
+
const isRoot = sameRelativePath(
|
|
21307
|
+
relativeDirPath,
|
|
21308
|
+
relativeFilePath,
|
|
21309
|
+
paths.root.relativeDirPath,
|
|
21310
|
+
paths.root.relativeFilePath
|
|
21311
|
+
);
|
|
21195
21312
|
return new _CopilotRule({
|
|
21196
21313
|
outputRoot,
|
|
21197
21314
|
relativeDirPath,
|
package/dist/cli/index.cjs
CHANGED
|
@@ -282,7 +282,8 @@ function validateOutputRoot(outputRoot) {
|
|
|
282
282
|
throw new Error("outputRoot cannot be an empty string");
|
|
283
283
|
}
|
|
284
284
|
if ((0, import_node_path2.isAbsolute)(outputRoot)) {
|
|
285
|
-
const
|
|
285
|
+
const separatorRegex = process.platform === "win32" ? /[/\\]/ : /\//;
|
|
286
|
+
const segments = outputRoot.split(separatorRegex);
|
|
286
287
|
if (segments.includes("..")) {
|
|
287
288
|
throw new Error(`Path traversal detected: ${outputRoot}`);
|
|
288
289
|
}
|
|
@@ -10125,6 +10126,7 @@ var ToolPermissions = class extends ToolFile {
|
|
|
10125
10126
|
};
|
|
10126
10127
|
|
|
10127
10128
|
// src/features/permissions/augmentcode-permissions.ts
|
|
10129
|
+
var moduleLogger = new ConsoleLogger();
|
|
10128
10130
|
var AugmentPermissionTypeSchema = import_mini30.z.enum(["allow", "deny", "ask-user"]);
|
|
10129
10131
|
var AugmentToolPermissionSchema = import_mini30.z.looseObject({
|
|
10130
10132
|
toolName: import_mini30.z.string(),
|
|
@@ -10216,6 +10218,33 @@ function shellRegexToGlob(regex) {
|
|
|
10216
10218
|
}
|
|
10217
10219
|
return glob;
|
|
10218
10220
|
}
|
|
10221
|
+
function isShellRegexRoundtrippable(regex) {
|
|
10222
|
+
if (!regex.startsWith("^") || !regex.endsWith("$")) {
|
|
10223
|
+
return false;
|
|
10224
|
+
}
|
|
10225
|
+
const body = regex.slice(1, -1);
|
|
10226
|
+
let i = 0;
|
|
10227
|
+
while (i < body.length) {
|
|
10228
|
+
const ch = body[i];
|
|
10229
|
+
if (ch === "\\" && i + 1 < body.length) {
|
|
10230
|
+
i += 2;
|
|
10231
|
+
continue;
|
|
10232
|
+
}
|
|
10233
|
+
if (ch === "." && body[i + 1] === "*") {
|
|
10234
|
+
i += 2;
|
|
10235
|
+
continue;
|
|
10236
|
+
}
|
|
10237
|
+
if (ch === ".") {
|
|
10238
|
+
i += 1;
|
|
10239
|
+
continue;
|
|
10240
|
+
}
|
|
10241
|
+
if (/[$^|+?*(){}[\]]/.test(ch ?? "")) {
|
|
10242
|
+
return false;
|
|
10243
|
+
}
|
|
10244
|
+
i += 1;
|
|
10245
|
+
}
|
|
10246
|
+
return true;
|
|
10247
|
+
}
|
|
10219
10248
|
var MANAGED_AUGMENT_TOOL_NAMES = new Set(Object.values(CANONICAL_TO_AUGMENT_TOOL_NAMES));
|
|
10220
10249
|
var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissions {
|
|
10221
10250
|
constructor(params) {
|
|
@@ -10223,6 +10252,12 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10223
10252
|
...params,
|
|
10224
10253
|
fileContent: params.fileContent ?? "{}"
|
|
10225
10254
|
});
|
|
10255
|
+
if (params.validate) {
|
|
10256
|
+
const result = this.validate();
|
|
10257
|
+
if (!result.success) {
|
|
10258
|
+
throw result.error;
|
|
10259
|
+
}
|
|
10260
|
+
}
|
|
10226
10261
|
}
|
|
10227
10262
|
isDeletable() {
|
|
10228
10263
|
return false;
|
|
@@ -10316,14 +10351,27 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10316
10351
|
);
|
|
10317
10352
|
}
|
|
10318
10353
|
const config = convertAugmentToRulesyncPermissions({
|
|
10319
|
-
entries: settings.toolPermissions ?? []
|
|
10354
|
+
entries: settings.toolPermissions ?? [],
|
|
10355
|
+
logger: moduleLogger
|
|
10320
10356
|
});
|
|
10321
10357
|
return this.toRulesyncPermissionsDefault({
|
|
10322
10358
|
fileContent: JSON.stringify(config, null, 2)
|
|
10323
10359
|
});
|
|
10324
10360
|
}
|
|
10325
10361
|
validate() {
|
|
10326
|
-
|
|
10362
|
+
try {
|
|
10363
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10364
|
+
const result = AugmentSettingsSchema.safeParse(parsed);
|
|
10365
|
+
if (!result.success) {
|
|
10366
|
+
return { success: false, error: result.error };
|
|
10367
|
+
}
|
|
10368
|
+
return { success: true, error: null };
|
|
10369
|
+
} catch (error) {
|
|
10370
|
+
return {
|
|
10371
|
+
success: false,
|
|
10372
|
+
error: new Error(`Failed to parse AugmentCode permissions JSON: ${formatError(error)}`)
|
|
10373
|
+
};
|
|
10374
|
+
}
|
|
10327
10375
|
}
|
|
10328
10376
|
static forDeletion({
|
|
10329
10377
|
outputRoot = process.cwd(),
|
|
@@ -10421,7 +10469,8 @@ function sortAugmentEntries(entries) {
|
|
|
10421
10469
|
return decorated.map((d) => d.entry);
|
|
10422
10470
|
}
|
|
10423
10471
|
function convertAugmentToRulesyncPermissions({
|
|
10424
|
-
entries
|
|
10472
|
+
entries,
|
|
10473
|
+
logger: logger5
|
|
10425
10474
|
}) {
|
|
10426
10475
|
const actionPriority = {
|
|
10427
10476
|
deny: 2,
|
|
@@ -10432,7 +10481,27 @@ function convertAugmentToRulesyncPermissions({
|
|
|
10432
10481
|
for (const entry of entries) {
|
|
10433
10482
|
const canonical = toCanonicalToolName(entry.toolName);
|
|
10434
10483
|
const action = augmentTypeToAction(entry.permission.type);
|
|
10435
|
-
|
|
10484
|
+
let pattern;
|
|
10485
|
+
if (entry.toolName === "launch-process" && entry.shellInputRegex) {
|
|
10486
|
+
const regex = entry.shellInputRegex;
|
|
10487
|
+
if (isShellRegexRoundtrippable(regex)) {
|
|
10488
|
+
pattern = shellRegexToGlob(regex);
|
|
10489
|
+
} else {
|
|
10490
|
+
if (action === "deny") {
|
|
10491
|
+
logger5?.warn(
|
|
10492
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as the catch-all '*' pattern (fail-closed) so the deny rule cannot be silently narrowed on regenerate.`
|
|
10493
|
+
);
|
|
10494
|
+
pattern = "*";
|
|
10495
|
+
} else {
|
|
10496
|
+
pattern = shellRegexToGlob(regex);
|
|
10497
|
+
logger5?.warn(
|
|
10498
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as glob '${pattern}'; the rule may match a different set of inputs after regenerate.`
|
|
10499
|
+
);
|
|
10500
|
+
}
|
|
10501
|
+
}
|
|
10502
|
+
} else {
|
|
10503
|
+
pattern = "*";
|
|
10504
|
+
}
|
|
10436
10505
|
if (!permission[canonical]) {
|
|
10437
10506
|
permission[canonical] = {};
|
|
10438
10507
|
}
|
|
@@ -10687,6 +10756,12 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10687
10756
|
...params,
|
|
10688
10757
|
fileContent: params.fileContent ?? "{}"
|
|
10689
10758
|
});
|
|
10759
|
+
if (params.validate) {
|
|
10760
|
+
const result = this.validate();
|
|
10761
|
+
if (!result.success) {
|
|
10762
|
+
throw result.error;
|
|
10763
|
+
}
|
|
10764
|
+
}
|
|
10690
10765
|
}
|
|
10691
10766
|
isDeletable() {
|
|
10692
10767
|
return false;
|
|
@@ -10825,7 +10900,19 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10825
10900
|
});
|
|
10826
10901
|
}
|
|
10827
10902
|
validate() {
|
|
10828
|
-
|
|
10903
|
+
try {
|
|
10904
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10905
|
+
const result = ClineCommandPermissionsSchema.safeParse(parsed);
|
|
10906
|
+
if (!result.success) {
|
|
10907
|
+
return { success: false, error: result.error };
|
|
10908
|
+
}
|
|
10909
|
+
return { success: true, error: null };
|
|
10910
|
+
} catch (error) {
|
|
10911
|
+
return {
|
|
10912
|
+
success: false,
|
|
10913
|
+
error: new Error(`Failed to parse Cline permissions JSON: ${formatError(error)}`)
|
|
10914
|
+
};
|
|
10915
|
+
}
|
|
10829
10916
|
}
|
|
10830
10917
|
static forDeletion({
|
|
10831
10918
|
outputRoot = process.cwd(),
|
|
@@ -11418,7 +11505,7 @@ var RESERVED_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
|
11418
11505
|
"constructor",
|
|
11419
11506
|
"prototype"
|
|
11420
11507
|
]);
|
|
11421
|
-
var
|
|
11508
|
+
var moduleLogger2 = new ConsoleLogger();
|
|
11422
11509
|
var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
11423
11510
|
static getSettablePaths(_options = {}) {
|
|
11424
11511
|
return {
|
|
@@ -11447,7 +11534,7 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11447
11534
|
rulesyncPermissions,
|
|
11448
11535
|
validate = true,
|
|
11449
11536
|
global = false,
|
|
11450
|
-
logger: logger5 =
|
|
11537
|
+
logger: logger5 = moduleLogger2
|
|
11451
11538
|
}) {
|
|
11452
11539
|
const paths = this.getSettablePaths({ global });
|
|
11453
11540
|
const fileContent = buildGeminicliPolicyContent(rulesyncPermissions.getJson(), logger5);
|
|
@@ -11472,31 +11559,31 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11472
11559
|
{ cause: error }
|
|
11473
11560
|
);
|
|
11474
11561
|
}
|
|
11475
|
-
const rules = extractRules(parsed,
|
|
11562
|
+
const rules = extractRules(parsed, moduleLogger2);
|
|
11476
11563
|
for (const [index, rule] of rules.entries()) {
|
|
11477
11564
|
const mappedCategory = Object.hasOwn(GEMINICLI_TO_RULESYNC_TOOL_NAME, rule.toolName) ? GEMINICLI_TO_RULESYNC_TOOL_NAME[rule.toolName] : void 0;
|
|
11478
11565
|
const category = mappedCategory ?? rule.toolName;
|
|
11479
11566
|
if (RESERVED_OBJECT_KEYS.has(category)) {
|
|
11480
|
-
|
|
11567
|
+
moduleLogger2.warn(
|
|
11481
11568
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: toolName "${rule.toolName}" maps to a reserved object key ("${category}") and would risk prototype pollution.`
|
|
11482
11569
|
);
|
|
11483
11570
|
continue;
|
|
11484
11571
|
}
|
|
11485
11572
|
const action = mapFromGeminicliDecision(rule.decision);
|
|
11486
11573
|
if (!action) {
|
|
11487
|
-
|
|
11574
|
+
moduleLogger2.warn(
|
|
11488
11575
|
`Skipping rule #${index} (toolName="${rule.toolName}", commandPrefix=${JSON.stringify(rule.commandPrefix)}, argsPattern=${JSON.stringify(rule.argsPattern)}) in ${this.getRelativeFilePath()}: unknown decision ${JSON.stringify(rule.decision)}`
|
|
11489
11576
|
);
|
|
11490
11577
|
continue;
|
|
11491
11578
|
}
|
|
11492
11579
|
if (rule.toolName === "run_shell_command" && rule.commandPrefix !== void 0 && rule.argsPattern !== void 0) {
|
|
11493
|
-
|
|
11580
|
+
moduleLogger2.warn(
|
|
11494
11581
|
`Rule #${index} in ${this.getRelativeFilePath()} sets both commandPrefix and argsPattern; rulesync will honor argsPattern and ignore commandPrefix=${JSON.stringify(rule.commandPrefix)}.`
|
|
11495
11582
|
);
|
|
11496
11583
|
}
|
|
11497
11584
|
const pattern = extractPattern(rule);
|
|
11498
11585
|
if (RESERVED_OBJECT_KEYS.has(pattern)) {
|
|
11499
|
-
|
|
11586
|
+
moduleLogger2.warn(
|
|
11500
11587
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: pattern "${pattern}" is a reserved object key.`
|
|
11501
11588
|
);
|
|
11502
11589
|
continue;
|
|
@@ -12265,7 +12352,7 @@ var QwenSettingsPermissionsSchema = import_mini36.z.looseObject({
|
|
|
12265
12352
|
var QwenSettingsSchema = import_mini36.z.looseObject({
|
|
12266
12353
|
permissions: import_mini36.z.optional(QwenSettingsPermissionsSchema)
|
|
12267
12354
|
});
|
|
12268
|
-
var
|
|
12355
|
+
var moduleLogger3 = new ConsoleLogger();
|
|
12269
12356
|
var CANONICAL_TO_QWEN_TOOL_NAMES = {
|
|
12270
12357
|
bash: "Bash",
|
|
12271
12358
|
read: "Read",
|
|
@@ -12320,6 +12407,12 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12320
12407
|
...params,
|
|
12321
12408
|
fileContent: params.fileContent ?? "{}"
|
|
12322
12409
|
});
|
|
12410
|
+
if (params.validate) {
|
|
12411
|
+
const result = this.validate();
|
|
12412
|
+
if (!result.success) {
|
|
12413
|
+
throw result.error;
|
|
12414
|
+
}
|
|
12415
|
+
}
|
|
12323
12416
|
}
|
|
12324
12417
|
isDeletable() {
|
|
12325
12418
|
return false;
|
|
@@ -12441,7 +12534,19 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12441
12534
|
});
|
|
12442
12535
|
}
|
|
12443
12536
|
validate() {
|
|
12444
|
-
|
|
12537
|
+
try {
|
|
12538
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
12539
|
+
const result = QwenSettingsSchema.safeParse(parsed);
|
|
12540
|
+
if (!result.success) {
|
|
12541
|
+
return { success: false, error: result.error };
|
|
12542
|
+
}
|
|
12543
|
+
return { success: true, error: null };
|
|
12544
|
+
} catch (error) {
|
|
12545
|
+
return {
|
|
12546
|
+
success: false,
|
|
12547
|
+
error: new Error(`Failed to parse Qwen permissions JSON: ${formatError(error)}`)
|
|
12548
|
+
};
|
|
12549
|
+
}
|
|
12445
12550
|
}
|
|
12446
12551
|
static forDeletion({
|
|
12447
12552
|
outputRoot = process.cwd(),
|
|
@@ -12482,7 +12587,7 @@ function convertRulesyncToQwenPermissions(config) {
|
|
|
12482
12587
|
}
|
|
12483
12588
|
function convertQwenToRulesyncPermissions(params) {
|
|
12484
12589
|
const permission = {};
|
|
12485
|
-
const logger5 = params.logger ??
|
|
12590
|
+
const logger5 = params.logger ?? moduleLogger3;
|
|
12486
12591
|
const processEntries = (entries, action) => {
|
|
12487
12592
|
for (const entry of entries) {
|
|
12488
12593
|
const parsed = parseQwenPermissionEntry(entry, { logger: logger5 });
|
|
@@ -21063,6 +21168,8 @@ var CopilotRuleFrontmatterSchema = import_mini77.z.object({
|
|
|
21063
21168
|
applyTo: import_mini77.z.optional(import_mini77.z.string()),
|
|
21064
21169
|
excludeAgent: import_mini77.z.optional(import_mini77.z.union([import_mini77.z.literal("code-review"), import_mini77.z.literal("coding-agent")]))
|
|
21065
21170
|
});
|
|
21171
|
+
var normalizeRelativePath = (path5) => path5.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
21172
|
+
var sameRelativePath = (leftDir, leftFile, rightDir, rightFile) => normalizeRelativePath((0, import_node_path136.join)(leftDir, leftFile)) === normalizeRelativePath((0, import_node_path136.join)(rightDir, rightFile));
|
|
21066
21173
|
var CopilotRule = class _CopilotRule extends ToolRule {
|
|
21067
21174
|
frontmatter;
|
|
21068
21175
|
body;
|
|
@@ -21180,7 +21287,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21180
21287
|
global = false
|
|
21181
21288
|
}) {
|
|
21182
21289
|
const paths = this.getSettablePaths({ global });
|
|
21183
|
-
const isRoot = relativeDirPath ? (
|
|
21290
|
+
const isRoot = relativeDirPath ? sameRelativePath(
|
|
21291
|
+
relativeDirPath,
|
|
21292
|
+
relativeFilePath,
|
|
21293
|
+
paths.root.relativeDirPath,
|
|
21294
|
+
paths.root.relativeFilePath
|
|
21295
|
+
) : relativeFilePath === paths.root.relativeFilePath;
|
|
21184
21296
|
const resolvedRelativeDirPath = relativeDirPath ?? (isRoot ? paths.root.relativeDirPath : paths.nonRoot?.relativeDirPath ?? paths.root.relativeDirPath);
|
|
21185
21297
|
if (isRoot) {
|
|
21186
21298
|
const relativePath2 = (0, import_node_path136.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
|
|
@@ -21224,7 +21336,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21224
21336
|
global = false
|
|
21225
21337
|
}) {
|
|
21226
21338
|
const paths = this.getSettablePaths({ global });
|
|
21227
|
-
const isRoot = (
|
|
21339
|
+
const isRoot = sameRelativePath(
|
|
21340
|
+
relativeDirPath,
|
|
21341
|
+
relativeFilePath,
|
|
21342
|
+
paths.root.relativeDirPath,
|
|
21343
|
+
paths.root.relativeFilePath
|
|
21344
|
+
);
|
|
21228
21345
|
return new _CopilotRule({
|
|
21229
21346
|
outputRoot,
|
|
21230
21347
|
relativeDirPath,
|
|
@@ -26171,7 +26288,10 @@ var GITIGNORE_ENTRY_REGISTRY = [
|
|
|
26171
26288
|
{ target: "kilo", feature: "commands", entry: "**/.kilo/workflows/" },
|
|
26172
26289
|
{ target: "kilo", feature: "mcp", entry: "**/.kilo/mcp.json" },
|
|
26173
26290
|
{ target: "kilo", feature: "ignore", entry: "**/.kiloignore" },
|
|
26174
|
-
|
|
26291
|
+
// No `**/kilo.jsonc` entry: structurally identical to `opencode.jsonc` (no
|
|
26292
|
+
// entry). The Kilo translator preserves non-permissions Kilo settings on
|
|
26293
|
+
// round-trip, so the file is intended to be checked in by the user — adding
|
|
26294
|
+
// `**/kilo.jsonc` would be too aggressive.
|
|
26175
26295
|
// Kiro
|
|
26176
26296
|
{ target: "kiro", feature: "rules", entry: "**/.kiro/steering/" },
|
|
26177
26297
|
{ target: "kiro", feature: "commands", entry: "**/.kiro/prompts/" },
|
|
@@ -31509,7 +31629,7 @@ function wrapCommand({
|
|
|
31509
31629
|
}
|
|
31510
31630
|
|
|
31511
31631
|
// src/cli/index.ts
|
|
31512
|
-
var getVersion = () => "8.15.
|
|
31632
|
+
var getVersion = () => "8.15.1";
|
|
31513
31633
|
function wrapCommand2(name, errorCode, handler) {
|
|
31514
31634
|
return wrapCommand({ name, errorCode, handler, getVersion });
|
|
31515
31635
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
stringifyFrontmatter,
|
|
80
80
|
toPosixPath,
|
|
81
81
|
writeFileContent
|
|
82
|
-
} from "../chunk-
|
|
82
|
+
} from "../chunk-3DM6NLND.js";
|
|
83
83
|
|
|
84
84
|
// src/cli/index.ts
|
|
85
85
|
import { Command } from "commander";
|
|
@@ -1408,7 +1408,10 @@ var GITIGNORE_ENTRY_REGISTRY = [
|
|
|
1408
1408
|
{ target: "kilo", feature: "commands", entry: "**/.kilo/workflows/" },
|
|
1409
1409
|
{ target: "kilo", feature: "mcp", entry: "**/.kilo/mcp.json" },
|
|
1410
1410
|
{ target: "kilo", feature: "ignore", entry: "**/.kiloignore" },
|
|
1411
|
-
|
|
1411
|
+
// No `**/kilo.jsonc` entry: structurally identical to `opencode.jsonc` (no
|
|
1412
|
+
// entry). The Kilo translator preserves non-permissions Kilo settings on
|
|
1413
|
+
// round-trip, so the file is intended to be checked in by the user — adding
|
|
1414
|
+
// `**/kilo.jsonc` would be too aggressive.
|
|
1412
1415
|
// Kiro
|
|
1413
1416
|
{ target: "kiro", feature: "rules", entry: "**/.kiro/steering/" },
|
|
1414
1417
|
{ target: "kiro", feature: "commands", entry: "**/.kiro/prompts/" },
|
|
@@ -6482,7 +6485,7 @@ function wrapCommand({
|
|
|
6482
6485
|
}
|
|
6483
6486
|
|
|
6484
6487
|
// src/cli/index.ts
|
|
6485
|
-
var getVersion = () => "8.15.
|
|
6488
|
+
var getVersion = () => "8.15.1";
|
|
6486
6489
|
function wrapCommand2(name, errorCode, handler) {
|
|
6487
6490
|
return wrapCommand({ name, errorCode, handler, getVersion });
|
|
6488
6491
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -232,7 +232,8 @@ function validateOutputRoot(outputRoot) {
|
|
|
232
232
|
throw new Error("outputRoot cannot be an empty string");
|
|
233
233
|
}
|
|
234
234
|
if ((0, import_node_path2.isAbsolute)(outputRoot)) {
|
|
235
|
-
const
|
|
235
|
+
const separatorRegex = process.platform === "win32" ? /[/\\]/ : /\//;
|
|
236
|
+
const segments = outputRoot.split(separatorRegex);
|
|
236
237
|
if (segments.includes("..")) {
|
|
237
238
|
throw new Error(`Path traversal detected: ${outputRoot}`);
|
|
238
239
|
}
|
|
@@ -9998,6 +9999,7 @@ var ToolPermissions = class extends ToolFile {
|
|
|
9998
9999
|
};
|
|
9999
10000
|
|
|
10000
10001
|
// src/features/permissions/augmentcode-permissions.ts
|
|
10002
|
+
var moduleLogger = new ConsoleLogger();
|
|
10001
10003
|
var AugmentPermissionTypeSchema = import_mini30.z.enum(["allow", "deny", "ask-user"]);
|
|
10002
10004
|
var AugmentToolPermissionSchema = import_mini30.z.looseObject({
|
|
10003
10005
|
toolName: import_mini30.z.string(),
|
|
@@ -10089,6 +10091,33 @@ function shellRegexToGlob(regex) {
|
|
|
10089
10091
|
}
|
|
10090
10092
|
return glob;
|
|
10091
10093
|
}
|
|
10094
|
+
function isShellRegexRoundtrippable(regex) {
|
|
10095
|
+
if (!regex.startsWith("^") || !regex.endsWith("$")) {
|
|
10096
|
+
return false;
|
|
10097
|
+
}
|
|
10098
|
+
const body = regex.slice(1, -1);
|
|
10099
|
+
let i = 0;
|
|
10100
|
+
while (i < body.length) {
|
|
10101
|
+
const ch = body[i];
|
|
10102
|
+
if (ch === "\\" && i + 1 < body.length) {
|
|
10103
|
+
i += 2;
|
|
10104
|
+
continue;
|
|
10105
|
+
}
|
|
10106
|
+
if (ch === "." && body[i + 1] === "*") {
|
|
10107
|
+
i += 2;
|
|
10108
|
+
continue;
|
|
10109
|
+
}
|
|
10110
|
+
if (ch === ".") {
|
|
10111
|
+
i += 1;
|
|
10112
|
+
continue;
|
|
10113
|
+
}
|
|
10114
|
+
if (/[$^|+?*(){}[\]]/.test(ch ?? "")) {
|
|
10115
|
+
return false;
|
|
10116
|
+
}
|
|
10117
|
+
i += 1;
|
|
10118
|
+
}
|
|
10119
|
+
return true;
|
|
10120
|
+
}
|
|
10092
10121
|
var MANAGED_AUGMENT_TOOL_NAMES = new Set(Object.values(CANONICAL_TO_AUGMENT_TOOL_NAMES));
|
|
10093
10122
|
var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissions {
|
|
10094
10123
|
constructor(params) {
|
|
@@ -10096,6 +10125,12 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10096
10125
|
...params,
|
|
10097
10126
|
fileContent: params.fileContent ?? "{}"
|
|
10098
10127
|
});
|
|
10128
|
+
if (params.validate) {
|
|
10129
|
+
const result = this.validate();
|
|
10130
|
+
if (!result.success) {
|
|
10131
|
+
throw result.error;
|
|
10132
|
+
}
|
|
10133
|
+
}
|
|
10099
10134
|
}
|
|
10100
10135
|
isDeletable() {
|
|
10101
10136
|
return false;
|
|
@@ -10189,14 +10224,27 @@ var AugmentcodePermissions = class _AugmentcodePermissions extends ToolPermissio
|
|
|
10189
10224
|
);
|
|
10190
10225
|
}
|
|
10191
10226
|
const config = convertAugmentToRulesyncPermissions({
|
|
10192
|
-
entries: settings.toolPermissions ?? []
|
|
10227
|
+
entries: settings.toolPermissions ?? [],
|
|
10228
|
+
logger: moduleLogger
|
|
10193
10229
|
});
|
|
10194
10230
|
return this.toRulesyncPermissionsDefault({
|
|
10195
10231
|
fileContent: JSON.stringify(config, null, 2)
|
|
10196
10232
|
});
|
|
10197
10233
|
}
|
|
10198
10234
|
validate() {
|
|
10199
|
-
|
|
10235
|
+
try {
|
|
10236
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10237
|
+
const result = AugmentSettingsSchema.safeParse(parsed);
|
|
10238
|
+
if (!result.success) {
|
|
10239
|
+
return { success: false, error: result.error };
|
|
10240
|
+
}
|
|
10241
|
+
return { success: true, error: null };
|
|
10242
|
+
} catch (error) {
|
|
10243
|
+
return {
|
|
10244
|
+
success: false,
|
|
10245
|
+
error: new Error(`Failed to parse AugmentCode permissions JSON: ${formatError(error)}`)
|
|
10246
|
+
};
|
|
10247
|
+
}
|
|
10200
10248
|
}
|
|
10201
10249
|
static forDeletion({
|
|
10202
10250
|
outputRoot = process.cwd(),
|
|
@@ -10294,7 +10342,8 @@ function sortAugmentEntries(entries) {
|
|
|
10294
10342
|
return decorated.map((d) => d.entry);
|
|
10295
10343
|
}
|
|
10296
10344
|
function convertAugmentToRulesyncPermissions({
|
|
10297
|
-
entries
|
|
10345
|
+
entries,
|
|
10346
|
+
logger
|
|
10298
10347
|
}) {
|
|
10299
10348
|
const actionPriority = {
|
|
10300
10349
|
deny: 2,
|
|
@@ -10305,7 +10354,27 @@ function convertAugmentToRulesyncPermissions({
|
|
|
10305
10354
|
for (const entry of entries) {
|
|
10306
10355
|
const canonical = toCanonicalToolName(entry.toolName);
|
|
10307
10356
|
const action = augmentTypeToAction(entry.permission.type);
|
|
10308
|
-
|
|
10357
|
+
let pattern;
|
|
10358
|
+
if (entry.toolName === "launch-process" && entry.shellInputRegex) {
|
|
10359
|
+
const regex = entry.shellInputRegex;
|
|
10360
|
+
if (isShellRegexRoundtrippable(regex)) {
|
|
10361
|
+
pattern = shellRegexToGlob(regex);
|
|
10362
|
+
} else {
|
|
10363
|
+
if (action === "deny") {
|
|
10364
|
+
logger?.warn(
|
|
10365
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as the catch-all '*' pattern (fail-closed) so the deny rule cannot be silently narrowed on regenerate.`
|
|
10366
|
+
);
|
|
10367
|
+
pattern = "*";
|
|
10368
|
+
} else {
|
|
10369
|
+
pattern = shellRegexToGlob(regex);
|
|
10370
|
+
logger?.warn(
|
|
10371
|
+
`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as glob '${pattern}'; the rule may match a different set of inputs after regenerate.`
|
|
10372
|
+
);
|
|
10373
|
+
}
|
|
10374
|
+
}
|
|
10375
|
+
} else {
|
|
10376
|
+
pattern = "*";
|
|
10377
|
+
}
|
|
10309
10378
|
if (!permission[canonical]) {
|
|
10310
10379
|
permission[canonical] = {};
|
|
10311
10380
|
}
|
|
@@ -10560,6 +10629,12 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10560
10629
|
...params,
|
|
10561
10630
|
fileContent: params.fileContent ?? "{}"
|
|
10562
10631
|
});
|
|
10632
|
+
if (params.validate) {
|
|
10633
|
+
const result = this.validate();
|
|
10634
|
+
if (!result.success) {
|
|
10635
|
+
throw result.error;
|
|
10636
|
+
}
|
|
10637
|
+
}
|
|
10563
10638
|
}
|
|
10564
10639
|
isDeletable() {
|
|
10565
10640
|
return false;
|
|
@@ -10698,7 +10773,19 @@ var ClinePermissions = class _ClinePermissions extends ToolPermissions {
|
|
|
10698
10773
|
});
|
|
10699
10774
|
}
|
|
10700
10775
|
validate() {
|
|
10701
|
-
|
|
10776
|
+
try {
|
|
10777
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
10778
|
+
const result = ClineCommandPermissionsSchema.safeParse(parsed);
|
|
10779
|
+
if (!result.success) {
|
|
10780
|
+
return { success: false, error: result.error };
|
|
10781
|
+
}
|
|
10782
|
+
return { success: true, error: null };
|
|
10783
|
+
} catch (error) {
|
|
10784
|
+
return {
|
|
10785
|
+
success: false,
|
|
10786
|
+
error: new Error(`Failed to parse Cline permissions JSON: ${formatError(error)}`)
|
|
10787
|
+
};
|
|
10788
|
+
}
|
|
10702
10789
|
}
|
|
10703
10790
|
static forDeletion({
|
|
10704
10791
|
outputRoot = process.cwd(),
|
|
@@ -11291,7 +11378,7 @@ var RESERVED_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
|
11291
11378
|
"constructor",
|
|
11292
11379
|
"prototype"
|
|
11293
11380
|
]);
|
|
11294
|
-
var
|
|
11381
|
+
var moduleLogger2 = new ConsoleLogger();
|
|
11295
11382
|
var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
11296
11383
|
static getSettablePaths(_options = {}) {
|
|
11297
11384
|
return {
|
|
@@ -11320,7 +11407,7 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11320
11407
|
rulesyncPermissions,
|
|
11321
11408
|
validate = true,
|
|
11322
11409
|
global = false,
|
|
11323
|
-
logger =
|
|
11410
|
+
logger = moduleLogger2
|
|
11324
11411
|
}) {
|
|
11325
11412
|
const paths = this.getSettablePaths({ global });
|
|
11326
11413
|
const fileContent = buildGeminicliPolicyContent(rulesyncPermissions.getJson(), logger);
|
|
@@ -11345,31 +11432,31 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
11345
11432
|
{ cause: error }
|
|
11346
11433
|
);
|
|
11347
11434
|
}
|
|
11348
|
-
const rules = extractRules(parsed,
|
|
11435
|
+
const rules = extractRules(parsed, moduleLogger2);
|
|
11349
11436
|
for (const [index, rule] of rules.entries()) {
|
|
11350
11437
|
const mappedCategory = Object.hasOwn(GEMINICLI_TO_RULESYNC_TOOL_NAME, rule.toolName) ? GEMINICLI_TO_RULESYNC_TOOL_NAME[rule.toolName] : void 0;
|
|
11351
11438
|
const category = mappedCategory ?? rule.toolName;
|
|
11352
11439
|
if (RESERVED_OBJECT_KEYS.has(category)) {
|
|
11353
|
-
|
|
11440
|
+
moduleLogger2.warn(
|
|
11354
11441
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: toolName "${rule.toolName}" maps to a reserved object key ("${category}") and would risk prototype pollution.`
|
|
11355
11442
|
);
|
|
11356
11443
|
continue;
|
|
11357
11444
|
}
|
|
11358
11445
|
const action = mapFromGeminicliDecision(rule.decision);
|
|
11359
11446
|
if (!action) {
|
|
11360
|
-
|
|
11447
|
+
moduleLogger2.warn(
|
|
11361
11448
|
`Skipping rule #${index} (toolName="${rule.toolName}", commandPrefix=${JSON.stringify(rule.commandPrefix)}, argsPattern=${JSON.stringify(rule.argsPattern)}) in ${this.getRelativeFilePath()}: unknown decision ${JSON.stringify(rule.decision)}`
|
|
11362
11449
|
);
|
|
11363
11450
|
continue;
|
|
11364
11451
|
}
|
|
11365
11452
|
if (rule.toolName === "run_shell_command" && rule.commandPrefix !== void 0 && rule.argsPattern !== void 0) {
|
|
11366
|
-
|
|
11453
|
+
moduleLogger2.warn(
|
|
11367
11454
|
`Rule #${index} in ${this.getRelativeFilePath()} sets both commandPrefix and argsPattern; rulesync will honor argsPattern and ignore commandPrefix=${JSON.stringify(rule.commandPrefix)}.`
|
|
11368
11455
|
);
|
|
11369
11456
|
}
|
|
11370
11457
|
const pattern = extractPattern(rule);
|
|
11371
11458
|
if (RESERVED_OBJECT_KEYS.has(pattern)) {
|
|
11372
|
-
|
|
11459
|
+
moduleLogger2.warn(
|
|
11373
11460
|
`Skipping rule #${index} in ${this.getRelativeFilePath()}: pattern "${pattern}" is a reserved object key.`
|
|
11374
11461
|
);
|
|
11375
11462
|
continue;
|
|
@@ -12138,7 +12225,7 @@ var QwenSettingsPermissionsSchema = import_mini36.z.looseObject({
|
|
|
12138
12225
|
var QwenSettingsSchema = import_mini36.z.looseObject({
|
|
12139
12226
|
permissions: import_mini36.z.optional(QwenSettingsPermissionsSchema)
|
|
12140
12227
|
});
|
|
12141
|
-
var
|
|
12228
|
+
var moduleLogger3 = new ConsoleLogger();
|
|
12142
12229
|
var CANONICAL_TO_QWEN_TOOL_NAMES = {
|
|
12143
12230
|
bash: "Bash",
|
|
12144
12231
|
read: "Read",
|
|
@@ -12193,6 +12280,12 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12193
12280
|
...params,
|
|
12194
12281
|
fileContent: params.fileContent ?? "{}"
|
|
12195
12282
|
});
|
|
12283
|
+
if (params.validate) {
|
|
12284
|
+
const result = this.validate();
|
|
12285
|
+
if (!result.success) {
|
|
12286
|
+
throw result.error;
|
|
12287
|
+
}
|
|
12288
|
+
}
|
|
12196
12289
|
}
|
|
12197
12290
|
isDeletable() {
|
|
12198
12291
|
return false;
|
|
@@ -12314,7 +12407,19 @@ var QwencodePermissions = class _QwencodePermissions extends ToolPermissions {
|
|
|
12314
12407
|
});
|
|
12315
12408
|
}
|
|
12316
12409
|
validate() {
|
|
12317
|
-
|
|
12410
|
+
try {
|
|
12411
|
+
const parsed = JSON.parse(this.fileContent || "{}");
|
|
12412
|
+
const result = QwenSettingsSchema.safeParse(parsed);
|
|
12413
|
+
if (!result.success) {
|
|
12414
|
+
return { success: false, error: result.error };
|
|
12415
|
+
}
|
|
12416
|
+
return { success: true, error: null };
|
|
12417
|
+
} catch (error) {
|
|
12418
|
+
return {
|
|
12419
|
+
success: false,
|
|
12420
|
+
error: new Error(`Failed to parse Qwen permissions JSON: ${formatError(error)}`)
|
|
12421
|
+
};
|
|
12422
|
+
}
|
|
12318
12423
|
}
|
|
12319
12424
|
static forDeletion({
|
|
12320
12425
|
outputRoot = process.cwd(),
|
|
@@ -12355,7 +12460,7 @@ function convertRulesyncToQwenPermissions(config) {
|
|
|
12355
12460
|
}
|
|
12356
12461
|
function convertQwenToRulesyncPermissions(params) {
|
|
12357
12462
|
const permission = {};
|
|
12358
|
-
const logger = params.logger ??
|
|
12463
|
+
const logger = params.logger ?? moduleLogger3;
|
|
12359
12464
|
const processEntries = (entries, action) => {
|
|
12360
12465
|
for (const entry of entries) {
|
|
12361
12466
|
const parsed = parseQwenPermissionEntry(entry, { logger });
|
|
@@ -20936,6 +21041,8 @@ var CopilotRuleFrontmatterSchema = import_mini77.z.object({
|
|
|
20936
21041
|
applyTo: import_mini77.z.optional(import_mini77.z.string()),
|
|
20937
21042
|
excludeAgent: import_mini77.z.optional(import_mini77.z.union([import_mini77.z.literal("code-review"), import_mini77.z.literal("coding-agent")]))
|
|
20938
21043
|
});
|
|
21044
|
+
var normalizeRelativePath = (path4) => path4.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
21045
|
+
var sameRelativePath = (leftDir, leftFile, rightDir, rightFile) => normalizeRelativePath((0, import_node_path136.join)(leftDir, leftFile)) === normalizeRelativePath((0, import_node_path136.join)(rightDir, rightFile));
|
|
20939
21046
|
var CopilotRule = class _CopilotRule extends ToolRule {
|
|
20940
21047
|
frontmatter;
|
|
20941
21048
|
body;
|
|
@@ -21053,7 +21160,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21053
21160
|
global = false
|
|
21054
21161
|
}) {
|
|
21055
21162
|
const paths = this.getSettablePaths({ global });
|
|
21056
|
-
const isRoot = relativeDirPath ? (
|
|
21163
|
+
const isRoot = relativeDirPath ? sameRelativePath(
|
|
21164
|
+
relativeDirPath,
|
|
21165
|
+
relativeFilePath,
|
|
21166
|
+
paths.root.relativeDirPath,
|
|
21167
|
+
paths.root.relativeFilePath
|
|
21168
|
+
) : relativeFilePath === paths.root.relativeFilePath;
|
|
21057
21169
|
const resolvedRelativeDirPath = relativeDirPath ?? (isRoot ? paths.root.relativeDirPath : paths.nonRoot?.relativeDirPath ?? paths.root.relativeDirPath);
|
|
21058
21170
|
if (isRoot) {
|
|
21059
21171
|
const relativePath2 = (0, import_node_path136.join)(paths.root.relativeDirPath, paths.root.relativeFilePath);
|
|
@@ -21097,7 +21209,12 @@ var CopilotRule = class _CopilotRule extends ToolRule {
|
|
|
21097
21209
|
global = false
|
|
21098
21210
|
}) {
|
|
21099
21211
|
const paths = this.getSettablePaths({ global });
|
|
21100
|
-
const isRoot = (
|
|
21212
|
+
const isRoot = sameRelativePath(
|
|
21213
|
+
relativeDirPath,
|
|
21214
|
+
relativeFilePath,
|
|
21215
|
+
paths.root.relativeDirPath,
|
|
21216
|
+
paths.root.relativeFilePath
|
|
21217
|
+
);
|
|
21101
21218
|
return new _CopilotRule({
|
|
21102
21219
|
outputRoot,
|
|
21103
21220
|
relativeDirPath,
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rulesync",
|
|
3
|
-
"version": "8.15.
|
|
3
|
+
"version": "8.15.1",
|
|
4
4
|
"description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"gray-matter": "4.0.3",
|
|
62
62
|
"js-yaml": "4.1.1",
|
|
63
63
|
"jsonc-parser": "3.3.1",
|
|
64
|
-
"smol-toml": "1.6.
|
|
64
|
+
"smol-toml": "1.6.1",
|
|
65
65
|
"sury": "10.0.4",
|
|
66
66
|
"zod": "4.3.6"
|
|
67
67
|
},
|