oc-codex-multi-auth 6.10.0 → 6.11.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 +28 -10
- package/config/README.md +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -225
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/server.d.ts.map +1 -1
- package/dist/lib/auth/server.js +7 -3
- package/dist/lib/auth/server.js.map +1 -1
- package/dist/lib/auto-update-checker.d.ts.map +1 -1
- package/dist/lib/auto-update-checker.js +3 -2
- package/dist/lib/auto-update-checker.js.map +1 -1
- package/dist/lib/codex-usage.d.ts +1 -0
- package/dist/lib/codex-usage.d.ts.map +1 -1
- package/dist/lib/codex-usage.js +17 -2
- package/dist/lib/codex-usage.js.map +1 -1
- package/dist/lib/oauth-success.d.ts +1 -0
- package/dist/lib/oauth-success.d.ts.map +1 -1
- package/dist/lib/oauth-success.html +198 -707
- package/dist/lib/oauth-success.js +202 -708
- package/dist/lib/oauth-success.js.map +1 -1
- package/dist/lib/tools/codex-doctor.d.ts.map +1 -1
- package/dist/lib/tools/codex-doctor.js +168 -142
- package/dist/lib/tools/codex-doctor.js.map +1 -1
- package/dist/lib/tools/codex-health.d.ts.map +1 -1
- package/dist/lib/tools/codex-health.js +41 -38
- package/dist/lib/tools/codex-health.js.map +1 -1
- package/dist/lib/tools/codex-refresh.d.ts.map +1 -1
- package/dist/lib/tools/codex-refresh.js +24 -103
- package/dist/lib/tools/codex-refresh.js.map +1 -1
- package/dist/lib/tools/index.d.ts +1 -0
- package/dist/lib/tools/index.d.ts.map +1 -1
- package/dist/lib/tools/index.js.map +1 -1
- package/dist/lib/tools/refresh-account.d.ts +63 -0
- package/dist/lib/tools/refresh-account.d.ts.map +1 -0
- package/dist/lib/tools/refresh-account.js +159 -0
- package/dist/lib/tools/refresh-account.js.map +1 -0
- package/dist/lib/ui/beginner.d.ts +1 -0
- package/dist/lib/ui/beginner.d.ts.map +1 -1
- package/dist/lib/ui/beginner.js +12 -1
- package/dist/lib/ui/beginner.js.map +1 -1
- package/package.json +157 -155
- package/scripts/install-oc-codex-multi-auth-core.js +195 -46
|
@@ -15,11 +15,13 @@ const STALE_MANAGED_MODEL_KEYS = new Set([
|
|
|
15
15
|
]);
|
|
16
16
|
const STANDALONE_COMMANDS = new Set(["doctor", "status", "list", "limits", "dashboard", "health", "diag", "warm"]);
|
|
17
17
|
const INSTALLER_COMMANDS = new Set(["install"]);
|
|
18
|
+
const UPDATE_COMMANDS = new Set(["update"]);
|
|
18
19
|
|
|
19
20
|
function splitCommandArgv(argv) {
|
|
20
21
|
const [first, ...rest] = argv;
|
|
21
22
|
if (!first) return { kind: "install", argv };
|
|
22
23
|
if (INSTALLER_COMMANDS.has(first)) return { kind: "install", argv: rest };
|
|
24
|
+
if (UPDATE_COMMANDS.has(first)) return { kind: "update", argv: rest };
|
|
23
25
|
if (STANDALONE_COMMANDS.has(first)) return { kind: "standalone", command: first, argv: rest };
|
|
24
26
|
if (first.startsWith("-")) return { kind: "install", argv };
|
|
25
27
|
return { kind: "unknown", command: first, argv: rest };
|
|
@@ -76,7 +78,8 @@ export function isDirectRunPath(argvPath, modulePath, resolveRealPath = realpath
|
|
|
76
78
|
function printHelp() {
|
|
77
79
|
console.log(`Usage: ${PACKAGE_NAME} [command] [options]\n\n` +
|
|
78
80
|
"Commands:\n" +
|
|
79
|
-
" install
|
|
81
|
+
" install Register plugin entries (default with no command)\n" +
|
|
82
|
+
" update Refresh the cached package without changing OpenCode config\n" +
|
|
80
83
|
" doctor Run local account/config diagnostics\n" +
|
|
81
84
|
" status Show account/config status\n" +
|
|
82
85
|
" list List configured accounts\n" +
|
|
@@ -85,14 +88,16 @@ function printHelp() {
|
|
|
85
88
|
" health Check local token/account health\n" +
|
|
86
89
|
" diag Alias for doctor --deep\n" +
|
|
87
90
|
" warm Open every enabled account's usage window now (one request each)\n\n" +
|
|
88
|
-
`Installer usage: ${PACKAGE_NAME} [--modern|--full|--legacy] [--dry-run] [--no-cache-clear]\n
|
|
91
|
+
`Installer usage: ${PACKAGE_NAME} install [--plugin-only|--modern|--full|--legacy] [--dry-run] [--no-cache-clear]\n` +
|
|
92
|
+
`Updater usage: ${PACKAGE_NAME} update [--dry-run]\n\n` +
|
|
89
93
|
"Default behavior:\n" +
|
|
90
|
-
" -
|
|
94
|
+
" - Registers plugin entries without changing provider.openai\n" +
|
|
91
95
|
" - Enables the prompt status bar TUI plugin at ~/.config/opencode/tui.json\n" +
|
|
92
|
-
" -
|
|
96
|
+
" - Installs model catalogs only with --modern, --full, or --legacy\n" +
|
|
93
97
|
" - Ensures plugin is unpinned (latest)\n" +
|
|
94
98
|
" - Clears OpenCode plugin cache\n\n" +
|
|
95
99
|
"Options:\n" +
|
|
100
|
+
" --plugin-only Register plugins without changing provider.openai\n" +
|
|
96
101
|
" --modern Force compact modern config (12 base OAuth models + --variant presets)\n" +
|
|
97
102
|
" --full Install compact base models plus 53 explicit selector entries\n" +
|
|
98
103
|
" --legacy Force explicit legacy config (53 preset model entries)\n" +
|
|
@@ -139,7 +144,10 @@ function buildPaths(homeDir) {
|
|
|
139
144
|
tuiConfigPath: join(configDir, "tui.json"),
|
|
140
145
|
cacheDir,
|
|
141
146
|
cacheNodeModulesPaths: getManagedPackageNames().map((name) => join(cacheDir, "node_modules", name)),
|
|
142
|
-
cachePackagePaths: getManagedPackageNames().
|
|
147
|
+
cachePackagePaths: getManagedPackageNames().flatMap((name) => [
|
|
148
|
+
join(cacheDir, "packages", name),
|
|
149
|
+
join(cacheDir, "packages", `${name}@latest`),
|
|
150
|
+
]),
|
|
143
151
|
cacheBunLock: join(cacheDir, "bun.lock"),
|
|
144
152
|
cachePackageJson: join(cacheDir, "package.json"),
|
|
145
153
|
modernTemplatePath,
|
|
@@ -158,21 +166,40 @@ function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
158
166
|
const requestedModern = args.has("--modern");
|
|
159
167
|
const requestedFull = args.has("--full");
|
|
160
168
|
const requestedLegacy = args.has("--legacy");
|
|
169
|
+
const explicitPluginOnly = args.has("--plugin-only");
|
|
161
170
|
|
|
162
171
|
const requestedModes = [requestedModern, requestedFull, requestedLegacy]
|
|
163
172
|
.filter(Boolean).length;
|
|
164
173
|
if (requestedModes > 1) {
|
|
165
174
|
throw new Error("Choose only one of --modern, --full, or --legacy.");
|
|
166
175
|
}
|
|
176
|
+
if (explicitPluginOnly && requestedModes > 0) {
|
|
177
|
+
throw new Error("--plugin-only cannot be combined with --modern, --full, or --legacy.");
|
|
178
|
+
}
|
|
179
|
+
const pluginOnly = explicitPluginOnly || requestedModes === 0;
|
|
167
180
|
|
|
168
181
|
return {
|
|
169
182
|
wantsHelp: false,
|
|
170
183
|
dryRun: args.has("--dry-run"),
|
|
171
184
|
skipCacheClear: args.has("--no-cache-clear"),
|
|
185
|
+
pluginOnly,
|
|
172
186
|
configMode: requestedFull ? "full" : requestedLegacy ? "legacy" : "modern",
|
|
173
187
|
};
|
|
174
188
|
}
|
|
175
189
|
|
|
190
|
+
function parseUpdateArgs(argv) {
|
|
191
|
+
const args = new Set(argv);
|
|
192
|
+
const supported = new Set(["--dry-run", "--help", "-h"]);
|
|
193
|
+
const unknown = argv.find((arg) => !supported.has(arg));
|
|
194
|
+
if (unknown) {
|
|
195
|
+
throw new Error(`Unknown option for update command: ${unknown}`);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
wantsHelp: args.has("--help") || args.has("-h"),
|
|
199
|
+
dryRun: args.has("--dry-run"),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
176
203
|
function normalizePluginEntryForMatch(entry) {
|
|
177
204
|
const trimmed = entry.trim();
|
|
178
205
|
let normalized = trimmed.toLowerCase();
|
|
@@ -602,6 +629,51 @@ function formatConfigDiff(existingConfig, nextConfig) {
|
|
|
602
629
|
return lines.join("\n");
|
|
603
630
|
}
|
|
604
631
|
|
|
632
|
+
function formatRedactedConfigDiff(existingConfig, nextConfig) {
|
|
633
|
+
const missing = Symbol("missing");
|
|
634
|
+
const changes = [];
|
|
635
|
+
const visit = (existing, next, path) => {
|
|
636
|
+
if (existing === missing) {
|
|
637
|
+
changes.push(`+ ${path}`);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (next === missing) {
|
|
641
|
+
changes.push(`- ${path}`);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
if (Object.is(existing, next)) return;
|
|
645
|
+
|
|
646
|
+
if (Array.isArray(existing) && Array.isArray(next)) {
|
|
647
|
+
const length = Math.max(existing.length, next.length);
|
|
648
|
+
for (let index = 0; index < length; index += 1) {
|
|
649
|
+
visit(
|
|
650
|
+
index < existing.length ? existing[index] : missing,
|
|
651
|
+
index < next.length ? next[index] : missing,
|
|
652
|
+
`${path}[${index}]`,
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (isPlainObject(existing) && isPlainObject(next)) {
|
|
659
|
+
const keys = new Set([...Object.keys(existing), ...Object.keys(next)]);
|
|
660
|
+
for (const key of keys) {
|
|
661
|
+
visit(
|
|
662
|
+
Object.hasOwn(existing, key) ? existing[key] : missing,
|
|
663
|
+
Object.hasOwn(next, key) ? next[key] : missing,
|
|
664
|
+
`${path}.${key}`,
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
changes.push(`~ ${path}`);
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
visit(existingConfig === undefined ? missing : existingConfig, nextConfig, "$");
|
|
674
|
+
return changes.length > 0 ? changes.join("\n") : "(no changes)";
|
|
675
|
+
}
|
|
676
|
+
|
|
605
677
|
function mergeFullTemplate(modernTemplate, legacyTemplate) {
|
|
606
678
|
const modernModels = modernTemplate.provider?.openai?.models ?? {};
|
|
607
679
|
const legacyModels = legacyTemplate.provider?.openai?.models ?? {};
|
|
@@ -657,6 +729,28 @@ async function renameWithWindowsRetry(sourcePath, destinationPath) {
|
|
|
657
729
|
}
|
|
658
730
|
}
|
|
659
731
|
|
|
732
|
+
async function removeWithWindowsRetry(path, options) {
|
|
733
|
+
let lastError = null;
|
|
734
|
+
|
|
735
|
+
for (let attempt = 0; attempt < WINDOWS_RENAME_RETRY_ATTEMPTS; attempt += 1) {
|
|
736
|
+
try {
|
|
737
|
+
await rm(path, options);
|
|
738
|
+
return;
|
|
739
|
+
} catch (error) {
|
|
740
|
+
if (isWindowsLockError(error)) {
|
|
741
|
+
lastError = error;
|
|
742
|
+
await delay(WINDOWS_RENAME_RETRY_BASE_DELAY_MS * 2 ** attempt);
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
throw error;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (lastError) {
|
|
750
|
+
throw lastError;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
660
754
|
async function writeFileAtomic(filePath, content) {
|
|
661
755
|
const uniqueSuffix = `${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
662
756
|
const tempPath = `${filePath}.${uniqueSuffix}.tmp`;
|
|
@@ -784,12 +878,12 @@ async function clearCache(paths, dryRun, skipCacheClear) {
|
|
|
784
878
|
log(`[dry-run] Would remove ${paths.cacheBunLock}`);
|
|
785
879
|
} else {
|
|
786
880
|
for (const cacheNodeModulesPath of paths.cacheNodeModulesPaths) {
|
|
787
|
-
await
|
|
881
|
+
await removeWithWindowsRetry(cacheNodeModulesPath, { recursive: true, force: true });
|
|
788
882
|
}
|
|
789
883
|
for (const cachePackagePath of paths.cachePackagePaths) {
|
|
790
|
-
await
|
|
884
|
+
await removeWithWindowsRetry(cachePackagePath, { recursive: true, force: true });
|
|
791
885
|
}
|
|
792
|
-
await
|
|
886
|
+
await removeWithWindowsRetry(paths.cacheBunLock, { force: true });
|
|
793
887
|
}
|
|
794
888
|
|
|
795
889
|
await removePluginFromCachePackage(paths, dryRun);
|
|
@@ -804,20 +898,37 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
804
898
|
printHelp();
|
|
805
899
|
throw new Error(`Unknown command: ${split.command}`);
|
|
806
900
|
}
|
|
901
|
+
const { env = process.env } = options;
|
|
902
|
+
const paths = buildPaths(resolveHomeDirectory(env));
|
|
903
|
+
if (split.kind === "update") {
|
|
904
|
+
const parsedUpdate = parseUpdateArgs(split.argv);
|
|
905
|
+
if (parsedUpdate.wantsHelp) {
|
|
906
|
+
printHelp();
|
|
907
|
+
return { exitCode: 0, action: "help" };
|
|
908
|
+
}
|
|
909
|
+
await clearCache(paths, parsedUpdate.dryRun, false);
|
|
910
|
+
log(`\n${parsedUpdate.dryRun ? "Dry run complete." : "Cache cleared."} Restart OpenCode to install the latest plugin.`);
|
|
911
|
+
return {
|
|
912
|
+
exitCode: 0,
|
|
913
|
+
action: "update",
|
|
914
|
+
dryRun: Boolean(parsedUpdate.dryRun),
|
|
915
|
+
};
|
|
916
|
+
}
|
|
807
917
|
const parsed = parseCliArgs(split.argv);
|
|
808
918
|
if (parsed.wantsHelp) {
|
|
809
919
|
printHelp();
|
|
810
920
|
return { exitCode: 0, action: "help" };
|
|
811
921
|
}
|
|
812
922
|
|
|
813
|
-
const {
|
|
814
|
-
const
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
923
|
+
const { configMode, dryRun, skipCacheClear, pluginOnly } = parsed;
|
|
924
|
+
const effectiveConfigMode = pluginOnly ? "plugin-only" : configMode;
|
|
925
|
+
const requiredTemplatePaths = pluginOnly
|
|
926
|
+
? []
|
|
927
|
+
: configMode === "modern"
|
|
928
|
+
? [paths.modernTemplatePath]
|
|
929
|
+
: configMode === "legacy"
|
|
930
|
+
? [paths.legacyTemplatePath]
|
|
931
|
+
: [paths.modernTemplatePath, paths.legacyTemplatePath];
|
|
821
932
|
|
|
822
933
|
for (const templatePath of requiredTemplatePaths) {
|
|
823
934
|
if (!existsSync(templatePath)) {
|
|
@@ -825,40 +936,51 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
825
936
|
}
|
|
826
937
|
}
|
|
827
938
|
|
|
828
|
-
const template =
|
|
939
|
+
const template = pluginOnly
|
|
940
|
+
? { $schema: "https://opencode.ai/config.json", plugin: [PACKAGE_NAME] }
|
|
941
|
+
: await loadTemplate(configMode, paths);
|
|
829
942
|
template.plugin = [PACKAGE_NAME];
|
|
830
943
|
const modelKeysToRemove = new Set(STALE_MANAGED_MODEL_KEYS);
|
|
831
|
-
if (configMode === "modern") {
|
|
944
|
+
if (!pluginOnly && configMode === "modern") {
|
|
832
945
|
for (const key of getTemplateModelKeys(await readJson(paths.legacyTemplatePath))) {
|
|
833
946
|
modelKeysToRemove.add(key);
|
|
834
947
|
}
|
|
835
948
|
}
|
|
836
|
-
if (configMode === "legacy") {
|
|
949
|
+
if (!pluginOnly && configMode === "legacy") {
|
|
837
950
|
for (const key of getTemplateModelKeys(await readJson(paths.modernTemplatePath))) {
|
|
838
951
|
modelKeysToRemove.add(key);
|
|
839
952
|
}
|
|
840
953
|
}
|
|
841
954
|
|
|
842
|
-
let nextConfig =
|
|
955
|
+
let nextConfig = pluginOnly
|
|
956
|
+
? { $schema: template.$schema, plugin: [PACKAGE_NAME] }
|
|
957
|
+
: template;
|
|
843
958
|
let existingConfig;
|
|
844
959
|
if (existsSync(paths.configPath)) {
|
|
845
|
-
const backupPath = await backupConfig(paths.configPath, dryRun);
|
|
846
|
-
log(`${dryRun ? "[dry-run] Would create backup" : "Backup created"}: ${backupPath}`);
|
|
847
|
-
|
|
848
960
|
try {
|
|
849
961
|
const existing = await readJson(paths.configPath);
|
|
962
|
+
if (!isPlainObject(existing)) {
|
|
963
|
+
throw new Error("config root must be a JSON object");
|
|
964
|
+
}
|
|
850
965
|
existingConfig = existing;
|
|
851
966
|
const merged = { ...existing };
|
|
852
967
|
merged.plugin = normalizePluginList(existing.plugin);
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
968
|
+
if (!pluginOnly) {
|
|
969
|
+
const provider = (existing.provider && typeof existing.provider === "object")
|
|
970
|
+
? { ...existing.provider }
|
|
971
|
+
: {};
|
|
972
|
+
provider.openai = mergeOpenaiProvider(existing.provider?.openai, template.provider?.openai, {
|
|
973
|
+
modelKeysToRemove,
|
|
974
|
+
});
|
|
975
|
+
merged.provider = provider;
|
|
976
|
+
}
|
|
860
977
|
nextConfig = merged;
|
|
861
978
|
} catch (error) {
|
|
979
|
+
if (pluginOnly) {
|
|
980
|
+
throw new Error(
|
|
981
|
+
`Could not parse existing config (${formatErrorForLog(error)}). Refusing to replace it in --plugin-only mode.`,
|
|
982
|
+
);
|
|
983
|
+
}
|
|
862
984
|
log(`Warning: Could not parse existing config (${formatErrorForLog(error)}). Replacing with template.`);
|
|
863
985
|
existingConfig = undefined;
|
|
864
986
|
nextConfig = template;
|
|
@@ -870,14 +992,19 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
870
992
|
let nextTuiConfig = mergeTuiConfig(undefined);
|
|
871
993
|
let existingTuiConfig;
|
|
872
994
|
if (existsSync(paths.tuiConfigPath)) {
|
|
873
|
-
const backupPath = await backupConfig(paths.tuiConfigPath, dryRun);
|
|
874
|
-
log(`${dryRun ? "[dry-run] Would create backup" : "Backup created"}: ${backupPath}`);
|
|
875
|
-
|
|
876
995
|
try {
|
|
877
996
|
const existing = await readJson(paths.tuiConfigPath);
|
|
997
|
+
if (!isPlainObject(existing)) {
|
|
998
|
+
throw new Error("TUI config root must be a JSON object");
|
|
999
|
+
}
|
|
878
1000
|
existingTuiConfig = existing;
|
|
879
1001
|
nextTuiConfig = mergeTuiConfig(existing);
|
|
880
1002
|
} catch (error) {
|
|
1003
|
+
if (pluginOnly) {
|
|
1004
|
+
throw new Error(
|
|
1005
|
+
`Could not parse existing TUI config (${formatErrorForLog(error)}). Refusing to replace it in --plugin-only mode.`,
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
881
1008
|
log(`Warning: Could not parse existing TUI config (${formatErrorForLog(error)}). Replacing with minimal TUI config.`);
|
|
882
1009
|
existingTuiConfig = undefined;
|
|
883
1010
|
nextTuiConfig = mergeTuiConfig(undefined);
|
|
@@ -886,40 +1013,60 @@ export async function runInstaller(argv = process.argv.slice(2), options = {}) {
|
|
|
886
1013
|
log("No existing TUI config found. Creating new global TUI config.");
|
|
887
1014
|
}
|
|
888
1015
|
|
|
1016
|
+
const configChanged = existingConfig === undefined || formatJson(existingConfig) !== formatJson(nextConfig);
|
|
1017
|
+
const tuiConfigChanged = existingTuiConfig === undefined || formatJson(existingTuiConfig) !== formatJson(nextTuiConfig);
|
|
889
1018
|
let wrote = false;
|
|
890
1019
|
if (dryRun) {
|
|
891
|
-
log(`[dry-run] Would write ${paths.configPath} using ${
|
|
1020
|
+
log(`[dry-run] ${configChanged ? "Would write" : "Would leave unchanged"} ${paths.configPath} using ${effectiveConfigMode} config`);
|
|
892
1021
|
log(`[dry-run] Diff for ${paths.configPath}:`);
|
|
893
|
-
log(
|
|
894
|
-
log(`[dry-run] Would write ${paths.tuiConfigPath} with the TUI status plugin`);
|
|
1022
|
+
log(formatRedactedConfigDiff(existingConfig, nextConfig));
|
|
1023
|
+
log(`[dry-run] ${tuiConfigChanged ? "Would write" : "Would leave unchanged"} ${paths.tuiConfigPath} with the TUI status plugin`);
|
|
895
1024
|
log(`[dry-run] Diff for ${paths.tuiConfigPath}:`);
|
|
896
|
-
log(
|
|
1025
|
+
log(formatRedactedConfigDiff(existingTuiConfig, nextTuiConfig));
|
|
897
1026
|
} else {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1027
|
+
if (configChanged) {
|
|
1028
|
+
if (existsSync(paths.configPath)) {
|
|
1029
|
+
const backupPath = await backupConfig(paths.configPath, false);
|
|
1030
|
+
log(`Backup created: ${backupPath}`);
|
|
1031
|
+
}
|
|
1032
|
+
await writeFileAtomic(paths.configPath, formatJson(nextConfig));
|
|
1033
|
+
wrote = true;
|
|
1034
|
+
log(`Wrote ${paths.configPath} (${effectiveConfigMode} config)`);
|
|
1035
|
+
} else {
|
|
1036
|
+
log(`Left ${paths.configPath} unchanged`);
|
|
1037
|
+
}
|
|
1038
|
+
if (tuiConfigChanged) {
|
|
1039
|
+
if (existsSync(paths.tuiConfigPath)) {
|
|
1040
|
+
const backupPath = await backupConfig(paths.tuiConfigPath, false);
|
|
1041
|
+
log(`Backup created: ${backupPath}`);
|
|
1042
|
+
}
|
|
1043
|
+
await writeFileAtomic(paths.tuiConfigPath, formatJson(nextTuiConfig));
|
|
1044
|
+
wrote = true;
|
|
1045
|
+
log(`Wrote ${paths.tuiConfigPath} (TUI status plugin)`);
|
|
1046
|
+
} else {
|
|
1047
|
+
log(`Left ${paths.tuiConfigPath} unchanged`);
|
|
1048
|
+
}
|
|
903
1049
|
}
|
|
904
1050
|
|
|
905
1051
|
await clearCache(paths, dryRun, skipCacheClear);
|
|
906
1052
|
|
|
907
1053
|
log("\nDone. Restart OpenCode to (re)install the plugin.");
|
|
908
1054
|
log("Example: opencode");
|
|
909
|
-
if (configMode === "modern") {
|
|
1055
|
+
if (!pluginOnly && configMode === "modern") {
|
|
910
1056
|
log("Note: Modern config intentionally shows 12 base OAuth model entries; use the variant picker for reasoning presets.");
|
|
911
1057
|
}
|
|
912
|
-
if (configMode === "legacy") {
|
|
1058
|
+
if (!pluginOnly && configMode === "legacy") {
|
|
913
1059
|
log("Note: Legacy config writes 53 explicit preset entries and is also safe for older OpenCode versions.");
|
|
914
1060
|
}
|
|
915
|
-
if (configMode === "full") {
|
|
1061
|
+
if (!pluginOnly && configMode === "full") {
|
|
916
1062
|
log("Note: Full config installs both compact base models and explicit preset entries for direct selector IDs.");
|
|
917
1063
|
}
|
|
918
1064
|
|
|
919
1065
|
return {
|
|
920
1066
|
exitCode: 0,
|
|
921
1067
|
action: "install",
|
|
922
|
-
configMode,
|
|
1068
|
+
configMode: effectiveConfigMode,
|
|
1069
|
+
pluginOnly,
|
|
923
1070
|
configPath: paths.configPath,
|
|
924
1071
|
tuiConfigPath: paths.tuiConfigPath,
|
|
925
1072
|
dryRun: Boolean(dryRun),
|
|
@@ -932,10 +1079,12 @@ export const __test = {
|
|
|
932
1079
|
backupConfig,
|
|
933
1080
|
copyFileWithWindowsRetry,
|
|
934
1081
|
formatConfigDiff,
|
|
1082
|
+
formatRedactedConfigDiff,
|
|
935
1083
|
mergeFullTemplate,
|
|
936
1084
|
mergeOpenaiProvider,
|
|
937
1085
|
mergeTuiConfig,
|
|
938
1086
|
parseCliArgs,
|
|
1087
|
+
removeWithWindowsRetry,
|
|
939
1088
|
runStandaloneCommand,
|
|
940
1089
|
splitCommandArgv,
|
|
941
1090
|
writeFileAtomic,
|