axconfig 2.0.0 → 3.0.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 +40 -40
- package/dist/agents/{claude-code-reader.js → claude-reader.js} +7 -3
- package/dist/agents/{claude-code.d.ts → claude.d.ts} +1 -1
- package/dist/agents/{claude-code.js → claude.js} +1 -1
- package/dist/agents/codex-reader.js +7 -3
- package/dist/agents/codex.js +2 -2
- package/dist/agents/copilot-reader.js +7 -24
- package/dist/agents/copilot.js +2 -2
- package/dist/agents/gemini-reader.js +7 -3
- package/dist/agents/gemini.js +1 -1
- package/dist/agents/opencode-reader.js +7 -3
- package/dist/agents/opencode.js +11 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +12 -12
- package/dist/get-agent-runtime-environment.d.ts +37 -0
- package/dist/get-agent-runtime-environment.js +48 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/resolve-config-path.d.ts +3 -1
- package/dist/resolve-config-path.js +5 -14
- package/dist/types.d.ts +12 -0
- package/package.json +2 -2
- /package/dist/agents/{claude-code-reader.d.ts → claude-reader.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -41,23 +41,23 @@ write:.env
|
|
|
41
41
|
|
|
42
42
|
Translates unified permissions to agent-specific formats:
|
|
43
43
|
|
|
44
|
-
| Agent
|
|
45
|
-
|
|
|
46
|
-
| claude
|
|
47
|
-
| codex
|
|
48
|
-
| gemini
|
|
49
|
-
| opencode
|
|
44
|
+
| Agent | Output Format |
|
|
45
|
+
| -------- | --------------------------------------------------------- |
|
|
46
|
+
| claude | JSON `settings.json` with `permissions.allow/deny` arrays |
|
|
47
|
+
| codex | TOML `config.toml` + Starlark `.rules` files |
|
|
48
|
+
| gemini | TOML policy files with `[[rule]]` entries |
|
|
49
|
+
| opencode | JSON with `permission.{edit,bash,webfetch}` |
|
|
50
50
|
|
|
51
51
|
### Capability Validation
|
|
52
52
|
|
|
53
53
|
Each agent has different capabilities:
|
|
54
54
|
|
|
55
|
-
| Agent
|
|
56
|
-
|
|
|
57
|
-
| claude
|
|
58
|
-
| codex
|
|
59
|
-
| gemini
|
|
60
|
-
| opencode
|
|
55
|
+
| Agent | Tool Perms | Bash Patterns | Path Restrictions | Can Deny Read |
|
|
56
|
+
| -------- | ----------- | ------------- | ----------------- | ------------- |
|
|
57
|
+
| claude | ✓ | ✓ | ✓ | ✓ |
|
|
58
|
+
| codex | ✗ (sandbox) | ✓ | ✗ | ✗ |
|
|
59
|
+
| gemini | ✓ | ✓ | ✗ | ✓ |
|
|
60
|
+
| opencode | ✓ | ✓ | ✗ | ✓ |
|
|
61
61
|
|
|
62
62
|
axconfig validates permissions against agent capabilities:
|
|
63
63
|
|
|
@@ -82,7 +82,7 @@ const permissions = parsePermissions(
|
|
|
82
82
|
|
|
83
83
|
// Build agent-specific config
|
|
84
84
|
const result = buildAgentConfig({
|
|
85
|
-
agentId: "claude
|
|
85
|
+
agentId: "claude",
|
|
86
86
|
allow: "read,glob,bash:git *",
|
|
87
87
|
deny: "bash:rm *",
|
|
88
88
|
output: "/tmp/my-config", // directory for config files
|
|
@@ -94,8 +94,8 @@ if (result.ok) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Read existing config
|
|
97
|
-
const reader = getConfigReader("claude
|
|
98
|
-
const configDir = resolveConfigPath("claude
|
|
97
|
+
const reader = getConfigReader("claude");
|
|
98
|
+
const configDir = resolveConfigPath("claude"); // ~/.claude/
|
|
99
99
|
|
|
100
100
|
const perms = reader.readPermissions(configDir);
|
|
101
101
|
if (perms.ok && perms.value) {
|
|
@@ -113,58 +113,58 @@ reader.writeRaw(configDir, "customSetting", { foo: "bar" });
|
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
115
|
# Create config with permissions (outputs env vars)
|
|
116
|
-
axconfig create --agent claude
|
|
116
|
+
axconfig create --agent claude --output /tmp/config \
|
|
117
117
|
--allow "read,glob,bash:git *" \
|
|
118
118
|
--deny "bash:rm *"
|
|
119
119
|
|
|
120
120
|
# Export for shell usage
|
|
121
|
-
eval $(axconfig create --agent claude
|
|
121
|
+
eval $(axconfig create --agent claude --output /tmp/config --allow read)
|
|
122
122
|
|
|
123
123
|
# Export as JSON for parsing
|
|
124
|
-
axconfig create --agent claude
|
|
124
|
+
axconfig create --agent claude --output /tmp/cfg --allow read --format json | jq '.env'
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
### Get/Set Unified Settings
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
130
|
# Get current settings (uses agent's default config location)
|
|
131
|
-
axconfig get --agent claude
|
|
131
|
+
axconfig get --agent claude allow
|
|
132
132
|
# Output: read,glob,bash:git *
|
|
133
133
|
|
|
134
|
-
axconfig get --agent claude
|
|
134
|
+
axconfig get --agent claude deny
|
|
135
135
|
# Output: bash:rm *
|
|
136
136
|
|
|
137
|
-
axconfig get --agent claude
|
|
137
|
+
axconfig get --agent claude model
|
|
138
138
|
# Output: sonnet
|
|
139
139
|
|
|
140
140
|
# Get settings as JSON
|
|
141
|
-
axconfig get --agent claude
|
|
141
|
+
axconfig get --agent claude allow --format json
|
|
142
142
|
# Output: ["Read", "Glob", {"Bash": {"command": "git", "args": "*"}}]
|
|
143
143
|
|
|
144
144
|
# Set settings (merge with existing by default)
|
|
145
|
-
axconfig set --agent claude
|
|
146
|
-
axconfig set --agent claude
|
|
147
|
-
axconfig set --agent claude
|
|
145
|
+
axconfig set --agent claude allow "read,glob"
|
|
146
|
+
axconfig set --agent claude deny "bash:rm *"
|
|
147
|
+
axconfig set --agent claude model "claude-sonnet-4-20250514"
|
|
148
148
|
|
|
149
149
|
# Replace instead of merge (for allow/deny)
|
|
150
|
-
axconfig set --agent claude
|
|
150
|
+
axconfig set --agent claude allow "read,glob" --replace
|
|
151
151
|
|
|
152
152
|
# Set with custom config path
|
|
153
|
-
axconfig set --agent claude
|
|
153
|
+
axconfig set --agent claude --path /tmp/cfg allow "read,glob"
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
### Get/Set Raw Config Values
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
159
|
# Get raw config value by dotted path
|
|
160
|
-
axconfig get-raw --agent claude
|
|
160
|
+
axconfig get-raw --agent claude permissions.allow
|
|
161
161
|
# Output: ["Read", "Glob"]
|
|
162
162
|
|
|
163
163
|
# Get raw value as JSON
|
|
164
|
-
axconfig get-raw --agent claude
|
|
164
|
+
axconfig get-raw --agent claude permissions --format json
|
|
165
165
|
|
|
166
166
|
# Set raw config value (JSON or string)
|
|
167
|
-
axconfig set-raw --agent claude
|
|
167
|
+
axconfig set-raw --agent claude permissions.allow '["Read", "Glob"]'
|
|
168
168
|
axconfig set-raw --agent opencode permission.edit allow
|
|
169
169
|
```
|
|
170
170
|
|
|
@@ -172,29 +172,29 @@ axconfig set-raw --agent opencode permission.edit allow
|
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
174
|
# Capture settings in shell variables
|
|
175
|
-
ALLOW=$(axconfig get --agent claude
|
|
176
|
-
MODEL=$(axconfig get --agent claude
|
|
175
|
+
ALLOW=$(axconfig get --agent claude allow)
|
|
176
|
+
MODEL=$(axconfig get --agent claude model)
|
|
177
177
|
|
|
178
178
|
# Extract allow rules as JSON and filter with jq
|
|
179
|
-
axconfig get --agent claude
|
|
179
|
+
axconfig get --agent claude allow --format json | jq '.'
|
|
180
180
|
|
|
181
181
|
# List all bash permissions, one per line
|
|
182
|
-
axconfig get --agent claude
|
|
182
|
+
axconfig get --agent claude allow | tr ',' '\n' | grep 'bash:'
|
|
183
183
|
|
|
184
184
|
# Count unique bash command prefixes
|
|
185
|
-
axconfig get --agent claude
|
|
185
|
+
axconfig get --agent claude allow \
|
|
186
186
|
| tr ',' '\n' | grep 'bash:' \
|
|
187
187
|
| cut -d: -f2 | cut -d' ' -f1 | sort | uniq -c | sort -rn
|
|
188
188
|
|
|
189
189
|
# Compare permissions between agents
|
|
190
|
-
diff <(axconfig get -a claude
|
|
190
|
+
diff <(axconfig get -a claude allow) <(axconfig get -a gemini allow)
|
|
191
191
|
|
|
192
192
|
# Check if a specific permission exists
|
|
193
|
-
axconfig get --agent claude
|
|
193
|
+
axconfig get --agent claude allow | grep -q 'bash:git' && echo "git allowed"
|
|
194
194
|
|
|
195
195
|
# Add a new permission to existing allow list
|
|
196
|
-
CURRENT=$(axconfig get --agent claude
|
|
197
|
-
axconfig set --agent claude
|
|
196
|
+
CURRENT=$(axconfig get --agent claude allow)
|
|
197
|
+
axconfig set --agent claude allow "$CURRENT,write" --replace
|
|
198
198
|
```
|
|
199
199
|
|
|
200
200
|
## Module Structure
|
|
@@ -215,7 +215,7 @@ src/
|
|
|
215
215
|
│ ├── get-raw.ts # Get raw config values
|
|
216
216
|
│ └── set-raw.ts # Set raw config values
|
|
217
217
|
└── agents/
|
|
218
|
-
├── claude
|
|
218
|
+
├── claude.ts # Claude Code config builder + reader
|
|
219
219
|
├── codex.ts # Codex config builder + reader
|
|
220
220
|
├── gemini.ts # Gemini CLI config builder + reader
|
|
221
221
|
└── opencode.ts # OpenCode config builder + reader
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Reads and writes Claude Code configuration from settings.json.
|
|
5
5
|
*/
|
|
6
6
|
import { mkdirSync } from "node:fs";
|
|
7
|
-
import { homedir } from "node:os";
|
|
8
7
|
import path from "node:path";
|
|
8
|
+
import { getAgentPathInfo } from "axshared";
|
|
9
9
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
10
10
|
import { registerConfigReader } from "../reader.js";
|
|
11
11
|
import { createJsonConfigOperations, readJsonConfig, } from "../read-write-json-config.js";
|
|
@@ -143,11 +143,15 @@ function writeModel(configDirectory, model) {
|
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
+
// Get path info from axshared (single source of truth)
|
|
147
|
+
const pathInfo = getAgentPathInfo("claude");
|
|
146
148
|
/** Claude Code ConfigReader */
|
|
147
149
|
const claudeCodeConfigReader = {
|
|
148
150
|
agentId: "claude",
|
|
149
|
-
defaultConfigDir:
|
|
150
|
-
envVar:
|
|
151
|
+
defaultConfigDir: pathInfo.defaultConfigDir,
|
|
152
|
+
envVar: pathInfo.envVar,
|
|
153
|
+
subdirectory: pathInfo.subdirectory,
|
|
154
|
+
buildRuntimeEnvironment: pathInfo.buildRuntimeEnvironment,
|
|
151
155
|
readPermissions,
|
|
152
156
|
readModel,
|
|
153
157
|
writeModel,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Path patterns like "Read(src/**)"
|
|
10
10
|
*/
|
|
11
11
|
import type { ConfigBuilder } from "../types.js";
|
|
12
|
-
export { claudeCodeConfigReader } from "./claude-
|
|
12
|
+
export { claudeCodeConfigReader } from "./claude-reader.js";
|
|
13
13
|
/** Claude Code ConfigBuilder */
|
|
14
14
|
declare const claudeCodeConfigBuilder: ConfigBuilder;
|
|
15
15
|
export { claudeCodeConfigBuilder };
|
|
@@ -13,7 +13,7 @@ import path from "node:path";
|
|
|
13
13
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
14
14
|
import { registerConfigBuilder } from "../builder.js";
|
|
15
15
|
// Re-export reader
|
|
16
|
-
export { claudeCodeConfigReader } from "./claude-
|
|
16
|
+
export { claudeCodeConfigReader } from "./claude-reader.js";
|
|
17
17
|
/** Claude Code tool name mapping */
|
|
18
18
|
const TOOL_MAP = {
|
|
19
19
|
read: "Read",
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Reads and writes Codex configuration from config.toml and .rules files.
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
7
|
-
import { homedir } from "node:os";
|
|
8
7
|
import path from "node:path";
|
|
9
8
|
import TOML from "@iarna/toml";
|
|
9
|
+
import { getAgentPathInfo } from "axshared";
|
|
10
10
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
11
11
|
import { registerConfigReader } from "../reader.js";
|
|
12
12
|
import { createTomlConfigOperations, readTomlConfig, } from "../read-write-toml-config.js";
|
|
@@ -145,11 +145,15 @@ function writeModel(configDirectory, model) {
|
|
|
145
145
|
return { ok: false, error: `Failed to write Codex model: ${message}` };
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
// Get path info from axshared (single source of truth)
|
|
149
|
+
const pathInfo = getAgentPathInfo("codex");
|
|
148
150
|
/** Codex ConfigReader */
|
|
149
151
|
const codexConfigReader = {
|
|
150
152
|
agentId: "codex",
|
|
151
|
-
defaultConfigDir:
|
|
152
|
-
envVar:
|
|
153
|
+
defaultConfigDir: pathInfo.defaultConfigDir,
|
|
154
|
+
envVar: pathInfo.envVar,
|
|
155
|
+
subdirectory: pathInfo.subdirectory,
|
|
156
|
+
buildRuntimeEnvironment: pathInfo.buildRuntimeEnvironment,
|
|
153
157
|
readPermissions,
|
|
154
158
|
readModel,
|
|
155
159
|
writeModel,
|
package/dist/agents/codex.js
CHANGED
|
@@ -68,7 +68,7 @@ function build(config, output) {
|
|
|
68
68
|
rule,
|
|
69
69
|
reason: "Codex sandbox mode always permits file reads",
|
|
70
70
|
suggestions: [
|
|
71
|
-
"Use a different agent that supports denying reads (e.g., claude
|
|
71
|
+
"Use a different agent that supports denying reads (e.g., claude)",
|
|
72
72
|
'Remove the --deny "read" rule',
|
|
73
73
|
],
|
|
74
74
|
});
|
|
@@ -80,7 +80,7 @@ function build(config, output) {
|
|
|
80
80
|
reason: "Codex does not support path restrictions",
|
|
81
81
|
suggestions: [
|
|
82
82
|
`Use "${rule.tool}" to deny all ${rule.tool} operations`,
|
|
83
|
-
"Use a different agent that supports path restrictions (e.g., claude
|
|
83
|
+
"Use a different agent that supports path restrictions (e.g., claude)",
|
|
84
84
|
],
|
|
85
85
|
});
|
|
86
86
|
}
|
|
@@ -8,33 +8,12 @@
|
|
|
8
8
|
* - Does NOT support tool permissions in the axconfig sense
|
|
9
9
|
*/
|
|
10
10
|
import { mkdirSync } from "node:fs";
|
|
11
|
-
import { homedir } from "node:os";
|
|
12
11
|
import path from "node:path";
|
|
12
|
+
import { getAgentPathInfo } from "axshared";
|
|
13
13
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
14
14
|
import { deleteByPath, getByPath } from "../object-path.js";
|
|
15
15
|
import { registerConfigReader } from "../reader.js";
|
|
16
16
|
import { createJsonConfigOperations, readJsonConfig, } from "../read-write-json-config.js";
|
|
17
|
-
/**
|
|
18
|
-
* Get the platform-specific config directory for Copilot CLI.
|
|
19
|
-
*
|
|
20
|
-
* Copilot CLI uses an unconventional XDG pattern: `$XDG_CONFIG_HOME/.copilot`
|
|
21
|
-
* (with the dot prefix inside XDG_CONFIG_HOME, unlike typical XDG conventions
|
|
22
|
-
* which would use `$XDG_CONFIG_HOME/copilot` without the dot).
|
|
23
|
-
*
|
|
24
|
-
* Verified against decompiled Copilot CLI source (sdk/index.js:67574):
|
|
25
|
-
* ```js
|
|
26
|
-
* path.join(process.env.XDG_CONFIG_HOME, ".copilot")
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Falls back to ~/.copilot when XDG_CONFIG_HOME is not set.
|
|
30
|
-
*/
|
|
31
|
-
function getPlatformConfigDirectory() {
|
|
32
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
33
|
-
if (xdgConfig) {
|
|
34
|
-
return path.join(xdgConfig, ".copilot");
|
|
35
|
-
}
|
|
36
|
-
return path.join(homedir(), ".copilot");
|
|
37
|
-
}
|
|
38
17
|
/**
|
|
39
18
|
* Get the config.json path for a config directory.
|
|
40
19
|
*/
|
|
@@ -103,11 +82,15 @@ function writeModel(configDirectory, model) {
|
|
|
103
82
|
};
|
|
104
83
|
}
|
|
105
84
|
}
|
|
85
|
+
// Get path info from axshared (single source of truth)
|
|
86
|
+
const pathInfo = getAgentPathInfo("copilot");
|
|
106
87
|
/** Copilot CLI ConfigReader */
|
|
107
88
|
const copilotConfigReader = {
|
|
108
89
|
agentId: "copilot",
|
|
109
|
-
defaultConfigDir:
|
|
110
|
-
envVar:
|
|
90
|
+
defaultConfigDir: pathInfo.defaultConfigDir,
|
|
91
|
+
envVar: pathInfo.envVar,
|
|
92
|
+
subdirectory: pathInfo.subdirectory,
|
|
93
|
+
buildRuntimeEnvironment: pathInfo.buildRuntimeEnvironment,
|
|
111
94
|
readPermissions,
|
|
112
95
|
readModel,
|
|
113
96
|
writeModel,
|
package/dist/agents/copilot.js
CHANGED
|
@@ -43,7 +43,7 @@ function build(config, output) {
|
|
|
43
43
|
reason: "Copilot CLI uses runtime approval prompts, not pre-configured allow lists",
|
|
44
44
|
suggestions: [
|
|
45
45
|
"Copilot CLI will prompt for approval when tools are used",
|
|
46
|
-
"Use a different agent for pre-configured permissions (e.g., claude
|
|
46
|
+
"Use a different agent for pre-configured permissions (e.g., claude)",
|
|
47
47
|
],
|
|
48
48
|
});
|
|
49
49
|
}
|
|
@@ -53,7 +53,7 @@ function build(config, output) {
|
|
|
53
53
|
rule,
|
|
54
54
|
reason: "Copilot CLI does not support denying tools via configuration",
|
|
55
55
|
suggestions: [
|
|
56
|
-
"Use a different agent that supports deny rules (e.g., claude
|
|
56
|
+
"Use a different agent that supports deny rules (e.g., claude)",
|
|
57
57
|
"Remove the deny rule",
|
|
58
58
|
],
|
|
59
59
|
});
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Reads and writes Gemini CLI configuration from settings.json and policy TOML files.
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
7
|
-
import { homedir } from "node:os";
|
|
8
7
|
import path from "node:path";
|
|
9
8
|
import TOML from "@iarna/toml";
|
|
9
|
+
import { getAgentPathInfo } from "axshared";
|
|
10
10
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
11
11
|
import { registerConfigReader } from "../reader.js";
|
|
12
12
|
import { createJsonConfigOperations, readJsonConfig, } from "../read-write-json-config.js";
|
|
@@ -141,11 +141,15 @@ function writeModel(configDirectory, model) {
|
|
|
141
141
|
return { ok: false, error: `Failed to write Gemini CLI model: ${message}` };
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
+
// Get path info from axshared (single source of truth)
|
|
145
|
+
const pathInfo = getAgentPathInfo("gemini");
|
|
144
146
|
/** Gemini CLI ConfigReader */
|
|
145
147
|
const geminiConfigReader = {
|
|
146
148
|
agentId: "gemini",
|
|
147
|
-
defaultConfigDir:
|
|
148
|
-
envVar:
|
|
149
|
+
defaultConfigDir: pathInfo.defaultConfigDir,
|
|
150
|
+
envVar: pathInfo.envVar,
|
|
151
|
+
subdirectory: pathInfo.subdirectory,
|
|
152
|
+
buildRuntimeEnvironment: pathInfo.buildRuntimeEnvironment,
|
|
149
153
|
readPermissions,
|
|
150
154
|
readModel,
|
|
151
155
|
writeModel,
|
package/dist/agents/gemini.js
CHANGED
|
@@ -106,7 +106,7 @@ function build(config, output) {
|
|
|
106
106
|
reason: "Gemini CLI does not support path restrictions",
|
|
107
107
|
suggestions: [
|
|
108
108
|
`Use "${rule.tool}" to deny all ${rule.tool} operations`,
|
|
109
|
-
"Use a different agent that supports path restrictions (e.g., claude
|
|
109
|
+
"Use a different agent that supports path restrictions (e.g., claude)",
|
|
110
110
|
],
|
|
111
111
|
});
|
|
112
112
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Reads and writes OpenCode configuration from opencode.json.
|
|
5
5
|
*/
|
|
6
6
|
import { mkdirSync } from "node:fs";
|
|
7
|
-
import { homedir } from "node:os";
|
|
8
7
|
import path from "node:path";
|
|
8
|
+
import { getAgentPathInfo } from "axshared";
|
|
9
9
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
10
10
|
import { registerConfigReader } from "../reader.js";
|
|
11
11
|
import { createJsonConfigOperations, readJsonConfig, } from "../read-write-json-config.js";
|
|
@@ -118,11 +118,15 @@ function writeModel(configDirectory, model) {
|
|
|
118
118
|
return { ok: false, error: `Failed to write OpenCode model: ${message}` };
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
// Get path info from axshared (single source of truth)
|
|
122
|
+
const pathInfo = getAgentPathInfo("opencode");
|
|
121
123
|
/** OpenCode ConfigReader */
|
|
122
124
|
const openCodeConfigReader = {
|
|
123
125
|
agentId: "opencode",
|
|
124
|
-
defaultConfigDir:
|
|
125
|
-
envVar:
|
|
126
|
+
defaultConfigDir: pathInfo.defaultConfigDir,
|
|
127
|
+
envVar: pathInfo.envVar,
|
|
128
|
+
subdirectory: pathInfo.subdirectory,
|
|
129
|
+
buildRuntimeEnvironment: pathInfo.buildRuntimeEnvironment,
|
|
126
130
|
readPermissions,
|
|
127
131
|
readModel,
|
|
128
132
|
writeModel,
|
package/dist/agents/opencode.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
12
12
|
import path from "node:path";
|
|
13
|
+
import { getAgentConfigSubdirectory } from "axshared";
|
|
13
14
|
import { atomicWriteFileSync } from "../atomic-write.js";
|
|
14
15
|
import { registerConfigBuilder } from "../builder.js";
|
|
15
16
|
// Re-export reader
|
|
@@ -51,7 +52,7 @@ function build(config, output) {
|
|
|
51
52
|
reason: "OpenCode does not support path restrictions",
|
|
52
53
|
suggestions: [
|
|
53
54
|
`Use "${rule.tool}" to deny all ${rule.tool} operations`,
|
|
54
|
-
"Use a different agent that supports path restrictions (e.g., claude
|
|
55
|
+
"Use a different agent that supports path restrictions (e.g., claude)",
|
|
55
56
|
],
|
|
56
57
|
});
|
|
57
58
|
}
|
|
@@ -61,7 +62,11 @@ function build(config, output) {
|
|
|
61
62
|
if (errors.length > 0) {
|
|
62
63
|
return { ok: false, errors };
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
// OpenCode expects config at XDG_CONFIG_HOME/opencode/opencode.json
|
|
66
|
+
const subdirectory = getAgentConfigSubdirectory("opencode") ?? "opencode";
|
|
67
|
+
const openCodeDirectory = path.join(output, subdirectory);
|
|
68
|
+
mkdirSync(openCodeDirectory, { recursive: true });
|
|
69
|
+
const configPath = path.join(openCodeDirectory, "opencode.json");
|
|
65
70
|
// Build permission config
|
|
66
71
|
const permissionConfig = {};
|
|
67
72
|
if (permissions) {
|
|
@@ -153,7 +158,10 @@ function build(config, output) {
|
|
|
153
158
|
atomicWriteFileSync(configPath, JSON.stringify(openCodeConfig, undefined, 2));
|
|
154
159
|
return {
|
|
155
160
|
ok: true,
|
|
156
|
-
env: {
|
|
161
|
+
env: {
|
|
162
|
+
XDG_CONFIG_HOME: output,
|
|
163
|
+
XDG_DATA_HOME: output,
|
|
164
|
+
},
|
|
157
165
|
warnings,
|
|
158
166
|
};
|
|
159
167
|
}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { handleGetRaw } from "./commands/get-raw.js";
|
|
|
13
13
|
import { handleSet } from "./commands/set.js";
|
|
14
14
|
import { handleSetRaw } from "./commands/set-raw.js";
|
|
15
15
|
// Import to trigger self-registration
|
|
16
|
-
import "./agents/claude
|
|
16
|
+
import "./agents/claude.js";
|
|
17
17
|
import "./agents/codex.js";
|
|
18
18
|
import "./agents/copilot.js";
|
|
19
19
|
import "./agents/gemini.js";
|
|
@@ -33,29 +33,29 @@ const program = new Command()
|
|
|
33
33
|
.addHelpText("after", String.raw `
|
|
34
34
|
Examples:
|
|
35
35
|
# Create config and source it in current shell
|
|
36
|
-
eval $(axconfig create --agent claude
|
|
36
|
+
eval $(axconfig create --agent claude --output /tmp/cfg --allow read)
|
|
37
37
|
|
|
38
38
|
# Get current settings
|
|
39
|
-
axconfig get --agent claude
|
|
40
|
-
axconfig get --agent claude
|
|
41
|
-
axconfig get --agent claude
|
|
39
|
+
axconfig get --agent claude allow
|
|
40
|
+
axconfig get --agent claude deny
|
|
41
|
+
axconfig get --agent claude model
|
|
42
42
|
|
|
43
43
|
# Set settings (merge with existing by default)
|
|
44
|
-
axconfig set --agent claude
|
|
45
|
-
axconfig set --agent claude
|
|
46
|
-
axconfig set --agent claude
|
|
44
|
+
axconfig set --agent claude allow "read,glob"
|
|
45
|
+
axconfig set --agent claude deny "bash:rm *"
|
|
46
|
+
axconfig set --agent claude model "claude-sonnet-4-20250514"
|
|
47
47
|
|
|
48
48
|
# Replace instead of merge
|
|
49
|
-
axconfig set --agent claude
|
|
49
|
+
axconfig set --agent claude allow "read,glob" --replace
|
|
50
50
|
|
|
51
51
|
# Get raw config value
|
|
52
|
-
axconfig get-raw --agent claude
|
|
52
|
+
axconfig get-raw --agent claude permissions.allow
|
|
53
53
|
|
|
54
54
|
# Extract allow rules as JSON and filter with jq
|
|
55
|
-
axconfig get --agent claude
|
|
55
|
+
axconfig get --agent claude allow --format json | jq '.'
|
|
56
56
|
|
|
57
57
|
# Capture in shell variable
|
|
58
|
-
MODEL=$(axconfig get --agent claude
|
|
58
|
+
MODEL=$(axconfig get --agent claude model)`);
|
|
59
59
|
program
|
|
60
60
|
.command("create")
|
|
61
61
|
.description("Create agent-specific configuration")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent runtime environment utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to compute environment variables for running agents
|
|
5
|
+
* with custom config directories. Delegates to axshared for path info.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentCli } from "axshared";
|
|
8
|
+
/** Result type for getAgentConfigEnvironment */
|
|
9
|
+
type GetAgentConfigEnvironmentResult = {
|
|
10
|
+
ok: true;
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
error: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Get agent-specific environment variables for a custom config directory.
|
|
18
|
+
*
|
|
19
|
+
* Computes the environment variables needed to run an agent with a specific
|
|
20
|
+
* config directory. This handles agents that require the env var to point to
|
|
21
|
+
* a parent directory (e.g., HOME for gemini, XDG_DATA_HOME for opencode).
|
|
22
|
+
*
|
|
23
|
+
* @param agent - The agent CLI identifier
|
|
24
|
+
* @param configDirectory - The config directory path (must end with expected suffix for some agents)
|
|
25
|
+
* @returns Result with agent-specific env vars, or error if configDirectory is invalid
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Claude: env var points directly to config dir
|
|
29
|
+
* getAgentConfigEnvironment("claude", "/tmp/test/.claude")
|
|
30
|
+
* // Returns: { ok: true, env: { CLAUDE_CONFIG_DIR: "/tmp/test/.claude" } }
|
|
31
|
+
*
|
|
32
|
+
* // Gemini: env var points to parent (HOME), config is in .gemini subdirectory
|
|
33
|
+
* getAgentConfigEnvironment("gemini", "/tmp/test/.gemini")
|
|
34
|
+
* // Returns: { ok: true, env: { HOME: "/tmp/test", GEMINI_FORCE_FILE_STORAGE: "true" } }
|
|
35
|
+
*/
|
|
36
|
+
declare function getAgentConfigEnvironment(agent: AgentCli, configDirectory: string): GetAgentConfigEnvironmentResult;
|
|
37
|
+
export { getAgentConfigEnvironment, type GetAgentConfigEnvironmentResult };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent runtime environment utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to compute environment variables for running agents
|
|
5
|
+
* with custom config directories. Delegates to axshared for path info.
|
|
6
|
+
*/
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { buildAgentRuntimeEnvironment, getAgentConfigSubdirectory, } from "axshared";
|
|
9
|
+
/**
|
|
10
|
+
* Get agent-specific environment variables for a custom config directory.
|
|
11
|
+
*
|
|
12
|
+
* Computes the environment variables needed to run an agent with a specific
|
|
13
|
+
* config directory. This handles agents that require the env var to point to
|
|
14
|
+
* a parent directory (e.g., HOME for gemini, XDG_DATA_HOME for opencode).
|
|
15
|
+
*
|
|
16
|
+
* @param agent - The agent CLI identifier
|
|
17
|
+
* @param configDirectory - The config directory path (must end with expected suffix for some agents)
|
|
18
|
+
* @returns Result with agent-specific env vars, or error if configDirectory is invalid
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // Claude: env var points directly to config dir
|
|
22
|
+
* getAgentConfigEnvironment("claude", "/tmp/test/.claude")
|
|
23
|
+
* // Returns: { ok: true, env: { CLAUDE_CONFIG_DIR: "/tmp/test/.claude" } }
|
|
24
|
+
*
|
|
25
|
+
* // Gemini: env var points to parent (HOME), config is in .gemini subdirectory
|
|
26
|
+
* getAgentConfigEnvironment("gemini", "/tmp/test/.gemini")
|
|
27
|
+
* // Returns: { ok: true, env: { HOME: "/tmp/test", GEMINI_FORCE_FILE_STORAGE: "true" } }
|
|
28
|
+
*/
|
|
29
|
+
function getAgentConfigEnvironment(agent, configDirectory) {
|
|
30
|
+
const subdirectory = getAgentConfigSubdirectory(agent);
|
|
31
|
+
const resolvedConfigDirectory = path.resolve(configDirectory);
|
|
32
|
+
// Validate subdirectory suffix for agents that require it
|
|
33
|
+
if (subdirectory !== undefined) {
|
|
34
|
+
const actualSuffix = path.basename(resolvedConfigDirectory);
|
|
35
|
+
if (actualSuffix !== subdirectory) {
|
|
36
|
+
return {
|
|
37
|
+
ok: false,
|
|
38
|
+
error: `Config directory for ${agent} must end with '${subdirectory}', got '${actualSuffix}'.\n` +
|
|
39
|
+
`Expected path like: /some/path/${subdirectory}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
env: buildAgentRuntimeEnvironment(agent, resolvedConfigDirectory),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export { getAgentConfigEnvironment };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,13 +21,14 @@ export { formatRule, parsePermissions, parseRule, parseRuleList, } from "./parse
|
|
|
21
21
|
export { getConfigBuilder, registerConfigBuilder } from "./builder.js";
|
|
22
22
|
export { getConfigReader, registerConfigReader } from "./reader.js";
|
|
23
23
|
export { resolveConfigPath } from "./resolve-config-path.js";
|
|
24
|
+
export { getAgentConfigEnvironment, type GetAgentConfigEnvironmentResult, } from "./get-agent-runtime-environment.js";
|
|
24
25
|
export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings, } from "./build-agent-config.js";
|
|
25
|
-
import "./agents/claude
|
|
26
|
+
import "./agents/claude.js";
|
|
26
27
|
import "./agents/codex.js";
|
|
27
28
|
import "./agents/copilot.js";
|
|
28
29
|
import "./agents/gemini.js";
|
|
29
30
|
import "./agents/opencode.js";
|
|
30
|
-
export { claudeCodeConfigBuilder, claudeCodeConfigReader, } from "./agents/claude
|
|
31
|
+
export { claudeCodeConfigBuilder, claudeCodeConfigReader, } from "./agents/claude.js";
|
|
31
32
|
export { codexConfigBuilder, codexConfigReader } from "./agents/codex.js";
|
|
32
33
|
export { copilotConfigBuilder, copilotConfigReader } from "./agents/copilot.js";
|
|
33
34
|
export { geminiConfigBuilder, geminiConfigReader } from "./agents/gemini.js";
|
package/dist/index.js
CHANGED
|
@@ -24,16 +24,18 @@ export { getConfigBuilder, registerConfigBuilder } from "./builder.js";
|
|
|
24
24
|
export { getConfigReader, registerConfigReader } from "./reader.js";
|
|
25
25
|
// Path resolution
|
|
26
26
|
export { resolveConfigPath } from "./resolve-config-path.js";
|
|
27
|
+
// Runtime environment
|
|
28
|
+
export { getAgentConfigEnvironment, } from "./get-agent-runtime-environment.js";
|
|
27
29
|
// High-level API
|
|
28
30
|
export { buildAgentConfig, formatPermissionErrors, formatPermissionWarnings, } from "./build-agent-config.js";
|
|
29
31
|
// Import agent modules to trigger self-registration
|
|
30
|
-
import "./agents/claude
|
|
32
|
+
import "./agents/claude.js";
|
|
31
33
|
import "./agents/codex.js";
|
|
32
34
|
import "./agents/copilot.js";
|
|
33
35
|
import "./agents/gemini.js";
|
|
34
36
|
import "./agents/opencode.js";
|
|
35
37
|
// Export agent builders for direct access
|
|
36
|
-
export { claudeCodeConfigBuilder, claudeCodeConfigReader, } from "./agents/claude
|
|
38
|
+
export { claudeCodeConfigBuilder, claudeCodeConfigReader, } from "./agents/claude.js";
|
|
37
39
|
export { codexConfigBuilder, codexConfigReader } from "./agents/codex.js";
|
|
38
40
|
export { copilotConfigBuilder, copilotConfigReader } from "./agents/copilot.js";
|
|
39
41
|
export { geminiConfigBuilder, geminiConfigReader } from "./agents/gemini.js";
|
|
@@ -10,10 +10,12 @@ import type { AgentCli } from "axshared";
|
|
|
10
10
|
* 2. Agent's environment variable
|
|
11
11
|
* 3. Agent's default config directory
|
|
12
12
|
*
|
|
13
|
+
* Delegates to axshared's resolveAgentConfigDirectory, which is the canonical
|
|
14
|
+
* source of truth for agent path resolution.
|
|
15
|
+
*
|
|
13
16
|
* @param agentId - The agent to resolve config for
|
|
14
17
|
* @param providedPath - Optional path from --path option
|
|
15
18
|
* @returns The resolved config directory path
|
|
16
|
-
* @throws Error if no reader is registered for the agent
|
|
17
19
|
*/
|
|
18
20
|
declare function resolveConfigPath(agentId: AgentCli, providedPath?: string): string;
|
|
19
21
|
export { resolveConfigPath };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolve agent config directory from --path option, env vars, or defaults.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { resolveAgentConfigDirectory } from "axshared";
|
|
5
5
|
/**
|
|
6
6
|
* Resolve the config directory for an agent.
|
|
7
7
|
*
|
|
@@ -10,23 +10,14 @@ import { getConfigReader } from "./reader.js";
|
|
|
10
10
|
* 2. Agent's environment variable
|
|
11
11
|
* 3. Agent's default config directory
|
|
12
12
|
*
|
|
13
|
+
* Delegates to axshared's resolveAgentConfigDirectory, which is the canonical
|
|
14
|
+
* source of truth for agent path resolution.
|
|
15
|
+
*
|
|
13
16
|
* @param agentId - The agent to resolve config for
|
|
14
17
|
* @param providedPath - Optional path from --path option
|
|
15
18
|
* @returns The resolved config directory path
|
|
16
|
-
* @throws Error if no reader is registered for the agent
|
|
17
19
|
*/
|
|
18
20
|
function resolveConfigPath(agentId, providedPath) {
|
|
19
|
-
|
|
20
|
-
return providedPath;
|
|
21
|
-
}
|
|
22
|
-
const reader = getConfigReader(agentId);
|
|
23
|
-
if (!reader) {
|
|
24
|
-
throw new Error(`No config reader registered for agent "${agentId}"`);
|
|
25
|
-
}
|
|
26
|
-
const environmentValue = process.env[reader.envVar];
|
|
27
|
-
if (environmentValue) {
|
|
28
|
-
return environmentValue;
|
|
29
|
-
}
|
|
30
|
-
return reader.defaultConfigDir();
|
|
21
|
+
return resolveAgentConfigDirectory(agentId, providedPath);
|
|
31
22
|
}
|
|
32
23
|
export { resolveConfigPath };
|
package/dist/types.d.ts
CHANGED
|
@@ -133,6 +133,18 @@ interface ConfigReader {
|
|
|
133
133
|
defaultConfigDir: () => string;
|
|
134
134
|
/** Environment variable that overrides the config directory */
|
|
135
135
|
envVar: string;
|
|
136
|
+
/**
|
|
137
|
+
* Subdirectory name within the base path for agents where the env var
|
|
138
|
+
* points to a parent directory (e.g., ".gemini" for HOME, "opencode" for XDG_DATA_HOME).
|
|
139
|
+
* Undefined if env var points directly to the config directory.
|
|
140
|
+
*/
|
|
141
|
+
subdirectory: string | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Build environment variables for running this agent with a custom config directory.
|
|
144
|
+
* @param basePath - The base path (parent of subdirectory, or config dir if no subdirectory)
|
|
145
|
+
* @returns Environment variables to set for the agent
|
|
146
|
+
*/
|
|
147
|
+
buildRuntimeEnvironment: (basePath: string) => Record<string, string>;
|
|
136
148
|
/** Read permissions from agent config and translate to unified format */
|
|
137
149
|
readPermissions: (configDirectory: string) => ReadPermissionsResult;
|
|
138
150
|
/** Read model from agent config */
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "axconfig",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "3.0.0",
|
|
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",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@commander-js/extra-typings": "^14.0.0",
|
|
70
70
|
"@iarna/toml": "^2.2.5",
|
|
71
|
-
"axshared": "^1.
|
|
71
|
+
"axshared": "^1.2.0",
|
|
72
72
|
"commander": "^14.0.2"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
File without changes
|