axconfig 3.5.0 → 3.5.2
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.
|
@@ -47,10 +47,25 @@ export declare function collectTools(rules: PermissionRule[]): Set<CanonicalTool
|
|
|
47
47
|
export declare function collectBashPatterns(rules: PermissionRule[]): string[];
|
|
48
48
|
/**
|
|
49
49
|
* Build bash permission config from patterns and tool permissions.
|
|
50
|
+
*
|
|
51
|
+
* IMPORTANT: The wildcard "*" rule must be added FIRST in the config object.
|
|
52
|
+
* OpenCode's `disabled()` function uses `findLast()` to find any rule matching
|
|
53
|
+
* the permission name, then checks if that rule has `pattern === "*"` and
|
|
54
|
+
* `action === "deny"`. If the "*" rule is last, bash gets disabled entirely
|
|
55
|
+
* even when specific patterns are allowed. By adding "*" first, `findLast()`
|
|
56
|
+
* returns a specific pattern rule instead, keeping bash available to the model.
|
|
57
|
+
*
|
|
58
|
+
* At execution time, `evaluate()` correctly handles rule precedence because it
|
|
59
|
+
* uses `findLast()` with BOTH permission AND pattern matching - so specific
|
|
60
|
+
* patterns still take priority over the wildcard when the command matches.
|
|
50
61
|
*/
|
|
51
62
|
export declare function buildBashPermission(allowPatterns: string[], denyPatterns: string[], bashAllowed: boolean, bashDenied: boolean): OpenCodePermission | Record<string, OpenCodePermission>;
|
|
52
63
|
/**
|
|
53
64
|
* Build tool permission config with optional path patterns.
|
|
65
|
+
*
|
|
66
|
+
* IMPORTANT: Like buildBashPermission, the wildcard "*" rule must be added
|
|
67
|
+
* FIRST to prevent OpenCode's disabled() from hiding the tool entirely.
|
|
68
|
+
* See buildBashPermission comment for detailed explanation.
|
|
54
69
|
*/
|
|
55
70
|
export declare function buildToolPermission(canonicalName: CanonicalTool, opencodeName: string, allowedTools: Set<CanonicalTool>, deniedTools: Set<CanonicalTool>, allowPathPatterns: Map<string, string[]>, denyPathPatterns: Map<string, string[]>): OpenCodePermission | Record<string, OpenCodePermission>;
|
|
56
71
|
/**
|
|
@@ -76,28 +76,69 @@ export function collectBashPatterns(rules) {
|
|
|
76
76
|
.filter((r) => r.type === "bash")
|
|
77
77
|
.map((r) => r.pattern);
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Normalize a bash pattern for OpenCode by adding a trailing wildcard if needed.
|
|
81
|
+
*
|
|
82
|
+
* OpenCode uses an "arity" system to extract command prefixes for permission
|
|
83
|
+
* checking. For example, `gh` has arity 3, so `gh api repos/foo/bar` extracts
|
|
84
|
+
* the prefix `gh api repos/foo/bar` (first 3 tokens). A pattern `gh api` won't
|
|
85
|
+
* match because it's missing the third token.
|
|
86
|
+
*
|
|
87
|
+
* By appending `*` to patterns that don't already have wildcards, we ensure
|
|
88
|
+
* patterns like `gh api` become `gh api*` which matches `gh api repos/...`.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* normalizeBashPattern("gh api") // "gh api*"
|
|
92
|
+
* normalizeBashPattern("git *") // "git *" (already has wildcard)
|
|
93
|
+
* normalizeBashPattern("cat") // "cat*"
|
|
94
|
+
*/
|
|
95
|
+
function normalizeBashPattern(pattern) {
|
|
96
|
+
// Don't add another * if pattern already ends with one
|
|
97
|
+
if (pattern.endsWith("*")) {
|
|
98
|
+
return pattern;
|
|
99
|
+
}
|
|
100
|
+
return `${pattern}*`;
|
|
101
|
+
}
|
|
79
102
|
/**
|
|
80
103
|
* Build bash permission config from patterns and tool permissions.
|
|
104
|
+
*
|
|
105
|
+
* IMPORTANT: The wildcard "*" rule must be added FIRST in the config object.
|
|
106
|
+
* OpenCode's `disabled()` function uses `findLast()` to find any rule matching
|
|
107
|
+
* the permission name, then checks if that rule has `pattern === "*"` and
|
|
108
|
+
* `action === "deny"`. If the "*" rule is last, bash gets disabled entirely
|
|
109
|
+
* even when specific patterns are allowed. By adding "*" first, `findLast()`
|
|
110
|
+
* returns a specific pattern rule instead, keeping bash available to the model.
|
|
111
|
+
*
|
|
112
|
+
* At execution time, `evaluate()` correctly handles rule precedence because it
|
|
113
|
+
* uses `findLast()` with BOTH permission AND pattern matching - so specific
|
|
114
|
+
* patterns still take priority over the wildcard when the command matches.
|
|
81
115
|
*/
|
|
82
116
|
export function buildBashPermission(allowPatterns, denyPatterns, bashAllowed, bashDenied) {
|
|
83
117
|
if (bashDenied && allowPatterns.length === 0) {
|
|
84
118
|
return "deny";
|
|
85
119
|
}
|
|
86
120
|
if (allowPatterns.length > 0 || denyPatterns.length > 0) {
|
|
87
|
-
|
|
121
|
+
// Add wildcard FIRST so specific patterns come after in ruleset order.
|
|
122
|
+
// This prevents OpenCode's disabled() from hiding bash from the model.
|
|
123
|
+
const bashConfig = {
|
|
124
|
+
"*": bashAllowed ? "allow" : "deny",
|
|
125
|
+
};
|
|
88
126
|
for (const pattern of allowPatterns) {
|
|
89
|
-
bashConfig[pattern] = "allow";
|
|
127
|
+
bashConfig[normalizeBashPattern(pattern)] = "allow";
|
|
90
128
|
}
|
|
91
129
|
for (const pattern of denyPatterns) {
|
|
92
|
-
bashConfig[pattern] = "deny";
|
|
130
|
+
bashConfig[normalizeBashPattern(pattern)] = "deny";
|
|
93
131
|
}
|
|
94
|
-
bashConfig["*"] = bashAllowed ? "allow" : "deny";
|
|
95
132
|
return bashConfig;
|
|
96
133
|
}
|
|
97
134
|
return bashAllowed ? "allow" : "deny";
|
|
98
135
|
}
|
|
99
136
|
/**
|
|
100
137
|
* Build tool permission config with optional path patterns.
|
|
138
|
+
*
|
|
139
|
+
* IMPORTANT: Like buildBashPermission, the wildcard "*" rule must be added
|
|
140
|
+
* FIRST to prevent OpenCode's disabled() from hiding the tool entirely.
|
|
141
|
+
* See buildBashPermission comment for detailed explanation.
|
|
101
142
|
*/
|
|
102
143
|
export function buildToolPermission(canonicalName, opencodeName, allowedTools, deniedTools, allowPathPatterns, denyPathPatterns) {
|
|
103
144
|
const hasAllowPatterns = allowPathPatterns.has(opencodeName);
|
|
@@ -114,14 +155,17 @@ export function buildToolPermission(canonicalName, opencodeName, allowedTools, d
|
|
|
114
155
|
return "deny";
|
|
115
156
|
}
|
|
116
157
|
if (hasAllowPatterns || hasDenyPatterns) {
|
|
117
|
-
|
|
158
|
+
// Add wildcard FIRST so specific patterns come after in ruleset order.
|
|
159
|
+
// This prevents OpenCode's disabled() from hiding the tool from the model.
|
|
160
|
+
const patternConfig = {
|
|
161
|
+
"*": effectiveAllowed ? "allow" : "deny",
|
|
162
|
+
};
|
|
118
163
|
for (const pattern of allowPathPatterns.get(opencodeName) ?? []) {
|
|
119
164
|
patternConfig[pattern] = "allow";
|
|
120
165
|
}
|
|
121
166
|
for (const pattern of denyPathPatterns.get(opencodeName) ?? []) {
|
|
122
167
|
patternConfig[pattern] = "deny";
|
|
123
168
|
}
|
|
124
|
-
patternConfig["*"] = effectiveAllowed ? "allow" : "deny";
|
|
125
169
|
return patternConfig;
|
|
126
170
|
}
|
|
127
171
|
return effectiveAllowed ? "allow" : "deny";
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "axconfig",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.2",
|
|
6
6
|
"description": "Unified configuration management for AI coding agents - common API for permissions, settings, and config across Claude Code, Codex, Gemini CLI, and OpenCode",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|