anygate 0.5.9 → 0.5.11
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/dist/{chunk-PJ3L2TW7.js → chunk-55RHVPE4.js} +3449 -3046
- package/dist/chunk-55RHVPE4.js.map +1 -0
- package/dist/{chunk-P36O5B7N.js → chunk-5UF4TVCM.js} +4 -2
- package/dist/chunk-5UF4TVCM.js.map +1 -0
- package/dist/cli.js +1181 -740
- package/dist/cli.js.map +1 -1
- package/dist/{command-5BWYQP5G.js → command-7AI36ICY.js} +5 -4
- package/dist/command-7AI36ICY.js.map +1 -0
- package/dist/{constants-5RN2WJSS.js → constants-HE3EOSMH.js} +2 -2
- package/dist/ui/dist/assets/index-qxVU3kMy.js +6 -0
- package/dist/ui/dist/index.html +1 -1
- package/package.json +3 -1
- package/dist/chunk-P36O5B7N.js.map +0 -1
- package/dist/chunk-PJ3L2TW7.js.map +0 -1
- package/dist/command-5BWYQP5G.js.map +0 -1
- package/dist/ui/dist/assets/index-gjYfrAXg.js +0 -6
- /package/dist/{constants-5RN2WJSS.js.map → constants-HE3EOSMH.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
getProvidersPath,
|
|
67
67
|
getProxyDebugLogPath,
|
|
68
68
|
getReasoningCapabilities,
|
|
69
|
+
getValidationStatus,
|
|
69
70
|
grabRoundTripSignature,
|
|
70
71
|
hasApplicationDefaultCredentials,
|
|
71
72
|
init_config,
|
|
@@ -101,13 +102,18 @@ import {
|
|
|
101
102
|
parseToolArguments,
|
|
102
103
|
prepareClaudeTraceLog,
|
|
103
104
|
printApiKeyPanel,
|
|
105
|
+
printApiKeyProviderPanel,
|
|
104
106
|
printAsciiBanner,
|
|
105
107
|
printCloudProviderPanel,
|
|
106
108
|
printDryRunPanel,
|
|
107
109
|
printEnvConflictPanel,
|
|
108
110
|
printImportConflictPanel,
|
|
111
|
+
printMainMenuPanel,
|
|
112
|
+
printOnboardingPanel,
|
|
109
113
|
printPanel,
|
|
114
|
+
printProviderCategoryPanel,
|
|
110
115
|
printProviderDetailPanel,
|
|
116
|
+
printSetupSummaryPanel,
|
|
111
117
|
printTraceLog,
|
|
112
118
|
printWelcomePanel,
|
|
113
119
|
providerAuthHelpText,
|
|
@@ -115,6 +121,8 @@ import {
|
|
|
115
121
|
providersForPicker,
|
|
116
122
|
providersForPickerWithTemplates,
|
|
117
123
|
providersForTarget,
|
|
124
|
+
pruneValidationCache,
|
|
125
|
+
quickValidateModel,
|
|
118
126
|
quitClaudeAppGracefully,
|
|
119
127
|
quitCodexAppGracefully,
|
|
120
128
|
readBody,
|
|
@@ -162,9 +170,10 @@ import {
|
|
|
162
170
|
upgradeLegacyCloudProviders,
|
|
163
171
|
upstreamHttpStatus,
|
|
164
172
|
validateCustomEndpointUrl,
|
|
173
|
+
validateModels,
|
|
165
174
|
writeSecureLogLine,
|
|
166
175
|
zenRegistryStub
|
|
167
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-55RHVPE4.js";
|
|
168
177
|
import {
|
|
169
178
|
BACKENDS,
|
|
170
179
|
CONFLICTING_ENV_VARS,
|
|
@@ -172,7 +181,7 @@ import {
|
|
|
172
181
|
MAX_MODEL_CATALOG,
|
|
173
182
|
VERSION,
|
|
174
183
|
VERTEX_ANTHROPIC_NPM
|
|
175
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-5UF4TVCM.js";
|
|
176
185
|
import {
|
|
177
186
|
filterTemplates,
|
|
178
187
|
getTemplateById,
|
|
@@ -183,7 +192,7 @@ import {
|
|
|
183
192
|
import "./chunk-72WNE2IK.js";
|
|
184
193
|
|
|
185
194
|
// src/cli.ts
|
|
186
|
-
import
|
|
195
|
+
import pc18 from "picocolors";
|
|
187
196
|
import { realpathSync } from "fs";
|
|
188
197
|
import { fileURLToPath } from "url";
|
|
189
198
|
|
|
@@ -241,7 +250,7 @@ function formatProviderModels(provider) {
|
|
|
241
250
|
function buildLiveStateSection() {
|
|
242
251
|
const prefs = loadPreferences();
|
|
243
252
|
const registry = loadRegistry();
|
|
244
|
-
const enabled = registry.providers.filter((
|
|
253
|
+
const enabled = registry.providers.filter((p18) => p18.enabled);
|
|
245
254
|
const prefLines = [];
|
|
246
255
|
if (prefs.lastProvider || prefs.lastModel) {
|
|
247
256
|
prefLines.push(` Claude last launch: provider=${prefs.lastProvider ?? "(none)"} model=${prefs.lastModel ?? "(none)"}`);
|
|
@@ -258,9 +267,9 @@ function buildLiveStateSection() {
|
|
|
258
267
|
prefLines.push(` ${f.providerId} / ${f.modelId}`);
|
|
259
268
|
}
|
|
260
269
|
}
|
|
261
|
-
const providerBlocks = enabled.length === 0 ? [" No registry providers configured. Built-in cloud: zen, go (OpenCode Zen/Go)."] : enabled.map((
|
|
262
|
-
` ${
|
|
263
|
-
formatProviderModels(
|
|
270
|
+
const providerBlocks = enabled.length === 0 ? [" No registry providers configured. Built-in cloud: zen, go (OpenCode Zen/Go)."] : enabled.map((p18) => [
|
|
271
|
+
` ${p18.name} (${p18.id}) \u2014 ${p18.modelsCache?.models.length ?? 0} cached model(s)`,
|
|
272
|
+
formatProviderModels(p18)
|
|
264
273
|
].join("\n"));
|
|
265
274
|
return `
|
|
266
275
|
================================================================================
|
|
@@ -755,13 +764,320 @@ function printAiInstallResult(result) {
|
|
|
755
764
|
return result.failed.length > 0 ? 1 : 0;
|
|
756
765
|
}
|
|
757
766
|
|
|
767
|
+
// src/cli/root.ts
|
|
768
|
+
import pc from "picocolors";
|
|
769
|
+
import * as p from "@clack/prompts";
|
|
770
|
+
import open from "open";
|
|
771
|
+
var ONBOARDING_TEMPLATES = ["kilo", "nvidia", "groq", "mistral", "cerebras"];
|
|
772
|
+
function categorizeOnboardingProviders() {
|
|
773
|
+
const templates = ONBOARDING_TEMPLATES.map((id) => getTemplateById(id)).filter((t) => t !== void 0 && t.supported);
|
|
774
|
+
const keyless = [];
|
|
775
|
+
const apiKeyRequired = [];
|
|
776
|
+
for (const t of templates) {
|
|
777
|
+
if (t.apiKeyOptional || t.anonymousFreeModels) {
|
|
778
|
+
keyless.push(t);
|
|
779
|
+
} else {
|
|
780
|
+
apiKeyRequired.push(t);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return { keyless, apiKeyRequired };
|
|
784
|
+
}
|
|
785
|
+
function hasConfiguredProviders() {
|
|
786
|
+
const registry = loadRegistry();
|
|
787
|
+
return registry.providers.length > 0;
|
|
788
|
+
}
|
|
789
|
+
async function handleKeylessProvider(template) {
|
|
790
|
+
p.log.info(`Adding ${template.name}...`);
|
|
791
|
+
const result = await addProviderFromTemplate(template, "");
|
|
792
|
+
if (result.added) {
|
|
793
|
+
p.log.success(`${template.name} enabled (no key needed)`);
|
|
794
|
+
return true;
|
|
795
|
+
}
|
|
796
|
+
if (result.error) {
|
|
797
|
+
p.log.error(`${template.name}: ${result.error}`);
|
|
798
|
+
}
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
async function handleApiKeyProvider(template) {
|
|
802
|
+
const signupUrl = template.signupUrl ?? "https://opencode.ai/auth";
|
|
803
|
+
printApiKeyProviderPanel(template.name, signupUrl);
|
|
804
|
+
let choice = await p.select({
|
|
805
|
+
message: `How would you like to set up ${template.name}?`,
|
|
806
|
+
options: [
|
|
807
|
+
{
|
|
808
|
+
value: "paste",
|
|
809
|
+
label: pc.cyan("I have a key \u2014 paste it now"),
|
|
810
|
+
hint: "Key stored securely in your system keychain"
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
value: "signup",
|
|
814
|
+
label: pc.cyan("Open signup page in browser"),
|
|
815
|
+
hint: `Free tier at ${signupUrl}`
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
value: "skip",
|
|
819
|
+
label: pc.dim("Skip for now"),
|
|
820
|
+
hint: "You can add this later with anygate providers add"
|
|
821
|
+
}
|
|
822
|
+
]
|
|
823
|
+
});
|
|
824
|
+
if (p.isCancel(choice)) return null;
|
|
825
|
+
if (choice === "signup") {
|
|
826
|
+
try {
|
|
827
|
+
await open(signupUrl);
|
|
828
|
+
p.log.info(`Opened ${signupUrl} in your browser.`);
|
|
829
|
+
} catch {
|
|
830
|
+
p.log.warn(`Could not open browser. Visit: ${signupUrl}`);
|
|
831
|
+
}
|
|
832
|
+
const retry = await p.confirm({
|
|
833
|
+
message: "Did you get your API key?",
|
|
834
|
+
initialValue: false
|
|
835
|
+
});
|
|
836
|
+
if (p.isCancel(retry) || !retry) return false;
|
|
837
|
+
choice = "paste";
|
|
838
|
+
}
|
|
839
|
+
if (choice === "paste") {
|
|
840
|
+
const apiKey = await p.password({
|
|
841
|
+
message: `Paste your ${template.name} API key:`,
|
|
842
|
+
validate: (val) => val.trim() ? void 0 : "Key cannot be empty"
|
|
843
|
+
});
|
|
844
|
+
if (p.isCancel(apiKey)) return null;
|
|
845
|
+
p.log.info(`Adding ${template.name}...`);
|
|
846
|
+
const result = await addProviderFromTemplate(template, String(apiKey).trim());
|
|
847
|
+
if (result.added) {
|
|
848
|
+
p.log.success(`${template.name} configured`);
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
if (result.error) {
|
|
852
|
+
p.log.error(`${template.name}: ${result.error}`);
|
|
853
|
+
}
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
async function step1CategorizeProviders(keyless, apiKeyRequired) {
|
|
859
|
+
printProviderCategoryPanel();
|
|
860
|
+
const options = [];
|
|
861
|
+
if (keyless.length > 0) {
|
|
862
|
+
options.push({
|
|
863
|
+
value: "__keyless_header__",
|
|
864
|
+
label: pc.dim("\u2500\u2500 Keyless (works instantly) \u2500\u2500"),
|
|
865
|
+
hint: ""
|
|
866
|
+
});
|
|
867
|
+
for (const t of keyless) {
|
|
868
|
+
options.push({
|
|
869
|
+
value: `keyless:${t.id}`,
|
|
870
|
+
label: `${pc.green("\u2713")} ${t.name}`,
|
|
871
|
+
hint: "no key needed"
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (apiKeyRequired.length > 0) {
|
|
876
|
+
options.push({
|
|
877
|
+
value: "__apikey_header__",
|
|
878
|
+
label: pc.dim("\u2500\u2500 API Key Required (free tier) \u2500\u2500"),
|
|
879
|
+
hint: ""
|
|
880
|
+
});
|
|
881
|
+
for (const t of apiKeyRequired) {
|
|
882
|
+
options.push({
|
|
883
|
+
value: `apikey:${t.id}`,
|
|
884
|
+
label: t.name,
|
|
885
|
+
hint: `free at ${t.signupUrl ?? "console.groq.com"}`
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
options.push({
|
|
890
|
+
value: "__continue__",
|
|
891
|
+
label: pc.cyan("Continue"),
|
|
892
|
+
hint: "configure selected providers"
|
|
893
|
+
});
|
|
894
|
+
const selected = /* @__PURE__ */ new Set();
|
|
895
|
+
let selectedKeyless = [];
|
|
896
|
+
let selectedApiKey = [];
|
|
897
|
+
while (true) {
|
|
898
|
+
const currentOptions = options.map((opt) => ({
|
|
899
|
+
...opt,
|
|
900
|
+
label: selected.has(opt.value) && !opt.value.startsWith("__") && opt.value !== "__continue__" ? `${pc.green("\u2713")} ${opt.label.replace(/^[✓●]\s*/, "")}` : opt.label
|
|
901
|
+
}));
|
|
902
|
+
const choice = await p.select({
|
|
903
|
+
message: "Select providers to configure (Space to toggle, Enter to continue):",
|
|
904
|
+
options: currentOptions
|
|
905
|
+
});
|
|
906
|
+
if (p.isCancel(choice)) return null;
|
|
907
|
+
if (choice === "__continue__") break;
|
|
908
|
+
if (selected.has(choice)) {
|
|
909
|
+
selected.delete(choice);
|
|
910
|
+
} else {
|
|
911
|
+
selected.add(choice);
|
|
912
|
+
}
|
|
913
|
+
selectedKeyless = [];
|
|
914
|
+
selectedApiKey = [];
|
|
915
|
+
for (const val of selected) {
|
|
916
|
+
if (val.startsWith("keyless:")) {
|
|
917
|
+
const t = keyless.find((k) => k.id === val.slice("keyless:".length));
|
|
918
|
+
if (t) selectedKeyless.push(t);
|
|
919
|
+
} else if (val.startsWith("apikey:")) {
|
|
920
|
+
const t = apiKeyRequired.find((k) => k.id === val.slice("apikey:".length));
|
|
921
|
+
if (t) selectedApiKey.push(t);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (selectedKeyless.length === 0 && selectedApiKey.length === 0) {
|
|
926
|
+
selectedKeyless = [...keyless];
|
|
927
|
+
selectedApiKey = [...apiKeyRequired];
|
|
928
|
+
}
|
|
929
|
+
return { selectedKeyless, selectedApiKey };
|
|
930
|
+
}
|
|
931
|
+
async function step2HandleSelections(keyless, apiKeyRequired) {
|
|
932
|
+
const configured = [];
|
|
933
|
+
const skipped = [];
|
|
934
|
+
for (const t of keyless) {
|
|
935
|
+
const result = await handleKeylessProvider(t);
|
|
936
|
+
if (result) {
|
|
937
|
+
configured.push({ name: t.name, keyless: true });
|
|
938
|
+
} else {
|
|
939
|
+
skipped.push(t.name);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
for (const t of apiKeyRequired) {
|
|
943
|
+
const result = await handleApiKeyProvider(t);
|
|
944
|
+
if (result === true) {
|
|
945
|
+
configured.push({ name: t.name, keyless: false });
|
|
946
|
+
} else if (result === false) {
|
|
947
|
+
skipped.push(t.name);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return { configured, skipped };
|
|
951
|
+
}
|
|
952
|
+
function step3Summary(configured, skipped) {
|
|
953
|
+
printSetupSummaryPanel(configured, skipped);
|
|
954
|
+
}
|
|
955
|
+
async function runOnboardingFlow() {
|
|
956
|
+
printOnboardingPanel();
|
|
957
|
+
const { keyless, apiKeyRequired } = categorizeOnboardingProviders();
|
|
958
|
+
if (keyless.length === 0 && apiKeyRequired.length === 0) {
|
|
959
|
+
p.log.warn("No providers available for onboarding.");
|
|
960
|
+
return 0;
|
|
961
|
+
}
|
|
962
|
+
const selection = await step1CategorizeProviders(keyless, apiKeyRequired);
|
|
963
|
+
if (!selection) return 0;
|
|
964
|
+
const { configured, skipped } = await step2HandleSelections(
|
|
965
|
+
selection.selectedKeyless,
|
|
966
|
+
selection.selectedApiKey
|
|
967
|
+
);
|
|
968
|
+
step3Summary(configured, skipped);
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
async function runMainMenu() {
|
|
972
|
+
const entries = await resolveProvidersForDisplay();
|
|
973
|
+
const providerCount = entries.length;
|
|
974
|
+
const onboardingEntries = entries.filter((e) => ONBOARDING_TEMPLATES.includes(e.id));
|
|
975
|
+
const freeHint = onboardingEntries.length > 0 ? `free: ${onboardingEntries.map((e) => e.name).join(", ")}` : providerCount > 0 ? `${providerCount} provider${providerCount === 1 ? "" : "s"} configured` : "no providers configured";
|
|
976
|
+
printMainMenuPanel(VERSION, providerCount);
|
|
977
|
+
const options = [
|
|
978
|
+
{
|
|
979
|
+
value: "claude",
|
|
980
|
+
label: pc.cyan("Launch Claude"),
|
|
981
|
+
hint: freeHint
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
value: "codex",
|
|
985
|
+
label: pc.cyan("Launch Codex"),
|
|
986
|
+
hint: "OpenAI Codex CLI with registry providers"
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
value: "providers",
|
|
990
|
+
label: pc.cyan("Configure Providers"),
|
|
991
|
+
hint: "Add, import, or manage AI providers"
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
value: "onboarding",
|
|
995
|
+
label: pc.cyan("Free Setup"),
|
|
996
|
+
hint: "Re-run the provider onboarding flow"
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
value: "doctor",
|
|
1000
|
+
label: pc.cyan("Doctor"),
|
|
1001
|
+
hint: "Run environment diagnostics"
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
value: "server",
|
|
1005
|
+
label: pc.cyan("Server"),
|
|
1006
|
+
hint: "Start a foreground API gateway"
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
value: "ui",
|
|
1010
|
+
label: pc.cyan("Dashboard"),
|
|
1011
|
+
hint: "Open the web dashboard"
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
value: "settings",
|
|
1015
|
+
label: pc.cyan("Settings"),
|
|
1016
|
+
hint: "Configure preferences and paths"
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
value: "quit",
|
|
1020
|
+
label: pc.dim("Quit"),
|
|
1021
|
+
hint: ""
|
|
1022
|
+
}
|
|
1023
|
+
];
|
|
1024
|
+
const choice = await p.select({
|
|
1025
|
+
message: "What would you like to do?",
|
|
1026
|
+
options
|
|
1027
|
+
});
|
|
1028
|
+
if (p.isCancel(choice) || choice === "quit") {
|
|
1029
|
+
gateOutro("Goodbye!");
|
|
1030
|
+
return 0;
|
|
1031
|
+
}
|
|
1032
|
+
switch (choice) {
|
|
1033
|
+
case "claude":
|
|
1034
|
+
gateOutro("Launching Claude Code...");
|
|
1035
|
+
return 0;
|
|
1036
|
+
// The actual launch is handled by the claude command
|
|
1037
|
+
case "codex":
|
|
1038
|
+
gateOutro("Launching Codex...");
|
|
1039
|
+
return 0;
|
|
1040
|
+
case "providers":
|
|
1041
|
+
gateOutro("Opening provider manager...");
|
|
1042
|
+
return 0;
|
|
1043
|
+
case "onboarding":
|
|
1044
|
+
return runOnboardingFlow();
|
|
1045
|
+
case "doctor":
|
|
1046
|
+
gateOutro("Running diagnostics...");
|
|
1047
|
+
return 0;
|
|
1048
|
+
case "server":
|
|
1049
|
+
gateOutro("Starting server...");
|
|
1050
|
+
return 0;
|
|
1051
|
+
case "ui":
|
|
1052
|
+
gateOutro("Opening dashboard...");
|
|
1053
|
+
return 0;
|
|
1054
|
+
case "settings":
|
|
1055
|
+
gateOutro("Opening settings...");
|
|
1056
|
+
return 0;
|
|
1057
|
+
default:
|
|
1058
|
+
return 0;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
async function handleRootCommand(_parsed) {
|
|
1062
|
+
if (!process.stdin.isTTY) {
|
|
1063
|
+
const { printHelp: printHelp2, rootHelpText: rootHelpText2 } = await import("./cli.js");
|
|
1064
|
+
printHelp2(rootHelpText2());
|
|
1065
|
+
return 0;
|
|
1066
|
+
}
|
|
1067
|
+
gateIntro("anygate");
|
|
1068
|
+
if (!hasConfiguredProviders()) {
|
|
1069
|
+
return runOnboardingFlow();
|
|
1070
|
+
}
|
|
1071
|
+
return runMainMenu();
|
|
1072
|
+
}
|
|
1073
|
+
|
|
758
1074
|
// src/cli/claude.ts
|
|
759
|
-
import
|
|
760
|
-
import * as
|
|
1075
|
+
import pc5 from "picocolors";
|
|
1076
|
+
import * as p6 from "@clack/prompts";
|
|
761
1077
|
|
|
762
1078
|
// src/apps/shared/first-run.ts
|
|
763
|
-
import
|
|
764
|
-
import * as
|
|
1079
|
+
import pc2 from "picocolors";
|
|
1080
|
+
import * as p3 from "@clack/prompts";
|
|
765
1081
|
|
|
766
1082
|
// src/registry/validation/validate-import-key.ts
|
|
767
1083
|
function reject(reason, detail) {
|
|
@@ -910,7 +1226,7 @@ async function importFromOpencode(options = {}) {
|
|
|
910
1226
|
}
|
|
911
1227
|
continue;
|
|
912
1228
|
}
|
|
913
|
-
const existingIdx = registry.providers.findIndex((
|
|
1229
|
+
const existingIdx = registry.providers.findIndex((p18) => p18.id === entry.id);
|
|
914
1230
|
const existing = existingIdx >= 0 ? registry.providers[existingIdx] : void 0;
|
|
915
1231
|
if (existing && options.resolveConflict) {
|
|
916
1232
|
const choice = await options.resolveConflict({
|
|
@@ -948,7 +1264,7 @@ async function importFromOpencode(options = {}) {
|
|
|
948
1264
|
if (isOAuth) oauthImported += 1;
|
|
949
1265
|
}
|
|
950
1266
|
const alreadyReportedIds = new Set(skipped.map((s) => s.id));
|
|
951
|
-
const registryProviderIds = new Set(registry.providers.map((
|
|
1267
|
+
const registryProviderIds = new Set(registry.providers.map((p18) => p18.id));
|
|
952
1268
|
for (const provider of listCredentialSkippedProviders(
|
|
953
1269
|
raw,
|
|
954
1270
|
authEntries,
|
|
@@ -971,7 +1287,7 @@ async function importFromOpencode(options = {}) {
|
|
|
971
1287
|
}
|
|
972
1288
|
|
|
973
1289
|
// src/apps/shared/key-setup.ts
|
|
974
|
-
import * as
|
|
1290
|
+
import * as p2 from "@clack/prompts";
|
|
975
1291
|
import { appendFileSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
976
1292
|
import { homedir as homedir2 } from "os";
|
|
977
1293
|
import { spawnSync } from "child_process";
|
|
@@ -1003,7 +1319,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1003
1319
|
}
|
|
1004
1320
|
if (!simulate) {
|
|
1005
1321
|
const keyDiag = (reason) => {
|
|
1006
|
-
|
|
1322
|
+
p2.log.warn(`Credential store unavailable \u2014 ${reason}`);
|
|
1007
1323
|
if (trace) {
|
|
1008
1324
|
writeSecureLogLine(getClaudeDebugLogPath(), `keyring: ${reason}`);
|
|
1009
1325
|
}
|
|
@@ -1011,18 +1327,18 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1011
1327
|
const storedKey = await readFromCredentialStore(keyDiag);
|
|
1012
1328
|
if (storedKey) {
|
|
1013
1329
|
const storeName = isMac ? "macOS Keychain" : isWindows4 ? "Windows Credential Manager" : "Secret Service";
|
|
1014
|
-
|
|
1330
|
+
p2.log.success(`Found key in ${storeName}`);
|
|
1015
1331
|
process.env["OPENCODE_API_KEY"] = storedKey;
|
|
1016
1332
|
return storedKey;
|
|
1017
1333
|
}
|
|
1018
1334
|
}
|
|
1019
1335
|
printApiKeyPanel("https://opencode.ai/auth");
|
|
1020
|
-
const key = await
|
|
1336
|
+
const key = await p2.password({
|
|
1021
1337
|
message: "Paste your OPENCODE_API_KEY:",
|
|
1022
1338
|
validate: (val) => val.trim() ? void 0 : "Key cannot be empty"
|
|
1023
1339
|
});
|
|
1024
|
-
if (
|
|
1025
|
-
|
|
1340
|
+
if (p2.isCancel(key)) {
|
|
1341
|
+
p2.cancel("Cancelled.");
|
|
1026
1342
|
return null;
|
|
1027
1343
|
}
|
|
1028
1344
|
const trimmedKey = key.trim();
|
|
@@ -1051,7 +1367,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1051
1367
|
if (secretServiceAvailable) {
|
|
1052
1368
|
opts.push({ value: "secret-service", label: "Secret Service (GNOME Keyring / KWallet)", hint: "Key stored securely in your desktop keyring; anygate reads it automatically next time" });
|
|
1053
1369
|
} else if (!simulate) {
|
|
1054
|
-
|
|
1370
|
+
p2.log.info("No keyring daemon detected \u2014 secure storage requires GNOME Keyring or KWallet running.");
|
|
1055
1371
|
}
|
|
1056
1372
|
opts.push(
|
|
1057
1373
|
{ value: "profile", label: `${display} (plaintext)`, hint: "Key written directly to your shell profile" },
|
|
@@ -1059,13 +1375,13 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1059
1375
|
);
|
|
1060
1376
|
return opts;
|
|
1061
1377
|
})();
|
|
1062
|
-
const saveChoice = await
|
|
1378
|
+
const saveChoice = await p2.select({
|
|
1063
1379
|
message: "Where should we save the key?",
|
|
1064
1380
|
options: saveOptions,
|
|
1065
1381
|
initialValue: isMac ? "keychain" : isWindows4 ? "credential-manager" : secretServiceAvailable ? "secret-service" : "profile"
|
|
1066
1382
|
});
|
|
1067
|
-
if (
|
|
1068
|
-
|
|
1383
|
+
if (p2.isCancel(saveChoice)) {
|
|
1384
|
+
p2.cancel("Cancelled.");
|
|
1069
1385
|
return null;
|
|
1070
1386
|
}
|
|
1071
1387
|
if (simulate) {
|
|
@@ -1078,12 +1394,12 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1078
1394
|
profile: `Would append OPENCODE_API_KEY export to ${display}`,
|
|
1079
1395
|
session: "Would use key for this session only"
|
|
1080
1396
|
};
|
|
1081
|
-
|
|
1397
|
+
p2.log.info(`[dry-run] ${dryRunMessages[saveChoice]}`);
|
|
1082
1398
|
} else if (saveChoice === "keychain") {
|
|
1083
1399
|
if (await saveToCredentialStore(trimmedKey)) {
|
|
1084
|
-
|
|
1400
|
+
p2.log.success("Key saved to macOS Keychain \u2014 active now and automatically loaded next time.");
|
|
1085
1401
|
} else {
|
|
1086
|
-
|
|
1402
|
+
p2.log.warn("Could not write to Keychain \u2014 key will be used for this session only");
|
|
1087
1403
|
}
|
|
1088
1404
|
} else if (saveChoice === "keychain-autoload") {
|
|
1089
1405
|
if (await saveToCredentialStore(trimmedKey)) {
|
|
@@ -1096,33 +1412,33 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
1096
1412
|
${autoLoadLine}
|
|
1097
1413
|
`);
|
|
1098
1414
|
}
|
|
1099
|
-
|
|
1415
|
+
p2.log.success(`Key saved to Keychain and auto-load added to ${display} \u2014 active now and in all future terminals.`);
|
|
1100
1416
|
} catch {
|
|
1101
|
-
|
|
1102
|
-
|
|
1417
|
+
p2.log.success("Key saved to Keychain \u2014 active now and automatically loaded next time.");
|
|
1418
|
+
p2.log.warn(`Could not write auto-load line to ${display}`);
|
|
1103
1419
|
}
|
|
1104
1420
|
} else {
|
|
1105
|
-
|
|
1421
|
+
p2.log.warn("Could not write to Keychain \u2014 key will be used for this session only");
|
|
1106
1422
|
}
|
|
1107
1423
|
} else if (saveChoice === "credential-manager") {
|
|
1108
1424
|
if (await saveToCredentialStore(trimmedKey)) {
|
|
1109
|
-
|
|
1425
|
+
p2.log.success("Key saved to Windows Credential Manager \u2014 active now and automatically loaded next time.");
|
|
1110
1426
|
} else {
|
|
1111
|
-
|
|
1427
|
+
p2.log.warn("Could not write to Credential Manager \u2014 key will be used for this session only");
|
|
1112
1428
|
}
|
|
1113
1429
|
} else if (saveChoice === "setx") {
|
|
1114
1430
|
try {
|
|
1115
1431
|
const result = spawnSync("setx", ["OPENCODE_API_KEY", trimmedKey], { stdio: ["pipe", "pipe", "pipe"] });
|
|
1116
1432
|
if (result.status !== 0) throw new Error("setx exited with non-zero status");
|
|
1117
|
-
|
|
1433
|
+
p2.log.success("Key saved as a user environment variable \u2014 active now and in all future terminals.");
|
|
1118
1434
|
} catch {
|
|
1119
|
-
|
|
1435
|
+
p2.log.warn("Could not run setx \u2014 key will be used for this session only");
|
|
1120
1436
|
}
|
|
1121
1437
|
} else if (saveChoice === "secret-service") {
|
|
1122
1438
|
if (await saveToCredentialStore(trimmedKey)) {
|
|
1123
|
-
|
|
1439
|
+
p2.log.success("Key saved to Secret Service \u2014 active now and automatically loaded next time.");
|
|
1124
1440
|
} else {
|
|
1125
|
-
|
|
1441
|
+
p2.log.warn("Could not write to Secret Service \u2014 key will be used for this session only");
|
|
1126
1442
|
}
|
|
1127
1443
|
} else if (saveChoice === "profile") {
|
|
1128
1444
|
try {
|
|
@@ -1131,9 +1447,9 @@ ${autoLoadLine}
|
|
|
1131
1447
|
appendFileSync(path2, `
|
|
1132
1448
|
export OPENCODE_API_KEY='${escapedKey}'
|
|
1133
1449
|
`);
|
|
1134
|
-
|
|
1450
|
+
p2.log.success(`Key saved to ${display} \u2014 active now and in all future terminals.`);
|
|
1135
1451
|
} catch {
|
|
1136
|
-
|
|
1452
|
+
p2.log.warn(`Could not write to ${display} \u2014 key will be used for this session only`);
|
|
1137
1453
|
}
|
|
1138
1454
|
}
|
|
1139
1455
|
if (!simulate) process.env["OPENCODE_API_KEY"] = trimmedKey;
|
|
@@ -1159,28 +1475,28 @@ async function runFirstRunWizard(trace = false) {
|
|
|
1159
1475
|
const options = [
|
|
1160
1476
|
{
|
|
1161
1477
|
value: "zen",
|
|
1162
|
-
label:
|
|
1478
|
+
label: pc2.cyan("Quick start with OpenCode Zen (free)"),
|
|
1163
1479
|
hint: "Enter your API key and pick a model \u2014 launches Claude Code"
|
|
1164
1480
|
},
|
|
1165
1481
|
{
|
|
1166
1482
|
value: "providers",
|
|
1167
|
-
label:
|
|
1483
|
+
label: pc2.cyan("Set up your own AI provider"),
|
|
1168
1484
|
hint: hasOpencode ? "Import providers you configured in OpenCode" : "Import from OpenCode or add providers via anygate providers"
|
|
1169
1485
|
}
|
|
1170
1486
|
];
|
|
1171
1487
|
if (hasOpencode) {
|
|
1172
1488
|
options.push({
|
|
1173
1489
|
value: "import",
|
|
1174
|
-
label:
|
|
1490
|
+
label: pc2.cyan("Bring settings from OpenCode"),
|
|
1175
1491
|
hint: "One-time import of your OpenCode provider config"
|
|
1176
1492
|
});
|
|
1177
1493
|
}
|
|
1178
|
-
const choice = await
|
|
1494
|
+
const choice = await p3.select({
|
|
1179
1495
|
message: "How do you want to get started?",
|
|
1180
1496
|
options
|
|
1181
1497
|
});
|
|
1182
|
-
if (
|
|
1183
|
-
|
|
1498
|
+
if (p3.isCancel(choice)) {
|
|
1499
|
+
p3.cancel("Cancelled.");
|
|
1184
1500
|
return "cancel";
|
|
1185
1501
|
}
|
|
1186
1502
|
if (choice === "zen") {
|
|
@@ -1188,40 +1504,40 @@ async function runFirstRunWizard(trace = false) {
|
|
|
1188
1504
|
if (!apiKey) return "cancel";
|
|
1189
1505
|
await upgradeGlobalOpencodeCredential();
|
|
1190
1506
|
ensureZenRegistryStub();
|
|
1191
|
-
|
|
1507
|
+
p3.log.success("OpenCode Zen ready \u2014 picking a model next.");
|
|
1192
1508
|
return "continue";
|
|
1193
1509
|
}
|
|
1194
1510
|
if (choice === "import" || choice === "providers") {
|
|
1195
1511
|
if (!hasOpencode && choice === "import") {
|
|
1196
|
-
|
|
1512
|
+
p3.log.error("OpenCode CLI not found. Install from https://opencode.ai");
|
|
1197
1513
|
return runFirstRunWizard(trace);
|
|
1198
1514
|
}
|
|
1199
1515
|
if (!hasOpencode) {
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
const retry = await
|
|
1516
|
+
p3.log.info("Run anygate providers to add providers, then anygate claude again.");
|
|
1517
|
+
p3.log.info("Quick start with Zen is the fastest path if you have an OpenCode API key.");
|
|
1518
|
+
const retry = await p3.select({
|
|
1203
1519
|
message: "What next?",
|
|
1204
1520
|
options: [
|
|
1205
1521
|
{ value: "zen", label: "Quick start with OpenCode Zen", hint: "" },
|
|
1206
1522
|
{ value: "cancel", label: "Cancel", hint: "" }
|
|
1207
1523
|
]
|
|
1208
1524
|
});
|
|
1209
|
-
if (
|
|
1525
|
+
if (p3.isCancel(retry) || retry === "cancel") return "cancel";
|
|
1210
1526
|
return runFirstRunWizard(trace);
|
|
1211
1527
|
}
|
|
1212
|
-
const spinner10 =
|
|
1528
|
+
const spinner10 = p3.spinner();
|
|
1213
1529
|
spinner10.start("Importing from OpenCode...");
|
|
1214
1530
|
const result = await importFromOpencode();
|
|
1215
1531
|
spinner10.stop("");
|
|
1216
1532
|
if (result.error) {
|
|
1217
|
-
|
|
1533
|
+
p3.log.error(result.error);
|
|
1218
1534
|
return runFirstRunWizard(trace);
|
|
1219
1535
|
}
|
|
1220
1536
|
if (result.imported.length === 0) {
|
|
1221
|
-
|
|
1537
|
+
p3.log.warn("No providers imported. Configure providers in OpenCode first, or use Quick start with Zen.");
|
|
1222
1538
|
return runFirstRunWizard(trace);
|
|
1223
1539
|
}
|
|
1224
|
-
|
|
1540
|
+
p3.log.success(
|
|
1225
1541
|
`Imported ${result.imported.length} provider${result.imported.length === 1 ? "" : "s"}.`
|
|
1226
1542
|
);
|
|
1227
1543
|
return "continue";
|
|
@@ -1233,8 +1549,8 @@ async function runFirstRunWizard(trace = false) {
|
|
|
1233
1549
|
init_config();
|
|
1234
1550
|
|
|
1235
1551
|
// src/apps/shared/prompts.ts
|
|
1236
|
-
import * as
|
|
1237
|
-
import
|
|
1552
|
+
import * as p4 from "@clack/prompts";
|
|
1553
|
+
import pc3 from "picocolors";
|
|
1238
1554
|
|
|
1239
1555
|
// src/apps/shared/model-search.ts
|
|
1240
1556
|
function normalizeModelSearchText(value) {
|
|
@@ -1342,12 +1658,12 @@ async function pickModelFromPagedList(list, toOption, messagePrefix, initialMode
|
|
|
1342
1658
|
options.push(navOption(SWITCH_SEARCH, "\u2190 New search", ""));
|
|
1343
1659
|
}
|
|
1344
1660
|
const initialValue = (initialModelId && pageItems.some((m) => m.id === initialModelId) ? initialModelId : pageItems[0]?.id) ?? options[0]?.value;
|
|
1345
|
-
const picked = await
|
|
1661
|
+
const picked = await p4.select({
|
|
1346
1662
|
message: `${messagePrefix} (page ${currentPage + 1} of ${totalPages})`,
|
|
1347
1663
|
options,
|
|
1348
1664
|
initialValue
|
|
1349
1665
|
});
|
|
1350
|
-
if (
|
|
1666
|
+
if (p4.isCancel(picked)) return "menu";
|
|
1351
1667
|
const choice = String(picked);
|
|
1352
1668
|
if (choice === PAGE_PREV) {
|
|
1353
1669
|
page = currentPage - 1;
|
|
@@ -1368,19 +1684,19 @@ async function selectLargeCatalog(models, browseList, toOption, message, initial
|
|
|
1368
1684
|
let mode = "choose";
|
|
1369
1685
|
while (true) {
|
|
1370
1686
|
if (mode === "choose") {
|
|
1371
|
-
const method = await
|
|
1687
|
+
const method = await p4.select({
|
|
1372
1688
|
message: `${message} (${models.length} available)`,
|
|
1373
1689
|
options: [
|
|
1374
|
-
{ value: MODE_SEARCH, label:
|
|
1690
|
+
{ value: MODE_SEARCH, label: pc3.cyan("Search models"), hint: "Filter by name, id, or brand" },
|
|
1375
1691
|
{
|
|
1376
1692
|
value: MODE_BROWSE,
|
|
1377
|
-
label:
|
|
1693
|
+
label: pc3.cyan("Browse all models"),
|
|
1378
1694
|
hint: `${MODEL_PAGE_SIZE} per page \xB7 ${Math.ceil(browseList.length / MODEL_PAGE_SIZE)} pages`
|
|
1379
1695
|
},
|
|
1380
1696
|
navOption("__back__", "\u2190 Go back", "Select a different provider")
|
|
1381
1697
|
]
|
|
1382
1698
|
});
|
|
1383
|
-
if (
|
|
1699
|
+
if (p4.isCancel(method) || String(method) === "__back__") {
|
|
1384
1700
|
return "back";
|
|
1385
1701
|
}
|
|
1386
1702
|
mode = method === MODE_BROWSE ? "browse" : "search";
|
|
@@ -1405,17 +1721,17 @@ async function selectLargeCatalog(models, browseList, toOption, message, initial
|
|
|
1405
1721
|
if (isSelectedModel(picked)) return picked;
|
|
1406
1722
|
continue;
|
|
1407
1723
|
}
|
|
1408
|
-
const searchInput = await
|
|
1724
|
+
const searchInput = await p4.text({
|
|
1409
1725
|
message: `Search models (${models.length} available):`,
|
|
1410
1726
|
placeholder: "e.g. claude, sonnet, llama"
|
|
1411
1727
|
});
|
|
1412
|
-
if (
|
|
1728
|
+
if (p4.isCancel(searchInput)) {
|
|
1413
1729
|
mode = "choose";
|
|
1414
1730
|
continue;
|
|
1415
1731
|
}
|
|
1416
1732
|
const matched = filterModelsBySearch(browseList, String(searchInput));
|
|
1417
1733
|
if (matched.length === 0) {
|
|
1418
|
-
|
|
1734
|
+
p4.log.warn("No models match \u2014 try a different search");
|
|
1419
1735
|
continue;
|
|
1420
1736
|
}
|
|
1421
1737
|
const result = await pickModelFromPagedList(
|
|
@@ -1446,12 +1762,12 @@ async function selectModelWithSearch(models, toOption, message, initialModelId,
|
|
|
1446
1762
|
navOption("__back__", "\u2190 Go back", "")
|
|
1447
1763
|
];
|
|
1448
1764
|
const initialValue = initialModelId && options.some((o) => o.value === initialModelId) ? initialModelId : options[0]?.value;
|
|
1449
|
-
const picked = await
|
|
1765
|
+
const picked = await p4.select({
|
|
1450
1766
|
message,
|
|
1451
1767
|
options,
|
|
1452
1768
|
initialValue
|
|
1453
1769
|
});
|
|
1454
|
-
if (
|
|
1770
|
+
if (p4.isCancel(picked) || String(picked) === "__back__") {
|
|
1455
1771
|
return "back";
|
|
1456
1772
|
}
|
|
1457
1773
|
const selected = models.find((m) => m.id === String(picked));
|
|
@@ -1485,12 +1801,12 @@ async function pickLocalModel(provider, conflicts, prefs) {
|
|
|
1485
1801
|
navOption(BROWSE_ALL, "Browse all models \u2192", `${provider.models.length} available`),
|
|
1486
1802
|
navOption("__back__", "\u2190 Go back", "Select a different provider")
|
|
1487
1803
|
];
|
|
1488
|
-
const picked = await
|
|
1804
|
+
const picked = await p4.select({
|
|
1489
1805
|
message: "Which model?",
|
|
1490
1806
|
options,
|
|
1491
1807
|
initialValue: recentModels[0].id
|
|
1492
1808
|
});
|
|
1493
|
-
if (
|
|
1809
|
+
if (p4.isCancel(picked) || String(picked) === "__back__") {
|
|
1494
1810
|
return "back";
|
|
1495
1811
|
}
|
|
1496
1812
|
if (String(picked) === BROWSE_ALL) {
|
|
@@ -1517,12 +1833,12 @@ async function pickLocalModel(provider, conflicts, prefs) {
|
|
|
1517
1833
|
}
|
|
1518
1834
|
noteEnvConflicts(conflicts);
|
|
1519
1835
|
const modelLabel = formatCodexModelLabel(selectedModel);
|
|
1520
|
-
const confirmed = await
|
|
1836
|
+
const confirmed = await p4.confirm({
|
|
1521
1837
|
message: confirmLaunchMessage("Claude Code", modelLabel, selectedModel.id, provider.name),
|
|
1522
1838
|
initialValue: true
|
|
1523
1839
|
});
|
|
1524
|
-
if (
|
|
1525
|
-
|
|
1840
|
+
if (p4.isCancel(confirmed) || !confirmed) {
|
|
1841
|
+
p4.cancel("Cancelled.");
|
|
1526
1842
|
return null;
|
|
1527
1843
|
}
|
|
1528
1844
|
gateOutro("Launching", fmtModel(modelLabel, selectedModel.id));
|
|
@@ -1538,7 +1854,7 @@ async function resolveLocalProviderApiKey(provider) {
|
|
|
1538
1854
|
if (template?.apiKeyOptional || template?.anonymousFreeModels) {
|
|
1539
1855
|
return "anonymous";
|
|
1540
1856
|
}
|
|
1541
|
-
const reg = loadRegistry().providers.find((
|
|
1857
|
+
const reg = loadRegistry().providers.find((p18) => p18.id === provider.id);
|
|
1542
1858
|
const authRef = reg?.authRef ?? (provider.id === "zen" || provider.id === "go" ? "keyring:global:opencode" : oauthAuthRef(provider.id));
|
|
1543
1859
|
return resolveProviderCredential(provider.id, authRef);
|
|
1544
1860
|
}
|
|
@@ -1645,7 +1961,7 @@ function resolveLaunchTarget(explicit, prefs, agent) {
|
|
|
1645
1961
|
}
|
|
1646
1962
|
function findProviderAndModel(providers, target) {
|
|
1647
1963
|
if (!target.providerId || !target.modelId) return null;
|
|
1648
|
-
const provider = providers.find((
|
|
1964
|
+
const provider = providers.find((p18) => p18.id === target.providerId);
|
|
1649
1965
|
if (!provider) return null;
|
|
1650
1966
|
const model = provider.models.find((m) => m.id === target.modelId);
|
|
1651
1967
|
if (!model) return null;
|
|
@@ -1709,8 +2025,8 @@ function isAntigravityNonInteractive(args) {
|
|
|
1709
2025
|
}
|
|
1710
2026
|
|
|
1711
2027
|
// src/cli/providers-command.ts
|
|
1712
|
-
import
|
|
1713
|
-
import * as
|
|
2028
|
+
import pc4 from "picocolors";
|
|
2029
|
+
import * as p5 from "@clack/prompts";
|
|
1714
2030
|
init_config();
|
|
1715
2031
|
function providerHubChoiceValue(entry) {
|
|
1716
2032
|
return `provider:${entry.id}`;
|
|
@@ -1720,54 +2036,54 @@ async function runProvidersImport() {
|
|
|
1720
2036
|
const hasExisting = registry.providers.length > 0;
|
|
1721
2037
|
const resolveConflict = hasExisting ? async (ctx) => {
|
|
1722
2038
|
printImportConflictPanel(ctx.existing.name, ctx.existingKeyHint, ctx.incomingKeyHint);
|
|
1723
|
-
const choice = await
|
|
2039
|
+
const choice = await p5.select({
|
|
1724
2040
|
message: "Which configuration should we keep?",
|
|
1725
2041
|
options: [
|
|
1726
|
-
{ value: "keep", label:
|
|
1727
|
-
{ value: "import", label:
|
|
1728
|
-
{ value: "skip", label:
|
|
2042
|
+
{ value: "keep", label: pc4.cyan("Keep mine"), hint: "Leave your current anygate config unchanged" },
|
|
2043
|
+
{ value: "import", label: pc4.cyan("Use imported"), hint: "Replace with OpenCode settings and refresh models" },
|
|
2044
|
+
{ value: "skip", label: pc4.dim("Skip this provider"), hint: "" }
|
|
1729
2045
|
]
|
|
1730
2046
|
});
|
|
1731
|
-
if (
|
|
2047
|
+
if (p5.isCancel(choice)) return "skip";
|
|
1732
2048
|
return choice;
|
|
1733
2049
|
} : void 0;
|
|
1734
|
-
const spinner10 =
|
|
2050
|
+
const spinner10 = p5.spinner();
|
|
1735
2051
|
spinner10.start("Importing from OpenCode...");
|
|
1736
2052
|
const result = await importFromOpencode({ resolveConflict });
|
|
1737
2053
|
spinner10.stop("");
|
|
1738
2054
|
if (result.error) {
|
|
1739
|
-
|
|
2055
|
+
p5.log.error(result.error);
|
|
1740
2056
|
return 1;
|
|
1741
2057
|
}
|
|
1742
2058
|
if (result.imported.length === 0 && result.skipped.length === 0) {
|
|
1743
|
-
|
|
1744
|
-
|
|
2059
|
+
p5.log.warn("No configured providers found in OpenCode.");
|
|
2060
|
+
p5.log.info("Add providers in OpenCode first, or use anygate providers add.");
|
|
1745
2061
|
return 0;
|
|
1746
2062
|
}
|
|
1747
2063
|
if (result.authFileWarning) {
|
|
1748
|
-
|
|
2064
|
+
p5.log.warn(result.authFileWarning);
|
|
1749
2065
|
}
|
|
1750
2066
|
const importedNames = result.imported.map((pr) => pr.name).join(", ");
|
|
1751
2067
|
const modelTotal = result.imported.reduce((n, pr) => n + (pr.modelsCache?.models.length ?? 0), 0);
|
|
1752
2068
|
const credNote = result.oauthImported > 0 ? ` (${result.oauthImported} via OAuth)` : "";
|
|
1753
|
-
|
|
2069
|
+
p5.log.success(
|
|
1754
2070
|
`Imported ${importedNames} \u2014 ${modelTotal} model${modelTotal === 1 ? "" : "s"}, ${result.keysSaved} credential${result.keysSaved === 1 ? "" : "s"} saved to Keychain${credNote}.`
|
|
1755
2071
|
);
|
|
1756
2072
|
if (result.skipped.length > 0) {
|
|
1757
2073
|
for (const s of result.skipped) {
|
|
1758
2074
|
const reason = s.reason === "user-skipped" ? "skipped by you" : s.reason === "conflict-kept" ? "kept your existing config" : s.reason === "oauth-no-token" ? "OAuth provider in OpenCode but not signed in \u2014 run anygate providers auth" : s.reason === "no-api-key" ? "no API key in OpenCode \u2014 add key there or use anygate providers add" : s.reason === "manual-only" ? "uses gcloud/AWS credentials \u2014 not importable via API key" : s.reason === "placeholder-key" ? "placeholder API key \u2014 provider not imported" : s.reason === "invalid-key" ? "API key failed verification \u2014 provider not imported" : s.reason === "credential-save-failed" ? "could not save credential \u2014 provider not imported" : s.reason;
|
|
1759
|
-
|
|
2075
|
+
p5.log.warn(`Skipped ${s.name} (${s.id}): ${reason}`);
|
|
1760
2076
|
}
|
|
1761
2077
|
}
|
|
1762
2078
|
if (result.keysSkipped.length > 0) {
|
|
1763
2079
|
for (const k of result.keysSkipped) {
|
|
1764
2080
|
if (k.detail) {
|
|
1765
|
-
|
|
2081
|
+
p5.log.info(`${k.name} (${k.id}): ${k.detail}`);
|
|
1766
2082
|
}
|
|
1767
2083
|
}
|
|
1768
2084
|
}
|
|
1769
2085
|
if (result.imported.length > 0) {
|
|
1770
|
-
const refreshSpinner =
|
|
2086
|
+
const refreshSpinner = p5.spinner();
|
|
1771
2087
|
refreshSpinner.start("Fetching model capabilities from providers...");
|
|
1772
2088
|
const currentReg = loadRegistry();
|
|
1773
2089
|
for (const provider of result.imported) {
|
|
@@ -1784,14 +2100,14 @@ async function runProvidersImport() {
|
|
|
1784
2100
|
async function runProvidersAuth(providerId, method) {
|
|
1785
2101
|
try {
|
|
1786
2102
|
const result = await authenticateProvider(providerId, { method });
|
|
1787
|
-
|
|
2103
|
+
p5.log.success(`Signed in to ${result.registryProvider.name} \u2014 credential saved to Keychain.`);
|
|
1788
2104
|
return 0;
|
|
1789
2105
|
} catch (err) {
|
|
1790
2106
|
if (err instanceof Error && err.message === "Cancelled") {
|
|
1791
|
-
|
|
2107
|
+
p5.cancel("Cancelled.");
|
|
1792
2108
|
return 0;
|
|
1793
2109
|
}
|
|
1794
|
-
|
|
2110
|
+
p5.log.error(err instanceof Error ? err.message : String(err));
|
|
1795
2111
|
return 1;
|
|
1796
2112
|
}
|
|
1797
2113
|
}
|
|
@@ -1799,41 +2115,41 @@ async function runProvidersRemove(id, interactive = false) {
|
|
|
1799
2115
|
const registry = loadRegistry();
|
|
1800
2116
|
const provider = registry.providers.find((pr) => pr.id === id);
|
|
1801
2117
|
if (!provider) {
|
|
1802
|
-
|
|
2118
|
+
p5.log.error(`Provider not found: ${id}`);
|
|
1803
2119
|
return 1;
|
|
1804
2120
|
}
|
|
1805
2121
|
if (interactive) {
|
|
1806
|
-
const
|
|
2122
|
+
const confirm11 = await p5.confirm({
|
|
1807
2123
|
message: `Remove ${provider.name} (${id})?`,
|
|
1808
2124
|
initialValue: false
|
|
1809
2125
|
});
|
|
1810
|
-
if (
|
|
1811
|
-
|
|
2126
|
+
if (p5.isCancel(confirm11) || !confirm11) {
|
|
2127
|
+
p5.cancel("Cancelled.");
|
|
1812
2128
|
return 0;
|
|
1813
2129
|
}
|
|
1814
2130
|
}
|
|
1815
2131
|
const result = await removeProviderFromRegistry(id);
|
|
1816
2132
|
if (!result.removed) {
|
|
1817
|
-
|
|
2133
|
+
p5.log.error(result.error ?? `Could not remove ${id}`);
|
|
1818
2134
|
return 1;
|
|
1819
2135
|
}
|
|
1820
|
-
|
|
2136
|
+
p5.log.success(`Removed ${result.name ?? id}.`);
|
|
1821
2137
|
if (result.credentialDeleted) {
|
|
1822
|
-
|
|
2138
|
+
p5.log.info("Provider API key removed from Keychain.");
|
|
1823
2139
|
}
|
|
1824
2140
|
return 0;
|
|
1825
2141
|
}
|
|
1826
2142
|
async function runProvidersList() {
|
|
1827
2143
|
const entries = await resolveProvidersForDisplay();
|
|
1828
2144
|
if (entries.length === 0) {
|
|
1829
|
-
|
|
2145
|
+
p5.log.info("No providers configured. Run anygate providers add or import.");
|
|
1830
2146
|
return 0;
|
|
1831
2147
|
}
|
|
1832
2148
|
console.log("");
|
|
1833
2149
|
for (const entry of entries) {
|
|
1834
|
-
const status = entry.enabled ?
|
|
2150
|
+
const status = entry.enabled ? pc4.green("\u25CF") : pc4.dim("\u25CB");
|
|
1835
2151
|
console.log(
|
|
1836
|
-
` ${status} ${
|
|
2152
|
+
` ${status} ${pc4.bold(entry.name)} ${pc4.dim(`(${entry.id})`)} \u2014 ${entry.modelCount} model${entry.modelCount === 1 ? "" : "s"}, auth: ${entry.authLabel}`
|
|
1837
2153
|
);
|
|
1838
2154
|
}
|
|
1839
2155
|
console.log("");
|
|
@@ -1845,10 +2161,10 @@ async function runProvidersRefreshModels(providerId) {
|
|
|
1845
2161
|
const registry = loadRegistry();
|
|
1846
2162
|
const provider = registry.providers.find((pItem) => pItem.id === providerId);
|
|
1847
2163
|
if (!provider) {
|
|
1848
|
-
|
|
2164
|
+
p5.log.error(`Provider not found: ${providerId}`);
|
|
1849
2165
|
return 1;
|
|
1850
2166
|
}
|
|
1851
|
-
const spinner11 =
|
|
2167
|
+
const spinner11 = p5.spinner();
|
|
1852
2168
|
spinner11.start(`Refreshing ${provider.name}...`);
|
|
1853
2169
|
const key = await resolveRefreshCredential(
|
|
1854
2170
|
provider,
|
|
@@ -1858,22 +2174,22 @@ async function runProvidersRefreshModels(providerId) {
|
|
|
1858
2174
|
spinner11.stop("");
|
|
1859
2175
|
if (result.skipped) {
|
|
1860
2176
|
const countNote = result.modelCount ? ` (${result.modelCount} cached models kept)` : "";
|
|
1861
|
-
|
|
2177
|
+
p5.log.warn(`${result.name}: ${result.reason}${countNote}`);
|
|
1862
2178
|
return 0;
|
|
1863
2179
|
}
|
|
1864
2180
|
if (!result.ok) {
|
|
1865
|
-
|
|
2181
|
+
p5.log.error(`${result.name}: ${result.reason ?? "Refresh failed."}`);
|
|
1866
2182
|
return 1;
|
|
1867
2183
|
}
|
|
1868
2184
|
const diff = result.previousModelCount === void 0 ? 0 : (result.modelCount ?? 0) - result.previousModelCount;
|
|
1869
2185
|
const diffStr = result.previousModelCount === void 0 ? "" : diff > 0 ? ` (+${diff})` : diff < 0 ? ` (${diff})` : "";
|
|
1870
|
-
|
|
2186
|
+
p5.log.success(`${result.name}: ${result.modelCount} model${result.modelCount === 1 ? "" : "s"} updated${diffStr}.`);
|
|
1871
2187
|
if (result.reason) {
|
|
1872
|
-
|
|
2188
|
+
p5.log.warn(result.reason);
|
|
1873
2189
|
}
|
|
1874
2190
|
return 0;
|
|
1875
2191
|
}
|
|
1876
|
-
const spinner10 =
|
|
2192
|
+
const spinner10 = p5.spinner();
|
|
1877
2193
|
spinner10.start("Refreshing model lists...");
|
|
1878
2194
|
const { refreshed } = await refreshAllProviderModels(resolveKey);
|
|
1879
2195
|
spinner10.stop("");
|
|
@@ -1881,22 +2197,22 @@ async function runProvidersRefreshModels(providerId) {
|
|
|
1881
2197
|
const skipped = refreshed.filter((r) => r.skipped);
|
|
1882
2198
|
const failed = refreshed.filter((r) => !r.ok);
|
|
1883
2199
|
if (ok.length > 0) {
|
|
1884
|
-
|
|
2200
|
+
p5.log.success(`Updated ${ok.length} provider${ok.length === 1 ? "" : "s"}.`);
|
|
1885
2201
|
for (const r of ok) {
|
|
1886
2202
|
const diff = r.previousModelCount === void 0 ? 0 : (r.modelCount ?? 0) - r.previousModelCount;
|
|
1887
2203
|
const diffStr = r.previousModelCount === void 0 ? "" : diff > 0 ? ` (+${diff})` : diff < 0 ? ` (${diff})` : "";
|
|
1888
|
-
|
|
2204
|
+
p5.log.info(` ${r.name}: ${r.modelCount} model${r.modelCount === 1 ? "" : "s"}${diffStr}`);
|
|
1889
2205
|
if (r.reason) {
|
|
1890
|
-
|
|
2206
|
+
p5.log.warn(` ${r.reason}`);
|
|
1891
2207
|
}
|
|
1892
2208
|
}
|
|
1893
2209
|
}
|
|
1894
2210
|
for (const r of skipped) {
|
|
1895
2211
|
const countNote = r.modelCount ? ` (${r.modelCount} cached models kept)` : "";
|
|
1896
|
-
|
|
2212
|
+
p5.log.warn(`Skipped ${r.name}: ${r.reason}${countNote}`);
|
|
1897
2213
|
}
|
|
1898
2214
|
for (const r of failed) {
|
|
1899
|
-
|
|
2215
|
+
p5.log.error(`${r.name}: ${r.reason ?? "Refresh failed."}`);
|
|
1900
2216
|
}
|
|
1901
2217
|
return failed.length > 0 ? 1 : 0;
|
|
1902
2218
|
}
|
|
@@ -1906,7 +2222,7 @@ async function pickTemplateFromCatalog() {
|
|
|
1906
2222
|
const configuredIds = new Set(registry.providers.map((pItem) => pItem.id));
|
|
1907
2223
|
const templates = listAddableTemplates(configuredIds);
|
|
1908
2224
|
if (templates.length === 0) return null;
|
|
1909
|
-
const method = await
|
|
2225
|
+
const method = await p5.select({
|
|
1910
2226
|
message: `Choose a provider (${templates.length} available)`,
|
|
1911
2227
|
options: [
|
|
1912
2228
|
{ value: "search", label: "Search providers", hint: "e.g. gro, mistral, together" },
|
|
@@ -1914,32 +2230,32 @@ async function pickTemplateFromCatalog() {
|
|
|
1914
2230
|
{ value: "back", label: "Back", hint: "" }
|
|
1915
2231
|
]
|
|
1916
2232
|
});
|
|
1917
|
-
if (
|
|
2233
|
+
if (p5.isCancel(method) || method === "back") return null;
|
|
1918
2234
|
if (method === "browse") {
|
|
1919
2235
|
const options2 = templates.map((t) => ({
|
|
1920
2236
|
value: t.id,
|
|
1921
2237
|
label: t.name,
|
|
1922
2238
|
hint: t.npm
|
|
1923
2239
|
}));
|
|
1924
|
-
const picked2 = await
|
|
1925
|
-
if (
|
|
2240
|
+
const picked2 = await p5.select({ message: "Select a provider", options: options2 });
|
|
2241
|
+
if (p5.isCancel(picked2)) continue;
|
|
1926
2242
|
const template2 = templates.find((t) => t.id === picked2);
|
|
1927
2243
|
if (template2) return template2;
|
|
1928
2244
|
continue;
|
|
1929
2245
|
}
|
|
1930
|
-
const searchInput = await
|
|
2246
|
+
const searchInput = await p5.text({
|
|
1931
2247
|
message: "Search providers:",
|
|
1932
2248
|
placeholder: "e.g. groq, mistral, openrouter"
|
|
1933
2249
|
});
|
|
1934
|
-
if (
|
|
2250
|
+
if (p5.isCancel(searchInput)) continue;
|
|
1935
2251
|
const query = String(searchInput);
|
|
1936
2252
|
const matched = filterTemplates(templates, query);
|
|
1937
2253
|
if (matched.length === 0) {
|
|
1938
2254
|
const alreadyAdded = filterTemplates(listSupportedTemplates(), query).filter((t) => configuredIds.has(t.id));
|
|
1939
2255
|
if (alreadyAdded.length > 0) {
|
|
1940
|
-
|
|
2256
|
+
p5.log.info(`Already configured: ${alreadyAdded.map((t) => t.name).join(", ")}`);
|
|
1941
2257
|
} else {
|
|
1942
|
-
|
|
2258
|
+
p5.log.warn("No providers match \u2014 try a different search");
|
|
1943
2259
|
}
|
|
1944
2260
|
continue;
|
|
1945
2261
|
}
|
|
@@ -1948,11 +2264,11 @@ async function pickTemplateFromCatalog() {
|
|
|
1948
2264
|
label: t.name,
|
|
1949
2265
|
hint: t.npm
|
|
1950
2266
|
}));
|
|
1951
|
-
const picked = await
|
|
2267
|
+
const picked = await p5.select({
|
|
1952
2268
|
message: matched.length === 1 ? "Match found" : `Select provider (${matched.length} matches)`,
|
|
1953
2269
|
options
|
|
1954
2270
|
});
|
|
1955
|
-
if (
|
|
2271
|
+
if (p5.isCancel(picked)) continue;
|
|
1956
2272
|
const template = matched.find((t) => t.id === picked);
|
|
1957
2273
|
if (template) return template;
|
|
1958
2274
|
}
|
|
@@ -1962,7 +2278,7 @@ async function runOpenCodeCloudDetail() {
|
|
|
1962
2278
|
const routes = registry.providers.filter((provider) => provider.id === "zen" || provider.id === "go");
|
|
1963
2279
|
printCloudProviderPanel("OpenCode Zen / Go");
|
|
1964
2280
|
if (routes.length === 0) return "back";
|
|
1965
|
-
const choice = await
|
|
2281
|
+
const choice = await p5.select({
|
|
1966
2282
|
message: "Manage an OpenCode catalog",
|
|
1967
2283
|
options: [
|
|
1968
2284
|
...routes.map((provider) => ({
|
|
@@ -1973,7 +2289,7 @@ async function runOpenCodeCloudDetail() {
|
|
|
1973
2289
|
{ value: "back", label: "Back", hint: "" }
|
|
1974
2290
|
]
|
|
1975
2291
|
});
|
|
1976
|
-
if (!
|
|
2292
|
+
if (!p5.isCancel(choice) && choice !== "back") {
|
|
1977
2293
|
await runProviderDetail(String(choice));
|
|
1978
2294
|
}
|
|
1979
2295
|
return "back";
|
|
@@ -2014,11 +2330,11 @@ async function runProviderDetail(id) {
|
|
|
2014
2330
|
{ value: "remove", label: "Remove provider", hint: "Delete from registry and Keychain when safe" },
|
|
2015
2331
|
{ value: "back", label: "Back", hint: "" }
|
|
2016
2332
|
);
|
|
2017
|
-
const action = await
|
|
2333
|
+
const action = await p5.select({
|
|
2018
2334
|
message: "What would you like to do?",
|
|
2019
2335
|
options: detailOptions
|
|
2020
2336
|
});
|
|
2021
|
-
if (
|
|
2337
|
+
if (p5.isCancel(action) || action === "back") return "back";
|
|
2022
2338
|
if (action === "browse") {
|
|
2023
2339
|
const cachedModels = provider.modelsCache?.models ?? [];
|
|
2024
2340
|
const localModels = cachedModels.map((m) => cachedModelToLocal(m, provider)).filter((m) => m !== null);
|
|
@@ -2042,7 +2358,7 @@ async function runProviderDetail(id) {
|
|
|
2042
2358
|
if (action === "toggle") {
|
|
2043
2359
|
const result = toggleProviderEnabled(id);
|
|
2044
2360
|
if (result.toggled) {
|
|
2045
|
-
|
|
2361
|
+
p5.log.success(`${provider.name} ${result.enabled ? "enabled" : "disabled"}.`);
|
|
2046
2362
|
}
|
|
2047
2363
|
return "back";
|
|
2048
2364
|
}
|
|
@@ -2050,7 +2366,7 @@ async function runProviderDetail(id) {
|
|
|
2050
2366
|
return code === 0 ? "removed" : "back";
|
|
2051
2367
|
}
|
|
2052
2368
|
function providerLabel(name, modelCount, enabled) {
|
|
2053
|
-
const status = enabled ?
|
|
2369
|
+
const status = enabled ? pc4.green("\u25CF") : pc4.dim("\u25CB");
|
|
2054
2370
|
return `${status} ${name} (${modelCount} model${modelCount === 1 ? "" : "s"})`;
|
|
2055
2371
|
}
|
|
2056
2372
|
function parseProvidersArgs(args) {
|
|
@@ -2081,9 +2397,9 @@ function parseProvidersArgs(args) {
|
|
|
2081
2397
|
return { subcommand: "hub", showHelp: false };
|
|
2082
2398
|
}
|
|
2083
2399
|
function providersHelpText() {
|
|
2084
|
-
return `${
|
|
2400
|
+
return `${pc4.bold("anygate providers")} \u2014 manage AI providers & model catalogs (Phase 1.1)
|
|
2085
2401
|
|
|
2086
|
-
${
|
|
2402
|
+
${pc4.bold("Usage:")}
|
|
2087
2403
|
anygate providers Open interactive provider manager
|
|
2088
2404
|
anygate providers add Add a provider (template, custom, or import)
|
|
2089
2405
|
anygate providers import Import providers from OpenCode CLI
|
|
@@ -2095,21 +2411,21 @@ ${pc3.bold("Usage:")}
|
|
|
2095
2411
|
async function runTemplateAddFlow(t) {
|
|
2096
2412
|
const template = t ?? await pickTemplateFromCatalog();
|
|
2097
2413
|
if (!template) return 0;
|
|
2098
|
-
const inputKey = await
|
|
2414
|
+
const inputKey = await p5.password({
|
|
2099
2415
|
message: `API key for ${template.name}${template.apiKeyOptional ? " (optional)" : ""}:`
|
|
2100
2416
|
});
|
|
2101
|
-
if (
|
|
2417
|
+
if (p5.isCancel(inputKey)) return 0;
|
|
2102
2418
|
const apiKey = String(inputKey ?? "").trim();
|
|
2103
2419
|
const result = await addProviderFromTemplate(template, apiKey);
|
|
2104
2420
|
if (!result.added) {
|
|
2105
|
-
if (result.error)
|
|
2421
|
+
if (result.error) p5.log.error(result.error);
|
|
2106
2422
|
return 1;
|
|
2107
2423
|
}
|
|
2108
2424
|
logConnected(template.name, result.modelCount ?? 0);
|
|
2109
2425
|
return 0;
|
|
2110
2426
|
}
|
|
2111
2427
|
async function runCustomEndpointAddFlow() {
|
|
2112
|
-
const kindChoice = await
|
|
2428
|
+
const kindChoice = await p5.select({
|
|
2113
2429
|
message: "Custom server type",
|
|
2114
2430
|
options: [
|
|
2115
2431
|
{
|
|
@@ -2125,52 +2441,52 @@ async function runCustomEndpointAddFlow() {
|
|
|
2125
2441
|
{ value: "back", label: "Back", hint: "" }
|
|
2126
2442
|
]
|
|
2127
2443
|
});
|
|
2128
|
-
if (
|
|
2129
|
-
const displayName = await
|
|
2444
|
+
if (p5.isCancel(kindChoice) || kindChoice === "back") return 0;
|
|
2445
|
+
const displayName = await p5.text({
|
|
2130
2446
|
message: "Display name:",
|
|
2131
2447
|
placeholder: "My Work LLM",
|
|
2132
2448
|
validate: (v) => v.trim() ? void 0 : "Name is required"
|
|
2133
2449
|
});
|
|
2134
|
-
if (
|
|
2135
|
-
const baseUrl = await
|
|
2450
|
+
if (p5.isCancel(displayName)) return 0;
|
|
2451
|
+
const baseUrl = await p5.text({
|
|
2136
2452
|
message: "Base URL:",
|
|
2137
2453
|
placeholder: kindChoice === "openai" ? "https://api.together.xyz/v1" : "https://api.anthropic.com",
|
|
2138
2454
|
validate: (v) => v.trim() ? void 0 : "URL is required"
|
|
2139
2455
|
});
|
|
2140
|
-
if (
|
|
2456
|
+
if (p5.isCancel(baseUrl)) return 0;
|
|
2141
2457
|
const usesHttp = /^http:\/\//i.test(String(baseUrl).trim());
|
|
2142
2458
|
let allowInsecureHttp = false;
|
|
2143
2459
|
if (usesHttp) {
|
|
2144
|
-
|
|
2145
|
-
const allowLocal = await
|
|
2460
|
+
p5.log.warn("HTTP is not encrypted. Only use it for a trusted local or LAN server, like Ollama on your own network.");
|
|
2461
|
+
const allowLocal = await p5.confirm({
|
|
2146
2462
|
message: "Allow insecure HTTP for this local/LAN server?",
|
|
2147
2463
|
initialValue: true
|
|
2148
2464
|
});
|
|
2149
|
-
if (
|
|
2465
|
+
if (p5.isCancel(allowLocal)) return 0;
|
|
2150
2466
|
allowInsecureHttp = allowLocal === true;
|
|
2151
2467
|
}
|
|
2152
|
-
const apiKey = await
|
|
2468
|
+
const apiKey = await p5.password({
|
|
2153
2469
|
message: "API key (leave empty for local servers without auth):"
|
|
2154
2470
|
});
|
|
2155
|
-
if (
|
|
2156
|
-
const wantsHeaders = await
|
|
2471
|
+
if (p5.isCancel(apiKey)) return 0;
|
|
2472
|
+
const wantsHeaders = await p5.confirm({
|
|
2157
2473
|
message: "Does this endpoint need extra custom headers? (e.g. a plan/auth-tracking header)",
|
|
2158
2474
|
initialValue: false
|
|
2159
2475
|
});
|
|
2160
|
-
if (
|
|
2476
|
+
if (p5.isCancel(wantsHeaders)) return 0;
|
|
2161
2477
|
const headers = {};
|
|
2162
2478
|
if (wantsHeaders) {
|
|
2163
2479
|
for (; ; ) {
|
|
2164
|
-
const headerLine = await
|
|
2480
|
+
const headerLine = await p5.text({
|
|
2165
2481
|
message: "Header (leave empty when done):",
|
|
2166
2482
|
placeholder: "X-Plan: coding"
|
|
2167
2483
|
});
|
|
2168
|
-
if (
|
|
2484
|
+
if (p5.isCancel(headerLine)) return 0;
|
|
2169
2485
|
const trimmed = String(headerLine).trim();
|
|
2170
2486
|
if (!trimmed) break;
|
|
2171
2487
|
const idx = trimmed.indexOf(":");
|
|
2172
2488
|
if (idx < 1) {
|
|
2173
|
-
|
|
2489
|
+
p5.log.warn('Use the format "Name: Value" \u2014 skipped.');
|
|
2174
2490
|
continue;
|
|
2175
2491
|
}
|
|
2176
2492
|
const name = trimmed.slice(0, idx).trim();
|
|
@@ -2178,7 +2494,7 @@ async function runCustomEndpointAddFlow() {
|
|
|
2178
2494
|
if (name) headers[name] = value;
|
|
2179
2495
|
}
|
|
2180
2496
|
}
|
|
2181
|
-
const spinner10 =
|
|
2497
|
+
const spinner10 = p5.spinner();
|
|
2182
2498
|
spinner10.start("Testing connection...");
|
|
2183
2499
|
const result = await addCustomEndpointProvider({
|
|
2184
2500
|
displayName: String(displayName).trim(),
|
|
@@ -2190,8 +2506,8 @@ async function runCustomEndpointAddFlow() {
|
|
|
2190
2506
|
});
|
|
2191
2507
|
spinner10.stop("");
|
|
2192
2508
|
if (!result.added) {
|
|
2193
|
-
|
|
2194
|
-
if (result.hint)
|
|
2509
|
+
p5.log.error(result.error ?? "Could not add custom provider.");
|
|
2510
|
+
if (result.hint) p5.log.info(result.hint);
|
|
2195
2511
|
return 1;
|
|
2196
2512
|
}
|
|
2197
2513
|
logConnected(result.provider?.name ?? "Provider", result.modelCount ?? 0);
|
|
@@ -2219,14 +2535,14 @@ async function runProvidersAdd() {
|
|
|
2219
2535
|
label: "Import providers from OpenCode CLI",
|
|
2220
2536
|
hint: hasOpencode ? "Import Groq, OpenAI, etc. from your OpenCode config" : "Requires OpenCode CLI"
|
|
2221
2537
|
});
|
|
2222
|
-
const choice = await
|
|
2223
|
-
if (
|
|
2224
|
-
|
|
2538
|
+
const choice = await p5.select({ message: "Add a provider", options });
|
|
2539
|
+
if (p5.isCancel(choice)) {
|
|
2540
|
+
p5.cancel("Cancelled.");
|
|
2225
2541
|
return 0;
|
|
2226
2542
|
}
|
|
2227
2543
|
if (choice === "import") {
|
|
2228
2544
|
if (!hasOpencode) {
|
|
2229
|
-
|
|
2545
|
+
p5.log.error("OpenCode CLI not found. Install from https://opencode.ai");
|
|
2230
2546
|
return 1;
|
|
2231
2547
|
}
|
|
2232
2548
|
return runProvidersImport();
|
|
@@ -2240,7 +2556,7 @@ async function runProvidersHub() {
|
|
|
2240
2556
|
while (true) {
|
|
2241
2557
|
const entries = await resolveProvidersForDisplay();
|
|
2242
2558
|
const options = [
|
|
2243
|
-
{ value: "add", label:
|
|
2559
|
+
{ value: "add", label: pc4.bold("+ Add a provider"), hint: "" }
|
|
2244
2560
|
];
|
|
2245
2561
|
for (const entry of entries) {
|
|
2246
2562
|
const hint = entry.id;
|
|
@@ -2259,11 +2575,11 @@ async function runProvidersHub() {
|
|
|
2259
2575
|
options.push({ value: "import", label: "\u2192 Import providers from OpenCode CLI", hint: "One-time import" });
|
|
2260
2576
|
}
|
|
2261
2577
|
options.push({ value: "done", label: "Done", hint: "" });
|
|
2262
|
-
const choice = await
|
|
2578
|
+
const choice = await p5.select({
|
|
2263
2579
|
message: entries.length > 0 ? "Your AI providers" : "Get started",
|
|
2264
2580
|
options
|
|
2265
2581
|
});
|
|
2266
|
-
if (
|
|
2582
|
+
if (p5.isCancel(choice) || choice === "done") {
|
|
2267
2583
|
return 0;
|
|
2268
2584
|
}
|
|
2269
2585
|
if (choice === "add") {
|
|
@@ -2282,10 +2598,10 @@ async function runProvidersHub() {
|
|
|
2282
2598
|
const configuredIds = loadRegistry().providers.map((provider) => provider.id);
|
|
2283
2599
|
const oauthTemplates = listVisibleOAuthTemplates(configuredIds);
|
|
2284
2600
|
if (oauthTemplates.length === 0) {
|
|
2285
|
-
|
|
2601
|
+
p5.log.info("All visible OAuth providers are already configured.");
|
|
2286
2602
|
continue;
|
|
2287
2603
|
}
|
|
2288
|
-
const providerId = await
|
|
2604
|
+
const providerId = await p5.select({
|
|
2289
2605
|
message: "Which provider?",
|
|
2290
2606
|
options: oauthTemplates.map((template) => ({
|
|
2291
2607
|
value: template.id,
|
|
@@ -2293,7 +2609,7 @@ async function runProvidersHub() {
|
|
|
2293
2609
|
hint: "device code"
|
|
2294
2610
|
}))
|
|
2295
2611
|
});
|
|
2296
|
-
if (!
|
|
2612
|
+
if (!p5.isCancel(providerId)) await runProvidersAuth(providerId);
|
|
2297
2613
|
continue;
|
|
2298
2614
|
}
|
|
2299
2615
|
if (typeof choice === "string" && choice.startsWith("cloud:")) {
|
|
@@ -2311,7 +2627,7 @@ async function runProvidersHub() {
|
|
|
2311
2627
|
async function runProvidersCommand(args) {
|
|
2312
2628
|
const parsed = parseProvidersArgs(args);
|
|
2313
2629
|
if (parsed.error) {
|
|
2314
|
-
|
|
2630
|
+
p5.log.error(parsed.error);
|
|
2315
2631
|
return 1;
|
|
2316
2632
|
}
|
|
2317
2633
|
if (parsed.showHelp) {
|
|
@@ -2341,7 +2657,7 @@ async function handleClaudeCommand(parsed) {
|
|
|
2341
2657
|
setAgentStdoutMode(agentStdout);
|
|
2342
2658
|
const claudePath = findClaudeBinary();
|
|
2343
2659
|
if (!claudePath) {
|
|
2344
|
-
console.error(
|
|
2660
|
+
console.error(pc5.red("\nError: claude binary not found on PATH.\n"));
|
|
2345
2661
|
console.error("Install Claude Code:");
|
|
2346
2662
|
console.error(" npm install -g @anthropic-ai/claude-code\n");
|
|
2347
2663
|
return 1;
|
|
@@ -2356,7 +2672,7 @@ async function handleClaudeCommand(parsed) {
|
|
|
2356
2672
|
prefs
|
|
2357
2673
|
});
|
|
2358
2674
|
if (launchPlan.error) {
|
|
2359
|
-
console.error(
|
|
2675
|
+
console.error(pc5.red(`
|
|
2360
2676
|
Error: ${launchPlan.error}
|
|
2361
2677
|
`));
|
|
2362
2678
|
return 1;
|
|
@@ -2364,7 +2680,7 @@ Error: ${launchPlan.error}
|
|
|
2364
2680
|
const switchMenuActive = favorites.length > 0 && !launchPlan.skip;
|
|
2365
2681
|
if (!agentStdout) gateIntro("Claude Code");
|
|
2366
2682
|
if (setup && !dryRun && !agentStdout) {
|
|
2367
|
-
|
|
2683
|
+
p6.log.info("Provider setup now lives in anygate providers \u2014 opening that next is recommended.");
|
|
2368
2684
|
}
|
|
2369
2685
|
if (!dryRun && await needsFirstRunSetup()) {
|
|
2370
2686
|
const firstRun = await runFirstRunWizard(trace);
|
|
@@ -2375,17 +2691,17 @@ Error: ${launchPlan.error}
|
|
|
2375
2691
|
try {
|
|
2376
2692
|
catalog = await fetchProviderCatalog();
|
|
2377
2693
|
} catch (err) {
|
|
2378
|
-
console.error(
|
|
2694
|
+
console.error(pc5.red(String(err instanceof Error ? err.message : err)));
|
|
2379
2695
|
return 1;
|
|
2380
2696
|
}
|
|
2381
2697
|
} else {
|
|
2382
|
-
const catalogSpinner =
|
|
2698
|
+
const catalogSpinner = p6.spinner();
|
|
2383
2699
|
catalogSpinner.start("Loading your providers...");
|
|
2384
2700
|
try {
|
|
2385
2701
|
catalog = await fetchProviderCatalog();
|
|
2386
2702
|
} catch (err) {
|
|
2387
2703
|
catalogSpinner.stop("");
|
|
2388
|
-
console.error(
|
|
2704
|
+
console.error(pc5.red(String(err instanceof Error ? err.message : err)));
|
|
2389
2705
|
return 1;
|
|
2390
2706
|
}
|
|
2391
2707
|
catalogSpinner.stop("");
|
|
@@ -2393,12 +2709,12 @@ Error: ${launchPlan.error}
|
|
|
2393
2709
|
const allProvidersWithTemplates = await providersForPickerWithTemplates("claude");
|
|
2394
2710
|
const allProviders = providersForTarget(allProvidersWithTemplates, "claude");
|
|
2395
2711
|
if (allProviders.length === 0) {
|
|
2396
|
-
|
|
2397
|
-
|
|
2712
|
+
p6.log.warn("No providers available.");
|
|
2713
|
+
p6.log.info(pc5.dim("Run anygate providers add or import to get started."));
|
|
2398
2714
|
return 0;
|
|
2399
2715
|
}
|
|
2400
|
-
const configuredProviders = allProviders.filter((
|
|
2401
|
-
const templateProviders = allProviders.filter((
|
|
2716
|
+
const configuredProviders = allProviders.filter((p18) => p18.inRegistry);
|
|
2717
|
+
const templateProviders = allProviders.filter((p18) => !p18.inRegistry);
|
|
2402
2718
|
const providerOptions = allProviders.map((lp) => {
|
|
2403
2719
|
const baseOption = providerSelectOption(lp);
|
|
2404
2720
|
if (!lp.inRegistry) {
|
|
@@ -2424,7 +2740,7 @@ Error: ${launchPlan.error}
|
|
|
2424
2740
|
if (launchPlan.skip && launchPlan.target) {
|
|
2425
2741
|
const resolved = findProviderAndModel(allProviders, launchPlan.target);
|
|
2426
2742
|
if (!resolved) {
|
|
2427
|
-
|
|
2743
|
+
p6.log.error(
|
|
2428
2744
|
`Provider/model not found: ${launchPlan.target.providerId} / ${launchPlan.target.modelId}`
|
|
2429
2745
|
);
|
|
2430
2746
|
return 1;
|
|
@@ -2432,19 +2748,19 @@ Error: ${launchPlan.error}
|
|
|
2432
2748
|
activeProvider = resolved.provider;
|
|
2433
2749
|
selectedModel = resolved.model;
|
|
2434
2750
|
if (!agentStdout) {
|
|
2435
|
-
|
|
2751
|
+
p6.log.step(`Using ${selectedModel.name || selectedModel.id} (${activeProvider.name})`);
|
|
2436
2752
|
}
|
|
2437
2753
|
if (!dryRun) recordLaunchSelection("claude", activeProvider.id, selectedModel.id, prefs);
|
|
2438
2754
|
} else {
|
|
2439
2755
|
let currentInitialProvider = initialProvider;
|
|
2440
2756
|
while (true) {
|
|
2441
|
-
const chosen = await
|
|
2757
|
+
const chosen = await p6.select({
|
|
2442
2758
|
message: "Which provider?",
|
|
2443
2759
|
options: providerOptions,
|
|
2444
2760
|
initialValue: currentInitialProvider
|
|
2445
2761
|
});
|
|
2446
|
-
if (
|
|
2447
|
-
|
|
2762
|
+
if (p6.isCancel(chosen)) {
|
|
2763
|
+
p6.cancel("Cancelled.");
|
|
2448
2764
|
return 0;
|
|
2449
2765
|
}
|
|
2450
2766
|
const providerChoice = chosen;
|
|
@@ -2456,7 +2772,7 @@ Error: ${launchPlan.error}
|
|
|
2456
2772
|
if (prov && mod) available.push({ provider: prov, model: mod });
|
|
2457
2773
|
}
|
|
2458
2774
|
if (available.length === 0) {
|
|
2459
|
-
|
|
2775
|
+
p6.log.warn("No saved favorites are currently available.");
|
|
2460
2776
|
return 0;
|
|
2461
2777
|
}
|
|
2462
2778
|
const favOptions = available.map((f, i) => ({
|
|
@@ -2464,13 +2780,13 @@ Error: ${launchPlan.error}
|
|
|
2464
2780
|
label: `${f.model.name || f.model.id} \u2014 ${f.provider.name}`,
|
|
2465
2781
|
hint: f.model.id
|
|
2466
2782
|
}));
|
|
2467
|
-
const pickedIdx = await
|
|
2783
|
+
const pickedIdx = await p6.select({
|
|
2468
2784
|
message: "Starting model?",
|
|
2469
2785
|
options: favOptions,
|
|
2470
2786
|
initialValue: "0"
|
|
2471
2787
|
});
|
|
2472
|
-
if (
|
|
2473
|
-
|
|
2788
|
+
if (p6.isCancel(pickedIdx)) {
|
|
2789
|
+
p6.cancel("Cancelled.");
|
|
2474
2790
|
return 0;
|
|
2475
2791
|
}
|
|
2476
2792
|
const sel = available[Number(pickedIdx)];
|
|
@@ -2481,10 +2797,10 @@ Error: ${launchPlan.error}
|
|
|
2481
2797
|
} else {
|
|
2482
2798
|
const selectedProvider = allProviders.find((lp) => lp.id === providerChoice);
|
|
2483
2799
|
if (!selectedProvider.inRegistry) {
|
|
2484
|
-
|
|
2800
|
+
p6.log.info(`Adding ${selectedProvider.name}...`);
|
|
2485
2801
|
const template = getTemplateById(selectedProvider.id);
|
|
2486
2802
|
if (!template) {
|
|
2487
|
-
|
|
2803
|
+
p6.log.error(`Template not found for ${selectedProvider.id}`);
|
|
2488
2804
|
continue;
|
|
2489
2805
|
}
|
|
2490
2806
|
const addResult = await runTemplateAddFlow(template);
|
|
@@ -2493,11 +2809,11 @@ Error: ${launchPlan.error}
|
|
|
2493
2809
|
await providersForPickerWithTemplates("claude"),
|
|
2494
2810
|
"claude"
|
|
2495
2811
|
);
|
|
2496
|
-
const newProvider = refreshedProviders.find((
|
|
2812
|
+
const newProvider = refreshedProviders.find((p18) => p18.id === selectedProvider.id);
|
|
2497
2813
|
if (newProvider) {
|
|
2498
2814
|
activeProvider = newProvider;
|
|
2499
2815
|
} else {
|
|
2500
|
-
|
|
2816
|
+
p6.log.error(`Failed to reload provider after adding`);
|
|
2501
2817
|
continue;
|
|
2502
2818
|
}
|
|
2503
2819
|
} else {
|
|
@@ -2525,30 +2841,39 @@ Error: ${launchPlan.error}
|
|
|
2525
2841
|
);
|
|
2526
2842
|
const startingRoute = resolveRoute(activeProvider.id, selectedModel.id) ?? null;
|
|
2527
2843
|
if (!startingRoute) {
|
|
2528
|
-
|
|
2844
|
+
p6.log.error("Could not resolve a proxy route for the selected model.");
|
|
2529
2845
|
return 1;
|
|
2530
2846
|
}
|
|
2531
2847
|
const { routes: catalogRoutes, droppedFavorites } = buildCatalogRoutes(startingRoute, favorites, resolveRoute);
|
|
2532
2848
|
if (droppedFavorites.length > 0) {
|
|
2533
|
-
|
|
2849
|
+
p6.log.warn(
|
|
2534
2850
|
`Skipping ${droppedFavorites.length} favorite${droppedFavorites.length === 1 ? "" : "s"} that are no longer available in /model`
|
|
2535
2851
|
);
|
|
2536
2852
|
}
|
|
2537
2853
|
if (dryRun) {
|
|
2538
2854
|
const endpoint = selectedModel.baseUrl ?? selectedModel.completionsUrl ?? "(unknown)";
|
|
2539
2855
|
console.log("");
|
|
2540
|
-
console.log(
|
|
2856
|
+
console.log(pc5.bold(pc5.cyan(" DRY RUN \u2014 would execute (switch-menu mode):")));
|
|
2541
2857
|
console.log("");
|
|
2542
|
-
console.log(` ${
|
|
2543
|
-
console.log(` ${
|
|
2544
|
-
console.log(` ${
|
|
2545
|
-
console.log(` ${
|
|
2546
|
-
catalogRoutes.forEach((r) => console.log(` ${
|
|
2858
|
+
console.log(` ${pc5.bold("Provider:")} ${activeProvider.name}`);
|
|
2859
|
+
console.log(` ${pc5.bold("Starting model:")} ${selectedModel.id}`);
|
|
2860
|
+
console.log(` ${pc5.bold("Endpoint:")} ${endpoint}`);
|
|
2861
|
+
console.log(` ${pc5.bold("/model catalog:")} ${catalogRoutes.length} model(s)`);
|
|
2862
|
+
catalogRoutes.forEach((r) => console.log(` ${pc5.dim(r.displayName)}`));
|
|
2547
2863
|
console.log("");
|
|
2548
|
-
console.log(
|
|
2864
|
+
console.log(pc5.dim(" (dry run complete \u2014 Claude Code was NOT launched)"));
|
|
2549
2865
|
console.log("");
|
|
2550
2866
|
return 0;
|
|
2551
2867
|
}
|
|
2868
|
+
const isAvailable2 = await quickValidateModel(activeProvider.id, selectedModel.id);
|
|
2869
|
+
if (!isAvailable2) {
|
|
2870
|
+
const cached = getValidationStatus(activeProvider.id, selectedModel.id);
|
|
2871
|
+
p6.log.error(
|
|
2872
|
+
`Model ${selectedModel.id} (${activeProvider.name}) has been marked as deprecated: ${cached?.error ?? "unknown"}.`
|
|
2873
|
+
);
|
|
2874
|
+
p6.log.info(`Run ${pc5.cyan("anygate providers refresh-models")} to re-check.`);
|
|
2875
|
+
return 1;
|
|
2876
|
+
}
|
|
2552
2877
|
return launchClaudeViaCatalog(
|
|
2553
2878
|
catalogRoutes,
|
|
2554
2879
|
startingRoute,
|
|
@@ -2561,25 +2886,34 @@ Error: ${launchPlan.error}
|
|
|
2561
2886
|
const formatDesc = selectedModel.modelFormat === "anthropic" ? "direct passthrough" : "via SDK adapter proxy";
|
|
2562
2887
|
const endpoint = selectedModel.modelFormat === "anthropic" ? selectedModel.baseUrl ?? "(unknown)" : selectedModel.npm ?? "SDK";
|
|
2563
2888
|
console.log("");
|
|
2564
|
-
console.log(
|
|
2889
|
+
console.log(pc5.bold(pc5.cyan(" DRY RUN \u2014 would execute:")));
|
|
2565
2890
|
console.log("");
|
|
2566
|
-
console.log(` ${
|
|
2567
|
-
console.log(` ${
|
|
2568
|
-
console.log(` ${
|
|
2569
|
-
console.log(` ${
|
|
2570
|
-
console.log(` ${
|
|
2891
|
+
console.log(` ${pc5.bold("Provider:")} ${activeProvider.name}`);
|
|
2892
|
+
console.log(` ${pc5.bold("Model:")} ${selectedModel.id}`);
|
|
2893
|
+
console.log(` ${pc5.bold("Format:")} ${selectedModel.modelFormat} (${formatDesc})`);
|
|
2894
|
+
console.log(` ${pc5.bold(selectedModel.modelFormat === "anthropic" ? "Endpoint:" : "SDK npm:")} ${endpoint}`);
|
|
2895
|
+
console.log(` ${pc5.bold("Key:")} ${activeProvider.name} provider key`);
|
|
2571
2896
|
console.log("");
|
|
2572
|
-
console.log(
|
|
2897
|
+
console.log(pc5.dim(" (dry run complete \u2014 Claude Code was NOT launched)"));
|
|
2573
2898
|
console.log("");
|
|
2574
2899
|
return 0;
|
|
2575
2900
|
}
|
|
2576
2901
|
const launchApiKey = await resolveLocalProviderApiKey(activeProvider);
|
|
2577
2902
|
if (!launchApiKey?.trim()) {
|
|
2578
|
-
|
|
2903
|
+
p6.log.error(
|
|
2579
2904
|
new CredentialUnavailableError(activeProvider.id).userMessage
|
|
2580
2905
|
);
|
|
2581
2906
|
return 1;
|
|
2582
2907
|
}
|
|
2908
|
+
const isAvailable = await quickValidateModel(activeProvider.id, selectedModel.id);
|
|
2909
|
+
if (!isAvailable) {
|
|
2910
|
+
const cached = getValidationStatus(activeProvider.id, selectedModel.id);
|
|
2911
|
+
p6.log.error(
|
|
2912
|
+
`Model ${selectedModel.id} (${activeProvider.name}) has been marked as deprecated: ${cached?.error ?? "unknown"}.`
|
|
2913
|
+
);
|
|
2914
|
+
p6.log.info(`Run ${pc5.cyan("anygate providers refresh-models")} to re-check.`);
|
|
2915
|
+
return 1;
|
|
2916
|
+
}
|
|
2583
2917
|
let proxyHandle = null;
|
|
2584
2918
|
let childEnv;
|
|
2585
2919
|
const isAntigravityOAuth = activeProvider.id === "antigravity" && activeProvider.authType === "oauth";
|
|
@@ -2600,9 +2934,9 @@ Error: ${launchPlan.error}
|
|
|
2600
2934
|
},
|
|
2601
2935
|
launchApiKey
|
|
2602
2936
|
);
|
|
2603
|
-
if (!isAgentStdoutMode())
|
|
2937
|
+
if (!isAgentStdoutMode()) p6.log.info(`Cloud Code proxy started on port ${proxyHandle.port}`);
|
|
2604
2938
|
} catch (err) {
|
|
2605
|
-
|
|
2939
|
+
p6.log.error(`Failed to start Cloud Code proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
2606
2940
|
return 1;
|
|
2607
2941
|
}
|
|
2608
2942
|
childEnv = buildChildEnv(
|
|
@@ -2629,9 +2963,9 @@ Error: ${launchPlan.error}
|
|
|
2629
2963
|
},
|
|
2630
2964
|
launchApiKey
|
|
2631
2965
|
);
|
|
2632
|
-
if (!isAgentStdoutMode())
|
|
2966
|
+
if (!isAgentStdoutMode()) p6.log.info(`OAuth proxy started on port ${proxyHandle.port}`);
|
|
2633
2967
|
} catch (err) {
|
|
2634
|
-
|
|
2968
|
+
p6.log.error(`Failed to start OAuth proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
2635
2969
|
return 1;
|
|
2636
2970
|
}
|
|
2637
2971
|
childEnv = buildChildEnv(
|
|
@@ -2673,12 +3007,12 @@ Error: ${launchPlan.error}
|
|
|
2673
3007
|
launchApiKey
|
|
2674
3008
|
);
|
|
2675
3009
|
if (!isAgentStdoutMode()) {
|
|
2676
|
-
|
|
2677
|
-
`SDK adapter proxy started on port ${proxyHandle.port}` + (selectedModel.npm ?
|
|
3010
|
+
p6.log.info(
|
|
3011
|
+
`SDK adapter proxy started on port ${proxyHandle.port}` + (selectedModel.npm ? pc5.dim(` (${selectedModel.npm})`) : "")
|
|
2678
3012
|
);
|
|
2679
3013
|
}
|
|
2680
3014
|
} catch (err) {
|
|
2681
|
-
|
|
3015
|
+
p6.log.error(`Failed to start SDK adapter proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
2682
3016
|
return 1;
|
|
2683
3017
|
}
|
|
2684
3018
|
childEnv = buildChildEnv(
|
|
@@ -2694,7 +3028,7 @@ Error: ${launchPlan.error}
|
|
|
2694
3028
|
}
|
|
2695
3029
|
const debugLogPath = prepareClaudeTraceLog();
|
|
2696
3030
|
const traceArgs = trace ? ["--debug-file", debugLogPath] : [];
|
|
2697
|
-
if (trace)
|
|
3031
|
+
if (trace) p6.log.info(`Debug log: ${debugLogPath}`);
|
|
2698
3032
|
const exitCode = await launchClaude(
|
|
2699
3033
|
childEnv,
|
|
2700
3034
|
claudeCodeClientModelId(selectedModel.id, selectedModel.contextWindow),
|
|
@@ -2708,11 +3042,11 @@ async function launchClaudeViaCatalog(catalogRoutes, startingRoute, contextWindo
|
|
|
2708
3042
|
let proxyHandle;
|
|
2709
3043
|
try {
|
|
2710
3044
|
proxyHandle = await startProxyCatalog(catalogRoutes, startingRoute.aliasId, trace);
|
|
2711
|
-
|
|
2712
|
-
`Switch menu active \u2014 proxy on port ${proxyHandle.port} ` +
|
|
3045
|
+
p6.log.info(
|
|
3046
|
+
`Switch menu active \u2014 proxy on port ${proxyHandle.port} ` + pc5.dim(`(${catalogRoutes.length} model${catalogRoutes.length !== 1 ? "s" : ""} in /model)`)
|
|
2713
3047
|
);
|
|
2714
3048
|
} catch (err) {
|
|
2715
|
-
|
|
3049
|
+
p6.log.error(`Failed to start proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
2716
3050
|
return 1;
|
|
2717
3051
|
}
|
|
2718
3052
|
const childEnv = buildChildEnv(
|
|
@@ -2725,7 +3059,7 @@ async function launchClaudeViaCatalog(catalogRoutes, startingRoute, contextWindo
|
|
|
2725
3059
|
);
|
|
2726
3060
|
const debugLogPath = prepareClaudeTraceLog();
|
|
2727
3061
|
const traceArgs = trace ? ["--debug-file", debugLogPath] : [];
|
|
2728
|
-
if (trace)
|
|
3062
|
+
if (trace) p6.log.info(`Debug log: ${debugLogPath}`);
|
|
2729
3063
|
const exitCode = await launchClaude(
|
|
2730
3064
|
childEnv,
|
|
2731
3065
|
claudeCodeClientModelId(startingRoute.aliasId, contextWindow),
|
|
@@ -2737,8 +3071,8 @@ async function launchClaudeViaCatalog(catalogRoutes, startingRoute, contextWindo
|
|
|
2737
3071
|
}
|
|
2738
3072
|
|
|
2739
3073
|
// src/apps/codex/cli.ts
|
|
2740
|
-
import
|
|
2741
|
-
import * as
|
|
3074
|
+
import pc8 from "picocolors";
|
|
3075
|
+
import * as p9 from "@clack/prompts";
|
|
2742
3076
|
init_config();
|
|
2743
3077
|
|
|
2744
3078
|
// src/apps/codex/proxy.ts
|
|
@@ -2796,7 +3130,7 @@ function applyClaudeCodeOAuthIdentity(input, sdkParams) {
|
|
|
2796
3130
|
import { streamText, generateText, tool, jsonSchema } from "ai";
|
|
2797
3131
|
function messageText(content) {
|
|
2798
3132
|
if (typeof content === "string") return content;
|
|
2799
|
-
return (content ?? []).map((
|
|
3133
|
+
return (content ?? []).map((p18) => p18.type === "output_text" || p18.type === "input_text" || p18.type === "text" ? p18.text ?? "" : "").join("");
|
|
2800
3134
|
}
|
|
2801
3135
|
function extractDeveloperAndInstructions(items, instructions) {
|
|
2802
3136
|
const developerParts = [];
|
|
@@ -3705,9 +4039,9 @@ function estimateCodexRequestChars(params) {
|
|
|
3705
4039
|
if (Array.isArray(msg.content)) {
|
|
3706
4040
|
for (const part of msg.content) {
|
|
3707
4041
|
if (!part || typeof part !== "object") continue;
|
|
3708
|
-
const
|
|
3709
|
-
if (typeof
|
|
3710
|
-
chars +=
|
|
4042
|
+
const p18 = part;
|
|
4043
|
+
if (typeof p18["text"] === "string") {
|
|
4044
|
+
chars += p18["text"].length;
|
|
3711
4045
|
} else {
|
|
3712
4046
|
chars += JSON.stringify(part).length;
|
|
3713
4047
|
}
|
|
@@ -3738,9 +4072,9 @@ function clipLargeTextParts(params, maxCharsPerPart) {
|
|
|
3738
4072
|
...msg,
|
|
3739
4073
|
content: msg.content.map((part) => {
|
|
3740
4074
|
if (!part || typeof part !== "object") return part;
|
|
3741
|
-
const
|
|
3742
|
-
if (typeof
|
|
3743
|
-
return { ...
|
|
4075
|
+
const p18 = part;
|
|
4076
|
+
if (typeof p18.text !== "string") return part;
|
|
4077
|
+
return { ...p18, text: clipTextForContext(p18.text, maxCharsPerPart) };
|
|
3744
4078
|
})
|
|
3745
4079
|
};
|
|
3746
4080
|
});
|
|
@@ -3774,7 +4108,7 @@ var COMPACTION_PROMPT_MARKER = "You are performing a CONTEXT CHECKPOINT COMPACTI
|
|
|
3774
4108
|
function inputItemText(content) {
|
|
3775
4109
|
if (typeof content === "string") return content;
|
|
3776
4110
|
if (!Array.isArray(content)) return "";
|
|
3777
|
-
return content.map((
|
|
4111
|
+
return content.map((p18) => p18 && typeof p18 === "object" && typeof p18.text === "string" ? p18.text : "").join("");
|
|
3778
4112
|
}
|
|
3779
4113
|
function isLikelyCodexCompactionRequest(body) {
|
|
3780
4114
|
if (!Array.isArray(body.input)) return false;
|
|
@@ -3860,16 +4194,16 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
3860
4194
|
}));
|
|
3861
4195
|
}
|
|
3862
4196
|
return new Promise((resolve, reject2) => {
|
|
3863
|
-
const
|
|
4197
|
+
const log17 = debug ? makeTraceLogger(getCodexProxyDebugLogPath()) : () => {
|
|
3864
4198
|
};
|
|
3865
4199
|
const onRejection = (reason) => {
|
|
3866
|
-
if (debug)
|
|
4200
|
+
if (debug) log17(`unhandled-rejection: ${formatUpstreamError(reason)}`);
|
|
3867
4201
|
};
|
|
3868
4202
|
process.on("unhandledRejection", onRejection);
|
|
3869
4203
|
const server = createServer(async (req, res) => {
|
|
3870
4204
|
const url = req.url ?? "/";
|
|
3871
4205
|
if (debug) {
|
|
3872
|
-
|
|
4206
|
+
log17(`-> ${req.method} ${url} content-type=${req.headers["content-type"] ?? "(none)"} content-encoding=${req.headers["content-encoding"] ?? "(none)"} content-length=${req.headers["content-length"] ?? "(none)"}`);
|
|
3873
4207
|
}
|
|
3874
4208
|
if (!requireAuth && req.method === "POST") {
|
|
3875
4209
|
const origin = req.headers.origin;
|
|
@@ -3947,7 +4281,7 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
3947
4281
|
rawBody = await readBody(req);
|
|
3948
4282
|
} catch (err) {
|
|
3949
4283
|
if (debug) {
|
|
3950
|
-
|
|
4284
|
+
log17(`Error: failed to read/decode request body on POST ${url}: ${formatUpstreamError(err)} content-encoding=${req.headers["content-encoding"] ?? "(none)"}`);
|
|
3951
4285
|
}
|
|
3952
4286
|
sendJson(res, 400, { error: { message: "Invalid request body", type: "invalid_request_error" } });
|
|
3953
4287
|
return;
|
|
@@ -3958,7 +4292,7 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
3958
4292
|
} catch (err) {
|
|
3959
4293
|
if (debug) {
|
|
3960
4294
|
const headers = JSON.stringify(req.headers);
|
|
3961
|
-
|
|
4295
|
+
log17(`Error: Invalid JSON body on POST ${url}: ${formatUpstreamError(err)} headers=${headers} rawBody=${JSON.stringify(rawBody.slice(0, 2e3))}`);
|
|
3962
4296
|
}
|
|
3963
4297
|
sendJson(res, 400, { error: { message: "Invalid JSON body", type: "invalid_request_error" } });
|
|
3964
4298
|
return;
|
|
@@ -3968,12 +4302,12 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
3968
4302
|
const inputItems = Array.isArray(body.input) ? body.input.length : typeof body.input === "string" ? 1 : 0;
|
|
3969
4303
|
const tools = Array.isArray(body.tools) ? body.tools : [];
|
|
3970
4304
|
const toolNames = tools.map((t) => t && typeof t === "object" && "name" in t ? t.name : "?").join(",");
|
|
3971
|
-
|
|
4305
|
+
log17(`request: model=${String(body.model ?? "")} previous_response_id=${prevId ?? "(none)"} input_items=${inputItems} body_bytes=${rawBody.length} tools=[${toolNames || "none"}]`);
|
|
3972
4306
|
const mcpTools = tools.filter((t) => t && typeof t === "object" && "name" in t && String(t.name).startsWith("mcp__"));
|
|
3973
4307
|
for (const t of mcpTools) {
|
|
3974
4308
|
const mt = t;
|
|
3975
4309
|
const subTools = mt.type === "namespace" && Array.isArray(mt.tools) ? ` subTools=[${mt.tools.length}]` : "";
|
|
3976
|
-
|
|
4310
|
+
log17(` mcp-tool: name=${mt.name} type=${mt.type} desc=${JSON.stringify(String(mt.description ?? "")).slice(0, 120)}${subTools}`);
|
|
3977
4311
|
}
|
|
3978
4312
|
}
|
|
3979
4313
|
const modelId = String(body.model ?? "");
|
|
@@ -3983,12 +4317,12 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
3983
4317
|
const fallbackLm = fallbackRoute ? models.get(fallbackRoute.modelId) : void 0;
|
|
3984
4318
|
if (fallbackRoute && fallbackLm) {
|
|
3985
4319
|
if (debug) {
|
|
3986
|
-
|
|
4320
|
+
log17(`resolveModel fallback: requested="${modelId}" \u2192 ${fallbackRoute.modelId}`);
|
|
3987
4321
|
}
|
|
3988
4322
|
resolved = { route: fallbackRoute, languageModel: fallbackLm };
|
|
3989
4323
|
} else {
|
|
3990
4324
|
if (debug) {
|
|
3991
|
-
|
|
4325
|
+
log17(`resolveModel failed: requested="${modelId}" known=[${routes.map((r) => r.modelId).join(", ")}]`);
|
|
3992
4326
|
}
|
|
3993
4327
|
sendJson(res, 404, { error: { message: `Unknown model: ${modelId}`, type: "invalid_request_error" } });
|
|
3994
4328
|
return;
|
|
@@ -4013,16 +4347,16 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
4013
4347
|
const before = params.messages.length;
|
|
4014
4348
|
const estimatedChars = estimateCodexRequestChars(params);
|
|
4015
4349
|
const compaction = isLikelyCodexCompactionRequest(body);
|
|
4016
|
-
if (debug)
|
|
4350
|
+
if (debug) log17(`context check: model=${route.modelId} window=${route.contextWindow} chars=${estimatedChars} compaction=${compaction ? "yes" : "no"} messages=${before}`);
|
|
4017
4351
|
params = protectCodexCompactionParams(body, params, route.contextWindow);
|
|
4018
4352
|
params.isCompaction = compaction;
|
|
4019
4353
|
if (debug && params.messages.length < before) {
|
|
4020
|
-
|
|
4354
|
+
log17(`context trim: model=${route.modelId} window=${route.contextWindow} kept=${params.messages.length}/${before} messages`);
|
|
4021
4355
|
}
|
|
4022
4356
|
}
|
|
4023
4357
|
if (debug) {
|
|
4024
4358
|
const effort = body.reasoning?.effort;
|
|
4025
|
-
|
|
4359
|
+
log17(`model=${route.modelId} effort=${effort ?? "(none)"} providerOptions=${JSON.stringify(params.providerOptions)}`);
|
|
4026
4360
|
}
|
|
4027
4361
|
if (body.stream) {
|
|
4028
4362
|
res.writeHead(200, {
|
|
@@ -4035,17 +4369,17 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
4035
4369
|
await streamResponsesResponse(languageModel, params, modelId, write, (summary) => {
|
|
4036
4370
|
if (debug) {
|
|
4037
4371
|
const failure = `${summary.aborted ? " aborted=yes" : ""}${summary.errorMessage ? ` error=${JSON.stringify(summary.errorMessage)}` : ""}`;
|
|
4038
|
-
|
|
4372
|
+
log17(`response done: model=${route.modelId} reasoningChars=${summary.reasoningChars} textChars=${summary.textChars} toolCalls=${summary.toolCallCount} toolNames=[${summary.toolNames.join(",")}] loopDetected=${summary.loopDetected ?? "no"} dsmlRecovered=${summary.dsmlToolCallsRecovered ?? 0}${failure} reasoningPreview=${JSON.stringify(summary.reasoningPreview)}`);
|
|
4039
4373
|
}
|
|
4040
4374
|
}, (progress) => {
|
|
4041
4375
|
if (debug) {
|
|
4042
|
-
|
|
4376
|
+
log17(`response progress: model=${route.modelId} elapsedMs=${progress.elapsedMs} reasoningChars=${progress.reasoningChars} textChars=${progress.textChars} toolCalls=${progress.toolCallCount} reasoningTail=${JSON.stringify(progress.reasoningTail)}`);
|
|
4043
4377
|
}
|
|
4044
4378
|
});
|
|
4045
4379
|
} catch (err) {
|
|
4046
4380
|
const msg = formatUpstreamError(err);
|
|
4047
4381
|
const status = upstreamHttpStatus(err);
|
|
4048
|
-
if (debug)
|
|
4382
|
+
if (debug) log17(`sdk error: ${route.modelId}: ${msg}`);
|
|
4049
4383
|
if (status === 429) {
|
|
4050
4384
|
writeResponsesRateLimitStream(modelId, msg, write);
|
|
4051
4385
|
} else {
|
|
@@ -4060,7 +4394,7 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
4060
4394
|
} catch (err) {
|
|
4061
4395
|
const msg = formatUpstreamError(err);
|
|
4062
4396
|
const status = upstreamHttpStatus(err);
|
|
4063
|
-
if (debug)
|
|
4397
|
+
if (debug) log17(`sdk error: ${route.modelId}: ${msg}`);
|
|
4064
4398
|
if (status === 429) {
|
|
4065
4399
|
sendJson(res, 200, responsesRateLimitBody(modelId, msg));
|
|
4066
4400
|
} else {
|
|
@@ -4070,7 +4404,7 @@ async function startCodexProxy(routes, options = {}) {
|
|
|
4070
4404
|
}
|
|
4071
4405
|
} catch (err) {
|
|
4072
4406
|
const msg = formatUpstreamError(err);
|
|
4073
|
-
|
|
4407
|
+
log17(`handler error: ${msg}`);
|
|
4074
4408
|
sendJson(res, 500, { error: { message: msg, type: "api_error" } });
|
|
4075
4409
|
}
|
|
4076
4410
|
return;
|
|
@@ -4188,7 +4522,7 @@ Sec-WebSocket-Accept: ${wsAcceptKey(clientKey)}\r
|
|
|
4188
4522
|
try {
|
|
4189
4523
|
body = JSON.parse(frame.text);
|
|
4190
4524
|
} catch {
|
|
4191
|
-
if (debug)
|
|
4525
|
+
if (debug) log17(`WS Error: Invalid JSON body: rawBody=${JSON.stringify(frame.text.slice(0, 2e3))}`);
|
|
4192
4526
|
sendWsEvent(`event: error
|
|
4193
4527
|
data: ${JSON.stringify({ error: { message: "Invalid JSON", type: "invalid_request_error" } })}
|
|
4194
4528
|
|
|
@@ -4201,7 +4535,7 @@ data: ${JSON.stringify({ error: { message: "Invalid JSON", type: "invalid_reques
|
|
|
4201
4535
|
const inputItems = Array.isArray(body.input) ? body.input.length : typeof body.input === "string" ? 1 : 0;
|
|
4202
4536
|
const tools = Array.isArray(body.tools) ? body.tools : [];
|
|
4203
4537
|
const toolNames = tools.map((t) => t && typeof t === "object" && "name" in t ? t.name : "?").join(",");
|
|
4204
|
-
|
|
4538
|
+
log17(`WS request: model=${String(body.model ?? "")} previous_response_id=${prevId ?? "(none)"} input_items=${inputItems} body_bytes=${frame.text.length} tools=[${toolNames || "none"}]`);
|
|
4205
4539
|
}
|
|
4206
4540
|
const modelId = String(body.model ?? "");
|
|
4207
4541
|
let resolved = resolveModel(routes, models, modelId);
|
|
@@ -4209,10 +4543,10 @@ data: ${JSON.stringify({ error: { message: "Invalid JSON", type: "invalid_reques
|
|
|
4209
4543
|
const fb = routes[0];
|
|
4210
4544
|
const fbLm = fb ? models.get(fb.modelId) : void 0;
|
|
4211
4545
|
if (fb && fbLm) {
|
|
4212
|
-
if (debug)
|
|
4546
|
+
if (debug) log17(`WS resolveModel fallback: requested="${modelId}" \u2192 ${fb.modelId}`);
|
|
4213
4547
|
resolved = { route: fb, languageModel: fbLm };
|
|
4214
4548
|
} else {
|
|
4215
|
-
if (debug)
|
|
4549
|
+
if (debug) log17(`WS resolveModel failed: requested="${modelId}" known=[${routes.map((r) => r.modelId).join(", ")}]`);
|
|
4216
4550
|
sendWsEvent(`event: error
|
|
4217
4551
|
data: ${JSON.stringify({ error: { message: `Unknown model: ${modelId}` } })}
|
|
4218
4552
|
|
|
@@ -4240,31 +4574,31 @@ data: ${JSON.stringify({ error: { message: `Unknown model: ${modelId}` } })}
|
|
|
4240
4574
|
const before = params.messages.length;
|
|
4241
4575
|
const estimatedChars = estimateCodexRequestChars(params);
|
|
4242
4576
|
const compaction = isLikelyCodexCompactionRequest(body);
|
|
4243
|
-
if (debug)
|
|
4577
|
+
if (debug) log17(`WS context check: model=${route.modelId} window=${route.contextWindow} chars=${estimatedChars} compaction=${compaction ? "yes" : "no"} messages=${before} tools=${params.tools ? Object.keys(params.tools).length : 0}`);
|
|
4244
4578
|
params = protectCodexCompactionParams(body, params, route.contextWindow);
|
|
4245
4579
|
params.isCompaction = compaction;
|
|
4246
4580
|
if (debug && params.messages.length < before) {
|
|
4247
|
-
|
|
4581
|
+
log17(`WS context trim: model=${route.modelId} window=${route.contextWindow} kept=${params.messages.length}/${before} messages tools=${params.tools ? Object.keys(params.tools).length : 0}`);
|
|
4248
4582
|
}
|
|
4249
4583
|
}
|
|
4250
4584
|
if (debug) {
|
|
4251
4585
|
const effort = body.reasoning?.effort;
|
|
4252
|
-
|
|
4586
|
+
log17(`WS model=${route.modelId} effort=${effort ?? "(none)"} providerOptions=${JSON.stringify(params.providerOptions)}`);
|
|
4253
4587
|
}
|
|
4254
4588
|
await streamResponsesResponse(languageModel, params, modelId, sendWsEvent, (summary) => {
|
|
4255
4589
|
if (debug) {
|
|
4256
4590
|
const failure = `${summary.aborted ? " aborted=yes" : ""}${summary.errorMessage ? ` error=${JSON.stringify(summary.errorMessage)}` : ""}`;
|
|
4257
|
-
|
|
4591
|
+
log17(`WS response done: model=${route.modelId} reasoningChars=${summary.reasoningChars} textChars=${summary.textChars} toolCalls=${summary.toolCallCount} toolNames=[${summary.toolNames.join(",")}] loopDetected=${summary.loopDetected ?? "no"} dsmlRecovered=${summary.dsmlToolCallsRecovered ?? 0}${failure} reasoningPreview=${JSON.stringify(summary.reasoningPreview)}`);
|
|
4258
4592
|
}
|
|
4259
4593
|
}, (progress) => {
|
|
4260
4594
|
if (debug) {
|
|
4261
|
-
|
|
4595
|
+
log17(`WS response progress: model=${route.modelId} elapsedMs=${progress.elapsedMs} reasoningChars=${progress.reasoningChars} textChars=${progress.textChars} toolCalls=${progress.toolCallCount} reasoningTail=${JSON.stringify(progress.reasoningTail)}`);
|
|
4262
4596
|
}
|
|
4263
4597
|
});
|
|
4264
4598
|
} catch (err) {
|
|
4265
4599
|
const msg = formatUpstreamError(err);
|
|
4266
4600
|
const status = upstreamHttpStatus(err);
|
|
4267
|
-
if (debug)
|
|
4601
|
+
if (debug) log17(`WS sdk error: ${route.modelId}: ${msg}`);
|
|
4268
4602
|
if (status === 429) {
|
|
4269
4603
|
writeResponsesRateLimitStream(modelId, msg, sendWsEvent);
|
|
4270
4604
|
} else {
|
|
@@ -4487,7 +4821,7 @@ function restoreCodexOverlay(env = process.env) {
|
|
|
4487
4821
|
return removed;
|
|
4488
4822
|
}
|
|
4489
4823
|
function remainingOverlayPaths(env = process.env) {
|
|
4490
|
-
return ownedOverlayPaths(env).filter((
|
|
4824
|
+
return ownedOverlayPaths(env).filter((p18) => existsSync3(p18));
|
|
4491
4825
|
}
|
|
4492
4826
|
function recoverInterruptedCodexSession(env = process.env) {
|
|
4493
4827
|
const before = remainingOverlayPaths(env);
|
|
@@ -4691,8 +5025,8 @@ function launchCodex(modelId, env, extraArgs) {
|
|
|
4691
5025
|
}
|
|
4692
5026
|
|
|
4693
5027
|
// src/apps/codex/prompts.ts
|
|
4694
|
-
import
|
|
4695
|
-
import * as
|
|
5028
|
+
import pc6 from "picocolors";
|
|
5029
|
+
import * as p7 from "@clack/prompts";
|
|
4696
5030
|
async function pickCodexProvider(providers, prefs, hasFavorites = false, initialProviderId, agentLabel = "Codex") {
|
|
4697
5031
|
if (providers.length === 0 && !hasFavorites) return null;
|
|
4698
5032
|
const options = providers.map((lp) => providerSelectOption(lp));
|
|
@@ -4704,13 +5038,13 @@ async function pickCodexProvider(providers, prefs, hasFavorites = false, initial
|
|
|
4704
5038
|
});
|
|
4705
5039
|
}
|
|
4706
5040
|
const initial = initialProviderId && options.some((o) => o.value === initialProviderId) ? initialProviderId : hasFavorites ? "__favorites__" : prefs.lastCodexProvider && options.some((o) => o.value === prefs.lastCodexProvider) ? prefs.lastCodexProvider : options[0].value;
|
|
4707
|
-
const chosen = await
|
|
5041
|
+
const chosen = await p7.select({
|
|
4708
5042
|
message: `Which provider for ${agentLabel}?`,
|
|
4709
5043
|
options,
|
|
4710
5044
|
initialValue: initial
|
|
4711
5045
|
});
|
|
4712
|
-
if (
|
|
4713
|
-
|
|
5046
|
+
if (p7.isCancel(chosen)) {
|
|
5047
|
+
p7.cancel("Cancelled.");
|
|
4714
5048
|
return null;
|
|
4715
5049
|
}
|
|
4716
5050
|
if (chosen === "__favorites__") return "__favorites__";
|
|
@@ -4727,12 +5061,12 @@ async function pickCodexModel(provider, prefs) {
|
|
|
4727
5061
|
navOption("__browse_all__", "Browse all models \u2192", `${provider.models.length} available`),
|
|
4728
5062
|
navOption("__back__", "\u2190 Go back", "Select a different provider")
|
|
4729
5063
|
];
|
|
4730
|
-
const picked = await
|
|
5064
|
+
const picked = await p7.select({
|
|
4731
5065
|
message: `Model for ${provider.name}?`,
|
|
4732
5066
|
options,
|
|
4733
5067
|
initialValue: recentModels[0].id
|
|
4734
5068
|
});
|
|
4735
|
-
if (
|
|
5069
|
+
if (p7.isCancel(picked) || String(picked) === "__back__") {
|
|
4736
5070
|
return "back";
|
|
4737
5071
|
}
|
|
4738
5072
|
if (String(picked) === "__browse_all__") {
|
|
@@ -4760,13 +5094,13 @@ async function pickCodexModel(provider, prefs) {
|
|
|
4760
5094
|
return selectedModel;
|
|
4761
5095
|
}
|
|
4762
5096
|
function confirmCodexLaunch(providerName, modelLabel, modelId, route) {
|
|
4763
|
-
const via = route.tier === "direct" ?
|
|
4764
|
-
return
|
|
4765
|
-
message: `${confirmLaunchMessage("Codex", modelLabel, modelId, providerName)} ${
|
|
5097
|
+
const via = route.tier === "direct" ? pc6.green("direct") : `${pc6.dim("via")} ${pc6.yellow("anygate proxy")}`;
|
|
5098
|
+
return p7.confirm({
|
|
5099
|
+
message: `${confirmLaunchMessage("Codex", modelLabel, modelId, providerName)} ${pc6.dim("(")}${via}${pc6.dim(")")}`,
|
|
4766
5100
|
initialValue: true
|
|
4767
5101
|
}).then((answer) => {
|
|
4768
|
-
if (
|
|
4769
|
-
|
|
5102
|
+
if (p7.isCancel(answer)) {
|
|
5103
|
+
p7.cancel("Cancelled.");
|
|
4770
5104
|
return false;
|
|
4771
5105
|
}
|
|
4772
5106
|
return answer;
|
|
@@ -4789,7 +5123,7 @@ function rejectManagedFlags(codexArgs) {
|
|
|
4789
5123
|
}
|
|
4790
5124
|
|
|
4791
5125
|
// src/apps/codex/ui.ts
|
|
4792
|
-
import
|
|
5126
|
+
import pc7 from "picocolors";
|
|
4793
5127
|
function codexAppIntro() {
|
|
4794
5128
|
gateIntro("Codex App");
|
|
4795
5129
|
}
|
|
@@ -4797,22 +5131,22 @@ function codexCliIntro() {
|
|
|
4797
5131
|
gateIntro("Codex");
|
|
4798
5132
|
}
|
|
4799
5133
|
function printCodexAppSessionPanel(opts) {
|
|
4800
|
-
printPanel(
|
|
4801
|
-
`${
|
|
4802
|
-
`${
|
|
5134
|
+
printPanel(pc7.cyan("Foreground session"), [
|
|
5135
|
+
`${pc7.bold("Model")} ${fmtModel(opts.modelLabel, opts.modelId)}`,
|
|
5136
|
+
`${pc7.bold("Provider")} ${fmtProvider(opts.providerName)}`,
|
|
4803
5137
|
"",
|
|
4804
|
-
`${
|
|
4805
|
-
`${
|
|
4806
|
-
`${
|
|
4807
|
-
`${
|
|
4808
|
-
`${
|
|
5138
|
+
`${pc7.yellow(pc7.bold("Keep this terminal open"))}${pc7.white(" while you use Codex.")}`,
|
|
5139
|
+
`${pc7.white("Press ")}${pc7.bold(pc7.red("Ctrl+C"))}${pc7.white(" to stop the proxy and restore ")}${fmtCommand("~/.codex/config.toml")}${pc7.white(".")}`,
|
|
5140
|
+
`${pc7.dim("Codex may show ")}${pc7.yellow('"Custom"')}${pc7.dim(" if the desktop picker cannot resolve registry models \u2014 check the terminal line above. After restart, pick your model from the picker if it appears.")}`,
|
|
5141
|
+
`${pc7.dim("If Codex asks you to sign in after restart: choose API key and enter any character \u2014 that unlocks the model picker for registry providers.")}`,
|
|
5142
|
+
`${pc7.dim("Stuck? Run ")}${fmtCommand(opts.restoreCommand)}${pc7.dim(".")}`
|
|
4809
5143
|
]);
|
|
4810
5144
|
}
|
|
4811
5145
|
function printCodexCliCleanupPanel(restoreCommand) {
|
|
4812
|
-
printPanel(
|
|
4813
|
-
`${
|
|
4814
|
-
`${
|
|
4815
|
-
`${
|
|
5146
|
+
printPanel(pc7.cyan("While Codex runs"), [
|
|
5147
|
+
`${pc7.white("Temporary profile: ")}${fmtCommand("~/.codex/anygate-launch.config.toml")}`,
|
|
5148
|
+
`${pc7.white("Removed automatically when Codex exits.")}`,
|
|
5149
|
+
`${pc7.dim("After a crash: ")}${fmtCommand(restoreCommand)}${pc7.dim(".")}`
|
|
4816
5150
|
]);
|
|
4817
5151
|
}
|
|
4818
5152
|
function codexAppOutro(modelLabel) {
|
|
@@ -4821,7 +5155,7 @@ function codexAppOutro(modelLabel) {
|
|
|
4821
5155
|
function codexCliOutro(providerName, modelLabel, modelId) {
|
|
4822
5156
|
gateOutro(
|
|
4823
5157
|
"Launching Codex",
|
|
4824
|
-
`${fmtProvider(providerName)} ${
|
|
5158
|
+
`${fmtProvider(providerName)} ${pc7.dim("/")} ${fmtModel(modelLabel, modelId)}`
|
|
4825
5159
|
);
|
|
4826
5160
|
}
|
|
4827
5161
|
|
|
@@ -4876,7 +5210,7 @@ function buildFavoritesAppCatalog(resolved) {
|
|
|
4876
5210
|
}
|
|
4877
5211
|
|
|
4878
5212
|
// src/apps/codex/favorites-launch.ts
|
|
4879
|
-
import * as
|
|
5213
|
+
import * as p8 from "@clack/prompts";
|
|
4880
5214
|
|
|
4881
5215
|
// src/apps/shared/favorites-resolver.ts
|
|
4882
5216
|
async function resolveFavorite(fav, ctx) {
|
|
@@ -4951,7 +5285,7 @@ async function pickFavoriteStartingModel(compatible, favorites, agent, productLa
|
|
|
4951
5285
|
if (provider && model) available.push({ provider, model });
|
|
4952
5286
|
}
|
|
4953
5287
|
if (available.length === 0) {
|
|
4954
|
-
|
|
5288
|
+
p8.log.warn(`No saved ${productLabel} favorites are currently available.`);
|
|
4955
5289
|
return "unavailable";
|
|
4956
5290
|
}
|
|
4957
5291
|
const favOptions = available.map((f, i) => ({
|
|
@@ -4959,13 +5293,13 @@ async function pickFavoriteStartingModel(compatible, favorites, agent, productLa
|
|
|
4959
5293
|
label: `${f.model.name || f.model.id} \u2014 ${f.provider.name}`,
|
|
4960
5294
|
hint: f.model.id
|
|
4961
5295
|
}));
|
|
4962
|
-
const pickedIdx = await
|
|
5296
|
+
const pickedIdx = await p8.select({
|
|
4963
5297
|
message: "Starting model?",
|
|
4964
5298
|
options: favOptions,
|
|
4965
5299
|
initialValue: "0"
|
|
4966
5300
|
});
|
|
4967
|
-
if (
|
|
4968
|
-
|
|
5301
|
+
if (p8.isCancel(pickedIdx)) {
|
|
5302
|
+
p8.cancel("Cancelled.");
|
|
4969
5303
|
return "cancelled";
|
|
4970
5304
|
}
|
|
4971
5305
|
return available[Number(pickedIdx)] ?? "unavailable";
|
|
@@ -5008,7 +5342,7 @@ function buildCodexProxyRoutesFromResolved(resolved, providersById) {
|
|
|
5008
5342
|
};
|
|
5009
5343
|
}).filter((r) => r !== void 0);
|
|
5010
5344
|
if (skippedOAuth.length > 0) {
|
|
5011
|
-
|
|
5345
|
+
p8.log.warn(
|
|
5012
5346
|
`Skipped ${skippedOAuth.length} OAuth favorite(s) (OAuth auth not supported in favorites catalog): ${skippedOAuth.join(", ")}`
|
|
5013
5347
|
);
|
|
5014
5348
|
}
|
|
@@ -5034,7 +5368,7 @@ async function resolveCodexFavorites(activeProvider, selectedModel, compatible,
|
|
|
5034
5368
|
ctx
|
|
5035
5369
|
);
|
|
5036
5370
|
if (droppedFavorites.length > 0) {
|
|
5037
|
-
|
|
5371
|
+
p8.log.warn(
|
|
5038
5372
|
`Skipped ${droppedFavorites.length} stale/unauthorized favorite(s): ${droppedFavorites.map((f) => `${f.providerId}:${f.modelId}`).join(", ")}`
|
|
5039
5373
|
);
|
|
5040
5374
|
}
|
|
@@ -5111,9 +5445,9 @@ async function startCloudCodeCatalogBackend(routes, startingAliasId, trace) {
|
|
|
5111
5445
|
|
|
5112
5446
|
// src/apps/codex/cli.ts
|
|
5113
5447
|
function codexHelpText() {
|
|
5114
|
-
return `${
|
|
5448
|
+
return `${pc8.bold("anygate codex")} \u2014 launch OpenAI Codex CLI with your registry providers
|
|
5115
5449
|
|
|
5116
|
-
${
|
|
5450
|
+
${pc8.bold("Usage:")}
|
|
5117
5451
|
anygate codex [options] [codex-flags]
|
|
5118
5452
|
anygate codex --vertex
|
|
5119
5453
|
anygate codex --restore
|
|
@@ -5121,7 +5455,7 @@ ${pc7.bold("Usage:")}
|
|
|
5121
5455
|
anygate codex --help
|
|
5122
5456
|
anygate codex --version
|
|
5123
5457
|
|
|
5124
|
-
${
|
|
5458
|
+
${pc8.bold("Options:")}
|
|
5125
5459
|
--trace Write proxy debug logs to ~/.anygate/logs/ and show errors on exit
|
|
5126
5460
|
--provider Boot provider id (skip wizard when paired with --model or non-interactive)
|
|
5127
5461
|
--model Boot model id (skip wizard when paired with --provider or non-interactive)
|
|
@@ -5131,30 +5465,30 @@ ${pc7.bold("Options:")}
|
|
|
5131
5465
|
--help Show this command help
|
|
5132
5466
|
--version Show version
|
|
5133
5467
|
|
|
5134
|
-
${
|
|
5468
|
+
${pc8.bold("Description:")}
|
|
5135
5469
|
Picks a provider and model from ~/.anygate/providers.json, writes a temporary
|
|
5136
5470
|
anygate-launch profile (never touches ~/.codex/config.toml), and launches Codex.
|
|
5137
5471
|
Overlay files are removed automatically when Codex exits; use --restore after a crash.
|
|
5138
5472
|
Anthropic and other registry models route through a local Responses API proxy.
|
|
5139
5473
|
|
|
5140
|
-
${
|
|
5474
|
+
${pc8.bold("Prerequisites:")}
|
|
5141
5475
|
npm install -g @openai/codex
|
|
5142
5476
|
|
|
5143
|
-
${
|
|
5477
|
+
${pc8.bold("Cleanup:")}
|
|
5144
5478
|
Temporary files: ~/.codex/anygate-launch.config.toml and ~/.anygate/codex/*
|
|
5145
5479
|
Auto-removed on normal exit. After crash or force-quit: anygate codex --restore
|
|
5146
5480
|
|
|
5147
|
-
${
|
|
5481
|
+
${pc8.bold("Passing flags to Codex:")}
|
|
5148
5482
|
Add Codex flags directly \u2014 no "--" separator needed.
|
|
5149
5483
|
anygate launches with sandbox disabled (danger-full-access) by default so shell
|
|
5150
5484
|
tools can reach the network. Override with your own -s flag if you want a tighter sandbox.
|
|
5151
5485
|
anygate manages --profile, -m, -p (profile), --provider, and --model; other flags go to Codex.
|
|
5152
5486
|
See docs/CODEX.md for sandbox, network, and troubleshooting.
|
|
5153
5487
|
|
|
5154
|
-
${
|
|
5488
|
+
${pc8.bold("OAuth:")}
|
|
5155
5489
|
For ChatGPT Plus/Pro, run anygate providers auth openai first.
|
|
5156
5490
|
|
|
5157
|
-
${
|
|
5491
|
+
${pc8.bold("Examples:")}
|
|
5158
5492
|
anygate codex
|
|
5159
5493
|
anygate codex --trace
|
|
5160
5494
|
anygate codex --provider zen --model deepseek-v4-flash-free
|
|
@@ -5162,8 +5496,8 @@ ${pc7.bold("Examples:")}
|
|
|
5162
5496
|
anygate codex -s workspace-write
|
|
5163
5497
|
anygate codex --restore
|
|
5164
5498
|
anygate codex --help
|
|
5165
|
-
${
|
|
5166
|
-
When you have saved favorites via ${
|
|
5499
|
+
${pc8.bold("Favorites:")}
|
|
5500
|
+
When you have saved favorites via ${pc8.cyan("anygate models")}, the Codex
|
|
5167
5501
|
picker will show your starting model + favorites for mid-session switching.
|
|
5168
5502
|
Zen/Go favorites are included when an OpenCode API key is available.`;
|
|
5169
5503
|
}
|
|
@@ -5213,14 +5547,14 @@ function printCodexCleanupReminder(hadProxy) {
|
|
|
5213
5547
|
if (isAgentStdoutMode()) return;
|
|
5214
5548
|
const left = remainingOverlayPaths();
|
|
5215
5549
|
if (left.length > 0) {
|
|
5216
|
-
|
|
5217
|
-
|
|
5550
|
+
p9.log.warn("Temporary Codex overlay files may still be on disk.");
|
|
5551
|
+
p9.log.info("Run: anygate codex --restore");
|
|
5218
5552
|
return;
|
|
5219
5553
|
}
|
|
5220
5554
|
const parts = ["Temporary Codex profile removed."];
|
|
5221
5555
|
if (hadProxy) parts.push("Local Responses proxy stopped.");
|
|
5222
5556
|
parts.push("If a future session acts stuck: anygate codex --restore");
|
|
5223
|
-
|
|
5557
|
+
p9.log.info(parts.join(" "));
|
|
5224
5558
|
}
|
|
5225
5559
|
function vertexEntryToLocalModel(entry) {
|
|
5226
5560
|
return {
|
|
@@ -5237,26 +5571,26 @@ function vertexEntryToLocalModel(entry) {
|
|
|
5237
5571
|
}
|
|
5238
5572
|
async function runCodexVertexLaunch(passthroughArgs, trace) {
|
|
5239
5573
|
if (!hasApplicationDefaultCredentials()) {
|
|
5240
|
-
|
|
5241
|
-
|
|
5574
|
+
p9.log.error("Google Application Default Credentials not found.");
|
|
5575
|
+
p9.log.info("Run: gcloud auth application-default login");
|
|
5242
5576
|
return 1;
|
|
5243
5577
|
}
|
|
5244
5578
|
const config = buildVertexRuntimeConfig();
|
|
5245
5579
|
if (!config) {
|
|
5246
|
-
|
|
5247
|
-
|
|
5580
|
+
p9.log.error("ANTHROPIC_VERTEX_PROJECT_ID (or GOOGLE_CLOUD_PROJECT) is not set.");
|
|
5581
|
+
p9.log.info("Set your project: export ANTHROPIC_VERTEX_PROJECT_ID=your-project-id");
|
|
5248
5582
|
return 1;
|
|
5249
5583
|
}
|
|
5250
5584
|
let selectedEntry;
|
|
5251
5585
|
if (config.models.length === 1) {
|
|
5252
5586
|
selectedEntry = config.models[0];
|
|
5253
5587
|
} else {
|
|
5254
|
-
const choice = await
|
|
5588
|
+
const choice = await p9.select({
|
|
5255
5589
|
message: "Select a Vertex AI model:",
|
|
5256
5590
|
options: config.models.map((m) => ({ value: m, label: m.display_name, hint: m.id }))
|
|
5257
5591
|
});
|
|
5258
|
-
if (
|
|
5259
|
-
|
|
5592
|
+
if (p9.isCancel(choice)) {
|
|
5593
|
+
p9.cancel("Cancelled.");
|
|
5260
5594
|
return 0;
|
|
5261
5595
|
}
|
|
5262
5596
|
selectedEntry = choice;
|
|
@@ -5284,7 +5618,7 @@ async function runCodexVertexLaunch(passthroughArgs, trace) {
|
|
|
5284
5618
|
const debugLogPath = getCodexProxyDebugLogPath();
|
|
5285
5619
|
let proxyHandle = null;
|
|
5286
5620
|
try {
|
|
5287
|
-
|
|
5621
|
+
p9.log.info(`Vertex AI \xB7 ${selectedEntry.display_name} \u2014 project: ${config.project} / location: ${config.location}`);
|
|
5288
5622
|
proxyHandle = await startCodexProxy(allRoutes, { debug: trace });
|
|
5289
5623
|
const proxyPort = proxyHandle.port;
|
|
5290
5624
|
const catalogPath = getCatalogOutputPath("vertex");
|
|
@@ -5335,7 +5669,7 @@ async function runCodexCommand(codexArgs, trace = false, launch = {}) {
|
|
|
5335
5669
|
}
|
|
5336
5670
|
const codexPath = findCodexBinary();
|
|
5337
5671
|
if (!codexPath) {
|
|
5338
|
-
console.error(
|
|
5672
|
+
console.error(pc8.red("\nError: codex binary not found on PATH.\n"));
|
|
5339
5673
|
console.error("Install OpenAI Codex CLI:");
|
|
5340
5674
|
console.error(" npm install -g @openai/codex\n");
|
|
5341
5675
|
return 1;
|
|
@@ -5347,7 +5681,7 @@ async function runCodexCommand(codexArgs, trace = false, launch = {}) {
|
|
|
5347
5681
|
setAgentStdoutMode(agentStdout);
|
|
5348
5682
|
const debugLogPath = getCodexProxyDebugLogPath();
|
|
5349
5683
|
if (trace && !configOnly) {
|
|
5350
|
-
|
|
5684
|
+
p9.log.info(`Debug log: ${debugLogPath}`);
|
|
5351
5685
|
}
|
|
5352
5686
|
const isTty = Boolean(process.stdin.isTTY);
|
|
5353
5687
|
if (launch.vertex) {
|
|
@@ -5355,10 +5689,10 @@ async function runCodexCommand(codexArgs, trace = false, launch = {}) {
|
|
|
5355
5689
|
const sessionCheck = checkSessionLock(isTty);
|
|
5356
5690
|
if (!sessionCheck.ok) {
|
|
5357
5691
|
if (sessionCheck.reason === "non_tty") {
|
|
5358
|
-
console.error(
|
|
5692
|
+
console.error(pc8.red("anygate codex --vertex requires an interactive terminal."));
|
|
5359
5693
|
return 1;
|
|
5360
5694
|
}
|
|
5361
|
-
console.error(
|
|
5695
|
+
console.error(pc8.yellow(`Another anygate codex session may be running (pid ${sessionCheck.lock.pid}).`));
|
|
5362
5696
|
console.error("Run anygate codex --restore to clean up, or wait for it to finish.");
|
|
5363
5697
|
return 1;
|
|
5364
5698
|
}
|
|
@@ -5373,7 +5707,7 @@ async function runCodexCommand(codexArgs, trace = false, launch = {}) {
|
|
|
5373
5707
|
prefs
|
|
5374
5708
|
});
|
|
5375
5709
|
if (launchPlan.error) {
|
|
5376
|
-
console.error(
|
|
5710
|
+
console.error(pc8.red(`
|
|
5377
5711
|
Error: ${launchPlan.error}
|
|
5378
5712
|
`));
|
|
5379
5713
|
return 1;
|
|
@@ -5383,12 +5717,12 @@ Error: ${launchPlan.error}
|
|
|
5383
5717
|
const sessionCheck = checkSessionLock(isTty || allowNonTty);
|
|
5384
5718
|
if (!sessionCheck.ok) {
|
|
5385
5719
|
if (sessionCheck.reason === "non_tty") {
|
|
5386
|
-
console.error(
|
|
5720
|
+
console.error(pc8.red(
|
|
5387
5721
|
"anygate codex requires an interactive terminal (or use --provider and --model for non-interactive launch)."
|
|
5388
5722
|
));
|
|
5389
5723
|
return 1;
|
|
5390
5724
|
}
|
|
5391
|
-
console.error(
|
|
5725
|
+
console.error(pc8.yellow(`Another anygate codex session may be running (pid ${sessionCheck.lock.pid}).`));
|
|
5392
5726
|
console.error("Run anygate codex --restore to clean up, or wait for it to finish.");
|
|
5393
5727
|
return 1;
|
|
5394
5728
|
}
|
|
@@ -5396,10 +5730,10 @@ Error: ${launchPlan.error}
|
|
|
5396
5730
|
if (!configOnly) {
|
|
5397
5731
|
if (!agentStdout) codexCliIntro();
|
|
5398
5732
|
if (interrupted.recovered && !agentStdout) {
|
|
5399
|
-
|
|
5733
|
+
p9.log.warn(
|
|
5400
5734
|
"Found leftover Codex files from an interrupted session (closed terminal, crash, or force-quit)."
|
|
5401
5735
|
);
|
|
5402
|
-
|
|
5736
|
+
p9.log.info(
|
|
5403
5737
|
`Removed ${interrupted.removedCount ?? "those"} file(s) automatically. If anything still looks wrong: anygate codex --restore`
|
|
5404
5738
|
);
|
|
5405
5739
|
}
|
|
@@ -5409,17 +5743,17 @@ Error: ${launchPlan.error}
|
|
|
5409
5743
|
try {
|
|
5410
5744
|
catalog = await fetchProviderCatalog({ agent: "codex" });
|
|
5411
5745
|
} catch (err) {
|
|
5412
|
-
console.error(
|
|
5746
|
+
console.error(pc8.red(String(err instanceof Error ? err.message : err)));
|
|
5413
5747
|
return 1;
|
|
5414
5748
|
}
|
|
5415
5749
|
} else {
|
|
5416
|
-
const catalogSpinner =
|
|
5750
|
+
const catalogSpinner = p9.spinner();
|
|
5417
5751
|
catalogSpinner.start("Loading your providers...");
|
|
5418
5752
|
try {
|
|
5419
5753
|
catalog = await fetchProviderCatalog({ agent: "codex" });
|
|
5420
5754
|
} catch (err) {
|
|
5421
5755
|
catalogSpinner.stop("");
|
|
5422
|
-
console.error(
|
|
5756
|
+
console.error(pc8.red(String(err instanceof Error ? err.message : err)));
|
|
5423
5757
|
return 1;
|
|
5424
5758
|
}
|
|
5425
5759
|
catalogSpinner.stop("");
|
|
@@ -5427,25 +5761,25 @@ Error: ${launchPlan.error}
|
|
|
5427
5761
|
const compatible = codexCompatibleProviders(providersForPicker(catalog), "codex");
|
|
5428
5762
|
if (compatible.length === 0) {
|
|
5429
5763
|
if (!configOnly) {
|
|
5430
|
-
|
|
5431
|
-
|
|
5764
|
+
p9.log.warn("No Codex-compatible providers in your registry.");
|
|
5765
|
+
p9.log.info("Add a provider with anygate providers add, or sign in with anygate providers auth openai.");
|
|
5432
5766
|
}
|
|
5433
5767
|
return 0;
|
|
5434
5768
|
}
|
|
5435
5769
|
const favorites = prefs.favoriteModels ?? [];
|
|
5436
5770
|
const favoritesActive = favorites.length > 0 && !launchPlan.skip;
|
|
5437
5771
|
if (favoritesActive && !configOnly) {
|
|
5438
|
-
|
|
5772
|
+
p9.log.info(
|
|
5439
5773
|
`Favorites mode active \u2014 Codex picker will show ${favorites.length + 1} models (1 starting + ${favorites.length} favorites).`
|
|
5440
5774
|
);
|
|
5441
|
-
|
|
5775
|
+
p9.log.info("Edit with `anygate models`.");
|
|
5442
5776
|
}
|
|
5443
5777
|
let activeProvider = compatible.find((lp) => lp.id === prefs.lastCodexProvider) ?? compatible[0];
|
|
5444
5778
|
let selectedModel = activeProvider.models.find((m) => m.id === prefs.lastCodexModel) ?? activeProvider.models[0];
|
|
5445
5779
|
if (!configOnly && launchPlan.skip && launchPlan.target) {
|
|
5446
5780
|
const resolved = findProviderAndModel(compatible, launchPlan.target);
|
|
5447
5781
|
if (!resolved) {
|
|
5448
|
-
|
|
5782
|
+
p9.log.error(
|
|
5449
5783
|
`Provider/model not found: ${launchPlan.target.providerId} / ${launchPlan.target.modelId}`
|
|
5450
5784
|
);
|
|
5451
5785
|
return 1;
|
|
@@ -5453,7 +5787,7 @@ Error: ${launchPlan.error}
|
|
|
5453
5787
|
activeProvider = resolved.provider;
|
|
5454
5788
|
selectedModel = resolved.model;
|
|
5455
5789
|
if (!agentStdout) {
|
|
5456
|
-
|
|
5790
|
+
p9.log.step(`Using ${selectedModel.name || selectedModel.id} (${activeProvider.name})`);
|
|
5457
5791
|
}
|
|
5458
5792
|
} else if (!configOnly) {
|
|
5459
5793
|
let currentInitialProvider = prefs.lastCodexProvider && compatible.some((o) => o.id === prefs.lastCodexProvider) ? prefs.lastCodexProvider : compatible[0].id;
|
|
@@ -5501,7 +5835,7 @@ Error: ${launchPlan.error}
|
|
|
5501
5835
|
const apiKey = await resolveLocalProviderApiKey(activeProvider);
|
|
5502
5836
|
if (!apiKey) {
|
|
5503
5837
|
if (!configOnly) {
|
|
5504
|
-
|
|
5838
|
+
p9.log.error(new CredentialUnavailableError(activeProvider.id).userMessage);
|
|
5505
5839
|
}
|
|
5506
5840
|
return 1;
|
|
5507
5841
|
}
|
|
@@ -5646,29 +5980,29 @@ Error: ${launchPlan.error}
|
|
|
5646
5980
|
});
|
|
5647
5981
|
if (configOnly) {
|
|
5648
5982
|
const home = process.env["HOME"] ?? "";
|
|
5649
|
-
const shortenPath = (
|
|
5983
|
+
const shortenPath = (p18) => home ? p18.replace(home, "~") : p18;
|
|
5650
5984
|
console.log("");
|
|
5651
|
-
console.log(
|
|
5985
|
+
console.log(pc8.bold(pc8.cyan(" CONFIG PREVIEW \u2014 anygate codex")));
|
|
5652
5986
|
console.log("");
|
|
5653
5987
|
if (favoritesActive && resolvedFavorites.length > 0) {
|
|
5654
|
-
console.log(` ${
|
|
5988
|
+
console.log(` ${pc8.bold("Mode:")} Favorites Catalog (${resolvedFavorites.length} model${resolvedFavorites.length !== 1 ? "s" : ""})`);
|
|
5655
5989
|
console.log("");
|
|
5656
|
-
console.log(` ${
|
|
5990
|
+
console.log(` ${pc8.bold("Models:")}`);
|
|
5657
5991
|
for (const r of resolvedFavorites) {
|
|
5658
|
-
console.log(` ${
|
|
5992
|
+
console.log(` ${pc8.cyan(r.model.id)} ${pc8.dim(`(${r.providerName})`)}`);
|
|
5659
5993
|
}
|
|
5660
5994
|
} else {
|
|
5661
|
-
console.log(` ${
|
|
5662
|
-
console.log(` ${
|
|
5663
|
-
console.log(` ${
|
|
5995
|
+
console.log(` ${pc8.bold("Mode:")} Single model`);
|
|
5996
|
+
console.log(` ${pc8.bold("Provider:")} ${activeProvider.name}`);
|
|
5997
|
+
console.log(` ${pc8.bold("Model:")} ${selectedModel.id}`);
|
|
5664
5998
|
}
|
|
5665
5999
|
console.log("");
|
|
5666
|
-
console.log(` ${
|
|
5667
|
-
console.log(` ${
|
|
5668
|
-
console.log(` ${
|
|
6000
|
+
console.log(` ${pc8.bold("Files written:")}`);
|
|
6001
|
+
console.log(` ${pc8.dim(shortenPath(profilePath))}`);
|
|
6002
|
+
console.log(` ${pc8.dim(shortenPath(catalogPath))}`);
|
|
5669
6003
|
console.log("");
|
|
5670
|
-
console.log(
|
|
5671
|
-
console.log(
|
|
6004
|
+
console.log(pc8.dim(" No Codex process was started."));
|
|
6005
|
+
console.log(pc8.dim(" Run ") + pc8.cyan("anygate codex") + pc8.dim(" to launch."));
|
|
5672
6006
|
console.log("");
|
|
5673
6007
|
restoreCodexOverlay();
|
|
5674
6008
|
return 0;
|
|
@@ -5719,7 +6053,7 @@ Error: ${launchPlan.error}
|
|
|
5719
6053
|
// src/cli/codex.ts
|
|
5720
6054
|
async function handleCodexCommand(parsed) {
|
|
5721
6055
|
if (parsed.showVersion) {
|
|
5722
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
6056
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
5723
6057
|
console.log(VERSION2);
|
|
5724
6058
|
return 0;
|
|
5725
6059
|
}
|
|
@@ -5735,8 +6069,8 @@ async function handleCodexCommand(parsed) {
|
|
|
5735
6069
|
}
|
|
5736
6070
|
|
|
5737
6071
|
// src/apps/codex/app.ts
|
|
5738
|
-
import
|
|
5739
|
-
import * as
|
|
6072
|
+
import pc9 from "picocolors";
|
|
6073
|
+
import * as p10 from "@clack/prompts";
|
|
5740
6074
|
init_config();
|
|
5741
6075
|
|
|
5742
6076
|
// src/apps/codex/app-provider-routes.ts
|
|
@@ -6230,29 +6564,29 @@ async function waitForShutdownWithConfirm() {
|
|
|
6230
6564
|
const signal = await waitForShutdown();
|
|
6231
6565
|
if (signal !== "sigint") break;
|
|
6232
6566
|
console.log("");
|
|
6233
|
-
const choice = await
|
|
6567
|
+
const choice = await p10.select({
|
|
6234
6568
|
message: "Close ChatGPT Desktop and restore your Codex config?",
|
|
6235
6569
|
options: [
|
|
6236
6570
|
{ value: "yes", label: "Yes, close ChatGPT Desktop and restore config" },
|
|
6237
6571
|
{ value: "no", label: "No, keep session running" }
|
|
6238
6572
|
]
|
|
6239
6573
|
});
|
|
6240
|
-
if (
|
|
6574
|
+
if (p10.isCancel(choice) || choice === "yes") break;
|
|
6241
6575
|
}
|
|
6242
6576
|
}
|
|
6243
6577
|
async function maybeCloseRunningCodexApp() {
|
|
6244
6578
|
if (!isCodexAppRunning()) return;
|
|
6245
|
-
const shouldClose = await
|
|
6246
|
-
if (shouldClose && !
|
|
6247
|
-
|
|
6579
|
+
const shouldClose = await p10.confirm({ message: "ChatGPT Desktop is still running. Close it?" });
|
|
6580
|
+
if (shouldClose && !p10.isCancel(shouldClose)) {
|
|
6581
|
+
p10.log.step("Stopping ChatGPT Desktop...");
|
|
6248
6582
|
quitCodexAppGracefully();
|
|
6249
6583
|
}
|
|
6250
6584
|
}
|
|
6251
6585
|
function codexAppHelpText() {
|
|
6252
|
-
return `${
|
|
6253
|
-
${
|
|
6586
|
+
return `${pc9.bold("anygate codex-app")} \u2014 launch the ChatGPT desktop app (Codex mode) with your registry providers
|
|
6587
|
+
${pc9.dim('(OpenAI merged the Codex app into ChatGPT desktop on 2026-07-09; "chatgpt" is an alias for this command)')}
|
|
6254
6588
|
|
|
6255
|
-
${
|
|
6589
|
+
${pc9.bold("Usage:")}
|
|
6256
6590
|
anygate codex-app [options]
|
|
6257
6591
|
anygate chatgpt [options]
|
|
6258
6592
|
anygate codex-app --vertex
|
|
@@ -6261,7 +6595,7 @@ ${pc8.bold("Usage:")}
|
|
|
6261
6595
|
anygate codex-app --help
|
|
6262
6596
|
anygate codex-app --version
|
|
6263
6597
|
|
|
6264
|
-
${
|
|
6598
|
+
${pc9.bold("Options:")}
|
|
6265
6599
|
--vertex Use Claude models through Google Vertex AI
|
|
6266
6600
|
--restore Restore Codex config after an interrupted app session
|
|
6267
6601
|
--config Preview the generated Codex app configuration without launching
|
|
@@ -6269,31 +6603,31 @@ ${pc8.bold("Options:")}
|
|
|
6269
6603
|
--help Show this command help
|
|
6270
6604
|
--version Show version
|
|
6271
6605
|
|
|
6272
|
-
${
|
|
6606
|
+
${pc9.bold("Description:")}
|
|
6273
6607
|
Picks a provider and model from ~/.anygate/providers.json, patches ~/.codex/config.toml
|
|
6274
6608
|
(with backup + restore on Ctrl+C), starts a local Responses proxy, and opens the
|
|
6275
6609
|
ChatGPT desktop app in Codex mode. Keep this terminal open while using Codex.
|
|
6276
6610
|
|
|
6277
|
-
${
|
|
6611
|
+
${pc9.bold("Platforms:")}
|
|
6278
6612
|
macOS and Windows. Linux is not supported (no ChatGPT desktop app).
|
|
6279
6613
|
|
|
6280
|
-
${
|
|
6614
|
+
${pc9.bold("Cleanup:")}
|
|
6281
6615
|
Ctrl+C stops the proxy and restores your previous Codex config.
|
|
6282
6616
|
After crash: anygate codex-app --restore
|
|
6283
6617
|
|
|
6284
|
-
${
|
|
6618
|
+
${pc9.bold("Preview (no writes):")}
|
|
6285
6619
|
anygate codex-app --config
|
|
6286
6620
|
|
|
6287
6621
|
See docs/CODEX.md for CLI vs app, files touched, and restore.
|
|
6288
6622
|
|
|
6289
|
-
${
|
|
6623
|
+
${pc9.bold("Examples:")}
|
|
6290
6624
|
anygate codex-app
|
|
6291
6625
|
anygate codex-app --vertex
|
|
6292
6626
|
anygate codex-app --config
|
|
6293
6627
|
anygate codex-app --restore
|
|
6294
6628
|
|
|
6295
|
-
${
|
|
6296
|
-
When you have saved favorites via ${
|
|
6629
|
+
${pc9.bold("Favorites:")}
|
|
6630
|
+
When you have saved favorites via ${pc9.cyan("anygate models")}, the Codex App
|
|
6297
6631
|
picker will show your starting model + favorites for mid-session switching.
|
|
6298
6632
|
Zen/Go favorites are included when an OpenCode API key is available.`;
|
|
6299
6633
|
}
|
|
@@ -6315,26 +6649,26 @@ function vertexEntryToLocalModel2(entry) {
|
|
|
6315
6649
|
}
|
|
6316
6650
|
async function runCodexAppVertexLaunch(configOnly, trace = false) {
|
|
6317
6651
|
if (!hasApplicationDefaultCredentials()) {
|
|
6318
|
-
|
|
6319
|
-
|
|
6652
|
+
p10.log.error("Google Application Default Credentials not found.");
|
|
6653
|
+
p10.log.info("Run: gcloud auth application-default login");
|
|
6320
6654
|
return 1;
|
|
6321
6655
|
}
|
|
6322
6656
|
const config = buildVertexRuntimeConfig();
|
|
6323
6657
|
if (!config) {
|
|
6324
|
-
|
|
6325
|
-
|
|
6658
|
+
p10.log.error("ANTHROPIC_VERTEX_PROJECT_ID (or GOOGLE_CLOUD_PROJECT) is not set.");
|
|
6659
|
+
p10.log.info("Set your project: export ANTHROPIC_VERTEX_PROJECT_ID=your-project-id");
|
|
6326
6660
|
return 1;
|
|
6327
6661
|
}
|
|
6328
6662
|
let selectedEntry;
|
|
6329
6663
|
if (config.models.length === 1) {
|
|
6330
6664
|
selectedEntry = config.models[0];
|
|
6331
6665
|
} else {
|
|
6332
|
-
const choice = await
|
|
6666
|
+
const choice = await p10.select({
|
|
6333
6667
|
message: "Select a starting Vertex AI model:",
|
|
6334
6668
|
options: config.models.map((m) => ({ value: m, label: m.display_name, hint: m.id }))
|
|
6335
6669
|
});
|
|
6336
|
-
if (
|
|
6337
|
-
|
|
6670
|
+
if (p10.isCancel(choice)) {
|
|
6671
|
+
p10.cancel("Cancelled.");
|
|
6338
6672
|
return 0;
|
|
6339
6673
|
}
|
|
6340
6674
|
selectedEntry = choice;
|
|
@@ -6357,19 +6691,19 @@ async function runCodexAppVertexLaunch(configOnly, trace = false) {
|
|
|
6357
6691
|
const home = process.env["HOME"] ?? "";
|
|
6358
6692
|
const shortenPath = (fp) => home ? fp.replace(home, "~") : fp;
|
|
6359
6693
|
console.log("");
|
|
6360
|
-
console.log(
|
|
6694
|
+
console.log(pc9.bold(pc9.cyan(" CONFIG PREVIEW \u2014 anygate codex-app --vertex")));
|
|
6361
6695
|
console.log("");
|
|
6362
|
-
console.log(` ${
|
|
6363
|
-
console.log(` ${
|
|
6364
|
-
console.log(` ${
|
|
6365
|
-
console.log(` ${
|
|
6366
|
-
console.log(` ${
|
|
6696
|
+
console.log(` ${pc9.bold("Mode:")} Vertex AI`);
|
|
6697
|
+
console.log(` ${pc9.bold("Project:")} ${config.project}`);
|
|
6698
|
+
console.log(` ${pc9.bold("Location:")} ${config.location}`);
|
|
6699
|
+
console.log(` ${pc9.bold("Model:")} ${selectedEntry.display_name}`);
|
|
6700
|
+
console.log(` ${pc9.bold("Catalog:")} ${vertexModels.length} model${vertexModels.length !== 1 ? "s" : ""} available`);
|
|
6367
6701
|
console.log("");
|
|
6368
|
-
console.log(` ${
|
|
6369
|
-
console.log(` ${
|
|
6702
|
+
console.log(` ${pc9.bold("Catalog file:")}`);
|
|
6703
|
+
console.log(` ${pc9.dim(shortenPath(catalogPath))}`);
|
|
6370
6704
|
console.log("");
|
|
6371
|
-
console.log(
|
|
6372
|
-
console.log(
|
|
6705
|
+
console.log(pc9.dim(" No app was launched."));
|
|
6706
|
+
console.log(pc9.dim(" Run ") + pc9.cyan("anygate codex-app --vertex") + pc9.dim(" to launch."));
|
|
6373
6707
|
console.log("");
|
|
6374
6708
|
return 0;
|
|
6375
6709
|
}
|
|
@@ -6409,14 +6743,14 @@ async function runCodexAppVertexLaunch(configOnly, trace = false) {
|
|
|
6409
6743
|
proxyPort
|
|
6410
6744
|
});
|
|
6411
6745
|
sessionActive = true;
|
|
6412
|
-
|
|
6746
|
+
p10.log.info(`Vertex AI \xB7 ${selectedEntry.display_name} \u2014 project: ${config.project} / location: ${config.location}`);
|
|
6413
6747
|
logProxy(proxyPort);
|
|
6414
6748
|
logActiveModel(selectedEntry.display_name, selectedEntry.id);
|
|
6415
6749
|
try {
|
|
6416
6750
|
await launchOrRestartCodexApp();
|
|
6417
6751
|
} catch (err) {
|
|
6418
|
-
|
|
6419
|
-
|
|
6752
|
+
p10.log.warn(String(err instanceof Error ? err.message : err));
|
|
6753
|
+
p10.log.info(codexAppInstallHint());
|
|
6420
6754
|
}
|
|
6421
6755
|
printCodexAppSessionPanel({
|
|
6422
6756
|
modelLabel: selectedEntry.display_name,
|
|
@@ -6451,7 +6785,7 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6451
6785
|
try {
|
|
6452
6786
|
codexAppSupported();
|
|
6453
6787
|
} catch (err) {
|
|
6454
|
-
console.error(
|
|
6788
|
+
console.error(pc9.red(String(err instanceof Error ? err.message : err)));
|
|
6455
6789
|
return 1;
|
|
6456
6790
|
}
|
|
6457
6791
|
const interrupted = recoverInterruptedCodexAppSession();
|
|
@@ -6459,17 +6793,17 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6459
6793
|
const trace = args.includes("--trace");
|
|
6460
6794
|
const debugLogPath = getCodexProxyDebugLogPath();
|
|
6461
6795
|
if (trace && !configOnly) {
|
|
6462
|
-
|
|
6796
|
+
p10.log.info(`Debug log: ${debugLogPath}`);
|
|
6463
6797
|
}
|
|
6464
6798
|
const isTty = Boolean(process.stdin.isTTY);
|
|
6465
6799
|
if (!configOnly) {
|
|
6466
6800
|
const sessionCheck = checkAppSessionLock(isTty);
|
|
6467
6801
|
if (!sessionCheck.ok) {
|
|
6468
6802
|
if (sessionCheck.reason === "non_tty") {
|
|
6469
|
-
console.error(
|
|
6803
|
+
console.error(pc9.red("anygate codex-app requires an interactive terminal."));
|
|
6470
6804
|
return 1;
|
|
6471
6805
|
}
|
|
6472
|
-
console.error(
|
|
6806
|
+
console.error(pc9.yellow(`Another anygate codex-app session may be running (pid ${sessionCheck.lock.pid}).`));
|
|
6473
6807
|
console.error("Stop it with Ctrl+C in that terminal, or run anygate codex-app --restore after it exits.");
|
|
6474
6808
|
return 1;
|
|
6475
6809
|
}
|
|
@@ -6477,28 +6811,28 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6477
6811
|
if (!configOnly) {
|
|
6478
6812
|
codexAppIntro();
|
|
6479
6813
|
if (interrupted.recovered) {
|
|
6480
|
-
|
|
6814
|
+
p10.log.warn("Recovered from an interrupted codex-app session (restored Codex config).");
|
|
6481
6815
|
}
|
|
6482
6816
|
}
|
|
6483
6817
|
if (opts.vertex) {
|
|
6484
6818
|
return runCodexAppVertexLaunch(configOnly, trace);
|
|
6485
6819
|
}
|
|
6486
|
-
const catalogSpinner =
|
|
6820
|
+
const catalogSpinner = p10.spinner();
|
|
6487
6821
|
catalogSpinner.start("Loading your providers...");
|
|
6488
6822
|
let catalog;
|
|
6489
6823
|
try {
|
|
6490
6824
|
catalog = await fetchProviderCatalog({ agent: "codex-app" });
|
|
6491
6825
|
} catch (err) {
|
|
6492
6826
|
catalogSpinner.stop("");
|
|
6493
|
-
console.error(
|
|
6827
|
+
console.error(pc9.red(String(err instanceof Error ? err.message : err)));
|
|
6494
6828
|
return 1;
|
|
6495
6829
|
}
|
|
6496
6830
|
catalogSpinner.stop("");
|
|
6497
6831
|
const compatible = codexCompatibleProviders(providersForPicker(catalog), "codex-app");
|
|
6498
6832
|
if (compatible.length === 0) {
|
|
6499
6833
|
if (!configOnly) {
|
|
6500
|
-
|
|
6501
|
-
|
|
6834
|
+
p10.log.warn("No Codex-compatible providers in your registry.");
|
|
6835
|
+
p10.log.info("Add a provider with anygate providers add.");
|
|
6502
6836
|
}
|
|
6503
6837
|
return 0;
|
|
6504
6838
|
}
|
|
@@ -6507,10 +6841,10 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6507
6841
|
const favoritesActive = favorites.length > 0;
|
|
6508
6842
|
const useFavoritesCatalog = args.includes("--favorites");
|
|
6509
6843
|
if (favoritesActive && !configOnly) {
|
|
6510
|
-
|
|
6844
|
+
p10.log.info(
|
|
6511
6845
|
`Favorites mode active \u2014 Codex App picker will show ${favorites.length + 1} models (1 starting + ${favorites.length} favorites).`
|
|
6512
6846
|
);
|
|
6513
|
-
|
|
6847
|
+
p10.log.info("Edit with `anygate models`.");
|
|
6514
6848
|
}
|
|
6515
6849
|
let activeProvider = providerForCodexPicker(
|
|
6516
6850
|
compatible.find((lp) => lp.id === prefs.lastCodexProvider) ?? compatible[0]
|
|
@@ -6524,7 +6858,7 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6524
6858
|
providerForCodexPicker
|
|
6525
6859
|
);
|
|
6526
6860
|
if ("error" in bootSelection) {
|
|
6527
|
-
|
|
6861
|
+
p10.log.error(bootSelection.error);
|
|
6528
6862
|
return 1;
|
|
6529
6863
|
}
|
|
6530
6864
|
activeProvider = bootSelection.provider;
|
|
@@ -6536,7 +6870,7 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6536
6870
|
compatible.map(providerForCodexPicker)
|
|
6537
6871
|
);
|
|
6538
6872
|
if (!firstFavorite) {
|
|
6539
|
-
|
|
6873
|
+
p10.log.warn("No saved favorites are currently available.");
|
|
6540
6874
|
return 0;
|
|
6541
6875
|
}
|
|
6542
6876
|
activeProvider = providerForCodexPicker(firstFavorite.provider);
|
|
@@ -6575,7 +6909,7 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6575
6909
|
const apiKey = await resolveLocalProviderApiKey(activeProvider);
|
|
6576
6910
|
if (!apiKey) {
|
|
6577
6911
|
if (!configOnly) {
|
|
6578
|
-
|
|
6912
|
+
p10.log.error(new CredentialUnavailableError(activeProvider.id).userMessage);
|
|
6579
6913
|
}
|
|
6580
6914
|
return 1;
|
|
6581
6915
|
}
|
|
@@ -6626,36 +6960,36 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6626
6960
|
const home = process.env["HOME"] ?? "";
|
|
6627
6961
|
const shortenPath = (fp) => home ? fp.replace(home, "~") : fp;
|
|
6628
6962
|
console.log("");
|
|
6629
|
-
console.log(
|
|
6963
|
+
console.log(pc9.bold(pc9.cyan(" CONFIG PREVIEW \u2014 anygate codex-app")));
|
|
6630
6964
|
console.log("");
|
|
6631
6965
|
if (favoritesActive) {
|
|
6632
|
-
console.log(` ${
|
|
6966
|
+
console.log(` ${pc9.bold("Mode:")} Favorites Catalog (${resolvedFavorites.length} model${resolvedFavorites.length !== 1 ? "s" : ""})`);
|
|
6633
6967
|
console.log("");
|
|
6634
|
-
console.log(` ${
|
|
6968
|
+
console.log(` ${pc9.bold("Models:")}`);
|
|
6635
6969
|
for (const r of resolvedFavorites) {
|
|
6636
|
-
console.log(` ${
|
|
6970
|
+
console.log(` ${pc9.cyan(r.model.id)} ${pc9.dim(`(${r.providerName})`)}`);
|
|
6637
6971
|
}
|
|
6638
6972
|
} else {
|
|
6639
|
-
console.log(` ${
|
|
6640
|
-
console.log(` ${
|
|
6641
|
-
console.log(` ${
|
|
6642
|
-
console.log(` ${
|
|
6973
|
+
console.log(` ${pc9.bold("Mode:")} Single model`);
|
|
6974
|
+
console.log(` ${pc9.bold("Provider:")} ${activeProvider.name}`);
|
|
6975
|
+
console.log(` ${pc9.bold("Model:")} ${formatCodexModelLabel(selectedModel)}`);
|
|
6976
|
+
console.log(` ${pc9.bold("Catalog:")} ${routable.length} model${routable.length !== 1 ? "s" : ""} available`);
|
|
6643
6977
|
}
|
|
6644
6978
|
console.log("");
|
|
6645
|
-
console.log(` ${
|
|
6979
|
+
console.log(` ${pc9.bold("config.toml patch preview:")}`);
|
|
6646
6980
|
const tomlPreview = previewAppConfigToml({
|
|
6647
6981
|
...specBase,
|
|
6648
6982
|
proxyPort: PREVIEW_PROXY_PORT
|
|
6649
6983
|
});
|
|
6650
6984
|
for (const line2 of tomlPreview.split("\n")) {
|
|
6651
|
-
console.log(` ${
|
|
6985
|
+
console.log(` ${pc9.dim(line2)}`);
|
|
6652
6986
|
}
|
|
6653
6987
|
console.log("");
|
|
6654
|
-
console.log(` ${
|
|
6655
|
-
console.log(` ${
|
|
6988
|
+
console.log(` ${pc9.bold("Catalog file:")}`);
|
|
6989
|
+
console.log(` ${pc9.dim(shortenPath(catalogPath))}`);
|
|
6656
6990
|
console.log("");
|
|
6657
|
-
console.log(
|
|
6658
|
-
console.log(
|
|
6991
|
+
console.log(pc9.dim(" No app was launched."));
|
|
6992
|
+
console.log(pc9.dim(" Run ") + pc9.cyan("anygate codex-app") + pc9.dim(" to launch."));
|
|
6659
6993
|
console.log("");
|
|
6660
6994
|
return 0;
|
|
6661
6995
|
}
|
|
@@ -6741,8 +7075,8 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6741
7075
|
try {
|
|
6742
7076
|
await launchOrRestartCodexApp();
|
|
6743
7077
|
} catch (err) {
|
|
6744
|
-
|
|
6745
|
-
|
|
7078
|
+
p10.log.warn(String(err instanceof Error ? err.message : err));
|
|
7079
|
+
p10.log.info(codexAppInstallHint());
|
|
6746
7080
|
}
|
|
6747
7081
|
printCodexAppSessionPanel({
|
|
6748
7082
|
modelLabel,
|
|
@@ -6775,7 +7109,7 @@ async function runCodexAppCommand(args, opts = {}) {
|
|
|
6775
7109
|
// src/cli/codex-app.ts
|
|
6776
7110
|
async function handleCodexAppCommand(parsed) {
|
|
6777
7111
|
if (parsed.showVersion) {
|
|
6778
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
7112
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
6779
7113
|
console.log(VERSION2);
|
|
6780
7114
|
return 0;
|
|
6781
7115
|
}
|
|
@@ -6807,8 +7141,8 @@ This command launches the ChatGPT Desktop app with anygate's provider registry.
|
|
|
6807
7141
|
}
|
|
6808
7142
|
|
|
6809
7143
|
// src/apps/claude/desktop.ts
|
|
6810
|
-
import
|
|
6811
|
-
import * as
|
|
7144
|
+
import pc10 from "picocolors";
|
|
7145
|
+
import * as p11 from "@clack/prompts";
|
|
6812
7146
|
init_config();
|
|
6813
7147
|
|
|
6814
7148
|
// src/apps/claude/desktop-app.ts
|
|
@@ -6980,30 +7314,30 @@ function setupExitCleanup(uuid) {
|
|
|
6980
7314
|
|
|
6981
7315
|
// src/apps/claude/desktop.ts
|
|
6982
7316
|
function claudeAppHelpText() {
|
|
6983
|
-
return `${
|
|
7317
|
+
return `${pc10.bold("anygate claude-app")} \u2014 launch Claude Desktop app in 3P mode with your registry providers
|
|
6984
7318
|
|
|
6985
|
-
${
|
|
7319
|
+
${pc10.bold("Usage:")}
|
|
6986
7320
|
anygate claude-app [options]
|
|
6987
7321
|
anygate claude-app --trace
|
|
6988
7322
|
anygate claude-app --restore
|
|
6989
7323
|
anygate claude-app --help
|
|
6990
7324
|
anygate claude-app --version
|
|
6991
7325
|
|
|
6992
|
-
${
|
|
7326
|
+
${pc10.bold("Options:")}
|
|
6993
7327
|
--trace Write proxy debug logs to ~/.anygate/logs/
|
|
6994
7328
|
--restore Restore Claude Desktop config after an interrupted app session
|
|
6995
7329
|
--help Show this command help
|
|
6996
7330
|
--version Show version
|
|
6997
7331
|
|
|
6998
|
-
${
|
|
7332
|
+
${pc10.bold("Description:")}
|
|
6999
7333
|
Picks a provider and model from ~/.anygate/providers.json, patches Claude Desktop config
|
|
7000
7334
|
(with backup + restore on Ctrl+C), starts a local Responses proxy, and opens
|
|
7001
7335
|
the Claude Desktop app. Keep this terminal open while using Claude.
|
|
7002
7336
|
|
|
7003
|
-
${
|
|
7337
|
+
${pc10.bold("Platforms:")}
|
|
7004
7338
|
macOS and Windows. Linux is not supported.
|
|
7005
7339
|
|
|
7006
|
-
${
|
|
7340
|
+
${pc10.bold("Cleanup:")}
|
|
7007
7341
|
Ctrl+C stops the proxy and restores your previous Claude config.
|
|
7008
7342
|
After a crash: anygate claude-app --restore
|
|
7009
7343
|
`;
|
|
@@ -7055,37 +7389,37 @@ async function runClaudeAppCommand(args, boot) {
|
|
|
7055
7389
|
try {
|
|
7056
7390
|
claudeAppSupported();
|
|
7057
7391
|
} catch (err) {
|
|
7058
|
-
console.error(
|
|
7392
|
+
console.error(pc10.red(String(err instanceof Error ? err.message : err)));
|
|
7059
7393
|
return 1;
|
|
7060
7394
|
}
|
|
7061
7395
|
const isTty = Boolean(process.stdin.isTTY);
|
|
7062
7396
|
if (!isTty) {
|
|
7063
|
-
console.error(
|
|
7397
|
+
console.error(pc10.red("anygate claude-app requires an interactive terminal."));
|
|
7064
7398
|
return 1;
|
|
7065
7399
|
}
|
|
7066
7400
|
if (isConcurrentLiveSession()) {
|
|
7067
|
-
console.error(
|
|
7401
|
+
console.error(pc10.yellow(`Another anygate claude-app session may be running.`));
|
|
7068
7402
|
console.error("Stop it with Ctrl+C in that terminal.");
|
|
7069
7403
|
return 1;
|
|
7070
7404
|
}
|
|
7071
7405
|
if (hasStaleSession()) {
|
|
7072
|
-
|
|
7406
|
+
p11.log.warn("Recovered from an interrupted claude-app session.");
|
|
7073
7407
|
recoverSession();
|
|
7074
7408
|
}
|
|
7075
|
-
const catalogSpinner =
|
|
7409
|
+
const catalogSpinner = p11.spinner();
|
|
7076
7410
|
catalogSpinner.start("Loading your providers...");
|
|
7077
7411
|
let catalog;
|
|
7078
7412
|
try {
|
|
7079
7413
|
catalog = await fetchProviderCatalog({ agent: "codex-app" });
|
|
7080
7414
|
} catch (err) {
|
|
7081
7415
|
catalogSpinner.stop("");
|
|
7082
|
-
console.error(
|
|
7416
|
+
console.error(pc10.red(String(err instanceof Error ? err.message : err)));
|
|
7083
7417
|
return 1;
|
|
7084
7418
|
}
|
|
7085
7419
|
catalogSpinner.stop("");
|
|
7086
7420
|
const compatible = codexCompatibleProviders(providersForPicker(catalog), "claude-app");
|
|
7087
7421
|
if (compatible.length === 0) {
|
|
7088
|
-
|
|
7422
|
+
p11.log.warn("No compatible providers in your registry.");
|
|
7089
7423
|
return 0;
|
|
7090
7424
|
}
|
|
7091
7425
|
const prefs = loadPreferences();
|
|
@@ -7102,7 +7436,7 @@ async function runClaudeAppCommand(args, boot) {
|
|
|
7102
7436
|
providerForClaudePicker
|
|
7103
7437
|
);
|
|
7104
7438
|
if ("error" in bootSelection) {
|
|
7105
|
-
|
|
7439
|
+
p11.log.error(bootSelection.error);
|
|
7106
7440
|
return 1;
|
|
7107
7441
|
}
|
|
7108
7442
|
activeProvider = bootSelection.provider;
|
|
@@ -7124,7 +7458,7 @@ async function runClaudeAppCommand(args, boot) {
|
|
|
7124
7458
|
if (activeProvider) {
|
|
7125
7459
|
const apiKey = await resolveLocalProviderApiKey(activeProvider);
|
|
7126
7460
|
if (!apiKey) {
|
|
7127
|
-
|
|
7461
|
+
p11.log.error(new CredentialUnavailableError(activeProvider.id).userMessage);
|
|
7128
7462
|
return 1;
|
|
7129
7463
|
}
|
|
7130
7464
|
activeProvider.apiKey = apiKey;
|
|
@@ -7236,21 +7570,21 @@ async function runClaudeAppCommand(args, boot) {
|
|
|
7236
7570
|
});
|
|
7237
7571
|
}
|
|
7238
7572
|
console.log(`
|
|
7239
|
-
${
|
|
7573
|
+
${pc10.green("\u2714")} Proxy started on port ${proxyHandle.port}`);
|
|
7240
7574
|
try {
|
|
7241
7575
|
await launchOrRestartClaudeApp();
|
|
7242
7576
|
} catch (err) {
|
|
7243
|
-
|
|
7577
|
+
p11.log.warn(String(err instanceof Error ? err.message : err));
|
|
7244
7578
|
}
|
|
7245
7579
|
console.log(`
|
|
7246
|
-
${
|
|
7580
|
+
${pc10.bold("Claude Desktop 3P Mode Active")}`);
|
|
7247
7581
|
if (useFavorites) {
|
|
7248
|
-
console.log(`${
|
|
7582
|
+
console.log(`${pc10.dim("Catalog:")} Favorite models only`);
|
|
7249
7583
|
} else {
|
|
7250
|
-
console.log(`${
|
|
7251
|
-
console.log(`${
|
|
7584
|
+
console.log(`${pc10.dim("Model:")} ${selectedModel.id}`);
|
|
7585
|
+
console.log(`${pc10.dim("Provider:")} ${activeProvider.name}`);
|
|
7252
7586
|
}
|
|
7253
|
-
console.log(`${
|
|
7587
|
+
console.log(`${pc10.cyan("Press Ctrl+C to stop and restore config.")}`);
|
|
7254
7588
|
await waitForShutdown2();
|
|
7255
7589
|
console.log("");
|
|
7256
7590
|
cleanupSession(uuid);
|
|
@@ -7258,8 +7592,8 @@ ${pc9.bold("Claude Desktop 3P Mode Active")}`);
|
|
|
7258
7592
|
if (cloudCodeBackend) cloudCodeBackend.handle.close();
|
|
7259
7593
|
if (cloudCodeFavBackend) cloudCodeFavBackend.handle.close();
|
|
7260
7594
|
if (isClaudeAppRunning()) {
|
|
7261
|
-
const shouldClose = await
|
|
7262
|
-
if (shouldClose && !
|
|
7595
|
+
const shouldClose = await p11.confirm({ message: "Claude Desktop is still running. Close it?" });
|
|
7596
|
+
if (shouldClose && !p11.isCancel(shouldClose)) {
|
|
7263
7597
|
quitClaudeAppGracefully();
|
|
7264
7598
|
}
|
|
7265
7599
|
}
|
|
@@ -7278,7 +7612,7 @@ ${pc9.bold("Claude Desktop 3P Mode Active")}`);
|
|
|
7278
7612
|
// src/cli/claude-app.ts
|
|
7279
7613
|
async function handleClaudeAppCommand(parsed) {
|
|
7280
7614
|
if (parsed.showVersion) {
|
|
7281
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
7615
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
7282
7616
|
console.log(VERSION2);
|
|
7283
7617
|
return 0;
|
|
7284
7618
|
}
|
|
@@ -7308,8 +7642,8 @@ This command launches the Claude Desktop app with anygate's provider registry.
|
|
|
7308
7642
|
}
|
|
7309
7643
|
|
|
7310
7644
|
// src/apps/gemini/cli.ts
|
|
7311
|
-
import
|
|
7312
|
-
import * as
|
|
7645
|
+
import pc11 from "picocolors";
|
|
7646
|
+
import * as p13 from "@clack/prompts";
|
|
7313
7647
|
init_config();
|
|
7314
7648
|
|
|
7315
7649
|
// src/apps/gemini/launch.ts
|
|
@@ -7400,7 +7734,7 @@ function launchGemini(geminiPath, modelId, env, extraArgs) {
|
|
|
7400
7734
|
}
|
|
7401
7735
|
|
|
7402
7736
|
// src/apps/gemini/prompts.ts
|
|
7403
|
-
import * as
|
|
7737
|
+
import * as p12 from "@clack/prompts";
|
|
7404
7738
|
async function pickGeminiProvider(providers, prefs, hasFavorites = false, initialProviderId) {
|
|
7405
7739
|
if (providers.length === 0 && !hasFavorites) return null;
|
|
7406
7740
|
const options = providers.map((lp) => providerSelectOption(lp));
|
|
@@ -7412,13 +7746,13 @@ async function pickGeminiProvider(providers, prefs, hasFavorites = false, initia
|
|
|
7412
7746
|
});
|
|
7413
7747
|
}
|
|
7414
7748
|
const initial = initialProviderId && options.some((o) => o.value === initialProviderId) ? initialProviderId : prefs.lastGeminiProvider && options.some((o) => o.value === prefs.lastGeminiProvider) ? prefs.lastGeminiProvider : options[0].value;
|
|
7415
|
-
const chosen = await
|
|
7749
|
+
const chosen = await p12.select({
|
|
7416
7750
|
message: "Which provider for Gemini CLI?",
|
|
7417
7751
|
options,
|
|
7418
7752
|
initialValue: initial
|
|
7419
7753
|
});
|
|
7420
|
-
if (
|
|
7421
|
-
|
|
7754
|
+
if (p12.isCancel(chosen)) {
|
|
7755
|
+
p12.cancel("Cancelled.");
|
|
7422
7756
|
return null;
|
|
7423
7757
|
}
|
|
7424
7758
|
if (chosen === "__favorites__") return "__favorites__";
|
|
@@ -7435,12 +7769,12 @@ async function pickGeminiModel(provider, prefs) {
|
|
|
7435
7769
|
navOption("__browse_all__", "Browse all models \u2192", `${provider.models.length} available`),
|
|
7436
7770
|
navOption("__back__", "\u2190 Go back", "Select a different provider")
|
|
7437
7771
|
];
|
|
7438
|
-
const picked = await
|
|
7772
|
+
const picked = await p12.select({
|
|
7439
7773
|
message: `Model for ${provider.name}?`,
|
|
7440
7774
|
options,
|
|
7441
7775
|
initialValue: recentModels[0].id
|
|
7442
7776
|
});
|
|
7443
|
-
if (
|
|
7777
|
+
if (p12.isCancel(picked) || String(picked) === "__back__") {
|
|
7444
7778
|
return "back";
|
|
7445
7779
|
}
|
|
7446
7780
|
if (String(picked) === "__browse_all__") {
|
|
@@ -7468,12 +7802,12 @@ async function pickGeminiModel(provider, prefs) {
|
|
|
7468
7802
|
return selectedModel;
|
|
7469
7803
|
}
|
|
7470
7804
|
function confirmGeminiLaunch(providerName, modelLabel, modelId) {
|
|
7471
|
-
return
|
|
7805
|
+
return p12.confirm({
|
|
7472
7806
|
message: confirmLaunchMessage("Gemini CLI", modelLabel, modelId, providerName),
|
|
7473
7807
|
initialValue: true
|
|
7474
7808
|
}).then((answer) => {
|
|
7475
|
-
if (
|
|
7476
|
-
|
|
7809
|
+
if (p12.isCancel(answer)) {
|
|
7810
|
+
p12.cancel("Cancelled.");
|
|
7477
7811
|
return false;
|
|
7478
7812
|
}
|
|
7479
7813
|
return answer;
|
|
@@ -7487,7 +7821,7 @@ async function pickGeminiFavoriteModel(providers, favorites) {
|
|
|
7487
7821
|
if (provider2 && model2) favList.push({ provider: provider2, model: model2 });
|
|
7488
7822
|
}
|
|
7489
7823
|
if (favList.length === 0) {
|
|
7490
|
-
|
|
7824
|
+
p12.log.warn("None of your saved favorites are available in the current registry.");
|
|
7491
7825
|
return null;
|
|
7492
7826
|
}
|
|
7493
7827
|
const options = [
|
|
@@ -7498,12 +7832,12 @@ async function pickGeminiFavoriteModel(providers, favorites) {
|
|
|
7498
7832
|
})),
|
|
7499
7833
|
{ value: "__back__", label: "\u2190 Go back", hint: "Select a different provider" }
|
|
7500
7834
|
];
|
|
7501
|
-
const picked = await
|
|
7835
|
+
const picked = await p12.select({
|
|
7502
7836
|
message: "Pick a favorite model for Gemini CLI:",
|
|
7503
7837
|
options,
|
|
7504
7838
|
initialValue: options[0].value
|
|
7505
7839
|
});
|
|
7506
|
-
if (
|
|
7840
|
+
if (p12.isCancel(picked) || String(picked) === "__back__") return "back";
|
|
7507
7841
|
const [pickedProviderId, pickedModelId] = picked.split("::");
|
|
7508
7842
|
const provider = providers.find((lp) => lp.id === pickedProviderId);
|
|
7509
7843
|
const model = provider?.models.find((m) => m.id === pickedModelId);
|
|
@@ -7583,7 +7917,7 @@ function stripGeminiIdentity(text4) {
|
|
|
7583
7917
|
function translateGeminiRequest(body, options = {}) {
|
|
7584
7918
|
let system;
|
|
7585
7919
|
if (body.systemInstruction?.parts) {
|
|
7586
|
-
const rawSystem = body.systemInstruction.parts.map((
|
|
7920
|
+
const rawSystem = body.systemInstruction.parts.map((p18) => p18.text || "").join("\n");
|
|
7587
7921
|
system = stripGeminiIdentity(rawSystem).trim();
|
|
7588
7922
|
}
|
|
7589
7923
|
const messages = [];
|
|
@@ -7594,9 +7928,9 @@ function translateGeminiRequest(body, options = {}) {
|
|
|
7594
7928
|
const parts = [];
|
|
7595
7929
|
const toolResults = [];
|
|
7596
7930
|
const turnParts = turn.parts || [];
|
|
7597
|
-
for (const
|
|
7598
|
-
if (
|
|
7599
|
-
const text4 = stripGeminiIdentity(
|
|
7931
|
+
for (const p18 of turnParts) {
|
|
7932
|
+
if (p18.text !== void 0) {
|
|
7933
|
+
const text4 = stripGeminiIdentity(p18.text);
|
|
7600
7934
|
if (text4.includes("<thinking>")) {
|
|
7601
7935
|
const tokens = text4.split(/<thinking>([\s\S]*?)<\/thinking>/);
|
|
7602
7936
|
for (let i = 0; i < tokens.length; i++) {
|
|
@@ -7607,25 +7941,25 @@ function translateGeminiRequest(body, options = {}) {
|
|
|
7607
7941
|
} else {
|
|
7608
7942
|
parts.push({ type: "text", text: text4 });
|
|
7609
7943
|
}
|
|
7610
|
-
} else if (
|
|
7944
|
+
} else if (p18.inlineData) {
|
|
7611
7945
|
parts.push({
|
|
7612
7946
|
type: "image",
|
|
7613
|
-
image: Buffer.from(
|
|
7614
|
-
mediaType:
|
|
7947
|
+
image: Buffer.from(p18.inlineData.data, "base64"),
|
|
7948
|
+
mediaType: p18.inlineData.mimeType
|
|
7615
7949
|
});
|
|
7616
|
-
} else if (
|
|
7950
|
+
} else if (p18.functionCall) {
|
|
7617
7951
|
const id = "call_" + randomUUID2().replace(/-/g, "");
|
|
7618
|
-
const name =
|
|
7952
|
+
const name = p18.functionCall.name;
|
|
7619
7953
|
if (!nameToIdList.has(name)) nameToIdList.set(name, []);
|
|
7620
7954
|
nameToIdList.get(name).push(id);
|
|
7621
7955
|
parts.push({
|
|
7622
7956
|
type: "tool-call",
|
|
7623
7957
|
toolCallId: id,
|
|
7624
7958
|
toolName: name,
|
|
7625
|
-
input:
|
|
7959
|
+
input: p18.functionCall.args || {}
|
|
7626
7960
|
});
|
|
7627
|
-
} else if (
|
|
7628
|
-
const name =
|
|
7961
|
+
} else if (p18.functionResponse) {
|
|
7962
|
+
const name = p18.functionResponse.name;
|
|
7629
7963
|
const idList = nameToIdList.get(name) || [];
|
|
7630
7964
|
const id = idList.shift() || "call_" + randomUUID2().replace(/-/g, "");
|
|
7631
7965
|
toolResults.push({
|
|
@@ -7634,7 +7968,7 @@ function translateGeminiRequest(body, options = {}) {
|
|
|
7634
7968
|
toolName: name,
|
|
7635
7969
|
output: {
|
|
7636
7970
|
type: "text",
|
|
7637
|
-
value: typeof
|
|
7971
|
+
value: typeof p18.functionResponse.response === "string" ? p18.functionResponse.response : JSON.stringify(p18.functionResponse.response || {})
|
|
7638
7972
|
}
|
|
7639
7973
|
});
|
|
7640
7974
|
}
|
|
@@ -7840,9 +8174,9 @@ ${JSON.stringify(params, null, 2)}`);
|
|
|
7840
8174
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
7841
8175
|
let isThinking = false;
|
|
7842
8176
|
for await (const part of fullStream) {
|
|
7843
|
-
const
|
|
7844
|
-
plog(`Stream chunk type: ${
|
|
7845
|
-
if (isThinking && (
|
|
8177
|
+
const p18 = part;
|
|
8178
|
+
plog(`Stream chunk type: ${p18.type}`);
|
|
8179
|
+
if (isThinking && (p18.type === "tool-input-start" || p18.type === "tool-call" || p18.type === "finish")) {
|
|
7846
8180
|
isThinking = false;
|
|
7847
8181
|
const chunk = {
|
|
7848
8182
|
candidates: [{ content: { role: "model", parts: [{ text: `
|
|
@@ -7855,8 +8189,8 @@ ${JSON.stringify(params, null, 2)}`);
|
|
|
7855
8189
|
|
|
7856
8190
|
`);
|
|
7857
8191
|
}
|
|
7858
|
-
if (
|
|
7859
|
-
let text4 =
|
|
8192
|
+
if (p18.type === "reasoning") {
|
|
8193
|
+
let text4 = p18.textDelta ?? p18.text ?? "";
|
|
7860
8194
|
if (!isThinking) {
|
|
7861
8195
|
isThinking = true;
|
|
7862
8196
|
text4 = `<thinking>
|
|
@@ -7869,8 +8203,8 @@ ${JSON.stringify(params, null, 2)}`);
|
|
|
7869
8203
|
res.write(`data: ${JSON.stringify(chunk)}
|
|
7870
8204
|
|
|
7871
8205
|
`);
|
|
7872
|
-
} else if (
|
|
7873
|
-
let text4 =
|
|
8206
|
+
} else if (p18.type === "text-delta") {
|
|
8207
|
+
let text4 = p18.textDelta ?? p18.text ?? "";
|
|
7874
8208
|
if (isThinking) {
|
|
7875
8209
|
isThinking = false;
|
|
7876
8210
|
text4 = `
|
|
@@ -7890,17 +8224,17 @@ ${JSON.stringify(params, null, 2)}`);
|
|
|
7890
8224
|
const data = `data: ${JSON.stringify(chunk)}
|
|
7891
8225
|
|
|
7892
8226
|
`;
|
|
7893
|
-
plog(`Streaming text delta: ${
|
|
8227
|
+
plog(`Streaming text delta: ${p18.textDelta}`);
|
|
7894
8228
|
res.write(data);
|
|
7895
|
-
} else if (
|
|
7896
|
-
toolCallBuffers.set(
|
|
7897
|
-
} else if (
|
|
7898
|
-
const buf = toolCallBuffers.get(
|
|
7899
|
-
if (buf) buf.json +=
|
|
7900
|
-
} else if (
|
|
7901
|
-
const buf = toolCallBuffers.get(
|
|
7902
|
-
const args = buf ? JSON.parse(buf.json || "{}") :
|
|
7903
|
-
const name = buf ? buf.name :
|
|
8229
|
+
} else if (p18.type === "tool-input-start") {
|
|
8230
|
+
toolCallBuffers.set(p18.toolCallId, { name: p18.toolName, json: "" });
|
|
8231
|
+
} else if (p18.type === "tool-input-delta") {
|
|
8232
|
+
const buf = toolCallBuffers.get(p18.toolCallId);
|
|
8233
|
+
if (buf) buf.json += p18.delta;
|
|
8234
|
+
} else if (p18.type === "tool-call") {
|
|
8235
|
+
const buf = toolCallBuffers.get(p18.toolCallId);
|
|
8236
|
+
const args = buf ? JSON.parse(buf.json || "{}") : p18.input || {};
|
|
8237
|
+
const name = buf ? buf.name : p18.toolName;
|
|
7904
8238
|
plog(`Streaming tool call: ${name} with args: ${JSON.stringify(args)}`);
|
|
7905
8239
|
const chunk = {
|
|
7906
8240
|
candidates: [{
|
|
@@ -7916,18 +8250,18 @@ ${JSON.stringify(params, null, 2)}`);
|
|
|
7916
8250
|
res.write(`data: ${JSON.stringify(chunk)}
|
|
7917
8251
|
|
|
7918
8252
|
`);
|
|
7919
|
-
} else if (
|
|
8253
|
+
} else if (p18.type === "finish") {
|
|
7920
8254
|
const chunk = {
|
|
7921
8255
|
candidates: [{
|
|
7922
|
-
finishReason: mapFinishReason(
|
|
8256
|
+
finishReason: mapFinishReason(p18.finishReason ?? "")
|
|
7923
8257
|
}],
|
|
7924
8258
|
usageMetadata: {
|
|
7925
|
-
promptTokenCount:
|
|
7926
|
-
candidatesTokenCount:
|
|
8259
|
+
promptTokenCount: p18.totalUsage?.inputTokens || 0,
|
|
8260
|
+
candidatesTokenCount: p18.totalUsage?.outputTokens || 0
|
|
7927
8261
|
},
|
|
7928
8262
|
modelVersion: route.aliasId
|
|
7929
8263
|
};
|
|
7930
|
-
plog(`Stream finish. Reason: ${
|
|
8264
|
+
plog(`Stream finish. Reason: ${p18.finishReason}`);
|
|
7931
8265
|
res.write(`data: ${JSON.stringify(chunk)}
|
|
7932
8266
|
|
|
7933
8267
|
`);
|
|
@@ -8184,34 +8518,34 @@ async function rewriteGeminiBackendRoutes(routes, launchModelId, trace) {
|
|
|
8184
8518
|
|
|
8185
8519
|
// src/apps/gemini/cli.ts
|
|
8186
8520
|
function geminiHelpText() {
|
|
8187
|
-
return `${
|
|
8521
|
+
return `${pc11.bold("anygate gemini")} v${VERSION}
|
|
8188
8522
|
Launch Google Gemini CLI with OpenCode Zen / Go or local registry providers.
|
|
8189
8523
|
|
|
8190
|
-
${
|
|
8524
|
+
${pc11.bold("Usage:")}
|
|
8191
8525
|
anygate gemini [options] [gemini-flags]
|
|
8192
8526
|
anygate gemini --help
|
|
8193
8527
|
anygate gemini --version
|
|
8194
8528
|
|
|
8195
|
-
${
|
|
8529
|
+
${pc11.bold("Options:")}
|
|
8196
8530
|
--trace Write proxy debug logs to ~/.anygate/logs/ and show errors on exit
|
|
8197
8531
|
--provider Boot provider id (skip wizard when paired with --model or non-interactive)
|
|
8198
8532
|
--model Boot model id (skip wizard when paired with --provider or non-interactive)
|
|
8199
8533
|
--help Show this command help
|
|
8200
8534
|
--version Show version
|
|
8201
8535
|
|
|
8202
|
-
${
|
|
8536
|
+
${pc11.bold("Description:")}
|
|
8203
8537
|
Picks a provider and model from ~/.anygate/providers.json, starts a local Gemini-to-SDK translation
|
|
8204
8538
|
proxy, and launches the Gemini CLI.
|
|
8205
8539
|
All registry models (Anthropic, OpenAI, custom endpoints, etc.) route through the local translation proxy.
|
|
8206
8540
|
|
|
8207
|
-
${
|
|
8541
|
+
${pc11.bold("Prerequisites:")}
|
|
8208
8542
|
npm install -g @google/gemini-cli
|
|
8209
8543
|
|
|
8210
|
-
${
|
|
8544
|
+
${pc11.bold("Passing flags to Gemini CLI:")}
|
|
8211
8545
|
Add Gemini flags directly \u2014 no "--" separator needed.
|
|
8212
8546
|
anygate manages -m / --model and -p / --prompt; other flags go to Gemini CLI.
|
|
8213
8547
|
|
|
8214
|
-
${
|
|
8548
|
+
${pc11.bold("Examples:")}
|
|
8215
8549
|
anygate gemini
|
|
8216
8550
|
anygate gemini --trace
|
|
8217
8551
|
anygate gemini --provider zen --model gemini-2.5-flash
|
|
@@ -8224,7 +8558,7 @@ async function runGeminiCommand(geminiArgs, trace = false, launch = {}) {
|
|
|
8224
8558
|
}
|
|
8225
8559
|
const geminiPath = findGeminiBinary();
|
|
8226
8560
|
if (!geminiPath) {
|
|
8227
|
-
console.error(
|
|
8561
|
+
console.error(pc11.red("\nError: gemini binary not found on PATH.\n"));
|
|
8228
8562
|
console.error("Install Google Gemini CLI:");
|
|
8229
8563
|
console.error(" npm install -g @google/gemini-cli\n");
|
|
8230
8564
|
return 1;
|
|
@@ -8240,7 +8574,7 @@ async function runGeminiCommand(geminiArgs, trace = false, launch = {}) {
|
|
|
8240
8574
|
prefs
|
|
8241
8575
|
});
|
|
8242
8576
|
if (launchPlan.error) {
|
|
8243
|
-
console.error(
|
|
8577
|
+
console.error(pc11.red(`
|
|
8244
8578
|
Error: ${launchPlan.error}
|
|
8245
8579
|
`));
|
|
8246
8580
|
return 1;
|
|
@@ -8250,38 +8584,38 @@ Error: ${launchPlan.error}
|
|
|
8250
8584
|
try {
|
|
8251
8585
|
catalog = await fetchProviderCatalog({ agent: "gemini" });
|
|
8252
8586
|
} catch (err) {
|
|
8253
|
-
console.error(
|
|
8587
|
+
console.error(pc11.red(String(err instanceof Error ? err.message : err)));
|
|
8254
8588
|
return 1;
|
|
8255
8589
|
}
|
|
8256
8590
|
} else {
|
|
8257
|
-
const catalogSpinner =
|
|
8591
|
+
const catalogSpinner = p13.spinner();
|
|
8258
8592
|
catalogSpinner.start("Loading your providers...");
|
|
8259
8593
|
try {
|
|
8260
8594
|
catalog = await fetchProviderCatalog({ agent: "gemini" });
|
|
8261
8595
|
} catch (err) {
|
|
8262
8596
|
catalogSpinner.stop("");
|
|
8263
|
-
console.error(
|
|
8597
|
+
console.error(pc11.red(String(err instanceof Error ? err.message : err)));
|
|
8264
8598
|
return 1;
|
|
8265
8599
|
}
|
|
8266
8600
|
catalogSpinner.stop("");
|
|
8267
8601
|
}
|
|
8268
8602
|
const compatible = providersForTarget(providersForPicker(catalog), "gemini");
|
|
8269
8603
|
if (compatible.length === 0) {
|
|
8270
|
-
|
|
8271
|
-
|
|
8604
|
+
p13.log.warn("No Gemini-compatible providers in your registry.");
|
|
8605
|
+
p13.log.info("Add a provider with anygate providers add, or sign in with anygate providers auth openai.");
|
|
8272
8606
|
return 0;
|
|
8273
8607
|
}
|
|
8274
8608
|
let activeProvider = compatible.find((lp) => lp.id === prefs.lastGeminiProvider) ?? compatible[0];
|
|
8275
8609
|
let selectedModel = activeProvider.models.find((m) => m.id === prefs.lastGeminiModel) ?? activeProvider.models[0];
|
|
8276
8610
|
if (!selectedModel) {
|
|
8277
|
-
|
|
8611
|
+
p13.log.error(`Provider "${activeProvider.name}" has no models available.`);
|
|
8278
8612
|
return 1;
|
|
8279
8613
|
}
|
|
8280
8614
|
;
|
|
8281
8615
|
if (launchPlan.skip && launchPlan.target) {
|
|
8282
8616
|
const resolved = findProviderAndModel(compatible, launchPlan.target);
|
|
8283
8617
|
if (!resolved) {
|
|
8284
|
-
|
|
8618
|
+
p13.log.error(
|
|
8285
8619
|
`Provider/model not found: ${launchPlan.target.providerId} / ${launchPlan.target.modelId}`
|
|
8286
8620
|
);
|
|
8287
8621
|
return 1;
|
|
@@ -8289,12 +8623,12 @@ Error: ${launchPlan.error}
|
|
|
8289
8623
|
activeProvider = resolved.provider;
|
|
8290
8624
|
selectedModel = resolved.model;
|
|
8291
8625
|
if (!agentStdout) {
|
|
8292
|
-
|
|
8626
|
+
p13.log.step(`Using ${selectedModel.name || selectedModel.id} (${activeProvider.name})`);
|
|
8293
8627
|
}
|
|
8294
8628
|
} else {
|
|
8295
8629
|
if (!agentStdout) {
|
|
8296
8630
|
console.log("");
|
|
8297
|
-
|
|
8631
|
+
p13.log.info(`Launching ${pc11.bold("Gemini CLI")} with anygate`);
|
|
8298
8632
|
}
|
|
8299
8633
|
const chosenProvider = await pickGeminiProvider(
|
|
8300
8634
|
compatible,
|
|
@@ -8326,7 +8660,7 @@ Error: ${launchPlan.error}
|
|
|
8326
8660
|
recordLaunchSelection("gemini", activeProvider.id, selectedModel.id, prefs);
|
|
8327
8661
|
const launchApiKey = await resolveLocalProviderApiKey(activeProvider);
|
|
8328
8662
|
if (!launchApiKey?.trim()) {
|
|
8329
|
-
|
|
8663
|
+
p13.log.error(
|
|
8330
8664
|
new CredentialUnavailableError(activeProvider.id).userMessage
|
|
8331
8665
|
);
|
|
8332
8666
|
return 1;
|
|
@@ -8422,14 +8756,14 @@ Error: ${launchPlan.error}
|
|
|
8422
8756
|
oauthBackend = backendRoutes.backend;
|
|
8423
8757
|
proxyHandle = await startGeminiProxy(finalRoutes, trace);
|
|
8424
8758
|
} catch (err) {
|
|
8425
|
-
|
|
8759
|
+
p13.log.error(`Failed to start Gemini proxy: ${err instanceof Error ? err.message : String(err)}`);
|
|
8426
8760
|
oauthBackend?.handle.close();
|
|
8427
8761
|
return 1;
|
|
8428
8762
|
}
|
|
8429
8763
|
const childEnv = prepareGeminiChildEnv(proxyHandle.port, proxyHandle.token);
|
|
8430
8764
|
if (!agentStdout) {
|
|
8431
|
-
|
|
8432
|
-
|
|
8765
|
+
p13.log.info(`Gemini proxy started on port ${proxyHandle.port}`);
|
|
8766
|
+
p13.log.info(`\u{1F4A1} Type ${pc11.bold(".model <id>")} in the chat to switch models mid-session.`);
|
|
8433
8767
|
}
|
|
8434
8768
|
let exitCode = 1;
|
|
8435
8769
|
try {
|
|
@@ -8440,7 +8774,7 @@ Error: ${launchPlan.error}
|
|
|
8440
8774
|
oauthBackend?.handle.close();
|
|
8441
8775
|
}
|
|
8442
8776
|
if (!agentStdout) {
|
|
8443
|
-
|
|
8777
|
+
p13.log.info("Gemini proxy stopped.");
|
|
8444
8778
|
}
|
|
8445
8779
|
if (trace) {
|
|
8446
8780
|
printTraceLog(getGeminiProxyDebugLogPath());
|
|
@@ -8451,7 +8785,7 @@ Error: ${launchPlan.error}
|
|
|
8451
8785
|
// src/cli/gemini.ts
|
|
8452
8786
|
async function handleGeminiCommand(parsed) {
|
|
8453
8787
|
if (parsed.showVersion) {
|
|
8454
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
8788
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
8455
8789
|
console.log(VERSION2);
|
|
8456
8790
|
return 0;
|
|
8457
8791
|
}
|
|
@@ -8467,8 +8801,8 @@ async function handleGeminiCommand(parsed) {
|
|
|
8467
8801
|
|
|
8468
8802
|
// src/apps/gemini/antigravity.ts
|
|
8469
8803
|
init_config();
|
|
8470
|
-
import
|
|
8471
|
-
import * as
|
|
8804
|
+
import pc12 from "picocolors";
|
|
8805
|
+
import * as p14 from "@clack/prompts";
|
|
8472
8806
|
import { appendFileSync as appendFileSync2 } from "fs";
|
|
8473
8807
|
|
|
8474
8808
|
// src/gateway/antigravity/cloud-code-gateway.ts
|
|
@@ -10171,7 +10505,7 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10171
10505
|
const templateKey = opts.templateKey ?? "gemini-3.5-flash-low";
|
|
10172
10506
|
const trace = opts.trace ?? false;
|
|
10173
10507
|
const trackActiveRoute = opts.trackActiveRoute ?? false;
|
|
10174
|
-
const
|
|
10508
|
+
const log17 = opts.logFn ?? (() => {
|
|
10175
10509
|
});
|
|
10176
10510
|
const catalogFixture = fetchAvailableModels_default;
|
|
10177
10511
|
const injectedCatalog = injectGatewayModels(catalogFixture, routes, templateKey);
|
|
@@ -10221,12 +10555,12 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10221
10555
|
const contentType = (req.headers["content-type"] ?? "").toLowerCase();
|
|
10222
10556
|
const lowerUrl = url.toLowerCase();
|
|
10223
10557
|
if (trace) {
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10558
|
+
log17(`[gateway] ${method} ${url}`);
|
|
10559
|
+
log17(`[gateway] content-type: ${contentType}`);
|
|
10560
|
+
log17(`[gateway] body-size: ${bodyStr.length}`);
|
|
10227
10561
|
}
|
|
10228
10562
|
if (contentType.includes("proto") || contentType.includes("grpc") && !contentType.includes("json")) {
|
|
10229
|
-
|
|
10563
|
+
log17(`[gateway] UNSUPPORTED content-type: ${contentType}`);
|
|
10230
10564
|
respondJson(res, 415, {
|
|
10231
10565
|
error: {
|
|
10232
10566
|
code: 415,
|
|
@@ -10242,35 +10576,35 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10242
10576
|
}
|
|
10243
10577
|
if (trace && parsed) {
|
|
10244
10578
|
const preview = JSON.stringify(parsed).slice(0, 500);
|
|
10245
|
-
|
|
10579
|
+
log17(`[gateway] body-preview: ${preview}`);
|
|
10246
10580
|
}
|
|
10247
10581
|
if (lowerUrl.includes("loadcodeassist")) {
|
|
10248
|
-
if (trace)
|
|
10582
|
+
if (trace) log17("[gateway] \u2192 loadCodeAssist");
|
|
10249
10583
|
respondJson(res, 200, loadCodeAssist_default);
|
|
10250
10584
|
return;
|
|
10251
10585
|
}
|
|
10252
10586
|
if (lowerUrl.includes("fetchavailablemodels") || lowerUrl.includes("getavailablemodels")) {
|
|
10253
|
-
if (trace)
|
|
10587
|
+
if (trace) log17("[gateway] \u2192 fetchAvailableModels");
|
|
10254
10588
|
respondJson(res, 200, injectedCatalog);
|
|
10255
10589
|
return;
|
|
10256
10590
|
}
|
|
10257
10591
|
if (lowerUrl.includes("modelconfigs")) {
|
|
10258
|
-
if (trace)
|
|
10592
|
+
if (trace) log17("[gateway] \u2192 listModelConfigs");
|
|
10259
10593
|
respondJson(res, 200, modelConfigsResponse);
|
|
10260
10594
|
return;
|
|
10261
10595
|
}
|
|
10262
10596
|
if (lowerUrl.includes("generatecontent") || lowerUrl.includes("generatechat")) {
|
|
10263
10597
|
const model = parsed?.model;
|
|
10264
|
-
if (trace)
|
|
10598
|
+
if (trace) log17(`[gateway] extracted model: ${model ?? "N/A"}`);
|
|
10265
10599
|
const route = resolveRouteForModel(model);
|
|
10266
10600
|
if (route) {
|
|
10267
10601
|
if (trackActiveRoute && selectedSlotIds.has(model ?? "") && isUserTurnRequest(parsed)) {
|
|
10268
10602
|
activeRoute = route;
|
|
10269
|
-
if (trace)
|
|
10603
|
+
if (trace) log17(`[gateway] active route: ${route.catalogId} via ${model}`);
|
|
10270
10604
|
}
|
|
10271
10605
|
if (isCloudCodeOAuthRoute(route)) {
|
|
10272
|
-
handleCloudCodeForwardRequest(res, route, parsed, lowerUrl,
|
|
10273
|
-
|
|
10606
|
+
handleCloudCodeForwardRequest(res, route, parsed, lowerUrl, log17).catch((err) => {
|
|
10607
|
+
log17(`[gateway] cloud-code forward error: ${err instanceof Error ? err.stack || err.message : String(err)}`);
|
|
10274
10608
|
if (!res.headersSent) {
|
|
10275
10609
|
respondJson(res, 500, { error: { code: 500, message: formatUpstreamError(err) } });
|
|
10276
10610
|
} else if (!res.writableEnded) {
|
|
@@ -10288,11 +10622,11 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10288
10622
|
rememberReasoningEcho(reasoningEchoesByConversation, conversationKey, reasoning);
|
|
10289
10623
|
};
|
|
10290
10624
|
if (isStream) {
|
|
10291
|
-
handleStreamingRequest(res, route, baseProviderOptions, parsed,
|
|
10625
|
+
handleStreamingRequest(res, route, baseProviderOptions, parsed, log17, {
|
|
10292
10626
|
requestOptions,
|
|
10293
10627
|
onReasoningWithToolCall: rememberReasoning
|
|
10294
10628
|
}).catch((err) => {
|
|
10295
|
-
|
|
10629
|
+
log17(`[gateway] stream error: ${err instanceof Error ? err.stack || err.message : String(err)}`);
|
|
10296
10630
|
if (!res.headersSent) {
|
|
10297
10631
|
respondJson(res, 500, { error: { code: 500, message: formatUpstreamError(err) } });
|
|
10298
10632
|
} else if (!res.writableEnded) {
|
|
@@ -10300,11 +10634,11 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10300
10634
|
}
|
|
10301
10635
|
});
|
|
10302
10636
|
} else {
|
|
10303
|
-
handleUnaryRequest(res, route, baseProviderOptions, parsed,
|
|
10637
|
+
handleUnaryRequest(res, route, baseProviderOptions, parsed, log17, {
|
|
10304
10638
|
requestOptions,
|
|
10305
10639
|
onReasoningWithToolCall: rememberReasoning
|
|
10306
10640
|
}).catch((err) => {
|
|
10307
|
-
|
|
10641
|
+
log17(`[gateway] unary error: ${err instanceof Error ? err.stack || err.message : String(err)}`);
|
|
10308
10642
|
if (!res.headersSent) {
|
|
10309
10643
|
respondJson(res, 500, { error: { code: 500, message: formatUpstreamError(err) } });
|
|
10310
10644
|
}
|
|
@@ -10400,7 +10734,7 @@ async function startCloudCodeGateway(routes, opts = {}) {
|
|
|
10400
10734
|
return;
|
|
10401
10735
|
}
|
|
10402
10736
|
if (trace) {
|
|
10403
|
-
|
|
10737
|
+
log17(`[gateway] unknown endpoint: ${url}`);
|
|
10404
10738
|
}
|
|
10405
10739
|
respondJson(res, 200, {});
|
|
10406
10740
|
}).catch((err) => {
|
|
@@ -10486,7 +10820,7 @@ function rememberReasoningEcho(cache, key, reasoning) {
|
|
|
10486
10820
|
existing.push(normalized);
|
|
10487
10821
|
cache.set(key, existing.slice(-MAX_REASONING_ECHOES_PER_CONVERSATION));
|
|
10488
10822
|
}
|
|
10489
|
-
async function handleCloudCodeForwardRequest(res, route, parsed, lowerUrl,
|
|
10823
|
+
async function handleCloudCodeForwardRequest(res, route, parsed, lowerUrl, log17) {
|
|
10490
10824
|
const projectId = typeof route.providerData?.projectId === "string" ? route.providerData.projectId : "";
|
|
10491
10825
|
if (!projectId) {
|
|
10492
10826
|
respondJson(res, 500, {
|
|
@@ -10515,7 +10849,7 @@ async function handleCloudCodeForwardRequest(res, route, parsed, lowerUrl, log16
|
|
|
10515
10849
|
});
|
|
10516
10850
|
if (!upstream.ok) {
|
|
10517
10851
|
const errBody = await upstream.text();
|
|
10518
|
-
|
|
10852
|
+
log17(`[gateway] cloud-code upstream error ${upstream.status}: ${errBody}`);
|
|
10519
10853
|
respondJson(res, upstream.status >= 500 ? 502 : upstream.status, {
|
|
10520
10854
|
error: { code: upstream.status, message: errBody || upstream.statusText }
|
|
10521
10855
|
});
|
|
@@ -10677,7 +11011,7 @@ function respondJson(res, status, data) {
|
|
|
10677
11011
|
});
|
|
10678
11012
|
res.end(body);
|
|
10679
11013
|
}
|
|
10680
|
-
async function handleStreamingRequest(res, route, providerOptions, parsed,
|
|
11014
|
+
async function handleStreamingRequest(res, route, providerOptions, parsed, log17, options = {}) {
|
|
10681
11015
|
const sdkParams = applyClaudeCodeOAuthIdentity(route, translateRequest(parsed, {
|
|
10682
11016
|
...options.requestOptions,
|
|
10683
11017
|
maxTools: maxToolsForNpm(route.npm)
|
|
@@ -10718,21 +11052,21 @@ async function handleStreamingRequest(res, route, providerOptions, parsed, log16
|
|
|
10718
11052
|
let responseReasoning = "";
|
|
10719
11053
|
let sawToolCall = false;
|
|
10720
11054
|
for await (const part of fullStream) {
|
|
10721
|
-
const
|
|
10722
|
-
if (
|
|
10723
|
-
const reasoning = reasoningDeltaText(
|
|
11055
|
+
const p18 = part;
|
|
11056
|
+
if (p18.type === "reasoning-delta" || p18.type === "reasoning") {
|
|
11057
|
+
const reasoning = reasoningDeltaText(p18);
|
|
10724
11058
|
responseReasoning += reasoning;
|
|
10725
11059
|
emitThinkingDelta(res, route, responseId, reasoning, startSse);
|
|
10726
11060
|
continue;
|
|
10727
11061
|
}
|
|
10728
|
-
if (
|
|
10729
|
-
const { thought, text: text4 } = thinkFilter(reasoningDeltaText(
|
|
11062
|
+
if (p18.type === "text-delta") {
|
|
11063
|
+
const { thought, text: text4 } = thinkFilter(reasoningDeltaText(p18));
|
|
10730
11064
|
if (thought) {
|
|
10731
11065
|
responseReasoning += thought;
|
|
10732
11066
|
emitThinkingDelta(res, route, responseId, thought, startSse);
|
|
10733
11067
|
}
|
|
10734
11068
|
if (text4) {
|
|
10735
|
-
|
|
11069
|
+
log17(`[gateway] text-delta: ${JSON.stringify(text4.slice(0, 500))}`);
|
|
10736
11070
|
startSse();
|
|
10737
11071
|
const chunk = formatCloudCodeChunk({
|
|
10738
11072
|
text: text4,
|
|
@@ -10743,25 +11077,25 @@ async function handleStreamingRequest(res, route, providerOptions, parsed, log16
|
|
|
10743
11077
|
|
|
10744
11078
|
`);
|
|
10745
11079
|
}
|
|
10746
|
-
} else if (
|
|
10747
|
-
const id =
|
|
10748
|
-
toolCallBuffers.set(id, { name:
|
|
10749
|
-
} else if (
|
|
10750
|
-
const id =
|
|
11080
|
+
} else if (p18.type === "tool-input-start") {
|
|
11081
|
+
const id = p18.id ?? p18.toolCallId;
|
|
11082
|
+
toolCallBuffers.set(id, { name: p18.toolName, json: "" });
|
|
11083
|
+
} else if (p18.type === "tool-input-delta") {
|
|
11084
|
+
const id = p18.id ?? p18.toolCallId;
|
|
10751
11085
|
const buf = toolCallBuffers.get(id);
|
|
10752
|
-
if (buf) buf.json +=
|
|
10753
|
-
} else if (
|
|
11086
|
+
if (buf) buf.json += p18.delta;
|
|
11087
|
+
} else if (p18.type === "tool-call") {
|
|
10754
11088
|
sawToolCall = true;
|
|
10755
|
-
const id =
|
|
11089
|
+
const id = p18.toolCallId ?? p18.id;
|
|
10756
11090
|
const buf = toolCallBuffers.get(id);
|
|
10757
11091
|
let args = {};
|
|
10758
11092
|
try {
|
|
10759
|
-
args = buf ? JSON.parse(buf.json || "{}") :
|
|
11093
|
+
args = buf ? JSON.parse(buf.json || "{}") : p18.input || {};
|
|
10760
11094
|
} catch {
|
|
10761
|
-
args =
|
|
11095
|
+
args = p18.input || {};
|
|
10762
11096
|
}
|
|
10763
|
-
const name = buf ? buf.name :
|
|
10764
|
-
|
|
11097
|
+
const name = buf ? buf.name : p18.toolName;
|
|
11098
|
+
log17(`[gateway] tool-call: ${name}`);
|
|
10765
11099
|
startSse();
|
|
10766
11100
|
const chunk = formatCloudCodeChunk({
|
|
10767
11101
|
functionCall: { name, args: normalizeFunctionCallArgs(args) },
|
|
@@ -10771,17 +11105,17 @@ async function handleStreamingRequest(res, route, providerOptions, parsed, log16
|
|
|
10771
11105
|
res.write(`data: ${JSON.stringify(chunk)}
|
|
10772
11106
|
|
|
10773
11107
|
`);
|
|
10774
|
-
} else if (
|
|
10775
|
-
|
|
11108
|
+
} else if (p18.type === "finish") {
|
|
11109
|
+
log17(`[gateway] finish: ${p18.finishReason ?? "unknown"}`);
|
|
10776
11110
|
startSse();
|
|
10777
|
-
const reason = mapFinishReason2(
|
|
11111
|
+
const reason = mapFinishReason2(p18.finishReason ?? "");
|
|
10778
11112
|
const chunk = formatCloudCodeChunk({
|
|
10779
11113
|
modelVersion: route.catalogId,
|
|
10780
11114
|
responseId,
|
|
10781
11115
|
finishReason: reason,
|
|
10782
11116
|
usage: {
|
|
10783
|
-
promptTokens:
|
|
10784
|
-
completionTokens:
|
|
11117
|
+
promptTokens: p18.totalUsage?.inputTokens || 0,
|
|
11118
|
+
completionTokens: p18.totalUsage?.outputTokens || 0
|
|
10785
11119
|
}
|
|
10786
11120
|
});
|
|
10787
11121
|
res.write(`data: ${JSON.stringify(chunk)}
|
|
@@ -10793,16 +11127,16 @@ async function handleStreamingRequest(res, route, providerOptions, parsed, log16
|
|
|
10793
11127
|
npm: route.npm,
|
|
10794
11128
|
providerId: route.providerId,
|
|
10795
11129
|
app: "Antigravity",
|
|
10796
|
-
inputTokens:
|
|
10797
|
-
outputTokens:
|
|
11130
|
+
inputTokens: p18.totalUsage?.inputTokens ?? 0,
|
|
11131
|
+
outputTokens: p18.totalUsage?.outputTokens ?? 0
|
|
10798
11132
|
});
|
|
10799
|
-
} else if (
|
|
10800
|
-
const message = formatUpstreamError(
|
|
10801
|
-
|
|
11133
|
+
} else if (p18.type === "error") {
|
|
11134
|
+
const message = formatUpstreamError(p18.error);
|
|
11135
|
+
log17(`[gateway] stream provider error: ${message}`);
|
|
10802
11136
|
emitStreamError(res, route, responseId, message, startSse);
|
|
10803
11137
|
break;
|
|
10804
|
-
} else if (
|
|
10805
|
-
|
|
11138
|
+
} else if (p18.type === "reasoning-start" || p18.type === "reasoning-end") {
|
|
11139
|
+
log17(`[gateway] ${p18.type}`);
|
|
10806
11140
|
}
|
|
10807
11141
|
}
|
|
10808
11142
|
if (!res.headersSent) {
|
|
@@ -11370,11 +11704,11 @@ function resolveAntigravityBootModel(provider, modelSelector) {
|
|
|
11370
11704
|
async function pickAntigravityCliFavoriteLaunchModel(favorites, allProviders) {
|
|
11371
11705
|
const resolved = favorites.map((favorite) => resolveFavoriteModel(favorite, allProviders)).filter((entry) => entry !== null);
|
|
11372
11706
|
if (resolved.length === 0) {
|
|
11373
|
-
|
|
11374
|
-
|
|
11707
|
+
p14.log.warn("No Antigravity CLI favorites are available.");
|
|
11708
|
+
p14.log.info(pc12.dim("Manage them with `anygate favorites --agy`."));
|
|
11375
11709
|
return null;
|
|
11376
11710
|
}
|
|
11377
|
-
const picked = await
|
|
11711
|
+
const picked = await p14.select({
|
|
11378
11712
|
message: "Launch from Antigravity CLI favorites",
|
|
11379
11713
|
options: resolved.map(({ provider, model }) => ({
|
|
11380
11714
|
value: `${provider.id}:${model.id}`,
|
|
@@ -11383,8 +11717,8 @@ async function pickAntigravityCliFavoriteLaunchModel(favorites, allProviders) {
|
|
|
11383
11717
|
})),
|
|
11384
11718
|
initialValue: `${resolved[0].provider.id}:${resolved[0].model.id}`
|
|
11385
11719
|
});
|
|
11386
|
-
if (
|
|
11387
|
-
|
|
11720
|
+
if (p14.isCancel(picked)) {
|
|
11721
|
+
p14.cancel("Cancelled.");
|
|
11388
11722
|
return null;
|
|
11389
11723
|
}
|
|
11390
11724
|
const [providerId, ...modelParts] = picked.split(":");
|
|
@@ -11393,31 +11727,31 @@ async function pickAntigravityCliFavoriteLaunchModel(favorites, allProviders) {
|
|
|
11393
11727
|
}
|
|
11394
11728
|
async function resolveAntigravityLaunch(prefs, boot) {
|
|
11395
11729
|
let catalog;
|
|
11396
|
-
const catalogSpinner =
|
|
11730
|
+
const catalogSpinner = p14.spinner();
|
|
11397
11731
|
catalogSpinner.start("Loading providers...");
|
|
11398
11732
|
try {
|
|
11399
11733
|
catalog = await fetchProviderCatalog();
|
|
11400
11734
|
} catch (err) {
|
|
11401
11735
|
catalogSpinner.stop("");
|
|
11402
|
-
|
|
11736
|
+
p14.log.error(String(err instanceof Error ? err.message : err));
|
|
11403
11737
|
return null;
|
|
11404
11738
|
}
|
|
11405
11739
|
catalogSpinner.stop("");
|
|
11406
11740
|
const allProviders = providersForTarget(providersForPicker(catalog), "antigravity");
|
|
11407
11741
|
if (allProviders.length === 0) {
|
|
11408
|
-
|
|
11409
|
-
|
|
11742
|
+
p14.log.warn("No providers available.");
|
|
11743
|
+
p14.log.info(pc12.dim("Run anygate providers add or import to get started."));
|
|
11410
11744
|
return null;
|
|
11411
11745
|
}
|
|
11412
11746
|
if (boot?.launchProvider && boot?.launchModel) {
|
|
11413
|
-
const provider = allProviders.find((
|
|
11747
|
+
const provider = allProviders.find((p18) => p18.id === boot.launchProvider);
|
|
11414
11748
|
if (!provider) {
|
|
11415
|
-
|
|
11749
|
+
p14.log.error(`Provider not found: ${boot.launchProvider}`);
|
|
11416
11750
|
return null;
|
|
11417
11751
|
}
|
|
11418
11752
|
const { model, error } = resolveAntigravityBootModel(provider, boot.launchModel);
|
|
11419
11753
|
if (!model) {
|
|
11420
|
-
|
|
11754
|
+
p14.log.error(error ?? `Model not found: ${boot.launchModel} on provider ${provider.name}`);
|
|
11421
11755
|
return null;
|
|
11422
11756
|
}
|
|
11423
11757
|
return { provider, model, allProviders };
|
|
@@ -11425,7 +11759,7 @@ async function resolveAntigravityLaunch(prefs, boot) {
|
|
|
11425
11759
|
const providerOptions = [
|
|
11426
11760
|
{
|
|
11427
11761
|
value: AGY_FAVORITES_PROVIDER_ID,
|
|
11428
|
-
label:
|
|
11762
|
+
label: pc12.cyan(AGY_FAVORITES_PROVIDER_LABEL),
|
|
11429
11763
|
hint: `${prefs.antigravityCliFavoriteModels?.length ?? 0}/6 saved \xB7 manage with anygate favorites --agy`
|
|
11430
11764
|
},
|
|
11431
11765
|
...allProviders.map((lp) => providerSelectOption(lp))
|
|
@@ -11434,13 +11768,13 @@ async function resolveAntigravityLaunch(prefs, boot) {
|
|
|
11434
11768
|
const conflicts = detectConflicts();
|
|
11435
11769
|
let currentInitialProvider = initialProvider;
|
|
11436
11770
|
while (true) {
|
|
11437
|
-
const chosen = await
|
|
11771
|
+
const chosen = await p14.select({
|
|
11438
11772
|
message: "Which provider?",
|
|
11439
11773
|
options: providerOptions,
|
|
11440
11774
|
initialValue: currentInitialProvider
|
|
11441
11775
|
});
|
|
11442
|
-
if (
|
|
11443
|
-
|
|
11776
|
+
if (p14.isCancel(chosen)) {
|
|
11777
|
+
p14.cancel("Cancelled.");
|
|
11444
11778
|
return null;
|
|
11445
11779
|
}
|
|
11446
11780
|
if (chosen === AGY_FAVORITES_PROVIDER_ID) {
|
|
@@ -11473,32 +11807,32 @@ async function resolveAndBuildRoutes(provider, model, allProviders, prefs, opts)
|
|
|
11473
11807
|
maxRoutes: opts.maxRoutes
|
|
11474
11808
|
});
|
|
11475
11809
|
if (!result) {
|
|
11476
|
-
|
|
11810
|
+
p14.log.error(new CredentialUnavailableError(provider.id).userMessage);
|
|
11477
11811
|
return null;
|
|
11478
11812
|
}
|
|
11479
11813
|
if (result.routes.length > 1) {
|
|
11480
|
-
|
|
11814
|
+
p14.log.info(
|
|
11481
11815
|
`Favorites mode active \u2014 Antigravity picker will show ${result.routes.length} models.`
|
|
11482
11816
|
);
|
|
11483
|
-
|
|
11817
|
+
p14.log.info("Edit with `anygate favorites --agy`.");
|
|
11484
11818
|
}
|
|
11485
11819
|
if (result.droppedFavorites.length > 0) {
|
|
11486
|
-
|
|
11820
|
+
p14.log.warn(
|
|
11487
11821
|
`Skipped ${result.droppedFavorites.length} stale/unauthorized favorite(s): ` + result.droppedFavorites.map((fav) => `${fav.providerId}:${fav.modelId}`).join(", ")
|
|
11488
11822
|
);
|
|
11489
11823
|
}
|
|
11490
11824
|
if (result.capacitySkippedFavorites.length > 0) {
|
|
11491
|
-
|
|
11492
|
-
|
|
11825
|
+
p14.log.warn(formatAgyCapacityWarning(opts.validatedSlotCount, result.capacitySkippedFavorites.length));
|
|
11826
|
+
p14.log.warn(
|
|
11493
11827
|
"Not exposed: " + result.capacitySkippedFavorites.map((fav) => `${fav.providerId}:${fav.modelId}`).join(", ")
|
|
11494
11828
|
);
|
|
11495
11829
|
if (opts.pauseForCapacityWarning && isInteractiveTerminal() && !agyArgsAreNonInteractive(opts.childArgs)) {
|
|
11496
|
-
const proceed = await
|
|
11830
|
+
const proceed = await p14.confirm({
|
|
11497
11831
|
message: "Continue with the validated AGY switch catalog?",
|
|
11498
11832
|
initialValue: true
|
|
11499
11833
|
});
|
|
11500
|
-
if (
|
|
11501
|
-
|
|
11834
|
+
if (p14.isCancel(proceed) || !proceed) {
|
|
11835
|
+
p14.cancel("Cancelled.");
|
|
11502
11836
|
return null;
|
|
11503
11837
|
}
|
|
11504
11838
|
}
|
|
@@ -11533,27 +11867,27 @@ async function runAntigravityCommand(intro, tracePrefix, trace, boot, launch, op
|
|
|
11533
11867
|
const prefs = loadPreferences();
|
|
11534
11868
|
gateIntro(intro);
|
|
11535
11869
|
if (tracePrefix === "agy" && (prefs.favoriteModels?.length ?? 0) > 0 && (prefs.antigravityCliFavoriteModels?.length ?? 0) === 0 && !prefs.antigravityCliFavoritesHintShown) {
|
|
11536
|
-
|
|
11870
|
+
p14.log.info("Tip: AGY uses its own favorites list. Run `anygate favorites --agy` to set up switching.");
|
|
11537
11871
|
savePreferences({ antigravityCliFavoritesHintShown: true });
|
|
11538
11872
|
}
|
|
11539
11873
|
const agyFavorites = prefs.antigravityCliFavoriteModels ?? [];
|
|
11540
11874
|
if (opts.useFavoritesCatalog && agyFavorites.length > 0) {
|
|
11541
|
-
const catalogSpinner =
|
|
11875
|
+
const catalogSpinner = p14.spinner();
|
|
11542
11876
|
catalogSpinner.start("Loading providers...");
|
|
11543
11877
|
let catalog;
|
|
11544
11878
|
try {
|
|
11545
11879
|
catalog = await fetchProviderCatalog();
|
|
11546
11880
|
} catch (err) {
|
|
11547
11881
|
catalogSpinner.stop("");
|
|
11548
|
-
|
|
11882
|
+
p14.log.error(String(err instanceof Error ? err.message : err));
|
|
11549
11883
|
return 1;
|
|
11550
11884
|
}
|
|
11551
11885
|
catalogSpinner.stop("");
|
|
11552
11886
|
const allProviders = providersForTarget(providersForPicker(catalog), "antigravity");
|
|
11553
11887
|
const firstFavorite = resolveFirstAvailableFavorite(agyFavorites, allProviders);
|
|
11554
11888
|
if (!firstFavorite) {
|
|
11555
|
-
|
|
11556
|
-
|
|
11889
|
+
p14.log.warn("No Antigravity CLI favorites are currently available.");
|
|
11890
|
+
p14.log.info(pc12.dim("Manage them with `anygate favorites --agy`."));
|
|
11557
11891
|
return 1;
|
|
11558
11892
|
}
|
|
11559
11893
|
const selection2 = { provider: firstFavorite.provider, model: firstFavorite.model, allProviders };
|
|
@@ -11572,7 +11906,7 @@ async function launchWithSelection(selection, prefs, opts, trace, tracePrefix, b
|
|
|
11572
11906
|
fixture: fetchAvailableModels_default
|
|
11573
11907
|
});
|
|
11574
11908
|
for (const warning of compatibility.warnings) {
|
|
11575
|
-
|
|
11909
|
+
p14.log.warn(warning);
|
|
11576
11910
|
}
|
|
11577
11911
|
const routeLimit = compatibility.mode === "multi-model" ? compatibility.validatedSwitchSlotCount : 1;
|
|
11578
11912
|
const routeResult = await resolveAndBuildRoutes(provider, model, allProviders, prefs, {
|
|
@@ -11598,12 +11932,12 @@ async function launchWithSelection(selection, prefs, opts, trace, tracePrefix, b
|
|
|
11598
11932
|
try {
|
|
11599
11933
|
gatewayHandle = await startCloudCodeGateway(routeResult.routes, { trace, logFn });
|
|
11600
11934
|
} catch (err) {
|
|
11601
|
-
|
|
11935
|
+
p14.log.error(`Failed to start Cloud Code gateway: ${err}`);
|
|
11602
11936
|
return 1;
|
|
11603
11937
|
}
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
if (trace)
|
|
11938
|
+
p14.log.info(`Cloud Code gateway on ${pc12.cyan(`127.0.0.1:${gatewayHandle.port}`)}`);
|
|
11939
|
+
p14.log.success(`Active model: ${formatCodexModelLabel(model)} ${pc12.dim("via")} ${provider.name}`);
|
|
11940
|
+
if (trace) p14.log.info(`Gateway trace \u2192 ${pc12.dim(traceLogPath)}`);
|
|
11607
11941
|
gateOutro("Launching", `${formatCodexModelLabel(model)} (${provider.name})`);
|
|
11608
11942
|
try {
|
|
11609
11943
|
const cleanEnv = buildAntigravityChildEnv(gatewayHandle.url);
|
|
@@ -11631,12 +11965,12 @@ async function runAntigravityAppCommand(childArgs, trace = false, boot) {
|
|
|
11631
11965
|
async (env, _routes, gatewayHandle) => {
|
|
11632
11966
|
const profileDir = join12(homedir10(), ".anygate", "antigravity", "app-profile");
|
|
11633
11967
|
if (isAntigravityAppRunning(profileDir)) {
|
|
11634
|
-
const restart = await
|
|
11968
|
+
const restart = await p14.confirm({
|
|
11635
11969
|
message: "Restart Antigravity to apply this Gateway gateway?",
|
|
11636
11970
|
initialValue: true
|
|
11637
11971
|
});
|
|
11638
|
-
if (
|
|
11639
|
-
|
|
11972
|
+
if (p14.isCancel(restart) || !restart) {
|
|
11973
|
+
p14.log.info("Quit and reopen Antigravity when you are ready for the new gateway to take effect.");
|
|
11640
11974
|
return 0;
|
|
11641
11975
|
}
|
|
11642
11976
|
quitAntigravityAppGracefully();
|
|
@@ -11647,18 +11981,18 @@ async function runAntigravityAppCommand(childArgs, trace = false, boot) {
|
|
|
11647
11981
|
}
|
|
11648
11982
|
const launchCode = await launchAntigravityApp(env, profileDir, gatewayHandle.url, childArgs);
|
|
11649
11983
|
if (launchCode !== 0) return launchCode;
|
|
11650
|
-
|
|
11651
|
-
|
|
11984
|
+
p14.log.info("Antigravity is using the Gateway Cloud Code gateway.");
|
|
11985
|
+
p14.log.info(pc12.cyan("Press Ctrl+C to stop the gateway."));
|
|
11652
11986
|
await waitForShutdown3();
|
|
11653
11987
|
await new Promise((r) => setTimeout(r, SHUTDOWN_DRAIN_MS));
|
|
11654
11988
|
console.log("");
|
|
11655
|
-
|
|
11656
|
-
const shouldClose = await
|
|
11989
|
+
p14.log.step("Gateway stopped.");
|
|
11990
|
+
const shouldClose = await p14.confirm({
|
|
11657
11991
|
message: "Close Antigravity?",
|
|
11658
11992
|
initialValue: true
|
|
11659
11993
|
});
|
|
11660
|
-
if (!
|
|
11661
|
-
|
|
11994
|
+
if (!p14.isCancel(shouldClose) && shouldClose) {
|
|
11995
|
+
p14.log.step("Stopping Antigravity...");
|
|
11662
11996
|
quitAntigravityAppGracefully();
|
|
11663
11997
|
if (!await waitForAntigravityAppQuit(profileDir)) {
|
|
11664
11998
|
forceQuitAntigravityApp(profileDir);
|
|
@@ -11679,12 +12013,12 @@ async function runAntigravityIdeCommand(childArgs, trace = false, boot) {
|
|
|
11679
12013
|
async (env, _routes, gatewayHandle) => {
|
|
11680
12014
|
const profileDir = join12(homedir10(), ".anygate", "antigravity", "profile");
|
|
11681
12015
|
if (isAntigravityIdeRunning(profileDir)) {
|
|
11682
|
-
const restart = await
|
|
12016
|
+
const restart = await p14.confirm({
|
|
11683
12017
|
message: "Restart Antigravity IDE to apply this Gateway gateway?",
|
|
11684
12018
|
initialValue: true
|
|
11685
12019
|
});
|
|
11686
|
-
if (
|
|
11687
|
-
|
|
12020
|
+
if (p14.isCancel(restart) || !restart) {
|
|
12021
|
+
p14.log.info("Quit and reopen Antigravity IDE when you are ready for the new gateway to take effect.");
|
|
11688
12022
|
return 0;
|
|
11689
12023
|
}
|
|
11690
12024
|
quitAntigravityIdeGracefully();
|
|
@@ -11695,18 +12029,18 @@ async function runAntigravityIdeCommand(childArgs, trace = false, boot) {
|
|
|
11695
12029
|
}
|
|
11696
12030
|
const launchCode = await launchAntigravityIde(env, profileDir, gatewayHandle.url, childArgs);
|
|
11697
12031
|
if (launchCode !== 0) return launchCode;
|
|
11698
|
-
|
|
11699
|
-
|
|
12032
|
+
p14.log.info("Antigravity IDE is using the Gateway Cloud Code gateway.");
|
|
12033
|
+
p14.log.info(pc12.cyan("Press Ctrl+C to stop the gateway."));
|
|
11700
12034
|
await waitForShutdown3();
|
|
11701
12035
|
await new Promise((r) => setTimeout(r, SHUTDOWN_DRAIN_MS));
|
|
11702
12036
|
console.log("");
|
|
11703
|
-
|
|
11704
|
-
const shouldClose = await
|
|
12037
|
+
p14.log.step("Gateway stopped.");
|
|
12038
|
+
const shouldClose = await p14.confirm({
|
|
11705
12039
|
message: "Close Antigravity IDE?",
|
|
11706
12040
|
initialValue: true
|
|
11707
12041
|
});
|
|
11708
|
-
if (!
|
|
11709
|
-
|
|
12042
|
+
if (!p14.isCancel(shouldClose) && shouldClose) {
|
|
12043
|
+
p14.log.step("Stopping Antigravity IDE...");
|
|
11710
12044
|
quitAntigravityIdeGracefully();
|
|
11711
12045
|
if (!await waitForAntigravityIdeQuit(profileDir)) {
|
|
11712
12046
|
forceQuitAntigravityIde(profileDir);
|
|
@@ -11805,7 +12139,7 @@ Examples:
|
|
|
11805
12139
|
`;
|
|
11806
12140
|
async function handleAgyCommand(parsed) {
|
|
11807
12141
|
if (parsed.showVersion) {
|
|
11808
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12142
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
11809
12143
|
console.log(VERSION2);
|
|
11810
12144
|
return 0;
|
|
11811
12145
|
}
|
|
@@ -11820,7 +12154,7 @@ async function handleAgyCommand(parsed) {
|
|
|
11820
12154
|
}
|
|
11821
12155
|
async function handleAntigravityAppCommand(parsed) {
|
|
11822
12156
|
if (parsed.showVersion) {
|
|
11823
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12157
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
11824
12158
|
console.log(VERSION2);
|
|
11825
12159
|
return 0;
|
|
11826
12160
|
}
|
|
@@ -11835,7 +12169,7 @@ async function handleAntigravityAppCommand(parsed) {
|
|
|
11835
12169
|
}
|
|
11836
12170
|
async function handleAntigravityIdeCommand(parsed) {
|
|
11837
12171
|
if (parsed.showVersion) {
|
|
11838
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12172
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
11839
12173
|
console.log(VERSION2);
|
|
11840
12174
|
return 0;
|
|
11841
12175
|
}
|
|
@@ -11940,18 +12274,18 @@ Options:
|
|
|
11940
12274
|
`);
|
|
11941
12275
|
return 0;
|
|
11942
12276
|
}
|
|
11943
|
-
const { runUiCommand } = await import("./command-
|
|
12277
|
+
const { runUiCommand } = await import("./command-7AI36ICY.js");
|
|
11944
12278
|
return runUiCommand({ trace: parsed.trace });
|
|
11945
12279
|
}
|
|
11946
12280
|
|
|
11947
12281
|
// src/cli/models.ts
|
|
11948
12282
|
init_config();
|
|
11949
|
-
import
|
|
11950
|
-
import * as
|
|
12283
|
+
import pc14 from "picocolors";
|
|
12284
|
+
import * as p16 from "@clack/prompts";
|
|
11951
12285
|
|
|
11952
12286
|
// src/apps/claude/favorites-picker.ts
|
|
11953
|
-
import * as
|
|
11954
|
-
import
|
|
12287
|
+
import * as p15 from "@clack/prompts";
|
|
12288
|
+
import pc13 from "picocolors";
|
|
11955
12289
|
|
|
11956
12290
|
// src/apps/claude/favorites.ts
|
|
11957
12291
|
function isFavorite(list, fav) {
|
|
@@ -12017,7 +12351,7 @@ function globalFavoriteSelectOption(entry, favorites) {
|
|
|
12017
12351
|
return {
|
|
12018
12352
|
value: globalFavoritePickKey(entry),
|
|
12019
12353
|
label: `${fmtModel(label, entry.model.id)} ${providerTag}`,
|
|
12020
|
-
hint: favorited ?
|
|
12354
|
+
hint: favorited ? pc13.dim("already in favorites") : ""
|
|
12021
12355
|
};
|
|
12022
12356
|
}
|
|
12023
12357
|
function parseGlobalFavoritePickKey(key, index) {
|
|
@@ -12028,25 +12362,25 @@ async function pickGlobalFavoriteModel(providers, favorites, opts) {
|
|
|
12028
12362
|
if (index.length === 0) return null;
|
|
12029
12363
|
const freeOnly = opts?.freeOnly === true;
|
|
12030
12364
|
while (true) {
|
|
12031
|
-
const searchInput = await
|
|
12365
|
+
const searchInput = await p15.text({
|
|
12032
12366
|
message: freeOnly ? `Search free models (${filterGlobalFavoriteIndex(index, "", { freeOnly: true }).length} models):` : `Search all providers (${index.length} models):`,
|
|
12033
12367
|
placeholder: "e.g. deepseek, claude, sonnet"
|
|
12034
12368
|
});
|
|
12035
|
-
if (
|
|
12036
|
-
const fallback = await
|
|
12369
|
+
if (p15.isCancel(searchInput)) {
|
|
12370
|
+
const fallback = await p15.select({
|
|
12037
12371
|
message: "Add a favorite",
|
|
12038
12372
|
options: [
|
|
12039
|
-
{ value: "back", label:
|
|
12040
|
-
{ value: ADD_BY_PROVIDER, label:
|
|
12373
|
+
{ value: "back", label: pc13.cyan("\u2190 Back to favorites"), hint: "" },
|
|
12374
|
+
{ value: ADD_BY_PROVIDER, label: pc13.cyan("Browse by provider \u2192"), hint: "Pick one provider first" }
|
|
12041
12375
|
]
|
|
12042
12376
|
});
|
|
12043
|
-
if (
|
|
12377
|
+
if (p15.isCancel(fallback) || fallback === "back") return null;
|
|
12044
12378
|
if (fallback === ADD_BY_PROVIDER) return ADD_BY_PROVIDER;
|
|
12045
12379
|
continue;
|
|
12046
12380
|
}
|
|
12047
12381
|
const matched = filterGlobalFavoriteIndex(index, String(searchInput), { freeOnly });
|
|
12048
12382
|
if (matched.length === 0) {
|
|
12049
|
-
|
|
12383
|
+
p15.log.warn("No models match \u2014 try a different search");
|
|
12050
12384
|
continue;
|
|
12051
12385
|
}
|
|
12052
12386
|
const result = await pickModelFromPagedList(
|
|
@@ -12064,7 +12398,7 @@ async function pickGlobalFavoriteModel(providers, favorites, opts) {
|
|
|
12064
12398
|
const picked = parseGlobalFavoritePickKey(result.id, matched);
|
|
12065
12399
|
if (!picked) continue;
|
|
12066
12400
|
if (isFavorite(favorites, { providerId: picked.providerId, modelId: picked.model.id })) {
|
|
12067
|
-
|
|
12401
|
+
p15.log.warn(`${picked.model.name || picked.model.id} (${picked.providerName}) is already in your favorites.`);
|
|
12068
12402
|
continue;
|
|
12069
12403
|
}
|
|
12070
12404
|
return picked;
|
|
@@ -12074,12 +12408,15 @@ async function pickGlobalFavoriteModel(providers, favorites, opts) {
|
|
|
12074
12408
|
// src/cli/models.ts
|
|
12075
12409
|
var AGY_CLI_FAVORITES_CAP = 6;
|
|
12076
12410
|
async function runModelsCommand(parsed) {
|
|
12411
|
+
if (parsed.validateSubcommand) {
|
|
12412
|
+
return runValidateSubcommand(parsed);
|
|
12413
|
+
}
|
|
12077
12414
|
const scope = parsed.favoritesAgy ? "agy" : "global";
|
|
12078
12415
|
const maxFavorites = scope === "agy" ? AGY_CLI_FAVORITES_CAP : 20;
|
|
12079
12416
|
const scopeName = scope === "agy" ? "Antigravity CLI Favorites" : "Favorite Models";
|
|
12080
12417
|
const configKey = scope === "agy" ? "antigravityCliFavoriteModels" : "favoriteModels";
|
|
12081
12418
|
gateIntro(scopeName);
|
|
12082
|
-
const spinner10 =
|
|
12419
|
+
const spinner10 = p16.spinner();
|
|
12083
12420
|
spinner10.start("Loading providers...");
|
|
12084
12421
|
const catalog = await fetchProviderCatalog();
|
|
12085
12422
|
spinner10.stop("");
|
|
@@ -12089,8 +12426,8 @@ async function runModelsCommand(parsed) {
|
|
|
12089
12426
|
name: favoriteProviderDisplayName(provider)
|
|
12090
12427
|
}));
|
|
12091
12428
|
if (favoriteProviders.length === 0) {
|
|
12092
|
-
|
|
12093
|
-
|
|
12429
|
+
p16.log.warn("No providers found.");
|
|
12430
|
+
p16.log.info(`OpenCode Zen/Go is always available. Add providers with ${pc14.cyan("anygate providers")}.`);
|
|
12094
12431
|
gateOutro("Done");
|
|
12095
12432
|
return 0;
|
|
12096
12433
|
}
|
|
@@ -12108,50 +12445,50 @@ async function runModelsCommand(parsed) {
|
|
|
12108
12445
|
for (let i = 0; i < favorites.length; i++) {
|
|
12109
12446
|
const fav = favorites[i];
|
|
12110
12447
|
const entry = modelLookup.get(`${fav.providerId}:${fav.modelId}`);
|
|
12111
|
-
const label = entry ? `${fmtEnabledStar(true)} ${fmtModel(entry.modelName)} ${
|
|
12448
|
+
const label = entry ? `${fmtEnabledStar(true)} ${fmtModel(entry.modelName)} ${pc14.dim(`(${entry.providerName})`)}` : pc14.dim(`\u2605 ${fav.modelId} \u2014 provider gone`);
|
|
12112
12449
|
options.push({ value: `fav-${i}`, label, hint: "select to remove" });
|
|
12113
12450
|
}
|
|
12114
12451
|
const atCap = favorites.length >= 20;
|
|
12115
12452
|
options.push({
|
|
12116
12453
|
value: "__add__",
|
|
12117
|
-
label: atCap ?
|
|
12454
|
+
label: atCap ? pc14.dim(`+ Add a model \u2192 (limit of 20 reached)`) : pc14.cyan("+ Add a model \u2192"),
|
|
12118
12455
|
hint: atCap ? "Remove a favorite first to make room" : `${favoriteProviders.length} provider${favoriteProviders.length !== 1 ? "s" : ""} available`
|
|
12119
12456
|
});
|
|
12120
12457
|
options.push({ value: "__done__", label: "Done", hint: "" });
|
|
12121
12458
|
const header = favorites.length === 0 ? `${scopeName} (0/20)` : `${scopeName} (${favorites.length}/20) \u2014 select to remove`;
|
|
12122
|
-
const choice = await
|
|
12459
|
+
const choice = await p16.select({
|
|
12123
12460
|
message: header,
|
|
12124
12461
|
options,
|
|
12125
12462
|
initialValue: "__done__"
|
|
12126
12463
|
});
|
|
12127
|
-
if (
|
|
12464
|
+
if (p16.isCancel(choice) || choice === "__done__") break;
|
|
12128
12465
|
if (choice === "__add__") {
|
|
12129
12466
|
if (atCap) {
|
|
12130
|
-
|
|
12467
|
+
p16.log.warn("Limit of 20 favorites reached \u2014 remove one first.");
|
|
12131
12468
|
continue;
|
|
12132
12469
|
}
|
|
12133
12470
|
const globalCount = buildGlobalFavoriteIndex(favoriteProviders).length;
|
|
12134
|
-
const addPath = await
|
|
12471
|
+
const addPath = await p16.select({
|
|
12135
12472
|
message: "Add a favorite",
|
|
12136
12473
|
options: [
|
|
12137
12474
|
{
|
|
12138
12475
|
value: "global",
|
|
12139
|
-
label:
|
|
12476
|
+
label: pc14.cyan("Search all providers"),
|
|
12140
12477
|
hint: `${globalCount} models \xB7 ${favoriteProviders.length} provider${favoriteProviders.length !== 1 ? "s" : ""}`
|
|
12141
12478
|
},
|
|
12142
12479
|
{
|
|
12143
12480
|
value: "free",
|
|
12144
|
-
label:
|
|
12481
|
+
label: pc14.cyan("Search free models"),
|
|
12145
12482
|
hint: `${buildGlobalFavoriteIndex(favoriteProviders).filter((e) => e.model.isFree || e.model.freeStatus === "verified_free" || e.model.freeStatus === "free_provider").length} free/free-access models`
|
|
12146
12483
|
},
|
|
12147
12484
|
{
|
|
12148
12485
|
value: "provider",
|
|
12149
|
-
label:
|
|
12486
|
+
label: pc14.cyan("Browse by provider \u2192"),
|
|
12150
12487
|
hint: "Pick one provider first"
|
|
12151
12488
|
}
|
|
12152
12489
|
]
|
|
12153
12490
|
});
|
|
12154
|
-
if (
|
|
12491
|
+
if (p16.isCancel(addPath)) continue;
|
|
12155
12492
|
let provider;
|
|
12156
12493
|
let browsedMultiple = [];
|
|
12157
12494
|
if (addPath === "global") {
|
|
@@ -12178,12 +12515,12 @@ async function runModelsCommand(parsed) {
|
|
|
12178
12515
|
label: ap.name,
|
|
12179
12516
|
hint: `${ap.models.length} models`
|
|
12180
12517
|
}));
|
|
12181
|
-
const pickedProviderId = await
|
|
12518
|
+
const pickedProviderId = await p16.select({
|
|
12182
12519
|
message: "Which provider?",
|
|
12183
12520
|
options: providerOptions,
|
|
12184
12521
|
initialValue: currentInitialProvider
|
|
12185
12522
|
});
|
|
12186
|
-
if (
|
|
12523
|
+
if (p16.isCancel(pickedProviderId)) break;
|
|
12187
12524
|
provider = favoriteProviders.find((ap) => ap.id === pickedProviderId);
|
|
12188
12525
|
const options2 = provider.models.map((m) => {
|
|
12189
12526
|
const favorited = isFavorite(favorites, { providerId: provider.id, modelId: m.id });
|
|
@@ -12191,15 +12528,15 @@ async function runModelsCommand(parsed) {
|
|
|
12191
12528
|
return {
|
|
12192
12529
|
value: m.id,
|
|
12193
12530
|
label: `${favorited ? "\u2605 " : ""}${fmtModel(label, m.id)}`,
|
|
12194
|
-
hint: favorited ?
|
|
12531
|
+
hint: favorited ? pc14.yellow("\u2605 already favorite") : ""
|
|
12195
12532
|
};
|
|
12196
12533
|
});
|
|
12197
|
-
const pickedModelIds = await
|
|
12198
|
-
message: `Select models to add from ${provider.name} ${
|
|
12534
|
+
const pickedModelIds = await p16.multiselect({
|
|
12535
|
+
message: `Select models to add from ${provider.name} ${pc14.dim("(Space to select, Enter to confirm)")}`,
|
|
12199
12536
|
options: options2,
|
|
12200
12537
|
required: false
|
|
12201
12538
|
});
|
|
12202
|
-
if (
|
|
12539
|
+
if (p16.isCancel(pickedModelIds)) {
|
|
12203
12540
|
currentInitialProvider = provider.id;
|
|
12204
12541
|
continue;
|
|
12205
12542
|
}
|
|
@@ -12234,27 +12571,27 @@ async function runModelsCommand(parsed) {
|
|
|
12234
12571
|
if (addedModels.length > 0) {
|
|
12235
12572
|
if (addedModels.length === 1) {
|
|
12236
12573
|
const modelName = addedModels[0].name || addedModels[0].id;
|
|
12237
|
-
|
|
12574
|
+
p16.log.success(`Added ${modelName} (${provider.name}) to favorites.`);
|
|
12238
12575
|
} else {
|
|
12239
|
-
|
|
12576
|
+
p16.log.success(`Added ${addedModels.length} models from ${provider.name} to favorites.`);
|
|
12240
12577
|
}
|
|
12241
12578
|
}
|
|
12242
12579
|
if (duplicateCount > 0) {
|
|
12243
|
-
|
|
12580
|
+
p16.log.warn(`${duplicateCount} selected model(s) were already in your favorites.`);
|
|
12244
12581
|
}
|
|
12245
12582
|
if (limitReached) {
|
|
12246
|
-
|
|
12583
|
+
p16.log.warn(`Limit of 20 favorites reached \u2014 some selected models could not be added.`);
|
|
12247
12584
|
}
|
|
12248
12585
|
} else if (choice.startsWith("fav-")) {
|
|
12249
12586
|
const idx = parseInt(choice.slice(4), 10);
|
|
12250
12587
|
const fav = favorites[idx];
|
|
12251
12588
|
const entry = modelLookup.get(`${fav.providerId}:${fav.modelId}`);
|
|
12252
12589
|
const label = entry ? `${entry.modelName} (${entry.providerName})` : fav.modelId;
|
|
12253
|
-
const confirmed = await
|
|
12254
|
-
if (
|
|
12590
|
+
const confirmed = await p16.confirm({ message: `Remove ${label} from favorites?` });
|
|
12591
|
+
if (p16.isCancel(confirmed) || !confirmed) continue;
|
|
12255
12592
|
favorites = removeFavorite(favorites, fav);
|
|
12256
12593
|
favoritesDirty = true;
|
|
12257
|
-
|
|
12594
|
+
p16.log.success(`Removed ${label} from favorites.`);
|
|
12258
12595
|
}
|
|
12259
12596
|
}
|
|
12260
12597
|
if (favoritesDirty) {
|
|
@@ -12263,15 +12600,101 @@ async function runModelsCommand(parsed) {
|
|
|
12263
12600
|
const favLabel = scope === "agy" ? "Antigravity CLI " : "";
|
|
12264
12601
|
gateOutro(
|
|
12265
12602
|
favorites.length === 0 ? `No ${favLabel}favorites saved` : `${favorites.length} ${favLabel}favorite${favorites.length !== 1 ? "s" : ""} saved`,
|
|
12266
|
-
favorites.length === 0 ?
|
|
12603
|
+
favorites.length === 0 ? pc14.dim("Launch uses single-model mode") : pc14.cyan("/model menu ready on next launch")
|
|
12267
12604
|
);
|
|
12268
12605
|
return 0;
|
|
12269
12606
|
}
|
|
12607
|
+
async function runValidateSubcommand(parsed) {
|
|
12608
|
+
gateIntro("Model Validation");
|
|
12609
|
+
const providerId = parsed.validateProvider;
|
|
12610
|
+
const force = parsed.force ?? false;
|
|
12611
|
+
const ttlMs = force ? 0 : void 0;
|
|
12612
|
+
const catalog = await fetchProviderCatalog();
|
|
12613
|
+
const registry = loadRegistry();
|
|
12614
|
+
let providersToValidate = catalog;
|
|
12615
|
+
if (providerId) {
|
|
12616
|
+
const found = catalog.find((p18) => p18.id === providerId);
|
|
12617
|
+
if (!found) {
|
|
12618
|
+
p16.log.error(`Provider not found: ${providerId}`);
|
|
12619
|
+
return 1;
|
|
12620
|
+
}
|
|
12621
|
+
providersToValidate = [found];
|
|
12622
|
+
}
|
|
12623
|
+
if (providersToValidate.length === 0) {
|
|
12624
|
+
p16.log.warn("No providers configured.");
|
|
12625
|
+
return 0;
|
|
12626
|
+
}
|
|
12627
|
+
const allParams = [];
|
|
12628
|
+
for (const provider of providersToValidate) {
|
|
12629
|
+
const regProvider = registry.providers.find((p18) => p18.id === provider.id);
|
|
12630
|
+
if (!regProvider) continue;
|
|
12631
|
+
const apiKey = provider.apiKey || await resolveProviderCredential(provider.id, regProvider.authRef).catch(() => "");
|
|
12632
|
+
if (!apiKey?.trim()) {
|
|
12633
|
+
p16.log.warn(`Skipping ${provider.name} \u2014 no API key available.`);
|
|
12634
|
+
continue;
|
|
12635
|
+
}
|
|
12636
|
+
const baseUrl = provider.models[0]?.apiBaseUrl || provider.models[0]?.completionsUrl || "";
|
|
12637
|
+
if (!baseUrl) {
|
|
12638
|
+
p16.log.warn(`Skipping ${provider.name} \u2014 no base URL available.`);
|
|
12639
|
+
continue;
|
|
12640
|
+
}
|
|
12641
|
+
for (const model of provider.models) {
|
|
12642
|
+
const completionsUrl = model.completionsUrl || model.apiBaseUrl || "";
|
|
12643
|
+
if (!completionsUrl) continue;
|
|
12644
|
+
allParams.push({
|
|
12645
|
+
modelId: model.id,
|
|
12646
|
+
providerId: provider.id,
|
|
12647
|
+
baseUrl: completionsUrl.replace(/\/chat\/completions$/, "").replace(/\/v1\/?$/, ""),
|
|
12648
|
+
apiKey,
|
|
12649
|
+
modelFormat: model.modelFormat === "anthropic" ? "anthropic" : "openai",
|
|
12650
|
+
headers: provider.headers
|
|
12651
|
+
});
|
|
12652
|
+
}
|
|
12653
|
+
}
|
|
12654
|
+
if (allParams.length === 0) {
|
|
12655
|
+
p16.log.warn("No models to validate.");
|
|
12656
|
+
return 0;
|
|
12657
|
+
}
|
|
12658
|
+
const spinner10 = p16.spinner();
|
|
12659
|
+
spinner10.start(`Validating ${allParams.length} model${allParams.length === 1 ? "" : "s"}...`);
|
|
12660
|
+
const results = await validateModels(allParams, { ttlMs });
|
|
12661
|
+
spinner10.stop("");
|
|
12662
|
+
const available = results.filter((r) => r.status === "available").length;
|
|
12663
|
+
const deprecated = results.filter((r) => r.status === "deprecated").length;
|
|
12664
|
+
const errors = results.filter((r) => r.status === "error").length;
|
|
12665
|
+
const unverified = results.filter((r) => r.status === "unverified").length;
|
|
12666
|
+
if (deprecated > 0) {
|
|
12667
|
+
p16.log.error(`${deprecated} model${deprecated === 1 ? "" : "s"} marked as deprecated:`);
|
|
12668
|
+
for (const r of results.filter((r2) => r2.status === "deprecated")) {
|
|
12669
|
+
p16.log.error(` ${r.modelId} (${r.providerId}): ${r.error ?? "unknown"}`);
|
|
12670
|
+
}
|
|
12671
|
+
}
|
|
12672
|
+
if (errors > 0) {
|
|
12673
|
+
p16.log.warn(`${errors} model${errors === 1 ? "" : "s"} with errors:`);
|
|
12674
|
+
for (const r of results.filter((r2) => r2.status === "error")) {
|
|
12675
|
+
p16.log.warn(` ${r.modelId} (${r.providerId}): ${r.error ?? "unknown"}`);
|
|
12676
|
+
}
|
|
12677
|
+
}
|
|
12678
|
+
if (unverified > 0) {
|
|
12679
|
+
p16.log.warn(`${unverified} model${unverified === 1 ? "" : "s"} unverified (will retry later):`);
|
|
12680
|
+
for (const r of results.filter((r2) => r2.status === "unverified")) {
|
|
12681
|
+
p16.log.warn(` ${r.modelId} (${r.providerId}): ${r.error ?? "unknown"}`);
|
|
12682
|
+
}
|
|
12683
|
+
}
|
|
12684
|
+
p16.log.success(
|
|
12685
|
+
`${available} available, ${deprecated} deprecated, ${errors} error${errors === 1 ? "" : "s"}, ${unverified} unverified`
|
|
12686
|
+
);
|
|
12687
|
+
const pruned = pruneValidationCache();
|
|
12688
|
+
if (pruned > 0) {
|
|
12689
|
+
p16.log.info(`Pruned ${pruned} stale cache entr${pruned === 1 ? "y" : "ies"}.`);
|
|
12690
|
+
}
|
|
12691
|
+
return deprecated > 0 ? 1 : 0;
|
|
12692
|
+
}
|
|
12270
12693
|
|
|
12271
12694
|
// src/cli/providers.ts
|
|
12272
12695
|
async function handleProvidersCommand(parsed) {
|
|
12273
12696
|
if (parsed.showVersion) {
|
|
12274
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12697
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
12275
12698
|
console.log(VERSION2);
|
|
12276
12699
|
return 0;
|
|
12277
12700
|
}
|
|
@@ -12286,7 +12709,7 @@ async function handleProvidersCommand(parsed) {
|
|
|
12286
12709
|
}
|
|
12287
12710
|
|
|
12288
12711
|
// src/apps/shared/doctor.ts
|
|
12289
|
-
import
|
|
12712
|
+
import pc15 from "picocolors";
|
|
12290
12713
|
import { createServer as createServer3 } from "net";
|
|
12291
12714
|
function nodeMajor() {
|
|
12292
12715
|
const raw = process.versions.node.split(".")[0] ?? "0";
|
|
@@ -12304,8 +12727,8 @@ function checkPortFree(port) {
|
|
|
12304
12727
|
});
|
|
12305
12728
|
}
|
|
12306
12729
|
function line(ok, label, detail = "") {
|
|
12307
|
-
const mark = ok ?
|
|
12308
|
-
const text4 = detail ? `${label} ${
|
|
12730
|
+
const mark = ok ? pc15.green("\u2713") : pc15.red("\u2717");
|
|
12731
|
+
const text4 = detail ? `${label} ${pc15.dim(`\u2014 ${detail}`)}` : label;
|
|
12309
12732
|
return ` ${mark} ${text4}`;
|
|
12310
12733
|
}
|
|
12311
12734
|
async function runDoctorCommand(_dryRun) {
|
|
@@ -12366,15 +12789,15 @@ async function runDoctorCommand(_dryRun) {
|
|
|
12366
12789
|
const reportLines = checks.map((c) => line(c.ok, c.label, c.detail));
|
|
12367
12790
|
reportLines.push("");
|
|
12368
12791
|
reportLines.push(
|
|
12369
|
-
|
|
12792
|
+
pc15.dim("Antigravity note: macOS-only today. Windows/Linux app launches are") + pc15.dim(" best-effort \u2014 see help for each agy/antigravity command.")
|
|
12370
12793
|
);
|
|
12371
12794
|
printPanel("Environment check", reportLines);
|
|
12372
12795
|
if (failedCritical.length > 0) {
|
|
12373
|
-
gateOutro("Problems found",
|
|
12796
|
+
gateOutro("Problems found", pc15.red(`${failedCritical.length} critical check(s) failed`));
|
|
12374
12797
|
return 1;
|
|
12375
12798
|
}
|
|
12376
12799
|
if (failedNonCritical.length > 0) {
|
|
12377
|
-
gateOutro("Mostly OK",
|
|
12800
|
+
gateOutro("Mostly OK", pc15.yellow(`${failedNonCritical.length} non-critical warning(s)`));
|
|
12378
12801
|
return 0;
|
|
12379
12802
|
}
|
|
12380
12803
|
gateOutro("All checks passed");
|
|
@@ -12384,7 +12807,7 @@ async function runDoctorCommand(_dryRun) {
|
|
|
12384
12807
|
// src/cli/doctor.ts
|
|
12385
12808
|
async function handleDoctorCommand(parsed) {
|
|
12386
12809
|
if (parsed.showVersion) {
|
|
12387
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12810
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
12388
12811
|
console.log(VERSION2);
|
|
12389
12812
|
return 0;
|
|
12390
12813
|
}
|
|
@@ -12413,7 +12836,7 @@ Checks:
|
|
|
12413
12836
|
}
|
|
12414
12837
|
|
|
12415
12838
|
// src/apps/shared/completions.ts
|
|
12416
|
-
import
|
|
12839
|
+
import pc16 from "picocolors";
|
|
12417
12840
|
var SUBCOMMANDS = [
|
|
12418
12841
|
"claude",
|
|
12419
12842
|
"claude-app",
|
|
@@ -12510,7 +12933,7 @@ var SCRIPTS = {
|
|
|
12510
12933
|
function runCompletionsCommand(shellArg) {
|
|
12511
12934
|
const shell = normalizeShell(shellArg) ?? detectShell();
|
|
12512
12935
|
if (!shell) {
|
|
12513
|
-
console.error(
|
|
12936
|
+
console.error(pc16.red("\\nError: could not detect your shell.\\n"));
|
|
12514
12937
|
console.error("Pass one explicitly: anygate completions <bash|zsh|fish|powershell>\\n");
|
|
12515
12938
|
return Promise.resolve(1);
|
|
12516
12939
|
}
|
|
@@ -12521,7 +12944,7 @@ function runCompletionsCommand(shellArg) {
|
|
|
12521
12944
|
// src/cli/completions.ts
|
|
12522
12945
|
async function handleCompletionsCommand(parsed) {
|
|
12523
12946
|
if (parsed.showVersion) {
|
|
12524
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
12947
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
12525
12948
|
console.log(VERSION2);
|
|
12526
12949
|
return 0;
|
|
12527
12950
|
}
|
|
@@ -12547,9 +12970,9 @@ Examples:
|
|
|
12547
12970
|
}
|
|
12548
12971
|
|
|
12549
12972
|
// src/apps/shared/self-update.ts
|
|
12550
|
-
import
|
|
12973
|
+
import pc17 from "picocolors";
|
|
12551
12974
|
import { spawn as spawn5, execFileSync as execFileSync4 } from "child_process";
|
|
12552
|
-
import * as
|
|
12975
|
+
import * as p17 from "@clack/prompts";
|
|
12553
12976
|
function resolveNpmBin() {
|
|
12554
12977
|
if (process.platform === "win32") {
|
|
12555
12978
|
try {
|
|
@@ -12564,41 +12987,41 @@ function resolveNpmBin() {
|
|
|
12564
12987
|
async function runUpdateCommand(dryRun) {
|
|
12565
12988
|
const update = await checkForUpdates();
|
|
12566
12989
|
if (!update.updateAvailable || !update.latestVersion) {
|
|
12567
|
-
|
|
12990
|
+
p17.log.success(`anygate is up to date (v${VERSION}).`);
|
|
12568
12991
|
return 0;
|
|
12569
12992
|
}
|
|
12570
|
-
|
|
12571
|
-
`Update available: ${
|
|
12993
|
+
p17.log.info(
|
|
12994
|
+
`Update available: ${pc17.cyan(`v${update.currentVersion}`)} \u2192 ${pc17.green(`v${update.latestVersion}`)}`
|
|
12572
12995
|
);
|
|
12573
12996
|
const npmBin = resolveNpmBin();
|
|
12574
12997
|
if (dryRun) {
|
|
12575
|
-
|
|
12576
|
-
|
|
12998
|
+
p17.log.step(`Would run: ${pc17.bold(`${npmBin} install -g anygate@latest`)}`);
|
|
12999
|
+
p17.log.warn("Dry run \u2014 no changes made.");
|
|
12577
13000
|
return 0;
|
|
12578
13001
|
}
|
|
12579
|
-
const confirmed = await
|
|
13002
|
+
const confirmed = await p17.confirm({
|
|
12580
13003
|
message: `Install anygate@${update.latestVersion} now?`,
|
|
12581
13004
|
initialValue: false
|
|
12582
13005
|
});
|
|
12583
|
-
if (
|
|
12584
|
-
|
|
13006
|
+
if (p17.isCancel(confirmed) || !confirmed) {
|
|
13007
|
+
p17.log.info(`Update skipped. Run ${pc17.cyan(UPDATE_COMMAND)} later if you change your mind.`);
|
|
12585
13008
|
return 0;
|
|
12586
13009
|
}
|
|
12587
|
-
|
|
13010
|
+
p17.log.info(`Running ${pc17.cyan(`${npmBin} install -g anygate@latest`)}...`);
|
|
12588
13011
|
const child = spawn5(npmBin, ["install", "-g", "anygate@latest"], {
|
|
12589
13012
|
stdio: "inherit",
|
|
12590
13013
|
windowsHide: true
|
|
12591
13014
|
});
|
|
12592
13015
|
return new Promise((resolve) => {
|
|
12593
13016
|
child.on("error", (err) => {
|
|
12594
|
-
|
|
13017
|
+
p17.log.error(`Failed to start npm: ${err instanceof Error ? err.message : String(err)}`);
|
|
12595
13018
|
resolve(1);
|
|
12596
13019
|
});
|
|
12597
13020
|
child.on("close", (code) => {
|
|
12598
13021
|
if (code === 0) {
|
|
12599
|
-
|
|
13022
|
+
p17.log.success("anygate updated. Restart your shell or re-run anygate to use the new version.");
|
|
12600
13023
|
} else {
|
|
12601
|
-
|
|
13024
|
+
p17.log.error(`Update failed (exit ${code}). Try ${pc17.cyan(UPDATE_COMMAND)} manually.`);
|
|
12602
13025
|
}
|
|
12603
13026
|
resolve(code ?? 1);
|
|
12604
13027
|
});
|
|
@@ -12608,7 +13031,7 @@ async function runUpdateCommand(dryRun) {
|
|
|
12608
13031
|
// src/cli/update.ts
|
|
12609
13032
|
async function handleUpdateCommand(parsed) {
|
|
12610
13033
|
if (parsed.showVersion) {
|
|
12611
|
-
const { VERSION: VERSION2 } = await import("./constants-
|
|
13034
|
+
const { VERSION: VERSION2 } = await import("./constants-HE3EOSMH.js");
|
|
12612
13035
|
console.log(VERSION2);
|
|
12613
13036
|
return 0;
|
|
12614
13037
|
}
|
|
@@ -12643,6 +13066,7 @@ async function dispatchCommand(parsed) {
|
|
|
12643
13066
|
}
|
|
12644
13067
|
return handler(parsed);
|
|
12645
13068
|
}
|
|
13069
|
+
registerCommand("root", handleRootCommand);
|
|
12646
13070
|
registerCommand("claude", handleClaudeCommand);
|
|
12647
13071
|
registerCommand("codex", handleCodexCommand);
|
|
12648
13072
|
registerCommand("codex-app", handleCodexAppCommand);
|
|
@@ -12746,7 +13170,7 @@ function parseArgs(args) {
|
|
|
12746
13170
|
aiInstallForce: args.includes("--force")
|
|
12747
13171
|
};
|
|
12748
13172
|
}
|
|
12749
|
-
if (args.length === 0) return { ...emptyParsed("root"), showHelp:
|
|
13173
|
+
if (args.length === 0) return { ...emptyParsed("root"), showHelp: false };
|
|
12750
13174
|
const [first, ...rest] = args;
|
|
12751
13175
|
if (first === "--help" || first === "-h") {
|
|
12752
13176
|
return { ...emptyParsed("root"), showHelp: true };
|
|
@@ -12792,10 +13216,21 @@ function parseArgs(args) {
|
|
|
12792
13216
|
}
|
|
12793
13217
|
if (first === "models" || first === "favorites") {
|
|
12794
13218
|
const parsed2 = emptyParsed("models");
|
|
12795
|
-
for (
|
|
13219
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
13220
|
+
const arg = rest[i];
|
|
12796
13221
|
if (arg === "--help" || arg === "-h") parsed2.showHelp = true;
|
|
12797
13222
|
else if (arg === "--version" || arg === "-v") parsed2.showVersion = true;
|
|
12798
13223
|
else if (arg === "--agy") parsed2.favoritesAgy = true;
|
|
13224
|
+
else if (arg === "--force") parsed2.force = true;
|
|
13225
|
+
else if (arg === "--provider" || arg.startsWith("--provider=")) {
|
|
13226
|
+
const value = arg.startsWith("--provider=") ? arg.slice("--provider=".length) : rest[i + 1];
|
|
13227
|
+
if (!value || value.startsWith("-")) {
|
|
13228
|
+
parsed2.error = "Missing value for --provider";
|
|
13229
|
+
return parsed2;
|
|
13230
|
+
}
|
|
13231
|
+
if (!arg.startsWith("--provider=")) i += 1;
|
|
13232
|
+
parsed2.validateProvider = value;
|
|
13233
|
+
} else if (arg === "validate") parsed2.validateSubcommand = true;
|
|
12799
13234
|
else if (!parsed2.error) parsed2.error = `Unknown models option: ${arg}`;
|
|
12800
13235
|
}
|
|
12801
13236
|
return parsed2;
|
|
@@ -13071,11 +13506,11 @@ ${text4}
|
|
|
13071
13506
|
`);
|
|
13072
13507
|
}
|
|
13073
13508
|
function rootHelpText() {
|
|
13074
|
-
return `${
|
|
13509
|
+
return `${pc18.bold("anygate")} v${VERSION}
|
|
13075
13510
|
Launch AI coding tools with OpenCode Zen / Go or local providers (Groq, Mistral,
|
|
13076
13511
|
OpenAI, Gemini, Ollama, and more).
|
|
13077
13512
|
|
|
13078
|
-
${
|
|
13513
|
+
${pc18.bold("Usage:")}
|
|
13079
13514
|
anygate claude [options] [claude-flags]
|
|
13080
13515
|
anygate claude-app [options]
|
|
13081
13516
|
anygate codex [options] [codex-flags]
|
|
@@ -13088,6 +13523,7 @@ ${pc17.bold("Usage:")}
|
|
|
13088
13523
|
anygate server [options]
|
|
13089
13524
|
anygate ui
|
|
13090
13525
|
anygate models
|
|
13526
|
+
anygate models validate [--provider <id>] [--force]
|
|
13091
13527
|
anygate favorites
|
|
13092
13528
|
anygate providers
|
|
13093
13529
|
anygate doctor
|
|
@@ -13099,14 +13535,14 @@ ${pc17.bold("Usage:")}
|
|
|
13099
13535
|
anygate --ai --install Install or upgrade agent skill when version changed
|
|
13100
13536
|
anygate --ai --install --force Reinstall skill even if already current
|
|
13101
13537
|
|
|
13102
|
-
${
|
|
13538
|
+
${pc18.bold("Root options:")}
|
|
13103
13539
|
-h, --help Show this help
|
|
13104
13540
|
-v, --version Show version
|
|
13105
13541
|
--ai Print the full reference for AI agents
|
|
13106
13542
|
--ai --install Install or upgrade the anygate agent skill
|
|
13107
13543
|
--force Reinstall the agent skill when used with --ai --install
|
|
13108
13544
|
|
|
13109
|
-
${
|
|
13545
|
+
${pc18.bold("Commands:")}
|
|
13110
13546
|
claude Launch Claude Code \u2014 pick a provider from your registry
|
|
13111
13547
|
models Manage favorite models for mid-session /model switching (max ${MAX_MODEL_CATALOG})
|
|
13112
13548
|
favorites Alias for models
|
|
@@ -13124,15 +13560,17 @@ ${pc17.bold("Commands:")}
|
|
|
13124
13560
|
completions Print a shell completion script for anygate
|
|
13125
13561
|
update Interactively upgrade anygate to the latest published version
|
|
13126
13562
|
|
|
13127
|
-
${
|
|
13563
|
+
${pc18.bold("Antigravity favorites:")}
|
|
13128
13564
|
agy, antigravity, and antigravity-ide share up to six Antigravity favorites
|
|
13129
13565
|
from anygate favorites --agy, plus the selected launch model.
|
|
13130
13566
|
|
|
13131
|
-
${
|
|
13132
|
-
|
|
13133
|
-
Use anygate claude for the
|
|
13567
|
+
${pc18.bold("Bare command:")}
|
|
13568
|
+
anygate (no subcommand) runs the onboarding flow on first run, or
|
|
13569
|
+
shows a main menu on subsequent runs. Use anygate claude for the
|
|
13570
|
+
Claude Code wizard and launcher.
|
|
13134
13571
|
|
|
13135
|
-
${
|
|
13572
|
+
${pc18.bold("Examples:")}
|
|
13573
|
+
anygate
|
|
13136
13574
|
anygate claude
|
|
13137
13575
|
anygate models
|
|
13138
13576
|
anygate providers
|
|
@@ -13149,15 +13587,15 @@ ${pc17.bold("Examples:")}
|
|
|
13149
13587
|
anygate claude -- --print "hello"`;
|
|
13150
13588
|
}
|
|
13151
13589
|
function claudeHelpText() {
|
|
13152
|
-
return `${
|
|
13590
|
+
return `${pc18.bold("anygate claude")} v${VERSION}
|
|
13153
13591
|
Launch Claude Code with OpenCode Zen, Go, or local providers as the API backend.
|
|
13154
13592
|
|
|
13155
|
-
${
|
|
13593
|
+
${pc18.bold("Usage:")}
|
|
13156
13594
|
anygate claude [options] [claude-flags]
|
|
13157
13595
|
anygate claude --help
|
|
13158
13596
|
anygate claude --version
|
|
13159
13597
|
|
|
13160
|
-
${
|
|
13598
|
+
${pc18.bold("Options:")}
|
|
13161
13599
|
--dry-run Run the wizard but show a preview instead of launching Claude Code
|
|
13162
13600
|
--setup Hint: use anygate providers to add or manage providers
|
|
13163
13601
|
--trace Write debug logs to ~/.anygate/logs/ and show errors on exit
|
|
@@ -13166,22 +13604,22 @@ ${pc17.bold("Options:")}
|
|
|
13166
13604
|
--help Show this command help
|
|
13167
13605
|
--version Show version
|
|
13168
13606
|
|
|
13169
|
-
${
|
|
13607
|
+
${pc18.bold("Providers:")}
|
|
13170
13608
|
Cloud (Zen/Go) Requires OPENCODE_API_KEY \u2014 get one at https://opencode.ai/auth
|
|
13171
13609
|
Registry Configure with anygate providers add or import (Groq, Mistral,
|
|
13172
13610
|
Nvidia, DeepSeek, OpenAI, custom endpoints, etc.).
|
|
13173
13611
|
|
|
13174
|
-
${
|
|
13612
|
+
${pc18.bold("Model switching:")}
|
|
13175
13613
|
Run anygate models to save favorites (max ${MAX_MODEL_CATALOG}).
|
|
13176
13614
|
When favorites exist, launch starts a multi-route proxy and Claude Code /model
|
|
13177
13615
|
lists your starting model plus favorites for live switching.
|
|
13178
13616
|
With no favorites, launch uses a single model as before.
|
|
13179
13617
|
|
|
13180
|
-
${
|
|
13618
|
+
${pc18.bold("Note:")}
|
|
13181
13619
|
Claude Code may save the launched model to ~/.claude/settings.json.
|
|
13182
13620
|
Bare claude later can still show that model \u2014 reset with claude --model sonnet.
|
|
13183
13621
|
|
|
13184
|
-
${
|
|
13622
|
+
${pc18.bold("Examples:")}
|
|
13185
13623
|
anygate claude
|
|
13186
13624
|
anygate claude -c
|
|
13187
13625
|
anygate claude --resume abc-123
|
|
@@ -13195,10 +13633,10 @@ ${pc17.bold("Examples:")}
|
|
|
13195
13633
|
anygate claude -- --dangerously-skip-permissions`;
|
|
13196
13634
|
}
|
|
13197
13635
|
function serverHelpText() {
|
|
13198
|
-
return `${
|
|
13636
|
+
return `${pc18.bold("anygate server")} v${VERSION}
|
|
13199
13637
|
Run a foreground API gateway for registry providers, Zen/Go, or Vertex AI.
|
|
13200
13638
|
|
|
13201
|
-
${
|
|
13639
|
+
${pc18.bold("Usage:")}
|
|
13202
13640
|
anygate server
|
|
13203
13641
|
anygate server --quick
|
|
13204
13642
|
anygate server --listen network --password <password>
|
|
@@ -13206,7 +13644,7 @@ ${pc17.bold("Usage:")}
|
|
|
13206
13644
|
anygate server --help
|
|
13207
13645
|
anygate server --version
|
|
13208
13646
|
|
|
13209
|
-
${
|
|
13647
|
+
${pc18.bold("Options:")}
|
|
13210
13648
|
--quick, --saved Start immediately from saved/default settings
|
|
13211
13649
|
--listen local|network One-run listen mode override
|
|
13212
13650
|
--providers all|favorites|id1,id2
|
|
@@ -13217,7 +13655,7 @@ ${pc17.bold("Options:")}
|
|
|
13217
13655
|
--password <value> One-run network-mode server password
|
|
13218
13656
|
--vertex Use Claude on Google Vertex AI
|
|
13219
13657
|
|
|
13220
|
-
${
|
|
13658
|
+
${pc18.bold("Behavior:")}
|
|
13221
13659
|
Default: interactive wizard for exposed providers, discovery id masking (for
|
|
13222
13660
|
Claude Desktop / Cowork), optional favorites-only catalog, then listen mode.
|
|
13223
13661
|
Quick mode skips prompts and uses saved settings. Any one-run option also
|
|
@@ -13227,129 +13665,129 @@ ${pc17.bold("Behavior:")}
|
|
|
13227
13665
|
local gcloud Application Default Credentials (no OpenCode API key).
|
|
13228
13666
|
Binds to port 17645. Network mode asks for a server password.
|
|
13229
13667
|
|
|
13230
|
-
${
|
|
13668
|
+
${pc18.bold("Vertex env:")}
|
|
13231
13669
|
ANTHROPIC_VERTEX_PROJECT_ID or GOOGLE_CLOUD_PROJECT \u2014 your GCP project
|
|
13232
13670
|
GOOGLE_CLOUD_LOCATION or CLOUD_ML_REGION \u2014 region (default: global)
|
|
13233
13671
|
Optional catalog: ~/.anygate/vertex-models.json (see assets/vertex-models.example.json)
|
|
13234
13672
|
|
|
13235
|
-
${
|
|
13673
|
+
${pc18.bold("Endpoints:")}
|
|
13236
13674
|
Anthropic-compatible: ANTHROPIC_BASE_URL=http://127.0.0.1:17645/anthropic
|
|
13237
13675
|
OpenAI-compatible: OPENAI_BASE_URL=http://127.0.0.1:17645/openai/v1
|
|
13238
13676
|
API key: use anything locally; use the server password in network mode.`;
|
|
13239
13677
|
}
|
|
13240
13678
|
function modelsHelpText() {
|
|
13241
|
-
return `${
|
|
13679
|
+
return `${pc18.bold("anygate favorites")} v${VERSION}
|
|
13242
13680
|
Manage favorite models for mid-session switching.
|
|
13243
13681
|
|
|
13244
|
-
${
|
|
13682
|
+
${pc18.bold("Usage:")}
|
|
13245
13683
|
anygate favorites
|
|
13246
13684
|
anygate favorites --agy
|
|
13247
13685
|
anygate models
|
|
13248
13686
|
anygate favorites --help
|
|
13249
13687
|
anygate favorites --version
|
|
13250
13688
|
|
|
13251
|
-
${
|
|
13689
|
+
${pc18.bold("Behavior:")}
|
|
13252
13690
|
Opens an interactive manager to add or remove favorites.
|
|
13253
13691
|
Search all providers at once (paginated results) or browse one provider at a time.
|
|
13254
13692
|
Pick from Zen, Go, or any provider in your registry.
|
|
13255
13693
|
Global favorites are saved to ~/.anygate/config.json (max ${MAX_MODEL_CATALOG}).
|
|
13256
13694
|
--agy manages Antigravity CLI favorites only (max 6).
|
|
13257
13695
|
|
|
13258
|
-
${
|
|
13696
|
+
${pc18.bold("How it works:")}
|
|
13259
13697
|
Claude/Codex/Gemini/server use the global favorites list.
|
|
13260
13698
|
Favorites appear in supported /model switch menus.
|
|
13261
13699
|
anygate agy, antigravity, and antigravity-ide use the Antigravity favorites
|
|
13262
13700
|
list so the limited native switch slots stay predictable: one selected launch
|
|
13263
13701
|
model plus up to six Antigravity favorites.
|
|
13264
13702
|
|
|
13265
|
-
${
|
|
13703
|
+
${pc18.bold("Examples:")}
|
|
13266
13704
|
anygate favorites
|
|
13267
13705
|
anygate favorites --agy
|
|
13268
13706
|
anygate claude # switch menu active when favorites are set`;
|
|
13269
13707
|
}
|
|
13270
13708
|
function antigravityCliHelpText() {
|
|
13271
|
-
return `${
|
|
13709
|
+
return `${pc18.bold("anygate agy")} v${VERSION}
|
|
13272
13710
|
Launch Antigravity CLI with anygate provider registry.
|
|
13273
13711
|
|
|
13274
|
-
${
|
|
13712
|
+
${pc18.bold("Usage:")}
|
|
13275
13713
|
anygate agy [options] [agy-flags]
|
|
13276
13714
|
anygate agy --help
|
|
13277
13715
|
anygate agy --version
|
|
13278
13716
|
|
|
13279
|
-
${
|
|
13717
|
+
${pc18.bold("Options:")}
|
|
13280
13718
|
--provider <id> Use a specific provider (skip picker)
|
|
13281
13719
|
--model <id> Use a specific model (skip picker)
|
|
13282
13720
|
--trace Write debug log to /tmp/anygate-debug.log
|
|
13283
13721
|
-h, --help Show this help
|
|
13284
13722
|
-v, --version Show version
|
|
13285
13723
|
|
|
13286
|
-
${
|
|
13724
|
+
${pc18.bold("How it works:")}
|
|
13287
13725
|
Starts a local Cloud Code gateway, points agy at it via CLOUD_CODE_URL,
|
|
13288
13726
|
and injects anygate models into Antigravity's native model picker.
|
|
13289
13727
|
All Cloud Code traffic routes through anygate \u2014 no Google Cloud Code upstream.
|
|
13290
13728
|
|
|
13291
|
-
${
|
|
13729
|
+
${pc18.bold("Examples:")}
|
|
13292
13730
|
anygate agy
|
|
13293
13731
|
anygate agy --provider zen --model deepseek-v4-flash-free
|
|
13294
13732
|
anygate agy -p "fix this bug"`;
|
|
13295
13733
|
}
|
|
13296
13734
|
function antigravityIdeHelpText() {
|
|
13297
|
-
return `${
|
|
13735
|
+
return `${pc18.bold("anygate antigravity-ide")} v${VERSION}
|
|
13298
13736
|
Launch Antigravity IDE with anygate provider registry.
|
|
13299
13737
|
|
|
13300
|
-
${
|
|
13738
|
+
${pc18.bold("Usage:")}
|
|
13301
13739
|
anygate antigravity-ide [options]
|
|
13302
13740
|
anygate antigravity-ide --help
|
|
13303
13741
|
anygate antigravity-ide --version
|
|
13304
13742
|
|
|
13305
|
-
${
|
|
13743
|
+
${pc18.bold("Options:")}
|
|
13306
13744
|
--provider <id> Use a specific provider (skip picker)
|
|
13307
13745
|
--model <id> Use a specific model (skip picker)
|
|
13308
13746
|
--trace Write debug log to /tmp/anygate-debug.log
|
|
13309
13747
|
-h, --help Show this help
|
|
13310
13748
|
-v, --version Show version
|
|
13311
13749
|
|
|
13312
|
-
${
|
|
13750
|
+
${pc18.bold("How it works:")}
|
|
13313
13751
|
Creates an isolated anygate-managed IDE profile, starts a local Cloud Code
|
|
13314
13752
|
gateway, and injects anygate models into Antigravity's native picker.
|
|
13315
13753
|
The normal IDE profile is never modified.
|
|
13316
13754
|
|
|
13317
|
-
${
|
|
13755
|
+
${pc18.bold("Platform:")}
|
|
13318
13756
|
macOS (Apple Silicon) \u2014 other platforms coming after testing.
|
|
13319
13757
|
|
|
13320
|
-
${
|
|
13758
|
+
${pc18.bold("Examples:")}
|
|
13321
13759
|
anygate antigravity-ide
|
|
13322
13760
|
anygate antigravity-ide --provider zen --model deepseek-v4-flash-free`;
|
|
13323
13761
|
}
|
|
13324
13762
|
function antigravityAppHelpText() {
|
|
13325
|
-
return `${
|
|
13763
|
+
return `${pc18.bold("anygate antigravity")} v${VERSION}
|
|
13326
13764
|
Launch Antigravity with anygate provider registry.
|
|
13327
13765
|
|
|
13328
|
-
${
|
|
13766
|
+
${pc18.bold("Usage:")}
|
|
13329
13767
|
anygate antigravity [options]
|
|
13330
13768
|
anygate antigravity --help
|
|
13331
13769
|
anygate antigravity --version
|
|
13332
13770
|
|
|
13333
|
-
${
|
|
13771
|
+
${pc18.bold("Options:")}
|
|
13334
13772
|
--provider <id> Use a specific provider (skip picker)
|
|
13335
13773
|
--model <id> Use a specific model (skip picker)
|
|
13336
13774
|
--trace Write debug log to /tmp/anygate-debug.log
|
|
13337
13775
|
-h, --help Show this help
|
|
13338
13776
|
-v, --version Show version
|
|
13339
13777
|
|
|
13340
|
-
${
|
|
13778
|
+
${pc18.bold("How it works:")}
|
|
13341
13779
|
Creates an isolated anygate-managed Antigravity profile, starts a local Cloud
|
|
13342
13780
|
Code gateway, and injects anygate models into Antigravity's native picker.
|
|
13343
13781
|
The normal Antigravity profile is never modified.
|
|
13344
13782
|
|
|
13345
|
-
${
|
|
13783
|
+
${pc18.bold("Favorites:")}
|
|
13346
13784
|
Uses the same Antigravity favorites list as anygate favorites --agy:
|
|
13347
13785
|
up to six saved favorites plus the selected launch model.
|
|
13348
13786
|
|
|
13349
|
-
${
|
|
13787
|
+
${pc18.bold("Platform:")}
|
|
13350
13788
|
macOS (Apple Silicon) \u2014 other platforms coming after testing.
|
|
13351
13789
|
|
|
13352
|
-
${
|
|
13790
|
+
${pc18.bold("Examples:")}
|
|
13353
13791
|
anygate antigravity
|
|
13354
13792
|
anygate antigravity --provider zen --model deepseek-v4-flash-free`;
|
|
13355
13793
|
}
|
|
@@ -13367,7 +13805,7 @@ ${formatUpdateNotification(update.currentVersion, update.latestVersion)}
|
|
|
13367
13805
|
else console.error(notice);
|
|
13368
13806
|
}
|
|
13369
13807
|
if (parsed.error) {
|
|
13370
|
-
console.error(
|
|
13808
|
+
console.error(pc18.red(`
|
|
13371
13809
|
Error: ${parsed.error}
|
|
13372
13810
|
`));
|
|
13373
13811
|
printHelp(rootHelpText());
|
|
@@ -13386,10 +13824,13 @@ Error: ${parsed.error}
|
|
|
13386
13824
|
}
|
|
13387
13825
|
if (parsed.showVersion) {
|
|
13388
13826
|
console.log(VERSION);
|
|
13389
|
-
|
|
13827
|
+
return 0;
|
|
13828
|
+
}
|
|
13829
|
+
if (parsed.showHelp) {
|
|
13390
13830
|
printHelp(rootHelpText());
|
|
13831
|
+
return 0;
|
|
13391
13832
|
}
|
|
13392
|
-
return
|
|
13833
|
+
return dispatchCommand(parsed);
|
|
13393
13834
|
}
|
|
13394
13835
|
if (parsed.showVersion) {
|
|
13395
13836
|
console.log(VERSION);
|
|
@@ -13436,7 +13877,7 @@ if (isCliEntryPoint()) {
|
|
|
13436
13877
|
if (err === /* @__PURE__ */ Symbol.for("clack:cancel")) {
|
|
13437
13878
|
process.exit(0);
|
|
13438
13879
|
}
|
|
13439
|
-
console.error(
|
|
13880
|
+
console.error(pc18.red("\nUnexpected error:"), err);
|
|
13440
13881
|
process.exit(1);
|
|
13441
13882
|
});
|
|
13442
13883
|
}
|