@praeviso/code-env-switch 0.1.8 → 0.1.10

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.
@@ -13,7 +13,9 @@ export function printUnset(config: Config): void {
13
13
  for (const type of DEFAULT_PROFILE_TYPES) {
14
14
  for (const key of getTypeDefaultUnsetKeys(type)) keySet.add(key);
15
15
  }
16
- if (keySet.size === 0) return;
17
- const lines = Array.from(keySet, (key) => `unset ${key}`);
16
+ const lines: string[] = ["command codenv __codex-clear"];
17
+ if (keySet.size > 0) {
18
+ lines.push(...Array.from(keySet, (key) => `unset ${key}`));
19
+ }
18
20
  console.log(lines.join("\n"));
19
21
  }
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Use command - apply profile environment
3
3
  */
4
- import * as path from "path";
5
4
  import type { Config, ProfileType } from "../types";
6
- import { CODEX_AUTH_PATH } from "../constants";
7
5
  import { shellEscape, expandEnv } from "../shell/utils";
8
6
  import { inferProfileType, getProfileDisplayName } from "../profile/type";
9
7
  import { shouldRemoveCodexAuth } from "../profile/match";
@@ -28,6 +26,10 @@ export function buildUseLines(
28
26
  const unsetKeys = new Set<string>();
29
27
  const activeType = inferProfileType(profileName, profile, requestedType);
30
28
  const effectiveEnv = buildEffectiveEnv(profile, activeType);
29
+ const managedCodexKeys =
30
+ activeType === "codex"
31
+ ? new Set(["OPENAI_BASE_URL", "OPENAI_API_KEY"])
32
+ : new Set<string>();
31
33
 
32
34
  const addUnset = (key: string) => {
33
35
  if (unsetKeys.has(key)) return;
@@ -49,6 +51,13 @@ export function buildUseLines(
49
51
  }
50
52
 
51
53
  for (const key of Object.keys(effectiveEnv)) {
54
+ if (managedCodexKeys.has(key)) {
55
+ if (!unsetKeys.has(key)) {
56
+ unsetKeys.add(key);
57
+ unsetLines.push(`unset ${key}`);
58
+ }
59
+ continue;
60
+ }
52
61
  const value = effectiveEnv[key];
53
62
  if (value === null || value === undefined || value === "") {
54
63
  if (!unsetKeys.has(key)) {
@@ -75,16 +84,7 @@ export function buildUseLines(
75
84
  }
76
85
 
77
86
  if (shouldRemoveCodexAuth(profileName, profile, requestedType)) {
78
- const codexApiKey = effectiveEnv.OPENAI_API_KEY;
79
- const authDir = path.dirname(CODEX_AUTH_PATH);
80
- const authJson =
81
- codexApiKey === null || codexApiKey === undefined || codexApiKey === ""
82
- ? "null"
83
- : JSON.stringify({ OPENAI_API_KEY: String(codexApiKey) });
84
- postLines.push(`mkdir -p ${shellEscape(authDir)}`);
85
- postLines.push(
86
- `printf '%s\\n' ${shellEscape(authJson)} > ${shellEscape(CODEX_AUTH_PATH)}`
87
- );
87
+ postLines.push("command codenv __codex-sync");
88
88
  }
89
89
 
90
90
  if (Array.isArray(profile.removeFiles)) {
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * codenv - switch Claude/Codex env vars
3
+ * codenv - switch Claude/Codex profiles
4
4
  * Main entry point
5
5
  */
6
6
  import * as fs from "fs";
@@ -38,6 +38,11 @@ import {
38
38
  } from "./commands";
39
39
  import { logProfileUse } from "./usage";
40
40
  import { createReadline, askConfirm, runInteractiveAdd, runInteractiveUse } from "./ui";
41
+ import {
42
+ clearManagedCodexProfile,
43
+ resolveCodexProfileFromEnv,
44
+ syncCodexProfile,
45
+ } from "./codex/config";
41
46
 
42
47
  function getErrorMessage(err: unknown): string {
43
48
  return err instanceof Error ? err.message : String(err);
@@ -59,6 +64,30 @@ async function main() {
59
64
 
60
65
  const cmd = args[0];
61
66
  try {
67
+ if (cmd === "__codex-sync") {
68
+ const configPath =
69
+ process.env.CODE_ENV_CONFIG_PATH || findConfigPath(parsed.configPath);
70
+ const config = readConfigIfExists(configPath);
71
+ const profileKey = process.env.CODE_ENV_PROFILE_KEY_CODEX || null;
72
+ const profileName = process.env.CODE_ENV_PROFILE_NAME_CODEX || null;
73
+ const resolvedProfile = resolveCodexProfileFromEnv(
74
+ config,
75
+ profileKey,
76
+ profileName
77
+ );
78
+ if (!resolvedProfile) return;
79
+ syncCodexProfile(config, resolvedProfile);
80
+ return;
81
+ }
82
+
83
+ if (cmd === "__codex-clear") {
84
+ const configPath =
85
+ process.env.CODE_ENV_CONFIG_PATH || findConfigPath(parsed.configPath);
86
+ const config = readConfigIfExists(configPath);
87
+ clearManagedCodexProfile(config);
88
+ return;
89
+ }
90
+
62
91
  if (cmd === "init") {
63
92
  const initArgs = parseInitArgs(args.slice(1));
64
93
  const shellName = detectShell(initArgs.shell);
@@ -36,6 +36,20 @@ export function envMatchesProfile(profile: Profile | undefined): boolean {
36
36
  return Object.keys(profile.env).length > 0;
37
37
  }
38
38
 
39
+ export function markerMatchesProfile(
40
+ profileKey: string,
41
+ profile: Profile | undefined,
42
+ activeType: ProfileType | null
43
+ ): boolean {
44
+ if (!activeType) return false;
45
+ const suffix = activeType.toUpperCase();
46
+ const activeKey = process.env[`CODE_ENV_PROFILE_KEY_${suffix}`];
47
+ if (activeKey) return activeKey === profileKey;
48
+ const activeName = process.env[`CODE_ENV_PROFILE_NAME_${suffix}`];
49
+ if (!activeName || !profile) return false;
50
+ return activeName === getProfileDisplayName(profileKey, profile, activeType);
51
+ }
52
+
39
53
  // Forward declaration to avoid circular dependency
40
54
  // getResolvedDefaultProfileKeys will be imported from config/defaults
41
55
  export function buildListRows(
@@ -63,7 +77,9 @@ export function buildListRows(
63
77
  if (defaultLabel) noteParts.push(defaultLabel);
64
78
  if (note) noteParts.push(note);
65
79
  const noteText = noteParts.join(" | ");
66
- const active = envMatchesProfile(safeProfile);
80
+ const active =
81
+ markerMatchesProfile(key, safeProfile, usageType) ||
82
+ envMatchesProfile(safeProfile);
67
83
  return { key, name: displayName, type, note: noteText, active, usageType };
68
84
  });
69
85
  rows.sort((a, b) => {