rulesync 16.23.0 → 16.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.cjs +3 -3
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-D420jbVB.cjs → import-C0WSCbU9.cjs} +325 -40
- package/dist/{import-DIDEUv63.js → import-DyWRanf6.js} +326 -41
- package/dist/import-DyWRanf6.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-DIDEUv63.js.map +0 -1
|
@@ -6633,10 +6633,25 @@ const CursorPermissionsOverrideSchema = z.looseObject({
|
|
|
6633
6633
|
* Tool-scoped override block for Qwen Code. Qwen's `settings.json` exposes
|
|
6634
6634
|
* autonomy/sandbox controls with no canonical permission category — under
|
|
6635
6635
|
* `tools` (`approvalMode` = plan/default/auto-edit/auto/yolo, `autoAccept`,
|
|
6636
|
-
* `sandbox`, `sandboxImage`, `disabled
|
|
6637
|
-
* `
|
|
6638
|
-
* Qwen Code
|
|
6639
|
-
*
|
|
6636
|
+
* `sandbox`, `sandboxImage`, `disabled`, `visible`, `listDirectory`,
|
|
6637
|
+
* `workflowsEnabled`) and `security` (`folderTrust`, `allowedHttpHookUrls`,
|
|
6638
|
+
* `allowPrivateNetworkHooks`, `allowedInsecureVoiceBaseUrls`). Qwen Code strips
|
|
6639
|
+
* `tools.workflowsEnabled`, `security.allowPrivateNetworkHooks` and
|
|
6640
|
+
* `security.allowedInsecureVoiceBaseUrls` out of workspace settings, so generate
|
|
6641
|
+
* skips those three in project scope and announces a granting value in global
|
|
6642
|
+
* scope. `security.allowedHttpHookUrls` (honored in a workspace only while no
|
|
6643
|
+
* higher scope sets it) and `security.folderTrust` (the initial trust decision
|
|
6644
|
+
* is made from user/system settings alone, before the workspace merge) are
|
|
6645
|
+
* written in both scopes, with a note in project scope and an announcement of
|
|
6646
|
+
* any global change. Every other key is honored in either scope, so a write that
|
|
6647
|
+
* changes what the file said is reported in either scope, naming what that key
|
|
6648
|
+
* decides there — the autonomy and containment
|
|
6649
|
+
* controls (`approvalMode`, `autoAccept`, `sandbox`, `sandboxImage`), the
|
|
6650
|
+
* registry controls (`disabled`, `visible`, `listDirectory`), the Auto Mode
|
|
6651
|
+
* classifier config, and, because these groups are loose objects, any key
|
|
6652
|
+
* rulesync does not model. Import flags a scope-dependent key only when it read
|
|
6653
|
+
* the project file, since that is the value a `--global` regenerate would
|
|
6654
|
+
* promote. It also
|
|
6640
6655
|
* exposes `permissions.autoMode` (the Auto Mode classifier config:
|
|
6641
6656
|
* `hints.{allow,softDeny,hardDeny}`, `environment`, `classifyAllShell` — see
|
|
6642
6657
|
* https://qwenlm.github.io/qwen-code-docs/en/users/features/auto-mode/), which
|
|
@@ -42479,15 +42494,129 @@ const QWEN_OVERRIDE_TOOLS_KEYS = [
|
|
|
42479
42494
|
"sandbox",
|
|
42480
42495
|
"sandboxImage",
|
|
42481
42496
|
"disabled",
|
|
42482
|
-
"visible"
|
|
42497
|
+
"visible",
|
|
42498
|
+
"listDirectory",
|
|
42499
|
+
"workflowsEnabled"
|
|
42483
42500
|
];
|
|
42484
42501
|
const QWEN_OVERRIDE_SECURITY_KEYS = [
|
|
42485
42502
|
"folderTrust",
|
|
42486
42503
|
"allowedHttpHookUrls",
|
|
42487
|
-
"allowPrivateNetworkHooks"
|
|
42504
|
+
"allowPrivateNetworkHooks",
|
|
42505
|
+
"allowedInsecureVoiceBaseUrls"
|
|
42488
42506
|
];
|
|
42489
|
-
|
|
42507
|
+
/**
|
|
42508
|
+
* What each rule means for the two directions, so a key's behavior is declared
|
|
42509
|
+
* once beside its rule rather than spelled out at every branch.
|
|
42510
|
+
*
|
|
42511
|
+
* `stripInProjectScope` separates the keys a project file cannot use at all from
|
|
42512
|
+
* the ones whose project value still does something, just not unconditionally —
|
|
42513
|
+
* only the former are dropped. `announceOnlyGrants` marks the rule whose risk is
|
|
42514
|
+
* a value that turns something on; for the others the dangerous value is often
|
|
42515
|
+
* the falsy one (an empty allow-all list, folder trust switched off, a sandbox
|
|
42516
|
+
* turned off), so every change is announced instead. `announceOnImport` marks
|
|
42517
|
+
* the keys whose meaning depends on the scope they are written in — importing
|
|
42518
|
+
* one and regenerating globally turns a value a workspace could not decide for
|
|
42519
|
+
* itself into one Qwen Code enforces everywhere. `global-machine-wide` keys are
|
|
42520
|
+
* honored identically in either scope, so import neither promotes nor weakens
|
|
42521
|
+
* them and the announcement on the generate side is the control point.
|
|
42522
|
+
* `projectNote` is `null` for a rule that has nothing to say about the project
|
|
42523
|
+
* scope. A `globalNote` here is the rule's default; a key whose meaning the
|
|
42524
|
+
* default does not describe carries its own.
|
|
42525
|
+
*/
|
|
42526
|
+
const QWEN_SCOPE_RULES = {
|
|
42527
|
+
"workspace-stripped": {
|
|
42528
|
+
stripInProjectScope: true,
|
|
42529
|
+
announceOnlyGrants: true,
|
|
42530
|
+
announceOnImport: true,
|
|
42531
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} is only honored in user/system settings, so it is skipped for the project-scoped ${filePath} (a value already in that file is left as it is). Check it if the override arrived with a repository you cloned, and author it in the global scope only if that is a value you want every project on this machine to run under.`,
|
|
42532
|
+
globalNote: "Qwen Code ignores this key in workspace settings so a repository cannot grant it per project; in the global scope it applies to every project on this machine."
|
|
42533
|
+
},
|
|
42534
|
+
"workspace-non-overriding": {
|
|
42535
|
+
stripInProjectScope: false,
|
|
42536
|
+
announceOnlyGrants: false,
|
|
42537
|
+
announceOnImport: true,
|
|
42538
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, but Qwen Code honors a workspace value for it only while no user, system, or system-defaults scope sets the key — a repository cannot replace the list a user configured in a higher scope. It does replace one written by hand in this same file, and an empty list is Qwen Code's allow-all, so check what it now says. Author it in the global scope if it has to apply unconditionally.`,
|
|
42539
|
+
globalNote: "A global value outranks every repository's own list for this key, and an empty list means allow-all, so this decides where HTTP hooks may send data for every project on this machine."
|
|
42540
|
+
},
|
|
42541
|
+
"user-scope-trust-check": {
|
|
42542
|
+
stripInProjectScope: false,
|
|
42543
|
+
announceOnlyGrants: false,
|
|
42544
|
+
announceOnImport: true,
|
|
42545
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, but Qwen Code makes the initial trust decision from user and system settings alone, before a workspace file is merged, so a project value cannot decide whether this workspace is trusted (it still drives folder trust once the workspace is trusted). Check it if the override arrived with a repository you cloned, and author it in the global scope only if that is a value you want every project on this machine to run under.`,
|
|
42546
|
+
globalNote: "Qwen Code reads this key from the global scope when it decides whether a workspace is trusted, so this changes which projects on this machine it trusts."
|
|
42547
|
+
},
|
|
42548
|
+
"global-machine-wide": {
|
|
42549
|
+
stripInProjectScope: false,
|
|
42550
|
+
announceOnlyGrants: false,
|
|
42551
|
+
announceOnImport: false,
|
|
42552
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}. Qwen Code honors this key in a workspace file, so it takes effect while you work in this repository. Check it if the override arrived with a repository you cloned.`,
|
|
42553
|
+
globalNote: "Qwen Code honors this key wherever it is written, so in the global scope it settles how much the agent may do unattended — how far approvals are skipped, and whether tool calls are contained at all — for every project on this machine."
|
|
42554
|
+
},
|
|
42555
|
+
unmodeled: {
|
|
42556
|
+
stripInProjectScope: false,
|
|
42557
|
+
announceOnlyGrants: false,
|
|
42558
|
+
announceOnImport: false,
|
|
42559
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}. This is not a key rulesync models, so it cannot say what Qwen Code does with it — and some settings in these groups are potent (\`tools.discoveryCommand\` and \`tools.callCommand\` are spawned as commands when Qwen Code starts). Check it if the override arrived with a repository you cloned.`,
|
|
42560
|
+
globalNote: "This is not a key rulesync models, so it cannot say what Qwen Code does with it — and some settings in these groups are potent (`tools.discoveryCommand` and `tools.callCommand` are spawned as commands when Qwen Code starts). Check what it now says for every project on this machine."
|
|
42561
|
+
}
|
|
42562
|
+
};
|
|
42563
|
+
const QWEN_OVERRIDE_GROUPS = [{
|
|
42564
|
+
groupName: "tools",
|
|
42565
|
+
overrideKeys: QWEN_OVERRIDE_TOOLS_KEYS,
|
|
42566
|
+
scopedKeys: {
|
|
42567
|
+
workflowsEnabled: { rule: "workspace-stripped" },
|
|
42568
|
+
approvalMode: {
|
|
42569
|
+
rule: "global-machine-wide",
|
|
42570
|
+
projectNote: autonomyProjectNote
|
|
42571
|
+
},
|
|
42572
|
+
autoAccept: {
|
|
42573
|
+
rule: "global-machine-wide",
|
|
42574
|
+
projectNote: autonomyProjectNote
|
|
42575
|
+
},
|
|
42576
|
+
sandbox: {
|
|
42577
|
+
rule: "global-machine-wide",
|
|
42578
|
+
projectNote: autonomyProjectNote
|
|
42579
|
+
},
|
|
42580
|
+
sandboxImage: {
|
|
42581
|
+
rule: "global-machine-wide",
|
|
42582
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, so a sandboxed run in this repository executes inside the named image — check that it is one you trust to run your code.`,
|
|
42583
|
+
globalNote: "Qwen Code honors this key wherever it is written, so in the global scope every sandboxed run on this machine executes inside the named image — check that it is one you trust to run your code."
|
|
42584
|
+
},
|
|
42585
|
+
disabled: {
|
|
42586
|
+
rule: "global-machine-wide",
|
|
42587
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, replacing the list in that file rather than adding to it, so a name that is gone is a tool the model can call again in this repository unless another scope still disables it.`,
|
|
42588
|
+
globalNote: "Qwen Code honors this key wherever it is written, and the override replaces the list in this file rather than adding to it, so in the global scope this decides which tools stay out of the registry for every project on this machine — dropping a name hands that tool back to the model unless another scope still disables it."
|
|
42589
|
+
},
|
|
42590
|
+
visible: {
|
|
42591
|
+
rule: "global-machine-wide",
|
|
42592
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, so it decides which deferred tools are visible at startup in this repository.`,
|
|
42593
|
+
globalNote: "Qwen Code honors this key wherever it is written, so in the global scope this decides which deferred tools are visible at startup for every project on this machine."
|
|
42594
|
+
},
|
|
42595
|
+
listDirectory: {
|
|
42596
|
+
rule: "global-machine-wide",
|
|
42597
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, so it decides whether the built-in \`list_directory\` tool is registered in this repository.`,
|
|
42598
|
+
globalNote: "Qwen Code honors this key wherever it is written, so in the global scope this decides whether the built-in `list_directory` tool is registered for every project on this machine."
|
|
42599
|
+
}
|
|
42600
|
+
}
|
|
42601
|
+
}, {
|
|
42602
|
+
groupName: "security",
|
|
42603
|
+
overrideKeys: QWEN_OVERRIDE_SECURITY_KEYS,
|
|
42604
|
+
scopedKeys: {
|
|
42605
|
+
allowPrivateNetworkHooks: { rule: "workspace-stripped" },
|
|
42606
|
+
allowedInsecureVoiceBaseUrls: {
|
|
42607
|
+
rule: "workspace-stripped",
|
|
42608
|
+
grants: isNonEmptyArray
|
|
42609
|
+
},
|
|
42610
|
+
allowedHttpHookUrls: { rule: "workspace-non-overriding" },
|
|
42611
|
+
folderTrust: { rule: "user-scope-trust-check" }
|
|
42612
|
+
}
|
|
42613
|
+
}];
|
|
42490
42614
|
const QWEN_OVERRIDE_PERMISSIONS_KEYS = ["autoMode"];
|
|
42615
|
+
const QWEN_SCOPED_PERMISSIONS_KEYS = { autoMode: {
|
|
42616
|
+
rule: "global-machine-wide",
|
|
42617
|
+
projectNote: ({ qualifiedKey, quotedValue, filePath }) => `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}, replacing the whole block rather than merging into it, so it rewrites the instructions Auto Mode's classifier follows in this repository — including any deny hint you had configured.`,
|
|
42618
|
+
globalNote: "Qwen Code honors this key wherever it is written, and the override replaces the whole block rather than merging into it, so in the global scope this rewrites the instructions Auto Mode's classifier follows — including any deny hint you had configured — for every project on this machine."
|
|
42619
|
+
} };
|
|
42491
42620
|
function asPlainRecord(value) {
|
|
42492
42621
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
42493
42622
|
}
|
|
@@ -42499,20 +42628,172 @@ function pickQwenOverrideKeys(group, keys) {
|
|
|
42499
42628
|
return picked;
|
|
42500
42629
|
}
|
|
42501
42630
|
/**
|
|
42502
|
-
*
|
|
42503
|
-
*
|
|
42504
|
-
*
|
|
42631
|
+
* Whether a value written for a scoped key actually grants something. Qwen Code
|
|
42632
|
+
* reads the boolean ones with a plain truthiness check, so anything truthy turns
|
|
42633
|
+
* the capability on — `1` and the string `"false"` included, which is why this is
|
|
42634
|
+
* not a `=== true` test. Not all of them are booleans either:
|
|
42635
|
+
* `security.allowedInsecureVoiceBaseUrls` is a list of base URLs, and an empty
|
|
42636
|
+
* list grants nothing.
|
|
42637
|
+
*
|
|
42638
|
+
* Only the rules whose `announceOnlyGrants` is set consult this, because "empty"
|
|
42639
|
+
* does not mean the same thing for every list: an empty
|
|
42640
|
+
* `security.allowedHttpHookUrls` is Qwen Code's allow-all, the widest value there
|
|
42641
|
+
* is, so that key is announced whatever it says.
|
|
42642
|
+
*/
|
|
42643
|
+
function isNonEmptyArray(value) {
|
|
42644
|
+
return Array.isArray(value) && value.length > 0;
|
|
42645
|
+
}
|
|
42646
|
+
/**
|
|
42647
|
+
* Whether a value turns something on, read the way Qwen Code reads it.
|
|
42648
|
+
*
|
|
42649
|
+
* Plain truthiness by default, because that is what Qwen Code applies to these
|
|
42650
|
+
* settings: `1` and the string `"false"` enable them, and so does an empty array
|
|
42651
|
+
* — which is why an empty list cannot be treated as harmless everywhere. A key
|
|
42652
|
+
* whose list Qwen Code matches against, rather than tests for truth, carries its
|
|
42653
|
+
* own `grants` instead.
|
|
42654
|
+
*/
|
|
42655
|
+
function grantsSomething(value, scopedKey) {
|
|
42656
|
+
return (scopedKey?.grants ?? Boolean)(value);
|
|
42657
|
+
}
|
|
42658
|
+
/**
|
|
42659
|
+
* The autonomy and containment controls say the same thing in project scope, so
|
|
42660
|
+
* they share one note rather than repeating it three times.
|
|
42505
42661
|
*/
|
|
42506
|
-
function
|
|
42507
|
-
|
|
42508
|
-
|
|
42509
|
-
|
|
42510
|
-
|
|
42511
|
-
|
|
42512
|
-
|
|
42662
|
+
function autonomyProjectNote({ qualifiedKey, quotedValue, filePath }) {
|
|
42663
|
+
return `${qualifiedKey} = ${quotedValue} was written to the project-scoped ${filePath}. Qwen Code honors this key in a workspace file, so it settles how far approvals are skipped and whether tool calls are contained while you work in this repository. Check it if the override arrived with a repository you cloned.`;
|
|
42664
|
+
}
|
|
42665
|
+
/**
|
|
42666
|
+
* Quote a `group.key` pair for a warning. The key goes through the same quoting
|
|
42667
|
+
* a value does, because it is one: the override's groups are `z.looseObject`s,
|
|
42668
|
+
* so a key the scope gate names may have been written by whoever authored the
|
|
42669
|
+
* `.rulesync/permissions.jsonc` rather than chosen from a list rulesync knows.
|
|
42670
|
+
* Serializing it — rather than wrapping it in quotes of our own — is what keeps
|
|
42671
|
+
* a key that contains a quote from closing it and continuing the sentence.
|
|
42672
|
+
*/
|
|
42673
|
+
function quoteQualifiedKey({ groupName, key }) {
|
|
42674
|
+
return quoteValueForWarning(`${groupName}.${key}`);
|
|
42675
|
+
}
|
|
42676
|
+
/**
|
|
42677
|
+
* Compare two settings values without letting key order decide the answer, so
|
|
42678
|
+
* re-emitting `{ enabled: true, note: "x" }` as `{ note: "x", enabled: true }`
|
|
42679
|
+
* is not announced as a change.
|
|
42680
|
+
*/
|
|
42681
|
+
function stableStringify(value) {
|
|
42682
|
+
return JSON.stringify(value, (_key, nested) => nested !== null && typeof nested === "object" && !Array.isArray(nested) ? Object.fromEntries(Object.entries(nested).toSorted(([left], [right]) => left.localeCompare(right))) : nested) ?? "undefined";
|
|
42683
|
+
}
|
|
42684
|
+
function sameSettingsValue(a, b) {
|
|
42685
|
+
return stableStringify(a) === stableStringify(b);
|
|
42686
|
+
}
|
|
42687
|
+
/**
|
|
42688
|
+
* Apply the scope rules for a settings group's scoped keys.
|
|
42689
|
+
*
|
|
42690
|
+
* Generating project settings drops the keys Qwen Code strips from a workspace
|
|
42691
|
+
* file before the merge — writing one there would be dead configuration — and
|
|
42692
|
+
* explains the keys whose project value is honored only conditionally rather
|
|
42693
|
+
* than dropping those. Either way only the override copy is touched, so a value
|
|
42694
|
+
* the user already wrote into the project file stays where it is.
|
|
42695
|
+
*
|
|
42696
|
+
* Generating global settings keeps every key, and announces the write: the
|
|
42697
|
+
* `.rulesync/permissions.jsonc` carrying it may have arrived with a cloned or
|
|
42698
|
+
* fetched repository, and the global file applies to every project on this
|
|
42699
|
+
* machine. So the new value is named alongside the one it replaces, exactly as
|
|
42700
|
+
* the deepagents startup override announces its own relaxations. Every key the
|
|
42701
|
+
* override writes is announced, not only the ones with a scope rule — the
|
|
42702
|
+
* groups are `z.looseObject`s, so an unmodeled key falls back to the
|
|
42703
|
+
* `unmodeled` rule rather than slipping past the gate that the modeled ones
|
|
42704
|
+
* pass through.
|
|
42705
|
+
*/
|
|
42706
|
+
function scopeOverrideGroup(overrideGroup, { groupName, scopedKeys, existingGroup, global, filePath, logger }) {
|
|
42707
|
+
const scoped = { ...asPlainRecord(overrideGroup) };
|
|
42708
|
+
const previous = asPlainRecord(existingGroup);
|
|
42709
|
+
const rulesByKey = new Map(Object.entries(scopedKeys));
|
|
42710
|
+
for (const key of Object.keys(scoped)) {
|
|
42711
|
+
const value = scoped[key];
|
|
42712
|
+
if (value === void 0) continue;
|
|
42713
|
+
const scopedKey = rulesByKey.get(key);
|
|
42714
|
+
const rule = scopedKey?.rule ?? "unmodeled";
|
|
42715
|
+
const { stripInProjectScope, announceOnlyGrants } = QWEN_SCOPE_RULES[rule];
|
|
42716
|
+
const projectNote = scopedKey?.projectNote ?? QWEN_SCOPE_RULES[rule].projectNote;
|
|
42717
|
+
const globalNote = scopedKey?.globalNote ?? QWEN_SCOPE_RULES[rule].globalNote;
|
|
42718
|
+
const previousValue = Object.hasOwn(previous, key) ? previous[key] : void 0;
|
|
42719
|
+
const unchanged = sameSettingsValue(previousValue, value);
|
|
42720
|
+
if (!global) {
|
|
42721
|
+
if (stripInProjectScope) delete scoped[key];
|
|
42722
|
+
else if (unchanged) continue;
|
|
42723
|
+
if (projectNote) warnWithFallback(logger, `Qwen permissions: ${projectNote({
|
|
42724
|
+
qualifiedKey: quoteQualifiedKey({
|
|
42725
|
+
groupName,
|
|
42726
|
+
key
|
|
42727
|
+
}),
|
|
42728
|
+
quotedValue: quoteValueForWarning(value),
|
|
42729
|
+
filePath
|
|
42730
|
+
})}`);
|
|
42731
|
+
continue;
|
|
42732
|
+
}
|
|
42733
|
+
if (unchanged) continue;
|
|
42734
|
+
if (announceOnlyGrants && !grantsSomething(value, scopedKey)) continue;
|
|
42735
|
+
const replaced = previousValue === void 0 ? "" : ` (was ${quoteValueForWarning(previousValue)})`;
|
|
42736
|
+
warnWithFallback(logger, `Qwen permissions: the qwencode override wrote ${quoteQualifiedKey({
|
|
42737
|
+
groupName,
|
|
42738
|
+
key
|
|
42739
|
+
})} = ${quoteValueForWarning(value)}${replaced} into ${filePath}, your global Qwen Code settings. ${globalNote}`);
|
|
42513
42740
|
}
|
|
42514
42741
|
return scoped;
|
|
42515
42742
|
}
|
|
42743
|
+
/**
|
|
42744
|
+
* Build the `tools`/`security` patch groups contributed by the `qwencode`
|
|
42745
|
+
* override. Each group is shallow-merged over what `settings.json` already has,
|
|
42746
|
+
* after the scope gate has handled the keys Qwen Code honors in one scope only.
|
|
42747
|
+
*/
|
|
42748
|
+
function buildOverrideGroupsPatch({ settings, override, global, filePath, logger }) {
|
|
42749
|
+
const patch = {};
|
|
42750
|
+
for (const { groupName, scopedKeys } of QWEN_OVERRIDE_GROUPS) {
|
|
42751
|
+
const overrideGroup = override?.[groupName];
|
|
42752
|
+
if (overrideGroup === void 0) continue;
|
|
42753
|
+
const existingGroup = settings[groupName];
|
|
42754
|
+
const scoped = scopeOverrideGroup(overrideGroup, {
|
|
42755
|
+
groupName,
|
|
42756
|
+
scopedKeys,
|
|
42757
|
+
existingGroup,
|
|
42758
|
+
global,
|
|
42759
|
+
filePath,
|
|
42760
|
+
logger
|
|
42761
|
+
});
|
|
42762
|
+
const merged = {
|
|
42763
|
+
...asPlainRecord(existingGroup),
|
|
42764
|
+
...scoped
|
|
42765
|
+
};
|
|
42766
|
+
if (Object.keys(merged).length > 0) patch[groupName] = merged;
|
|
42767
|
+
}
|
|
42768
|
+
return patch;
|
|
42769
|
+
}
|
|
42770
|
+
/**
|
|
42771
|
+
* Warn about a scoped key lifted out of a *project* settings file being
|
|
42772
|
+
* imported. The file carries no scope marker, so import keeps the key either
|
|
42773
|
+
* way — but regenerating in the global scope would turn a value a workspace
|
|
42774
|
+
* could not decide for itself into one Qwen Code enforces everywhere, and a
|
|
42775
|
+
* settings file read out of a cloned repository is exactly where such a value
|
|
42776
|
+
* comes from. Importing the global file is the case this has nothing to say
|
|
42777
|
+
* about: the value is already in the scope the warning would send it to.
|
|
42778
|
+
*/
|
|
42779
|
+
function warnAboutImportedScopedKeys(groups) {
|
|
42780
|
+
for (const { groupName, scopedKeys } of QWEN_OVERRIDE_GROUPS) {
|
|
42781
|
+
const group = groups[groupName];
|
|
42782
|
+
for (const [key, scopedKey] of Object.entries(scopedKeys)) {
|
|
42783
|
+
const { rule } = scopedKey;
|
|
42784
|
+
const value = group[key];
|
|
42785
|
+
if (value === void 0) continue;
|
|
42786
|
+
const { announceOnlyGrants, announceOnImport } = QWEN_SCOPE_RULES[rule];
|
|
42787
|
+
if (!announceOnImport) continue;
|
|
42788
|
+
if (announceOnlyGrants && !grantsSomething(value, scopedKey)) continue;
|
|
42789
|
+
const globalNote = scopedKey.globalNote ?? QWEN_SCOPE_RULES[rule].globalNote;
|
|
42790
|
+
moduleLogger$1.warn(`Qwen permissions: imported ${quoteQualifiedKey({
|
|
42791
|
+
groupName,
|
|
42792
|
+
key
|
|
42793
|
+
})} = ${quoteValueForWarning(value)}. ${globalNote} Review it before generating with the global scope.`);
|
|
42794
|
+
}
|
|
42795
|
+
}
|
|
42796
|
+
}
|
|
42516
42797
|
var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
42517
42798
|
constructor(params) {
|
|
42518
42799
|
super({
|
|
@@ -42541,7 +42822,8 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
42541
42822
|
relativeDirPath: paths.relativeDirPath,
|
|
42542
42823
|
relativeFilePath: paths.relativeFilePath,
|
|
42543
42824
|
fileContent,
|
|
42544
|
-
validate
|
|
42825
|
+
validate,
|
|
42826
|
+
global
|
|
42545
42827
|
});
|
|
42546
42828
|
}
|
|
42547
42829
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, global = false, logger }) {
|
|
@@ -42557,6 +42839,7 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
42557
42839
|
} catch (error) {
|
|
42558
42840
|
throw new Error(`Failed to parse existing Qwen settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
42559
42841
|
}
|
|
42842
|
+
const displayPath = toPosixPath(join(global ? "~" : ".", paths.relativeDirPath, paths.relativeFilePath));
|
|
42560
42843
|
const config = rulesyncPermissions.getJson();
|
|
42561
42844
|
const { allow, ask, deny } = convertRulesyncToQwenPermissions(config);
|
|
42562
42845
|
const managedToolNames = new Set(Object.keys(config.permission).map((category) => toQwenToolName(category)));
|
|
@@ -42575,24 +42858,25 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
42575
42858
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
42576
42859
|
else delete mergedPermissions.deny;
|
|
42577
42860
|
const override = config.qwencode;
|
|
42578
|
-
if (override?.autoMode !== void 0)
|
|
42579
|
-
|
|
42580
|
-
|
|
42581
|
-
|
|
42582
|
-
|
|
42583
|
-
};
|
|
42584
|
-
if (override?.security !== void 0) {
|
|
42585
|
-
const scopedSecurity = scopeOverrideSecurity(override.security, {
|
|
42861
|
+
if (override?.autoMode !== void 0) {
|
|
42862
|
+
const scopedAutoMode = scopeOverrideGroup({ autoMode: override.autoMode }, {
|
|
42863
|
+
groupName: "permissions",
|
|
42864
|
+
scopedKeys: QWEN_SCOPED_PERMISSIONS_KEYS,
|
|
42865
|
+
existingGroup: existingPermissions,
|
|
42586
42866
|
global,
|
|
42587
|
-
|
|
42867
|
+
filePath: displayPath,
|
|
42588
42868
|
logger
|
|
42589
42869
|
});
|
|
42590
|
-
|
|
42591
|
-
...asPlainRecord(settings.security),
|
|
42592
|
-
...scopedSecurity
|
|
42593
|
-
};
|
|
42594
|
-
if (Object.keys(mergedSecurity).length > 0) patch.security = mergedSecurity;
|
|
42870
|
+
if (scopedAutoMode.autoMode !== void 0) mergedPermissions.autoMode = scopedAutoMode.autoMode;
|
|
42595
42871
|
}
|
|
42872
|
+
const patch = { permissions: mergedPermissions };
|
|
42873
|
+
Object.assign(patch, buildOverrideGroupsPatch({
|
|
42874
|
+
settings,
|
|
42875
|
+
override,
|
|
42876
|
+
global,
|
|
42877
|
+
filePath: displayPath,
|
|
42878
|
+
logger
|
|
42879
|
+
}));
|
|
42596
42880
|
const fileContent = applySharedConfigPatch({
|
|
42597
42881
|
fileKey: sharedConfigFileKey(paths),
|
|
42598
42882
|
feature: "permissions",
|
|
@@ -42624,16 +42908,17 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
42624
42908
|
ask: permissions.ask ?? [],
|
|
42625
42909
|
deny: permissions.deny ?? []
|
|
42626
42910
|
});
|
|
42627
|
-
const
|
|
42628
|
-
|
|
42629
|
-
|
|
42630
|
-
|
|
42631
|
-
|
|
42632
|
-
}
|
|
42911
|
+
const overrideGroups = {
|
|
42912
|
+
tools: pickQwenOverrideKeys(settings.tools, QWEN_OVERRIDE_TOOLS_KEYS),
|
|
42913
|
+
security: pickQwenOverrideKeys(settings.security, QWEN_OVERRIDE_SECURITY_KEYS)
|
|
42914
|
+
};
|
|
42915
|
+
if (!this.global) warnAboutImportedScopedKeys(overrideGroups);
|
|
42633
42916
|
const overridePermissions = pickQwenOverrideKeys(settings.permissions, QWEN_OVERRIDE_PERMISSIONS_KEYS);
|
|
42634
42917
|
const qwencodeOverride = {};
|
|
42635
|
-
|
|
42636
|
-
|
|
42918
|
+
for (const { groupName } of QWEN_OVERRIDE_GROUPS) {
|
|
42919
|
+
const group = overrideGroups[groupName];
|
|
42920
|
+
if (Object.keys(group).length > 0) qwencodeOverride[groupName] = group;
|
|
42921
|
+
}
|
|
42637
42922
|
if (overridePermissions.autoMode !== void 0) qwencodeOverride.autoMode = overridePermissions.autoMode;
|
|
42638
42923
|
const result = { ...config };
|
|
42639
42924
|
if (Object.keys(qwencodeOverride).length > 0) result.qwencode = qwencodeOverride;
|
|
@@ -69137,4 +69422,4 @@ async function importChecksCore(params) {
|
|
|
69137
69422
|
//#endregion
|
|
69138
69423
|
export { RulesyncCheckFrontmatterSchema as $, ALL_TOOL_TARGETS_WITH_WILDCARD as $t, FACTORYDROID_DIR as A, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as An, fileExists as At, RulesyncSkillFrontmatterSchema as B, stripControlCharacters as Bn, readFileContent as Bt, CODEXCLI_BASH_RULES_FILE_NAME as C, RULESYNC_PERMISSIONS_LEGACY_FILE_NAME as Cn, assertDirectoryIfExists as Ct, CLAUDECODE_MEMORIES_DIR_NAME as D, RULESYNC_RULES_RELATIVE_DIR_PATH as Dn, createTempDirectory as Dt, CLAUDECODE_LOCAL_RULE_FILE_NAME as E, RULESYNC_RELATIVE_DIR_PATH as En, checkPathTraversal as Et, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as F, formatError as Fn, isSymlink as Ft, RulesyncIgnore as G, removeFileStrict as Gt, RulesyncRuleFrontmatterSchema as H, stripHiddenCharacters as Hn, removeDirectory as Ht, getLocalSkillDirNames as I, truncateText as In, listDirectoryEntryNames as It, resolveRulesyncSourceWritePath as J, runWithDirectoryRollback as Jt, RulesyncHooks as K, removeTempDirectory as Kt, RulesyncSubagent as L, hasDeceptiveHiddenCharacters as Ln, listFilePathsRecursively as Lt, caseFoldIdentity as M, ALL_FEATURES as Mn, getHomeDirectory as Mt, groupSpellingsByCaseFoldedIdentity as N, ALL_FEATURES_WITH_WILDCARD as Nn, isFileNotFoundError as Nt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as O, RULESYNC_SKILLS_RELATIVE_DIR_PATH as On, directoryExists as Ot, AUGMENTCODE_DIR as P, DEPRECATED_FEATURE_REPLACEMENTS as Pn, isFileSystemError as Pt, RulesyncCheck as Q, ALL_TOOL_TARGETS as Qt, RulesyncSubagentFrontmatterSchema as R, hasEnclosingMarkOutsideKeycap as Rn, listSubdirectoryNames as Rt, ChecksProcessor as S, RULESYNC_PERMISSIONS_FILE_NAME as Sn, applyFileMode as St, CLAUDECODE_DIR as T, RULESYNC_PERMISSIONS_SCHEMA_URL as Tn, assertWritablePathInsideRoot as Tt, RulesyncPermissions as U, removeDirectoryStrict as Ut, RulesyncRule as V, stripControlCharactersKeepingLineFeeds as Vn, readFileContentOrNull as Vt, RulesyncMcp as W, removeFile as Wt, RulesyncCommand as X, writeFileBuffer as Xt, parseJsonc as Y, toPosixPath as Yt, RulesyncCommandFrontmatterSchema as Z, writeFileContent as Zt, IgnoreProcessor as _, RULESYNC_MCP_FILE_NAME as _n, withFallbackLoggerTarget as _t, getProcessorRegistryEntry as a, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as an, mergeInputRootConfigs as at, QWENCODE_DIR as b, RULESYNC_MCP_SCHEMA_URL as bn, CLIError as bt, RulesProcessor as c, RULESYNC_CONFIG_RELATIVE_FILE_PATH as cn, ConfigFileSchema as ct, CODEBUDDY_DIR as d, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as dn, findControlCharacter as dt, PACKAGING_TOOL_TARGETS as en, stringifyFrontmatter as et, CODEBUDDY_LOCAL_RULE_FILE_NAME as f, RULESYNC_HOOKS_FILE_NAME as fn, ConsoleLogger as ft, McpProcessor as g, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as gn, warnOnConflictingFlags as gt, shortenToWidth as h, RULESYNC_IGNORE_RELATIVE_FILE_PATH as hn, fallbackLogger as ht, inspectInputRoots as i, RULESYNC_AIIGNORE_FILE_NAME as in, ConfigResolver as it, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as j, parseCommaSeparatedList as jn, getFileSize as jt, CLAUDECODE_SKILLS_DIR_PATH as k, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as kn, ensureDir as kt, SubagentsProcessor as l, RULESYNC_CONFIG_SCHEMA_URL as ln, GITIGNORE_DESTINATION_KEY as lt, displayWidthOf as m, RULESYNC_HOOKS_RELATIVE_FILE_PATH as mn, WarningCollectingLogger as mt, formatSourceLoadFailure as n, CURATED_RULES_FEATURE_SUBDIR as nn, SHARED_USER_MANAGED_CONFIG_PATHS as nt, convertFromTool as o, RULESYNC_CHECKS_RELATIVE_DIR_PATH as on, resolveEffectiveInputRoots as ot, ELLIPSIS_WIDTH as p, RULESYNC_HOOKS_LEGACY_FILE_NAME as pn, JsonLogger as pt, getRulesyncSourceCandidates as q, resolvePath as qt, generate as r, MAX_FILE_SIZE as rn, SKILL_FILE_NAME as rt, isPackagingToolTarget as s, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as sn, CONFLICTING_TARGET_PAIRS as st, importFromTool as t, ToolTargetSchema as tn, loadYaml as tt, SkillsProcessor as u, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as un, SourceEntrySchema as ut, HooksProcessor as v, RULESYNC_MCP_LEGACY_FILE_NAME as vn, resetRunWarningState as vt, CODEXCLI_DIR as w, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as wn, assertTreeContainsNoSymlinks as wt, QWENCODE_LOCAL_RULE_FILE_NAME as x, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as xn, ErrorCodes as xt, CommandsProcessor as y, RULESYNC_MCP_RELATIVE_FILE_PATH as yn, withWarnOnceScope as yt, RulesyncSkill as z, quoteForLog as zn, pathEscapesRoot as zt };
|
|
69139
69424
|
|
|
69140
|
-
//# sourceMappingURL=import-
|
|
69425
|
+
//# sourceMappingURL=import-DyWRanf6.js.map
|