@praeviso/code-env-switch 0.1.1 → 0.1.3
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/.github/workflows/npm-publish.yml +25 -0
- package/AGENTS.md +32 -0
- package/PLAN.md +33 -0
- package/README.md +24 -0
- package/README_zh.md +24 -0
- package/bin/cli/args.js +303 -0
- package/bin/cli/help.js +77 -0
- package/bin/cli/index.js +13 -0
- package/bin/commands/add.js +81 -0
- package/bin/commands/index.js +21 -0
- package/bin/commands/launch.js +330 -0
- package/bin/commands/list.js +57 -0
- package/bin/commands/show.js +10 -0
- package/bin/commands/statusline.js +12 -0
- package/bin/commands/unset.js +20 -0
- package/bin/commands/use.js +92 -0
- package/bin/config/defaults.js +85 -0
- package/bin/config/index.js +20 -0
- package/bin/config/io.js +72 -0
- package/bin/constants.js +27 -0
- package/bin/index.js +279 -0
- package/bin/profile/display.js +78 -0
- package/bin/profile/index.js +26 -0
- package/bin/profile/match.js +40 -0
- package/bin/profile/resolve.js +79 -0
- package/bin/profile/type.js +90 -0
- package/bin/shell/detect.js +40 -0
- package/bin/shell/index.js +18 -0
- package/bin/shell/snippet.js +92 -0
- package/bin/shell/utils.js +35 -0
- package/bin/statusline/claude.js +153 -0
- package/bin/statusline/codex.js +356 -0
- package/bin/statusline/index.js +631 -0
- package/bin/types.js +5 -0
- package/bin/ui/index.js +16 -0
- package/bin/ui/interactive.js +189 -0
- package/bin/ui/readline.js +76 -0
- package/bin/usage/index.js +832 -0
- package/code-env.example.json +11 -0
- package/package.json +2 -2
- package/src/cli/args.ts +318 -0
- package/src/cli/help.ts +75 -0
- package/src/cli/index.ts +5 -0
- package/src/commands/add.ts +91 -0
- package/src/commands/index.ts +10 -0
- package/src/commands/launch.ts +395 -0
- package/src/commands/list.ts +91 -0
- package/src/commands/show.ts +12 -0
- package/src/commands/statusline.ts +18 -0
- package/src/commands/unset.ts +19 -0
- package/src/commands/use.ts +121 -0
- package/src/config/defaults.ts +88 -0
- package/src/config/index.ts +19 -0
- package/src/config/io.ts +69 -0
- package/src/constants.ts +28 -0
- package/src/index.ts +359 -0
- package/src/profile/display.ts +77 -0
- package/src/profile/index.ts +12 -0
- package/src/profile/match.ts +41 -0
- package/src/profile/resolve.ts +84 -0
- package/src/profile/type.ts +83 -0
- package/src/shell/detect.ts +30 -0
- package/src/shell/index.ts +6 -0
- package/src/shell/snippet.ts +92 -0
- package/src/shell/utils.ts +30 -0
- package/src/statusline/claude.ts +172 -0
- package/src/statusline/codex.ts +393 -0
- package/src/statusline/index.ts +920 -0
- package/src/types.ts +95 -0
- package/src/ui/index.ts +5 -0
- package/src/ui/interactive.ts +220 -0
- package/src/ui/readline.ts +85 -0
- package/src/usage/index.ts +979 -0
- package/bin/codenv.js +0 -1316
- package/src/codenv.ts +0 -1478
package/code-env.example.json
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
"codex": "primary",
|
|
5
5
|
"claude": "default"
|
|
6
6
|
},
|
|
7
|
+
"codexStatusline": {
|
|
8
|
+
"command": ["codenv", "statusline", "--type", "codex", "--sync-usage"],
|
|
9
|
+
"showHints": false,
|
|
10
|
+
"updateIntervalMs": 300,
|
|
11
|
+
"timeoutMs": 1000
|
|
12
|
+
},
|
|
13
|
+
"claudeStatusline": {
|
|
14
|
+
"command": "codenv statusline --type claude --sync-usage",
|
|
15
|
+
"type": "command",
|
|
16
|
+
"padding": 0
|
|
17
|
+
},
|
|
7
18
|
"profiles": {
|
|
8
19
|
"p_a1b2c3": {
|
|
9
20
|
"name": "primary",
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praeviso/code-env-switch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Switch between Claude Code and Codex environment variables from a single CLI",
|
|
5
5
|
"bin": {
|
|
6
|
-
"codenv": "bin/
|
|
6
|
+
"codenv": "bin/index.js"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc -p tsconfig.json",
|
package/src/cli/args.ts
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI argument parsing
|
|
3
|
+
*/
|
|
4
|
+
import type {
|
|
5
|
+
ParsedArgs,
|
|
6
|
+
InitArgs,
|
|
7
|
+
AddArgs,
|
|
8
|
+
ProfileType,
|
|
9
|
+
StatuslineArgs,
|
|
10
|
+
} from "../types";
|
|
11
|
+
import { normalizeType } from "../profile/type";
|
|
12
|
+
|
|
13
|
+
export function parseArgs(argv: string[]): ParsedArgs {
|
|
14
|
+
let configPath: string | null = null;
|
|
15
|
+
const args: string[] = [];
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === "-h" || arg === "--help") {
|
|
19
|
+
return { args: [], configPath: null, help: true };
|
|
20
|
+
}
|
|
21
|
+
if (arg === "-c" || arg === "--config") {
|
|
22
|
+
configPath = argv[i + 1];
|
|
23
|
+
i++;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg.startsWith("--config=")) {
|
|
27
|
+
configPath = arg.slice("--config=".length);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
args.push(arg);
|
|
31
|
+
}
|
|
32
|
+
return { args, configPath, help: false };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function parseInitArgs(args: string[]): InitArgs {
|
|
36
|
+
const result: InitArgs = { apply: true, print: false, shell: null };
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
const arg = args[i];
|
|
39
|
+
if (arg === "--apply") {
|
|
40
|
+
result.apply = true;
|
|
41
|
+
result.print = false;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg === "--print") {
|
|
45
|
+
result.print = true;
|
|
46
|
+
result.apply = false;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (arg === "--shell") {
|
|
50
|
+
const val = args[i + 1];
|
|
51
|
+
if (!val) throw new Error("Missing value for --shell.");
|
|
52
|
+
result.shell = val;
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (arg.startsWith("--shell=")) {
|
|
57
|
+
result.shell = arg.slice("--shell=".length);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`Unknown init argument: ${arg}`);
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function parseAddArgs(args: string[]): AddArgs {
|
|
66
|
+
const result: AddArgs = {
|
|
67
|
+
profile: null,
|
|
68
|
+
pairs: [],
|
|
69
|
+
note: null,
|
|
70
|
+
removeFiles: [],
|
|
71
|
+
commands: [],
|
|
72
|
+
unset: [],
|
|
73
|
+
type: null,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < args.length; i++) {
|
|
77
|
+
const arg = args[i];
|
|
78
|
+
if (!result.profile && !arg.startsWith("-")) {
|
|
79
|
+
result.profile = arg;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (arg === "-n" || arg === "--note") {
|
|
83
|
+
const val = args[i + 1];
|
|
84
|
+
if (!val) throw new Error("Missing value for --note.");
|
|
85
|
+
result.note = val;
|
|
86
|
+
i++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (arg.startsWith("--note=")) {
|
|
90
|
+
result.note = arg.slice("--note=".length);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (arg === "-t" || arg === "--type") {
|
|
94
|
+
const val = args[i + 1];
|
|
95
|
+
if (!val) throw new Error("Missing value for --type.");
|
|
96
|
+
result.type = val as ProfileType;
|
|
97
|
+
i++;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (arg.startsWith("--type=")) {
|
|
101
|
+
result.type = arg.slice("--type=".length) as ProfileType;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (arg === "-r" || arg === "--remove-file") {
|
|
105
|
+
const val = args[i + 1];
|
|
106
|
+
if (!val) throw new Error("Missing value for --remove-file.");
|
|
107
|
+
result.removeFiles.push(val);
|
|
108
|
+
i++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (arg.startsWith("--remove-file=")) {
|
|
112
|
+
result.removeFiles.push(arg.slice("--remove-file=".length));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (arg === "-x" || arg === "--command") {
|
|
116
|
+
const val = args[i + 1];
|
|
117
|
+
if (!val) throw new Error("Missing value for --command.");
|
|
118
|
+
result.commands.push(val);
|
|
119
|
+
i++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg.startsWith("--command=")) {
|
|
123
|
+
result.commands.push(arg.slice("--command=".length));
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (arg === "-u" || arg === "--unset") {
|
|
127
|
+
const val = args[i + 1];
|
|
128
|
+
if (!val) throw new Error("Missing value for --unset.");
|
|
129
|
+
result.unset.push(val);
|
|
130
|
+
i++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (arg.startsWith("--unset=")) {
|
|
134
|
+
result.unset.push(arg.slice("--unset=".length));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (arg.includes("=")) {
|
|
138
|
+
result.pairs.push(arg);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`Unknown add argument: ${arg}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!result.profile) {
|
|
145
|
+
throw new Error("Missing profile name.");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (result.type) {
|
|
149
|
+
const normalized = normalizeType(result.type);
|
|
150
|
+
if (!normalized) {
|
|
151
|
+
throw new Error(`Unknown type: ${result.type}`);
|
|
152
|
+
}
|
|
153
|
+
result.type = normalized;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function parseNumberFlag(value: string | null | undefined, flag: string): number {
|
|
160
|
+
if (value === null || value === undefined || value === "") {
|
|
161
|
+
throw new Error(`Missing value for ${flag}.`);
|
|
162
|
+
}
|
|
163
|
+
const num = Number(value);
|
|
164
|
+
if (!Number.isFinite(num)) {
|
|
165
|
+
throw new Error(`Invalid number for ${flag}: ${value}`);
|
|
166
|
+
}
|
|
167
|
+
return num;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function parseStatuslineArgs(args: string[]): StatuslineArgs {
|
|
171
|
+
const result: StatuslineArgs = {
|
|
172
|
+
format: "text",
|
|
173
|
+
cwd: null,
|
|
174
|
+
type: null,
|
|
175
|
+
profileKey: null,
|
|
176
|
+
profileName: null,
|
|
177
|
+
model: null,
|
|
178
|
+
usageToday: null,
|
|
179
|
+
usageTotal: null,
|
|
180
|
+
usageInput: null,
|
|
181
|
+
usageOutput: null,
|
|
182
|
+
syncUsage: false,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
for (let i = 0; i < args.length; i++) {
|
|
186
|
+
const arg = args[i];
|
|
187
|
+
if (arg === "--format") {
|
|
188
|
+
const val = args[i + 1];
|
|
189
|
+
if (!val) throw new Error("Missing value for --format.");
|
|
190
|
+
const normalized = val.toLowerCase();
|
|
191
|
+
if (normalized !== "text" && normalized !== "json") {
|
|
192
|
+
throw new Error(`Unknown format: ${val}`);
|
|
193
|
+
}
|
|
194
|
+
result.format = normalized as "text" | "json";
|
|
195
|
+
i++;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (arg.startsWith("--format=")) {
|
|
199
|
+
const val = arg.slice("--format=".length);
|
|
200
|
+
const normalized = val.toLowerCase();
|
|
201
|
+
if (normalized !== "text" && normalized !== "json") {
|
|
202
|
+
throw new Error(`Unknown format: ${val}`);
|
|
203
|
+
}
|
|
204
|
+
result.format = normalized as "text" | "json";
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (arg === "--cwd") {
|
|
208
|
+
const val = args[i + 1];
|
|
209
|
+
if (!val) throw new Error("Missing value for --cwd.");
|
|
210
|
+
result.cwd = val;
|
|
211
|
+
i++;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (arg.startsWith("--cwd=")) {
|
|
215
|
+
result.cwd = arg.slice("--cwd=".length);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (arg === "--type") {
|
|
219
|
+
const val = args[i + 1];
|
|
220
|
+
if (!val) throw new Error("Missing value for --type.");
|
|
221
|
+
result.type = val;
|
|
222
|
+
i++;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (arg.startsWith("--type=")) {
|
|
226
|
+
result.type = arg.slice("--type=".length);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (arg === "--profile-key") {
|
|
230
|
+
const val = args[i + 1];
|
|
231
|
+
if (!val) throw new Error("Missing value for --profile-key.");
|
|
232
|
+
result.profileKey = val;
|
|
233
|
+
i++;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (arg.startsWith("--profile-key=")) {
|
|
237
|
+
result.profileKey = arg.slice("--profile-key=".length);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (arg === "--profile-name") {
|
|
241
|
+
const val = args[i + 1];
|
|
242
|
+
if (!val) throw new Error("Missing value for --profile-name.");
|
|
243
|
+
result.profileName = val;
|
|
244
|
+
i++;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (arg.startsWith("--profile-name=")) {
|
|
248
|
+
result.profileName = arg.slice("--profile-name=".length);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (arg === "--model") {
|
|
252
|
+
const val = args[i + 1];
|
|
253
|
+
if (!val) throw new Error("Missing value for --model.");
|
|
254
|
+
result.model = val;
|
|
255
|
+
i++;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (arg.startsWith("--model=")) {
|
|
259
|
+
result.model = arg.slice("--model=".length);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (arg === "--usage-today") {
|
|
263
|
+
result.usageToday = parseNumberFlag(args[i + 1], "--usage-today");
|
|
264
|
+
i++;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (arg.startsWith("--usage-today=")) {
|
|
268
|
+
result.usageToday = parseNumberFlag(
|
|
269
|
+
arg.slice("--usage-today=".length),
|
|
270
|
+
"--usage-today"
|
|
271
|
+
);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (arg === "--usage-total") {
|
|
275
|
+
result.usageTotal = parseNumberFlag(args[i + 1], "--usage-total");
|
|
276
|
+
i++;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (arg.startsWith("--usage-total=")) {
|
|
280
|
+
result.usageTotal = parseNumberFlag(
|
|
281
|
+
arg.slice("--usage-total=".length),
|
|
282
|
+
"--usage-total"
|
|
283
|
+
);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (arg === "--usage-input") {
|
|
287
|
+
result.usageInput = parseNumberFlag(args[i + 1], "--usage-input");
|
|
288
|
+
i++;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (arg.startsWith("--usage-input=")) {
|
|
292
|
+
result.usageInput = parseNumberFlag(
|
|
293
|
+
arg.slice("--usage-input=".length),
|
|
294
|
+
"--usage-input"
|
|
295
|
+
);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (arg === "--usage-output") {
|
|
299
|
+
result.usageOutput = parseNumberFlag(args[i + 1], "--usage-output");
|
|
300
|
+
i++;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (arg.startsWith("--usage-output=")) {
|
|
304
|
+
result.usageOutput = parseNumberFlag(
|
|
305
|
+
arg.slice("--usage-output=".length),
|
|
306
|
+
"--usage-output"
|
|
307
|
+
);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (arg === "--sync-usage") {
|
|
311
|
+
result.syncUsage = true;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
throw new Error(`Unknown statusline argument: ${arg}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return result;
|
|
318
|
+
}
|
package/src/cli/help.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help message for codenv CLI
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function printHelp(): void {
|
|
6
|
+
const msg = `codenv - switch Claude/Codex env vars
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
codenv list
|
|
10
|
+
codenv ls
|
|
11
|
+
codenv config
|
|
12
|
+
codenv auto
|
|
13
|
+
codenv use
|
|
14
|
+
codenv use <profile>
|
|
15
|
+
codenv use <type> <name>
|
|
16
|
+
codenv show <profile>
|
|
17
|
+
codenv show <type> <name>
|
|
18
|
+
codenv default <profile>
|
|
19
|
+
codenv default <type> <name>
|
|
20
|
+
codenv default --clear
|
|
21
|
+
codenv remove <profile> [<profile> ...]
|
|
22
|
+
codenv remove <type> <name> [<type> <name> ...]
|
|
23
|
+
codenv remove --all
|
|
24
|
+
codenv unset
|
|
25
|
+
codenv add <profile> KEY=VALUE [KEY=VALUE ...]
|
|
26
|
+
codenv add
|
|
27
|
+
codenv launch <codex|claude> [--] [args...]
|
|
28
|
+
codenv init
|
|
29
|
+
codenv statusline [options]
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
-c, --config <path> Path to config JSON
|
|
33
|
+
-h, --help Show help
|
|
34
|
+
|
|
35
|
+
Init options:
|
|
36
|
+
--apply Append shell helper to your shell rc (default)
|
|
37
|
+
--print Print helper snippet to stdout
|
|
38
|
+
--shell <bash|zsh|fish> Explicitly set the target shell
|
|
39
|
+
|
|
40
|
+
Add options:
|
|
41
|
+
-t, --type <codex|claude> Set profile type (alias: cc)
|
|
42
|
+
-n, --note <text> Set profile note
|
|
43
|
+
-r, --remove-file <path> Add a removeFiles entry (repeat)
|
|
44
|
+
-x, --command <cmd> Add a commands entry (repeat)
|
|
45
|
+
-u, --unset <KEY> Add a global unset key (repeat)
|
|
46
|
+
|
|
47
|
+
Statusline options:
|
|
48
|
+
--format <text|json> Output format (default: text)
|
|
49
|
+
--cwd <path> Override working directory
|
|
50
|
+
--type <type> Set profile type
|
|
51
|
+
--profile-key <key> Set profile key
|
|
52
|
+
--profile-name <name> Set profile name
|
|
53
|
+
--model <model> Set model label
|
|
54
|
+
--usage-today <n> Set today's token usage
|
|
55
|
+
--usage-total <n> Set total token usage
|
|
56
|
+
--usage-input <n> Set input token usage
|
|
57
|
+
--usage-output <n> Set output token usage
|
|
58
|
+
--sync-usage Sync usage from sessions before reading
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
codenv init
|
|
62
|
+
codenv use codex primary
|
|
63
|
+
codenv list
|
|
64
|
+
codenv default codex primary
|
|
65
|
+
codenv remove codex primary
|
|
66
|
+
codenv remove codex primary claude default
|
|
67
|
+
codenv remove --all
|
|
68
|
+
codenv launch codex -- --help
|
|
69
|
+
codenv statusline --format json
|
|
70
|
+
CODE_ENV_CONFIG=~/.config/code-env/config.json codenv use claude default
|
|
71
|
+
codenv add --type codex primary OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_API_KEY=YOUR_API_KEY
|
|
72
|
+
codenv add
|
|
73
|
+
`;
|
|
74
|
+
console.log(msg);
|
|
75
|
+
}
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add command - add/update profile configuration
|
|
3
|
+
*/
|
|
4
|
+
import type { Config, AddArgs } from "../types";
|
|
5
|
+
import { findProfileKeysByName } from "../profile/match";
|
|
6
|
+
import { generateProfileKey } from "../profile/resolve";
|
|
7
|
+
|
|
8
|
+
export function addConfig(config: Config, addArgs: AddArgs): Config {
|
|
9
|
+
if (!config.profiles || typeof config.profiles !== "object") {
|
|
10
|
+
config.profiles = {};
|
|
11
|
+
}
|
|
12
|
+
let targetKey: string | null = null;
|
|
13
|
+
let matchedByName = false;
|
|
14
|
+
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(config.profiles, addArgs.profile!)) {
|
|
16
|
+
targetKey = addArgs.profile;
|
|
17
|
+
} else {
|
|
18
|
+
const matches = findProfileKeysByName(
|
|
19
|
+
config,
|
|
20
|
+
addArgs.profile!,
|
|
21
|
+
addArgs.type
|
|
22
|
+
);
|
|
23
|
+
if (matches.length === 1) {
|
|
24
|
+
targetKey = matches[0];
|
|
25
|
+
matchedByName = true;
|
|
26
|
+
} else if (matches.length > 1) {
|
|
27
|
+
const hint = addArgs.type
|
|
28
|
+
? `Use profile key: ${matches.join(", ")}`
|
|
29
|
+
: `Use: codenv add --type <type> ${addArgs.profile} ... (or profile key: ${matches.join(
|
|
30
|
+
", "
|
|
31
|
+
)})`;
|
|
32
|
+
throw new Error(`Multiple profiles named "${addArgs.profile}". ${hint}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!targetKey) {
|
|
37
|
+
targetKey = generateProfileKey(config);
|
|
38
|
+
matchedByName = true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!config.profiles[targetKey]) {
|
|
42
|
+
config.profiles[targetKey] = {};
|
|
43
|
+
}
|
|
44
|
+
const profile = config.profiles[targetKey];
|
|
45
|
+
if (!profile.env || typeof profile.env !== "object") {
|
|
46
|
+
profile.env = {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (matchedByName) {
|
|
50
|
+
profile.name = addArgs.profile!;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (addArgs.type) {
|
|
54
|
+
profile.type = addArgs.type;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const pair of addArgs.pairs) {
|
|
58
|
+
const idx = pair.indexOf("=");
|
|
59
|
+
if (idx <= 0) throw new Error(`Invalid KEY=VALUE: ${pair}`);
|
|
60
|
+
const key = pair.slice(0, idx);
|
|
61
|
+
const value = pair.slice(idx + 1);
|
|
62
|
+
profile.env[key] = value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (addArgs.note !== null && addArgs.note !== undefined) {
|
|
66
|
+
profile.note = addArgs.note;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (addArgs.removeFiles.length > 0) {
|
|
70
|
+
if (!Array.isArray(profile.removeFiles)) profile.removeFiles = [];
|
|
71
|
+
for (const p of addArgs.removeFiles) {
|
|
72
|
+
if (!profile.removeFiles.includes(p)) profile.removeFiles.push(p);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (addArgs.commands.length > 0) {
|
|
77
|
+
if (!Array.isArray(profile.commands)) profile.commands = [];
|
|
78
|
+
for (const cmd of addArgs.commands) {
|
|
79
|
+
if (!profile.commands.includes(cmd)) profile.commands.push(cmd);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (addArgs.unset.length > 0) {
|
|
84
|
+
if (!Array.isArray(config.unset)) config.unset = [];
|
|
85
|
+
for (const key of addArgs.unset) {
|
|
86
|
+
if (!config.unset.includes(key)) config.unset.push(key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return config;
|
|
91
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commands module exports
|
|
3
|
+
*/
|
|
4
|
+
export { buildUseLines, printUse } from "./use";
|
|
5
|
+
export { printList } from "./list";
|
|
6
|
+
export { addConfig } from "./add";
|
|
7
|
+
export { printShow } from "./show";
|
|
8
|
+
export { printUnset } from "./unset";
|
|
9
|
+
export { runLaunch } from "./launch";
|
|
10
|
+
export { printStatusline } from "./statusline";
|