@praeviso/code-env-switch 0.1.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 +90 -0
- package/bin/codenv.js +377 -0
- package/code-env.example.json +40 -0
- package/package.json +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# code-env-switch
|
|
2
|
+
|
|
3
|
+
A tiny CLI to switch between Claude Code and Codex environment variables.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1) Copy the example config and fill in your keys:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cp code-env.example.json code-env.json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2) Install from npm (after publish) or locally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g code-env-switch
|
|
17
|
+
# or local dev
|
|
18
|
+
npm install -g .
|
|
19
|
+
# or
|
|
20
|
+
npm link
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
List profiles:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
codenv list
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Add or update a profile from the CLI:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
codenv add codex-88 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_API_KEY=sk-REPLACE_ME --note "OpenAI official"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Switch in the current shell (bash/zsh):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
eval "$(codenv use codex-88)"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Unset all known keys:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
eval "$(codenv unset)"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Config lookup order
|
|
50
|
+
|
|
51
|
+
`codenv` searches in this order:
|
|
52
|
+
|
|
53
|
+
1) `--config <path>`
|
|
54
|
+
2) `CODE_ENV_CONFIG`
|
|
55
|
+
3) `./code-env.json`
|
|
56
|
+
4) `./profiles.json`
|
|
57
|
+
5) `./code-env.config.json`
|
|
58
|
+
6) `~/.config/code-env/config.json`
|
|
59
|
+
|
|
60
|
+
## Config format
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"unset": ["OPENAI_BASE_URL", "OPENAI_API_KEY"],
|
|
65
|
+
"profiles": {
|
|
66
|
+
"codex-88": {
|
|
67
|
+
"note": "OpenAI official",
|
|
68
|
+
"env": {
|
|
69
|
+
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
|
70
|
+
"OPENAI_API_KEY": "sk-REPLACE_ME",
|
|
71
|
+
"CODEX_PROVIDER": "OpenAI"
|
|
72
|
+
},
|
|
73
|
+
"removeFiles": ["$HOME/.config/openai/auth.json"],
|
|
74
|
+
"commands": ["echo \"Switched to codex-88\""]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Notes:
|
|
81
|
+
- `removeFiles` is optional; when present, `codenv use <profile>` emits `rm -f` lines for those paths.
|
|
82
|
+
- `commands` is optional; any strings are emitted as-is.
|
|
83
|
+
- `note` is shown in `codenv list` output.
|
|
84
|
+
- `codenv add` creates the config file if it does not exist (default: `./code-env.json`).
|
|
85
|
+
|
|
86
|
+
## Fish shell
|
|
87
|
+
|
|
88
|
+
```fish
|
|
89
|
+
codenv use codex-88 | source
|
|
90
|
+
```
|
package/bin/codenv.js
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
function printHelp() {
|
|
9
|
+
const msg = `codenv - switch Claude/Codex env vars\n\nUsage:\n codenv list\n codenv use <profile>\n codenv show <profile>\n codenv unset\n codenv add <profile> KEY=VALUE [KEY=VALUE ...]\n\nOptions:\n -c, --config <path> Path to config JSON\n -h, --help Show help\n\nAdd options:\n -n, --note <text> Set profile note\n -r, --remove-file <path> Add a removeFiles entry (repeat)\n -x, --command <cmd> Add a commands entry (repeat)\n -u, --unset <KEY> Add a global unset key (repeat)\n\nExamples:\n eval "$(codenv use codex)"\n codenv list\n CODE_ENV_CONFIG=./code-env.json codenv use claude\n codenv add codex-88 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_API_KEY=sk-REPLACE_ME\n`;
|
|
10
|
+
console.log(msg);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parseArgs(argv) {
|
|
14
|
+
let configPath = null;
|
|
15
|
+
const args = [];
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === "-h" || arg === "--help") return { help: true };
|
|
19
|
+
if (arg === "-c" || arg === "--config") {
|
|
20
|
+
configPath = argv[i + 1];
|
|
21
|
+
i++;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (arg.startsWith("--config=")) {
|
|
25
|
+
configPath = arg.slice("--config=".length);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
args.push(arg);
|
|
29
|
+
}
|
|
30
|
+
return { args, configPath, help: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolvePath(p) {
|
|
34
|
+
if (!p) return null;
|
|
35
|
+
if (p.startsWith("~")) {
|
|
36
|
+
return path.join(os.homedir(), p.slice(1));
|
|
37
|
+
}
|
|
38
|
+
if (path.isAbsolute(p)) return p;
|
|
39
|
+
return path.resolve(process.cwd(), p);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function findConfigPath(explicitPath) {
|
|
43
|
+
if (explicitPath) {
|
|
44
|
+
const resolved = resolvePath(explicitPath);
|
|
45
|
+
if (fs.existsSync(resolved)) return resolved;
|
|
46
|
+
return resolved; // let readConfig raise a helpful error
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (process.env.CODE_ENV_CONFIG) {
|
|
50
|
+
const fromEnv = resolvePath(process.env.CODE_ENV_CONFIG);
|
|
51
|
+
if (fs.existsSync(fromEnv)) return fromEnv;
|
|
52
|
+
return fromEnv;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const candidates = [
|
|
56
|
+
path.resolve(process.cwd(), "code-env.json"),
|
|
57
|
+
path.resolve(process.cwd(), "profiles.json"),
|
|
58
|
+
path.resolve(process.cwd(), "code-env.config.json"),
|
|
59
|
+
path.join(os.homedir(), ".config", "code-env", "config.json"),
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
for (const p of candidates) {
|
|
63
|
+
if (fs.existsSync(p)) return p;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function findConfigPathForWrite(explicitPath) {
|
|
70
|
+
if (explicitPath) return resolvePath(explicitPath);
|
|
71
|
+
if (process.env.CODE_ENV_CONFIG) return resolvePath(process.env.CODE_ENV_CONFIG);
|
|
72
|
+
const existing = findConfigPath(null);
|
|
73
|
+
if (existing) return existing;
|
|
74
|
+
return path.resolve(process.cwd(), "code-env.json");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function readConfig(configPath) {
|
|
78
|
+
if (!configPath) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"No config file found. Use --config or set CODE_ENV_CONFIG."
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (!fs.existsSync(configPath)) {
|
|
84
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
85
|
+
}
|
|
86
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(raw);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
throw new Error(`Invalid JSON in config: ${configPath}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readConfigIfExists(configPath) {
|
|
95
|
+
if (!configPath || !fs.existsSync(configPath)) {
|
|
96
|
+
return { unset: [], profiles: {} };
|
|
97
|
+
}
|
|
98
|
+
return readConfig(configPath);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeConfig(configPath, config) {
|
|
102
|
+
if (!configPath) {
|
|
103
|
+
throw new Error("Missing config path for write.");
|
|
104
|
+
}
|
|
105
|
+
const dir = path.dirname(configPath);
|
|
106
|
+
if (!fs.existsSync(dir)) {
|
|
107
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
const data = JSON.stringify(config, null, 2);
|
|
110
|
+
fs.writeFileSync(configPath, `${data}\n`, "utf8");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function shellEscape(value) {
|
|
114
|
+
const str = String(value);
|
|
115
|
+
return `'${str.replace(/'/g, `'\\''`)}'`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function expandEnv(input) {
|
|
119
|
+
if (!input) return input;
|
|
120
|
+
let out = String(input);
|
|
121
|
+
if (out.startsWith("~")) {
|
|
122
|
+
out = path.join(os.homedir(), out.slice(1));
|
|
123
|
+
}
|
|
124
|
+
out = out.replace(/\$\{([^}]+)\}/g, (_, key) => process.env[key] || "");
|
|
125
|
+
out = out.replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_, key) => process.env[key] || "");
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function parseAddArgs(args) {
|
|
130
|
+
const result = {
|
|
131
|
+
profile: null,
|
|
132
|
+
pairs: [],
|
|
133
|
+
note: null,
|
|
134
|
+
removeFiles: [],
|
|
135
|
+
commands: [],
|
|
136
|
+
unset: [],
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i < args.length; i++) {
|
|
140
|
+
const arg = args[i];
|
|
141
|
+
if (!result.profile && !arg.startsWith("-")) {
|
|
142
|
+
result.profile = arg;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (arg === "-n" || arg === "--note") {
|
|
146
|
+
const val = args[i + 1];
|
|
147
|
+
if (!val) throw new Error("Missing value for --note.");
|
|
148
|
+
result.note = val;
|
|
149
|
+
i++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (arg.startsWith("--note=")) {
|
|
153
|
+
result.note = arg.slice("--note=".length);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (arg === "-r" || arg === "--remove-file") {
|
|
157
|
+
const val = args[i + 1];
|
|
158
|
+
if (!val) throw new Error("Missing value for --remove-file.");
|
|
159
|
+
result.removeFiles.push(val);
|
|
160
|
+
i++;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (arg.startsWith("--remove-file=")) {
|
|
164
|
+
result.removeFiles.push(arg.slice("--remove-file=".length));
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (arg === "-x" || arg === "--command") {
|
|
168
|
+
const val = args[i + 1];
|
|
169
|
+
if (!val) throw new Error("Missing value for --command.");
|
|
170
|
+
result.commands.push(val);
|
|
171
|
+
i++;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (arg.startsWith("--command=")) {
|
|
175
|
+
result.commands.push(arg.slice("--command=".length));
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (arg === "-u" || arg === "--unset") {
|
|
179
|
+
const val = args[i + 1];
|
|
180
|
+
if (!val) throw new Error("Missing value for --unset.");
|
|
181
|
+
result.unset.push(val);
|
|
182
|
+
i++;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (arg.startsWith("--unset=")) {
|
|
186
|
+
result.unset.push(arg.slice("--unset=".length));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (arg.includes("=")) {
|
|
190
|
+
result.pairs.push(arg);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
throw new Error(`Unknown add argument: ${arg}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!result.profile) {
|
|
197
|
+
throw new Error("Missing profile name.");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function addConfig(config, addArgs) {
|
|
204
|
+
if (!config.profiles || typeof config.profiles !== "object") {
|
|
205
|
+
config.profiles = {};
|
|
206
|
+
}
|
|
207
|
+
if (!config.profiles[addArgs.profile]) {
|
|
208
|
+
config.profiles[addArgs.profile] = {};
|
|
209
|
+
}
|
|
210
|
+
const profile = config.profiles[addArgs.profile];
|
|
211
|
+
if (!profile.env || typeof profile.env !== "object") {
|
|
212
|
+
profile.env = {};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const pair of addArgs.pairs) {
|
|
216
|
+
const idx = pair.indexOf("=");
|
|
217
|
+
if (idx <= 0) throw new Error(`Invalid KEY=VALUE: ${pair}`);
|
|
218
|
+
const key = pair.slice(0, idx);
|
|
219
|
+
const value = pair.slice(idx + 1);
|
|
220
|
+
profile.env[key] = value;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (addArgs.note !== null && addArgs.note !== undefined) {
|
|
224
|
+
profile.note = addArgs.note;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (addArgs.removeFiles.length > 0) {
|
|
228
|
+
if (!Array.isArray(profile.removeFiles)) profile.removeFiles = [];
|
|
229
|
+
for (const p of addArgs.removeFiles) {
|
|
230
|
+
if (!profile.removeFiles.includes(p)) profile.removeFiles.push(p);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (addArgs.commands.length > 0) {
|
|
235
|
+
if (!Array.isArray(profile.commands)) profile.commands = [];
|
|
236
|
+
for (const cmd of addArgs.commands) {
|
|
237
|
+
if (!profile.commands.includes(cmd)) profile.commands.push(cmd);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (addArgs.unset.length > 0) {
|
|
242
|
+
if (!Array.isArray(config.unset)) config.unset = [];
|
|
243
|
+
for (const key of addArgs.unset) {
|
|
244
|
+
if (!config.unset.includes(key)) config.unset.push(key);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return config;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function printList(config) {
|
|
252
|
+
const profiles = config && config.profiles ? config.profiles : {};
|
|
253
|
+
const names = Object.keys(profiles).sort();
|
|
254
|
+
if (names.length === 0) {
|
|
255
|
+
console.log("(no profiles found)");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
for (const name of names) {
|
|
259
|
+
const note = profiles[name] && profiles[name].note ? `\t${profiles[name].note}` : "";
|
|
260
|
+
console.log(`${name}${note}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function printShow(config, profileName) {
|
|
265
|
+
const profile = config.profiles && config.profiles[profileName];
|
|
266
|
+
if (!profile) {
|
|
267
|
+
throw new Error(`Unknown profile: ${profileName}`);
|
|
268
|
+
}
|
|
269
|
+
console.log(JSON.stringify(profile, null, 2));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function printUnset(config) {
|
|
273
|
+
const keys = Array.isArray(config.unset) ? config.unset : [];
|
|
274
|
+
if (keys.length === 0) return;
|
|
275
|
+
const lines = keys.map((k) => `unset ${k}`);
|
|
276
|
+
console.log(lines.join("\n"));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function printUse(config, profileName) {
|
|
280
|
+
const profile = config.profiles && config.profiles[profileName];
|
|
281
|
+
if (!profile) {
|
|
282
|
+
throw new Error(`Unknown profile: ${profileName}`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const env = profile.env || {};
|
|
286
|
+
const lines = [];
|
|
287
|
+
|
|
288
|
+
if (Array.isArray(config.unset)) {
|
|
289
|
+
for (const key of config.unset) {
|
|
290
|
+
if (!Object.prototype.hasOwnProperty.call(env, key)) {
|
|
291
|
+
lines.push(`unset ${key}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
for (const key of Object.keys(env)) {
|
|
297
|
+
const value = env[key];
|
|
298
|
+
if (value === null || value === undefined || value === "") {
|
|
299
|
+
lines.push(`unset ${key}`);
|
|
300
|
+
} else {
|
|
301
|
+
lines.push(`export ${key}=${shellEscape(value)}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (Array.isArray(profile.removeFiles)) {
|
|
306
|
+
for (const p of profile.removeFiles) {
|
|
307
|
+
const expanded = expandEnv(p);
|
|
308
|
+
if (expanded) lines.push(`rm -f ${shellEscape(expanded)}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (Array.isArray(profile.commands)) {
|
|
313
|
+
for (const cmd of profile.commands) {
|
|
314
|
+
if (cmd && String(cmd).trim()) lines.push(String(cmd));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
console.log(lines.join("\n"));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function main() {
|
|
322
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
323
|
+
if (parsed.help) {
|
|
324
|
+
printHelp();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const args = parsed.args || [];
|
|
329
|
+
|
|
330
|
+
if (args.length === 0) {
|
|
331
|
+
printHelp();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const cmd = args[0];
|
|
336
|
+
try {
|
|
337
|
+
if (cmd === "add") {
|
|
338
|
+
const addArgs = parseAddArgs(args.slice(1));
|
|
339
|
+
const writePath = findConfigPathForWrite(parsed.configPath);
|
|
340
|
+
const config = readConfigIfExists(writePath);
|
|
341
|
+
const updated = addConfig(config, addArgs);
|
|
342
|
+
writeConfig(writePath, updated);
|
|
343
|
+
console.log(`Updated config: ${writePath}`);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const configPath = findConfigPath(parsed.configPath);
|
|
348
|
+
const config = readConfig(configPath);
|
|
349
|
+
if (cmd === "list") {
|
|
350
|
+
printList(config);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (cmd === "use") {
|
|
354
|
+
const profileName = args[1];
|
|
355
|
+
if (!profileName) throw new Error("Missing profile name.");
|
|
356
|
+
printUse(config, profileName);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (cmd === "show") {
|
|
360
|
+
const profileName = args[1];
|
|
361
|
+
if (!profileName) throw new Error("Missing profile name.");
|
|
362
|
+
printShow(config, profileName);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (cmd === "unset") {
|
|
366
|
+
printUnset(config);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
throw new Error(`Unknown command: ${cmd}`);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
console.error(`codenv: ${err.message}`);
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
main();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"unset": [
|
|
3
|
+
"OPENAI_BASE_URL",
|
|
4
|
+
"OPENAI_API_KEY",
|
|
5
|
+
"CODEX_PROVIDER",
|
|
6
|
+
"ANTHROPIC_API_KEY",
|
|
7
|
+
"CLAUDE_CODE_BASE_URL"
|
|
8
|
+
],
|
|
9
|
+
"profiles": {
|
|
10
|
+
"codex-88": {
|
|
11
|
+
"note": "OpenAI official",
|
|
12
|
+
"env": {
|
|
13
|
+
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
|
14
|
+
"OPENAI_API_KEY": "sk-REPLACE_ME",
|
|
15
|
+
"CODEX_PROVIDER": "OpenAI"
|
|
16
|
+
},
|
|
17
|
+
"removeFiles": [
|
|
18
|
+
"$HOME/.config/openai/auth.json"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"codex-mirror": {
|
|
22
|
+
"note": "AICodeMirror",
|
|
23
|
+
"env": {
|
|
24
|
+
"OPENAI_BASE_URL": "https://api.aicodemirror.com/api/codex/backend-api/codex",
|
|
25
|
+
"OPENAI_API_KEY": "sk-REPLACE_ME",
|
|
26
|
+
"CODEX_PROVIDER": "AICodeMirror"
|
|
27
|
+
},
|
|
28
|
+
"removeFiles": [
|
|
29
|
+
"$HOME/.config/openai/auth.json"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"claude": {
|
|
33
|
+
"note": "Claude Code",
|
|
34
|
+
"env": {
|
|
35
|
+
"ANTHROPIC_API_KEY": "sk-REPLACE_ME",
|
|
36
|
+
"CLAUDE_CODE_BASE_URL": "https://api.anthropic.com"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@praeviso/code-env-switch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Switch between Claude Code and Codex environment variables from a single CLI",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codenv": "bin/codenv.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "commonjs",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=16"
|
|
12
|
+
}
|
|
13
|
+
}
|