codex-multi-auth 2.1.5 → 2.1.6

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.
Files changed (85) hide show
  1. package/README.md +45 -21
  2. package/config/README.md +2 -3
  3. package/dist/index.js +22 -22
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/auth/device-auth.d.ts.map +1 -1
  6. package/dist/lib/auth/device-auth.js +18 -1
  7. package/dist/lib/auth/device-auth.js.map +1 -1
  8. package/dist/lib/codex-manager/commands/account.js +6 -6
  9. package/dist/lib/codex-manager/commands/account.js.map +1 -1
  10. package/dist/lib/codex-manager/commands/best.js +1 -1
  11. package/dist/lib/codex-manager/commands/best.js.map +1 -1
  12. package/dist/lib/codex-manager/commands/bridge.js +5 -5
  13. package/dist/lib/codex-manager/commands/bridge.js.map +1 -1
  14. package/dist/lib/codex-manager/commands/budget.js +3 -3
  15. package/dist/lib/codex-manager/commands/budget.js.map +1 -1
  16. package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
  17. package/dist/lib/codex-manager/commands/forecast.js +18 -4
  18. package/dist/lib/codex-manager/commands/forecast.js.map +1 -1
  19. package/dist/lib/codex-manager/commands/integrations.js +1 -1
  20. package/dist/lib/codex-manager/commands/integrations.js.map +1 -1
  21. package/dist/lib/codex-manager/commands/models.js +1 -1
  22. package/dist/lib/codex-manager/commands/models.js.map +1 -1
  23. package/dist/lib/codex-manager/commands/monitor.js +1 -1
  24. package/dist/lib/codex-manager/commands/monitor.js.map +1 -1
  25. package/dist/lib/codex-manager/commands/report.js +1 -1
  26. package/dist/lib/codex-manager/commands/report.js.map +1 -1
  27. package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
  28. package/dist/lib/codex-manager/commands/rotation.js +23 -14
  29. package/dist/lib/codex-manager/commands/rotation.js.map +1 -1
  30. package/dist/lib/codex-manager/commands/switch.js +1 -1
  31. package/dist/lib/codex-manager/commands/switch.js.map +1 -1
  32. package/dist/lib/codex-manager/commands/uninstall.d.ts +36 -0
  33. package/dist/lib/codex-manager/commands/uninstall.d.ts.map +1 -0
  34. package/dist/lib/codex-manager/commands/uninstall.js +284 -0
  35. package/dist/lib/codex-manager/commands/uninstall.js.map +1 -0
  36. package/dist/lib/codex-manager/commands/usage.js +2 -2
  37. package/dist/lib/codex-manager/commands/usage.js.map +1 -1
  38. package/dist/lib/codex-manager/commands/verify.js +4 -4
  39. package/dist/lib/codex-manager/commands/verify.js.map +1 -1
  40. package/dist/lib/codex-manager/commands/why-selected.js +3 -3
  41. package/dist/lib/codex-manager/commands/why-selected.js.map +1 -1
  42. package/dist/lib/codex-manager/forecast-report-commands.js +3 -3
  43. package/dist/lib/codex-manager/forecast-report-commands.js.map +1 -1
  44. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  45. package/dist/lib/codex-manager/help.js +27 -26
  46. package/dist/lib/codex-manager/help.js.map +1 -1
  47. package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
  48. package/dist/lib/codex-manager/repair-commands.js +23 -11
  49. package/dist/lib/codex-manager/repair-commands.js.map +1 -1
  50. package/dist/lib/codex-manager.d.ts.map +1 -1
  51. package/dist/lib/codex-manager.js +47 -6
  52. package/dist/lib/codex-manager.js.map +1 -1
  53. package/dist/lib/forecast.js +1 -1
  54. package/dist/lib/forecast.js.map +1 -1
  55. package/dist/lib/request/fetch-helpers.d.ts +1 -1
  56. package/dist/lib/request/fetch-helpers.js +8 -8
  57. package/dist/lib/request/fetch-helpers.js.map +1 -1
  58. package/dist/lib/request/stream-failover.d.ts.map +1 -1
  59. package/dist/lib/request/stream-failover.js +12 -1
  60. package/dist/lib/request/stream-failover.js.map +1 -1
  61. package/dist/lib/rotation.d.ts +1 -1
  62. package/dist/lib/rotation.js +1 -1
  63. package/dist/lib/runtime/app-bind.d.ts.map +1 -1
  64. package/dist/lib/runtime/app-bind.js +28 -3
  65. package/dist/lib/runtime/app-bind.js.map +1 -1
  66. package/dist/lib/runtime/config-toml.d.ts.map +1 -1
  67. package/dist/lib/runtime/config-toml.js +29 -3
  68. package/dist/lib/runtime/config-toml.js.map +1 -1
  69. package/dist/lib/runtime/hydrate-emails.d.ts.map +1 -1
  70. package/dist/lib/runtime/hydrate-emails.js +6 -1
  71. package/dist/lib/runtime/hydrate-emails.js.map +1 -1
  72. package/dist/lib/runtime/runtime-current-account.d.ts.map +1 -1
  73. package/dist/lib/runtime/runtime-current-account.js +10 -1
  74. package/dist/lib/runtime/runtime-current-account.js.map +1 -1
  75. package/dist/lib/runtime/storage-scope.js +2 -2
  76. package/dist/lib/runtime/storage-scope.js.map +1 -1
  77. package/dist/lib/runtime-rotation-proxy.js +1 -1
  78. package/dist/lib/runtime-rotation-proxy.js.map +1 -1
  79. package/dist/lib/storage/transactions.d.ts +2 -1
  80. package/dist/lib/storage/transactions.d.ts.map +1 -1
  81. package/dist/lib/storage/transactions.js +9 -3
  82. package/dist/lib/storage/transactions.js.map +1 -1
  83. package/package.json +26 -17
  84. package/scripts/install-codex-auth-utils.js +48 -0
  85. package/scripts/preuninstall.js +254 -0
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+
3
+ // @ts-check
4
+
5
+ import { readFile, writeFile, rm } from "node:fs/promises";
6
+ import { resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import process from "node:process";
9
+ import {
10
+ isCiEnvironment,
11
+ resolveInstallPaths,
12
+ removePluginFromList,
13
+ withFileOperationRetry,
14
+ } from "./install-codex-auth-utils.js";
15
+
16
+ async function loadAppBindModule() {
17
+ try {
18
+ return await import("../dist/lib/runtime/app-bind.js");
19
+ } catch (error) {
20
+ if (
21
+ error &&
22
+ typeof error === "object" &&
23
+ "code" in error &&
24
+ error.code === "ERR_MODULE_NOT_FOUND"
25
+ ) {
26
+ return null;
27
+ }
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ function defaultPreuninstallLog(message) {
33
+ console.error(`codex-multi-auth: ${message}`);
34
+ }
35
+
36
+ /**
37
+ * @param {{
38
+ * unbindCodexApp?: (dryRun: boolean) => Promise<void>,
39
+ * removeLauncher?: (options: { dryRun: boolean, log: (m: string) => void }) => Promise<void>,
40
+ * removePluginFromConfig?: (dryRun: boolean, log: (m: string) => void) => Promise<{ bunLockState: "safe" | "uncertain" }>,
41
+ * clearCache?: (dryRun: boolean, log: (m: string) => void, bunLockSafe: boolean) => Promise<void>,
42
+ * log?: (message: string) => void,
43
+ * env?: NodeJS.ProcessEnv,
44
+ * home?: string,
45
+ * dryRun?: boolean,
46
+ * }} [deps]
47
+ */
48
+ export async function runPreuninstallCleanup(deps = {}) {
49
+ const log = deps.log ?? defaultPreuninstallLog;
50
+ const env = deps.env ?? process.env;
51
+ const home =
52
+ deps.home ??
53
+ (deps.env
54
+ ? env.HOME || env.USERPROFILE || ""
55
+ : undefined);
56
+ const dryRun = deps.dryRun ?? process.argv.includes("--dry-run");
57
+
58
+ if (isCiEnvironment(env)) {
59
+ return 0;
60
+ }
61
+
62
+ /** @type {"safe" | "uncertain"} */
63
+ let bunLockState = "uncertain";
64
+
65
+ // Unbind Codex app runtime rotation (reverses postinstall bind)
66
+ try {
67
+ if (deps.unbindCodexApp) {
68
+ await deps.unbindCodexApp(dryRun);
69
+ } else {
70
+ const appBindModule = await loadAppBindModule();
71
+ if (
72
+ appBindModule &&
73
+ typeof appBindModule.unbindCodexAppRuntimeRotation === "function"
74
+ ) {
75
+ if (dryRun) {
76
+ log("[dry-run] Would unbind Codex app runtime rotation");
77
+ } else {
78
+ await appBindModule.unbindCodexAppRuntimeRotation();
79
+ }
80
+ }
81
+ }
82
+ } catch (error) {
83
+ log(
84
+ `app unbind skipped: ${error instanceof Error ? error.message : String(error)}`,
85
+ );
86
+ }
87
+
88
+ // Remove OS-level launcher (reverses postinstall launcher install)
89
+ try {
90
+ if (deps.removeLauncher) {
91
+ await deps.removeLauncher({ dryRun, log });
92
+ } else {
93
+ const launcherModule = await import("./codex-app-launcher.js");
94
+ if (typeof launcherModule.installCodexAppLauncher === "function") {
95
+ await launcherModule.installCodexAppLauncher({ remove: true, dryRun, log });
96
+ }
97
+ }
98
+ } catch (error) {
99
+ log(
100
+ `launcher removal skipped: ${error instanceof Error ? error.message : String(error)}`,
101
+ );
102
+ }
103
+
104
+ // Remove plugin entry from Codex.json and track whether we're certain that
105
+ // no other plugins remain. bun.lock is shared across all Codex plugins, so
106
+ // it's only safe to delete when:
107
+ // - File ENOENT → safe (nothing to protect)
108
+ // - Parse error / read fail → uncertain (be conservative)
109
+ // - File ok, no plugins[] → uncertain (we don't know what's installed)
110
+ // - File ok, plugins[]=[] → safe
111
+ // - File ok, plugins[]≠[] → uncertain
112
+ try {
113
+ if (deps.removePluginFromConfig) {
114
+ const result = await deps.removePluginFromConfig(dryRun, log);
115
+ if (result && typeof result === "object" && "bunLockState" in result) {
116
+ bunLockState = result.bunLockState === "safe" ? "safe" : "uncertain";
117
+ }
118
+ } else {
119
+ const paths = resolveInstallPaths(
120
+ process.platform,
121
+ env,
122
+ home || undefined,
123
+ );
124
+ try {
125
+ const raw = await withFileOperationRetry(() =>
126
+ readFile(paths.configPath, "utf8"),
127
+ );
128
+ const config = JSON.parse(raw);
129
+ if (Array.isArray(config.plugins)) {
130
+ const next = removePluginFromList(config.plugins);
131
+ bunLockState = next.length === 0 ? "safe" : "uncertain";
132
+ if (dryRun) {
133
+ log(
134
+ `[dry-run] Would remove codex-multi-auth from ${paths.configPath}`,
135
+ );
136
+ } else {
137
+ config.plugins = next;
138
+ await withFileOperationRetry(() =>
139
+ writeFile(
140
+ paths.configPath,
141
+ JSON.stringify(config, null, "\t") + "\n",
142
+ "utf8",
143
+ ),
144
+ );
145
+ }
146
+ } else if (dryRun) {
147
+ log(
148
+ `[dry-run] Would remove codex-multi-auth from ${paths.configPath}`,
149
+ );
150
+ }
151
+ } catch (fileError) {
152
+ const code =
153
+ fileError &&
154
+ typeof fileError === "object" &&
155
+ "code" in fileError
156
+ ? fileError.code
157
+ : undefined;
158
+ if (code === "ENOENT") {
159
+ bunLockState = "safe";
160
+ if (dryRun) {
161
+ log(
162
+ `[dry-run] Would remove codex-multi-auth from ${paths.configPath}`,
163
+ );
164
+ }
165
+ } else {
166
+ log(
167
+ `config cleanup skipped: ${fileError instanceof Error ? fileError.message : String(fileError)}`,
168
+ );
169
+ }
170
+ }
171
+ }
172
+ } catch (error) {
173
+ log(
174
+ `config cleanup skipped: ${error instanceof Error ? error.message : String(error)}`,
175
+ );
176
+ }
177
+
178
+ const bunLockSafe = bunLockState === "safe";
179
+
180
+ // Clear plugin cache dirs
181
+ try {
182
+ if (deps.clearCache) {
183
+ await deps.clearCache(dryRun, log, bunLockSafe);
184
+ } else {
185
+ const paths = resolveInstallPaths(
186
+ process.platform,
187
+ env,
188
+ home || undefined,
189
+ );
190
+ if (dryRun) {
191
+ log(`[dry-run] Would remove ${paths.cacheNodeModules}`);
192
+ if (bunLockSafe) {
193
+ log(`[dry-run] Would remove ${paths.cacheBunLock}`);
194
+ } else {
195
+ log(
196
+ `[dry-run] Would skip ${paths.cacheBunLock} (other plugins still installed)`,
197
+ );
198
+ }
199
+ } else {
200
+ try {
201
+ await withFileOperationRetry(() =>
202
+ rm(paths.cacheNodeModules, { recursive: true, force: true }),
203
+ );
204
+ if (bunLockSafe) {
205
+ await withFileOperationRetry(() =>
206
+ rm(paths.cacheBunLock, { force: true }),
207
+ );
208
+ }
209
+ } catch (error) {
210
+ log(
211
+ `cache clear skipped: ${error instanceof Error ? error.message : String(error)}`,
212
+ );
213
+ }
214
+ }
215
+ }
216
+ } catch (error) {
217
+ log(
218
+ `cache clear skipped: ${error instanceof Error ? error.message : String(error)}`,
219
+ );
220
+ }
221
+
222
+ return 0;
223
+ }
224
+
225
+ async function main() {
226
+ return runPreuninstallCleanup();
227
+ }
228
+
229
+ function normalizeExitCode(exitCode) {
230
+ return Number.isInteger(exitCode) && exitCode >= 0 && exitCode <= 255
231
+ ? exitCode
232
+ : 0;
233
+ }
234
+
235
+ const isDirectRun = (() => {
236
+ try {
237
+ return resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url);
238
+ } catch {
239
+ return false;
240
+ }
241
+ })();
242
+
243
+ if (isDirectRun) {
244
+ main()
245
+ .then((exitCode) => {
246
+ process.exitCode = normalizeExitCode(exitCode);
247
+ })
248
+ .catch((error) => {
249
+ defaultPreuninstallLog(
250
+ `preuninstall cleanup skipped: ${error instanceof Error ? error.message : String(error)}`,
251
+ );
252
+ process.exitCode = 0;
253
+ });
254
+ }