oc-codex-multi-auth 6.1.3 → 6.1.7
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 +17 -10
- package/config/README.md +12 -12
- package/config/opencode-legacy.json +125 -0
- package/config/opencode-modern.json +43 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/auto-update-checker.d.ts +7 -1
- package/dist/lib/auto-update-checker.d.ts.map +1 -1
- package/dist/lib/auto-update-checker.js +51 -3
- package/dist/lib/auto-update-checker.js.map +1 -1
- package/dist/lib/codex-usage.d.ts +91 -0
- package/dist/lib/codex-usage.d.ts.map +1 -0
- package/dist/lib/codex-usage.js +368 -0
- package/dist/lib/codex-usage.js.map +1 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +4 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/schemas.d.ts +1 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +1 -0
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/tools/codex-limits.d.ts.map +1 -1
- package/dist/lib/tools/codex-limits.js +39 -340
- package/dist/lib/tools/codex-limits.js.map +1 -1
- package/dist/lib/tools/codex-switch.d.ts.map +1 -1
- package/dist/lib/tools/codex-switch.js +9 -0
- package/dist/lib/tools/codex-switch.js.map +1 -1
- package/dist/lib/tui-quota-cache.d.ts +33 -0
- package/dist/lib/tui-quota-cache.d.ts.map +1 -0
- package/dist/lib/tui-quota-cache.js +247 -0
- package/dist/lib/tui-quota-cache.js.map +1 -0
- package/dist/lib/tui-status.d.ts +55 -0
- package/dist/lib/tui-status.d.ts.map +1 -0
- package/dist/lib/tui-status.js +343 -0
- package/dist/lib/tui-status.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +363 -0
- package/dist/tui.js.map +1 -0
- package/package.json +16 -2
- package/scripts/install-oc-codex-multi-auth-core.js +119 -18
|
@@ -8,21 +8,28 @@ const PACKAGE_NAME = "oc-codex-multi-auth";
|
|
|
8
8
|
const LEGACY_PACKAGE_NAMES = ["oc-chatgpt-multi-auth"];
|
|
9
9
|
const WINDOWS_RENAME_RETRY_ATTEMPTS = 5;
|
|
10
10
|
const WINDOWS_RENAME_RETRY_BASE_DELAY_MS = 10;
|
|
11
|
+
const STALE_MANAGED_MODEL_KEYS = new Set([
|
|
12
|
+
"gpt-5.2",
|
|
13
|
+
"gpt-5.3-codex",
|
|
14
|
+
"gpt-5.4",
|
|
15
|
+
]);
|
|
11
16
|
|
|
12
17
|
function getManagedPackageNames() {
|
|
13
18
|
return [PACKAGE_NAME, ...LEGACY_PACKAGE_NAMES];
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
function printHelp() {
|
|
17
|
-
console.log(`Usage: ${PACKAGE_NAME} [--modern|--legacy] [--dry-run] [--no-cache-clear]\n\n` +
|
|
22
|
+
console.log(`Usage: ${PACKAGE_NAME} [--modern|--full|--legacy] [--dry-run] [--no-cache-clear]\n\n` +
|
|
18
23
|
"Default behavior:\n" +
|
|
19
24
|
" - Installs/updates global config at ~/.config/opencode/opencode.json\n" +
|
|
20
|
-
" -
|
|
25
|
+
" - Enables the prompt status bar TUI plugin at ~/.config/opencode/tui.json\n" +
|
|
26
|
+
" - Uses compact UI config by default (9 base OAuth models + variant picker presets)\n" +
|
|
21
27
|
" - Ensures plugin is unpinned (latest)\n" +
|
|
22
28
|
" - Clears OpenCode plugin cache\n\n" +
|
|
23
29
|
"Options:\n" +
|
|
24
|
-
" --modern Force compact modern config (9 base models + --variant presets)\n" +
|
|
25
|
-
" --
|
|
30
|
+
" --modern Force compact modern config (9 base OAuth models + --variant presets)\n" +
|
|
31
|
+
" --full Install compact base models plus 36 explicit selector entries\n" +
|
|
32
|
+
" --legacy Force explicit legacy config (36 preset model entries)\n" +
|
|
26
33
|
" --dry-run Show actions without writing\n" +
|
|
27
34
|
" --no-cache-clear Skip clearing OpenCode cache\n"
|
|
28
35
|
);
|
|
@@ -63,8 +70,10 @@ function buildPaths(homeDir) {
|
|
|
63
70
|
return {
|
|
64
71
|
configDir,
|
|
65
72
|
configPath: join(configDir, "opencode.json"),
|
|
73
|
+
tuiConfigPath: join(configDir, "tui.json"),
|
|
66
74
|
cacheDir,
|
|
67
75
|
cacheNodeModulesPaths: getManagedPackageNames().map((name) => join(cacheDir, "node_modules", name)),
|
|
76
|
+
cachePackagePaths: getManagedPackageNames().map((name) => join(cacheDir, "packages", `${name}@latest`)),
|
|
68
77
|
cacheBunLock: join(cacheDir, "bun.lock"),
|
|
69
78
|
cachePackageJson: join(cacheDir, "package.json"),
|
|
70
79
|
modernTemplatePath,
|
|
@@ -81,30 +90,67 @@ function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
const requestedModern = args.has("--modern");
|
|
93
|
+
const requestedFull = args.has("--full");
|
|
84
94
|
const requestedLegacy = args.has("--legacy");
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
const requestedModes = [requestedModern, requestedFull, requestedLegacy]
|
|
97
|
+
.filter(Boolean).length;
|
|
98
|
+
if (requestedModes > 1) {
|
|
99
|
+
throw new Error("Choose only one of --modern, --full, or --legacy.");
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
return {
|
|
91
103
|
wantsHelp: false,
|
|
92
104
|
dryRun: args.has("--dry-run"),
|
|
93
105
|
skipCacheClear: args.has("--no-cache-clear"),
|
|
94
|
-
configMode:
|
|
106
|
+
configMode: requestedFull ? "full" : requestedLegacy ? "legacy" : "modern",
|
|
95
107
|
};
|
|
96
108
|
}
|
|
97
109
|
|
|
110
|
+
function normalizePluginEntryForMatch(entry) {
|
|
111
|
+
const trimmed = entry.trim();
|
|
112
|
+
let normalized = trimmed.toLowerCase();
|
|
113
|
+
try {
|
|
114
|
+
normalized = decodeURIComponent(normalized);
|
|
115
|
+
} catch {
|
|
116
|
+
// Keep the raw lowercased value when a malformed URI escape is present.
|
|
117
|
+
}
|
|
118
|
+
normalized = normalized.replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
119
|
+
if (normalized.endsWith("/dist")) {
|
|
120
|
+
normalized = normalized.slice(0, -"/dist".length);
|
|
121
|
+
}
|
|
122
|
+
return normalized;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isManagedPluginEntry(entry) {
|
|
126
|
+
if (typeof entry !== "string") return false;
|
|
127
|
+
const trimmed = entry.trim().toLowerCase();
|
|
128
|
+
const normalized = normalizePluginEntryForMatch(entry);
|
|
129
|
+
return getManagedPackageNames().some((name) => {
|
|
130
|
+
const lowerName = name.toLowerCase();
|
|
131
|
+
return trimmed === lowerName ||
|
|
132
|
+
trimmed.startsWith(`${lowerName}@`) ||
|
|
133
|
+
normalized.endsWith(`/${lowerName}`) ||
|
|
134
|
+
normalized.endsWith(`/node_modules/${lowerName}`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
98
138
|
function normalizePluginList(list) {
|
|
99
139
|
const entries = Array.isArray(list) ? list.filter(Boolean) : [];
|
|
100
|
-
const
|
|
101
|
-
const filtered = entries.filter((entry) => {
|
|
102
|
-
if (typeof entry !== "string") return true;
|
|
103
|
-
return !managedNames.some((name) => entry === name || entry.startsWith(`${name}@`));
|
|
104
|
-
});
|
|
140
|
+
const filtered = entries.filter((entry) => !isManagedPluginEntry(entry));
|
|
105
141
|
return [...filtered, PACKAGE_NAME];
|
|
106
142
|
}
|
|
107
143
|
|
|
144
|
+
function mergeTuiConfig(existingConfig) {
|
|
145
|
+
const existing = isPlainObject(existingConfig) ? { ...existingConfig } : {};
|
|
146
|
+
const next = { ...existing };
|
|
147
|
+
if (typeof next.$schema !== "string" || !next.$schema.trim()) {
|
|
148
|
+
next.$schema = "https://opencode.ai/tui.json";
|
|
149
|
+
}
|
|
150
|
+
next.plugin = normalizePluginList(existing.plugin);
|
|
151
|
+
return next;
|
|
152
|
+
}
|
|
153
|
+
|
|
108
154
|
function formatJson(obj) {
|
|
109
155
|
return `${JSON.stringify(obj, null, 2)}\n`;
|
|
110
156
|
}
|
|
@@ -125,9 +171,12 @@ function isPlainObject(value) {
|
|
|
125
171
|
// installer overwrite the managed shape it ships. This replaces the earlier
|
|
126
172
|
// wholesale overwrite which clobbered custom user-added keys (see audit top-20
|
|
127
173
|
// #6).
|
|
128
|
-
function mergeOpenaiProvider(existingOpenai, templateOpenai) {
|
|
174
|
+
function mergeOpenaiProvider(existingOpenai, templateOpenai, options = {}) {
|
|
129
175
|
const existingSafe = isPlainObject(existingOpenai) ? existingOpenai : {};
|
|
130
176
|
const templateSafe = isPlainObject(templateOpenai) ? templateOpenai : {};
|
|
177
|
+
const modelKeysToRemove = options.modelKeysToRemove instanceof Set
|
|
178
|
+
? options.modelKeysToRemove
|
|
179
|
+
: new Set();
|
|
131
180
|
|
|
132
181
|
const result = {};
|
|
133
182
|
|
|
@@ -147,7 +196,10 @@ function mergeOpenaiProvider(existingOpenai, templateOpenai) {
|
|
|
147
196
|
// 3. Merge `models` by id: template wins on collision, user-added ids survive.
|
|
148
197
|
const existingModels = isPlainObject(existingSafe.models) ? existingSafe.models : {};
|
|
149
198
|
const templateModels = isPlainObject(templateSafe.models) ? templateSafe.models : {};
|
|
150
|
-
const
|
|
199
|
+
const prunedExistingModels = Object.fromEntries(
|
|
200
|
+
Object.entries(existingModels).filter(([key]) => !modelKeysToRemove.has(key)),
|
|
201
|
+
);
|
|
202
|
+
const mergedModels = { ...prunedExistingModels, ...templateModels };
|
|
151
203
|
if (Object.keys(mergedModels).length > 0) {
|
|
152
204
|
result.models = mergedModels;
|
|
153
205
|
}
|
|
@@ -203,6 +255,10 @@ function mergeFullTemplate(modernTemplate, legacyTemplate) {
|
|
|
203
255
|
};
|
|
204
256
|
}
|
|
205
257
|
|
|
258
|
+
function getTemplateModelKeys(template) {
|
|
259
|
+
return new Set(Object.keys(template.provider?.openai?.models ?? {}));
|
|
260
|
+
}
|
|
261
|
+
|
|
206
262
|
async function readJson(filePath) {
|
|
207
263
|
const content = await readFile(filePath, "utf-8");
|
|
208
264
|
return JSON.parse(content.charCodeAt(0) === 0xfeff ? content.slice(1) : content);
|
|
@@ -351,11 +407,17 @@ async function clearCache(paths, dryRun, skipCacheClear) {
|
|
|
351
407
|
for (const cacheNodeModulesPath of paths.cacheNodeModulesPaths) {
|
|
352
408
|
log(`[dry-run] Would remove ${cacheNodeModulesPath}`);
|
|
353
409
|
}
|
|
410
|
+
for (const cachePackagePath of paths.cachePackagePaths) {
|
|
411
|
+
log(`[dry-run] Would remove ${cachePackagePath}`);
|
|
412
|
+
}
|
|
354
413
|
log(`[dry-run] Would remove ${paths.cacheBunLock}`);
|
|
355
414
|
} else {
|
|
356
415
|
for (const cacheNodeModulesPath of paths.cacheNodeModulesPaths) {
|
|
357
416
|
await rm(cacheNodeModulesPath, { recursive: true, force: true });
|
|
358
417
|
}
|
|
418
|
+
for (const cachePackagePath of paths.cachePackagePaths) {
|
|
419
|
+
await rm(cachePackagePath, { recursive: true, force: true });
|
|
420
|
+
}
|
|
359
421
|
await rm(paths.cacheBunLock, { force: true });
|
|
360
422
|
}
|
|
361
423
|
|
|
@@ -386,6 +448,17 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
386
448
|
|
|
387
449
|
const template = await loadTemplate(configMode, paths);
|
|
388
450
|
template.plugin = [PACKAGE_NAME];
|
|
451
|
+
const modelKeysToRemove = new Set(STALE_MANAGED_MODEL_KEYS);
|
|
452
|
+
if (configMode === "modern") {
|
|
453
|
+
for (const key of getTemplateModelKeys(await readJson(paths.legacyTemplatePath))) {
|
|
454
|
+
modelKeysToRemove.add(key);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (configMode === "legacy") {
|
|
458
|
+
for (const key of getTemplateModelKeys(await readJson(paths.modernTemplatePath))) {
|
|
459
|
+
modelKeysToRemove.add(key);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
389
462
|
|
|
390
463
|
let nextConfig = template;
|
|
391
464
|
let existingConfig;
|
|
@@ -401,7 +474,9 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
401
474
|
const provider = (existing.provider && typeof existing.provider === "object")
|
|
402
475
|
? { ...existing.provider }
|
|
403
476
|
: {};
|
|
404
|
-
provider.openai = mergeOpenaiProvider(existing.provider?.openai, template.provider?.openai
|
|
477
|
+
provider.openai = mergeOpenaiProvider(existing.provider?.openai, template.provider?.openai, {
|
|
478
|
+
modelKeysToRemove,
|
|
479
|
+
});
|
|
405
480
|
merged.provider = provider;
|
|
406
481
|
nextConfig = merged;
|
|
407
482
|
} catch (error) {
|
|
@@ -413,15 +488,39 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
413
488
|
log("No existing config found. Creating new global config.");
|
|
414
489
|
}
|
|
415
490
|
|
|
491
|
+
let nextTuiConfig = mergeTuiConfig(undefined);
|
|
492
|
+
let existingTuiConfig;
|
|
493
|
+
if (existsSync(paths.tuiConfigPath)) {
|
|
494
|
+
const backupPath = await backupConfig(paths.tuiConfigPath, dryRun);
|
|
495
|
+
log(`${dryRun ? "[dry-run] Would create backup" : "Backup created"}: ${backupPath}`);
|
|
496
|
+
|
|
497
|
+
try {
|
|
498
|
+
const existing = await readJson(paths.tuiConfigPath);
|
|
499
|
+
existingTuiConfig = existing;
|
|
500
|
+
nextTuiConfig = mergeTuiConfig(existing);
|
|
501
|
+
} catch (error) {
|
|
502
|
+
log(`Warning: Could not parse existing TUI config (${formatErrorForLog(error)}). Replacing with minimal TUI config.`);
|
|
503
|
+
existingTuiConfig = undefined;
|
|
504
|
+
nextTuiConfig = mergeTuiConfig(undefined);
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
log("No existing TUI config found. Creating new global TUI config.");
|
|
508
|
+
}
|
|
509
|
+
|
|
416
510
|
let wrote = false;
|
|
417
511
|
if (dryRun) {
|
|
418
512
|
log(`[dry-run] Would write ${paths.configPath} using ${configMode} config`);
|
|
419
513
|
log(`[dry-run] Diff for ${paths.configPath}:`);
|
|
420
514
|
log(formatConfigDiff(existingConfig, nextConfig));
|
|
515
|
+
log(`[dry-run] Would write ${paths.tuiConfigPath} with the TUI status plugin`);
|
|
516
|
+
log(`[dry-run] Diff for ${paths.tuiConfigPath}:`);
|
|
517
|
+
log(formatConfigDiff(existingTuiConfig, nextTuiConfig));
|
|
421
518
|
} else {
|
|
422
519
|
await writeFileAtomic(paths.configPath, formatJson(nextConfig));
|
|
520
|
+
await writeFileAtomic(paths.tuiConfigPath, formatJson(nextTuiConfig));
|
|
423
521
|
wrote = true;
|
|
424
522
|
log(`Wrote ${paths.configPath} (${configMode} config)`);
|
|
523
|
+
log(`Wrote ${paths.tuiConfigPath} (TUI status plugin)`);
|
|
425
524
|
}
|
|
426
525
|
|
|
427
526
|
await clearCache(paths, dryRun, skipCacheClear);
|
|
@@ -429,13 +528,13 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
429
528
|
log("\nDone. Restart OpenCode to (re)install the plugin.");
|
|
430
529
|
log("Example: opencode");
|
|
431
530
|
if (configMode === "modern") {
|
|
432
|
-
log("Note: Modern config intentionally shows 9 base model entries; use
|
|
531
|
+
log("Note: Modern config intentionally shows 9 base OAuth model entries; use the variant picker for reasoning presets.");
|
|
433
532
|
}
|
|
434
533
|
if (configMode === "legacy") {
|
|
435
|
-
log("Note: Legacy config writes
|
|
534
|
+
log("Note: Legacy config writes 36 explicit preset entries and is also safe for older OpenCode versions.");
|
|
436
535
|
}
|
|
437
536
|
if (configMode === "full") {
|
|
438
|
-
log("Note: Full config installs both
|
|
537
|
+
log("Note: Full config installs both compact base models and explicit preset entries for direct selector IDs.");
|
|
439
538
|
}
|
|
440
539
|
|
|
441
540
|
return {
|
|
@@ -443,6 +542,7 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
443
542
|
action: "install",
|
|
444
543
|
configMode,
|
|
445
544
|
configPath: paths.configPath,
|
|
545
|
+
tuiConfigPath: paths.tuiConfigPath,
|
|
446
546
|
dryRun: Boolean(dryRun),
|
|
447
547
|
wrote,
|
|
448
548
|
};
|
|
@@ -455,6 +555,7 @@ export const __test = {
|
|
|
455
555
|
formatConfigDiff,
|
|
456
556
|
mergeFullTemplate,
|
|
457
557
|
mergeOpenaiProvider,
|
|
558
|
+
mergeTuiConfig,
|
|
458
559
|
parseCliArgs,
|
|
459
560
|
writeFileAtomic,
|
|
460
561
|
renameWithWindowsRetry,
|