anygate 0.5.11 → 0.6.1
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-6AFYEDSU.js → chunk-4N4RDHGZ.js} +21 -6
- package/dist/{chunk-6AFYEDSU.js.map → chunk-4N4RDHGZ.js.map} +1 -1
- package/dist/{chunk-55RHVPE4.js → chunk-BY4AKT2X.js} +1540 -829
- package/dist/chunk-BY4AKT2X.js.map +1 -0
- package/dist/{chunk-5UF4TVCM.js → chunk-UE2I2ETX.js} +25 -3
- package/dist/chunk-UE2I2ETX.js.map +1 -0
- package/dist/{chunk-72WNE2IK.js → chunk-UT3JLF3M.js} +2 -13
- package/dist/cli.js +1728 -680
- package/dist/cli.js.map +1 -1
- package/dist/{command-7AI36ICY.js → command-XIDZGWNR.js} +417 -108
- package/dist/command-XIDZGWNR.js.map +1 -0
- package/dist/{constants-HE3EOSMH.js → constants-WLMOLKEO.js} +9 -3
- package/dist/{provider-templates-MNJZTG3Z.js → provider-templates-336QE7ZV.js} +3 -3
- package/dist/registry/data/templates/agentrouter.json +19 -0
- package/dist/registry/data/templates/cohere.json +5 -2
- package/dist/registry/data/templates/fireworks.json +1 -1
- package/dist/registry/data/templates/sambanova.json +8 -7
- package/dist/ui/dist/assets/index-Bnth1xGD.js +7 -0
- package/dist/ui/dist/assets/index-bNoUNC_v.css +1 -0
- package/dist/ui/dist/index.html +2 -2
- package/package.json +110 -94
- package/dist/chunk-55RHVPE4.js.map +0 -1
- package/dist/chunk-5UF4TVCM.js.map +0 -1
- package/dist/command-7AI36ICY.js.map +0 -1
- package/dist/ui/dist/assets/index-DWAOH_B3.css +0 -1
- package/dist/ui/dist/assets/index-qxVU3kMy.js +0 -6
- /package/dist/{chunk-72WNE2IK.js.map → chunk-UT3JLF3M.js.map} +0 -0
- /package/dist/{constants-HE3EOSMH.js.map → constants-WLMOLKEO.js.map} +0 -0
- /package/dist/{provider-templates-MNJZTG3Z.js.map → provider-templates-336QE7ZV.js.map} +0 -0
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
checkForUpdates,
|
|
9
9
|
completeAntigravityExchange,
|
|
10
10
|
createGatewayModelCatalog,
|
|
11
|
+
detectConflicts,
|
|
12
|
+
emitAppEvent,
|
|
11
13
|
favoriteProviderDisplayName,
|
|
12
14
|
fetchProviderCatalog,
|
|
13
15
|
filterServerModelsByFavorites,
|
|
@@ -29,8 +31,8 @@ import {
|
|
|
29
31
|
getServerMaskGatewayIds,
|
|
30
32
|
getUiDebugLogPath,
|
|
31
33
|
guiCallbackRedirectUri,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
isSecretServiceAvailable,
|
|
35
|
+
loadLaunchPresets,
|
|
34
36
|
loadPreferences,
|
|
35
37
|
loadRegistry,
|
|
36
38
|
loadServerModels,
|
|
@@ -41,6 +43,7 @@ import {
|
|
|
41
43
|
pollXaiDeviceCodeToken,
|
|
42
44
|
providerOptionsFromCatalog,
|
|
43
45
|
readBody,
|
|
46
|
+
readFromCredentialStore,
|
|
44
47
|
recordLaunchFolder,
|
|
45
48
|
refreshAllProviderModels,
|
|
46
49
|
refreshProviderModels,
|
|
@@ -51,6 +54,7 @@ import {
|
|
|
51
54
|
resolveInputTypes,
|
|
52
55
|
resolveProviderCredential,
|
|
53
56
|
resolveServerUpstreamApiKey,
|
|
57
|
+
saveLaunchPresets,
|
|
54
58
|
saveNativeOAuthCredential,
|
|
55
59
|
savePreferences,
|
|
56
60
|
saveProviderCredential,
|
|
@@ -63,34 +67,41 @@ import {
|
|
|
63
67
|
setServerListenMode,
|
|
64
68
|
setServerMaskGatewayIds,
|
|
65
69
|
startServer,
|
|
70
|
+
subscribeToAppEvents,
|
|
66
71
|
summarizeServerProviders,
|
|
67
72
|
validateCustomEndpointUrl,
|
|
68
73
|
writeSecureLogLine
|
|
69
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-BY4AKT2X.js";
|
|
70
75
|
import {
|
|
71
76
|
BACKENDS,
|
|
77
|
+
GATEWAY_PORT,
|
|
72
78
|
MAX_MODEL_CATALOG
|
|
73
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-UE2I2ETX.js";
|
|
74
80
|
import {
|
|
75
81
|
getTemplateById,
|
|
76
|
-
|
|
82
|
+
listAddableTemplates,
|
|
77
83
|
listVisibleOAuthTemplates
|
|
78
|
-
} from "./chunk-
|
|
79
|
-
import "./chunk-
|
|
84
|
+
} from "./chunk-4N4RDHGZ.js";
|
|
85
|
+
import "./chunk-UT3JLF3M.js";
|
|
80
86
|
|
|
81
87
|
// src/ui/command.ts
|
|
82
|
-
|
|
83
|
-
import { createServer } from "http";
|
|
88
|
+
import { createServer as createServer2 } from "http";
|
|
84
89
|
import { execSync } from "child_process";
|
|
85
|
-
import {
|
|
90
|
+
import {
|
|
91
|
+
readFileSync,
|
|
92
|
+
readdirSync,
|
|
93
|
+
writeFileSync as writeFileSync2,
|
|
94
|
+
unlinkSync,
|
|
95
|
+
existsSync as existsSync3,
|
|
96
|
+
mkdirSync
|
|
97
|
+
} from "fs";
|
|
86
98
|
import { join as join2 } from "path";
|
|
87
99
|
import { fileURLToPath } from "url";
|
|
88
100
|
import { dirname } from "path";
|
|
89
|
-
import
|
|
101
|
+
import pc2 from "picocolors";
|
|
90
102
|
import * as p from "@clack/prompts";
|
|
91
103
|
|
|
92
104
|
// src/apps/shared/native-launcher.ts
|
|
93
|
-
init_config();
|
|
94
105
|
import { chmodSync, existsSync, mkdtempSync, writeFileSync } from "fs";
|
|
95
106
|
import { homedir } from "os";
|
|
96
107
|
import { tmpdir } from "os";
|
|
@@ -98,10 +109,38 @@ import { join } from "path";
|
|
|
98
109
|
var isWindows = process.platform === "win32";
|
|
99
110
|
var isMac = process.platform === "darwin";
|
|
100
111
|
var SUPPORTED_APPS = [
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
{
|
|
113
|
+
id: "claude",
|
|
114
|
+
name: "Claude Code CLI",
|
|
115
|
+
type: "cli",
|
|
116
|
+
detectId: "claude",
|
|
117
|
+
gatewayCommand: "claude",
|
|
118
|
+
installHint: "npm install -g @anthropic-ai/claude-code"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "codex",
|
|
122
|
+
name: "Codex CLI",
|
|
123
|
+
type: "cli",
|
|
124
|
+
detectId: "codex",
|
|
125
|
+
gatewayCommand: "codex",
|
|
126
|
+
installHint: "npm install -g @openai/codex"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "gemini",
|
|
130
|
+
name: "Gemini CLI",
|
|
131
|
+
type: "cli",
|
|
132
|
+
detectId: "gemini",
|
|
133
|
+
gatewayCommand: "gemini",
|
|
134
|
+
installHint: "npm install -g @google/gemini-cli"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "agy",
|
|
138
|
+
name: "Antigravity CLI",
|
|
139
|
+
type: "cli",
|
|
140
|
+
detectId: "agy",
|
|
141
|
+
gatewayCommand: "agy",
|
|
142
|
+
installHint: "npm install -g @google/antigravity-cli"
|
|
143
|
+
},
|
|
105
144
|
{
|
|
106
145
|
id: "antigravity",
|
|
107
146
|
name: "Antigravity (App)",
|
|
@@ -142,30 +181,21 @@ function fallbackPathsForApp(id, platform = process.platform) {
|
|
|
142
181
|
const localAppData = process.env["LOCALAPPDATA"] ?? join(homedir(), "AppData", "Local");
|
|
143
182
|
switch (id) {
|
|
144
183
|
case "claude":
|
|
145
|
-
return windows ? [
|
|
146
|
-
join(appData, "npm", "claude.cmd"),
|
|
147
|
-
join(appData, "npm", "claude")
|
|
148
|
-
] : [
|
|
184
|
+
return windows ? [join(appData, "npm", "claude.cmd"), join(appData, "npm", "claude")] : [
|
|
149
185
|
join(homedir(), ".local", "bin", "claude"),
|
|
150
186
|
join(homedir(), ".npm", "bin", "claude"),
|
|
151
187
|
"/usr/local/bin/claude",
|
|
152
188
|
"/opt/homebrew/bin/claude"
|
|
153
189
|
];
|
|
154
190
|
case "codex":
|
|
155
|
-
return windows ? [
|
|
156
|
-
join(appData, "npm", "codex.cmd"),
|
|
157
|
-
join(appData, "npm", "codex")
|
|
158
|
-
] : [
|
|
191
|
+
return windows ? [join(appData, "npm", "codex.cmd"), join(appData, "npm", "codex")] : [
|
|
159
192
|
join(homedir(), ".local", "bin", "codex"),
|
|
160
193
|
join(homedir(), ".npm", "bin", "codex"),
|
|
161
194
|
"/usr/local/bin/codex",
|
|
162
195
|
"/opt/homebrew/bin/codex"
|
|
163
196
|
];
|
|
164
197
|
case "gemini":
|
|
165
|
-
return windows ? [
|
|
166
|
-
join(appData, "npm", "gemini.cmd"),
|
|
167
|
-
join(appData, "npm", "gemini")
|
|
168
|
-
] : [
|
|
198
|
+
return windows ? [join(appData, "npm", "gemini.cmd"), join(appData, "npm", "gemini")] : [
|
|
169
199
|
join(homedir(), ".local", "bin", "gemini"),
|
|
170
200
|
join(homedir(), ".npm", "bin", "gemini"),
|
|
171
201
|
"/usr/local/bin/gemini",
|
|
@@ -186,7 +216,16 @@ function fallbackPathsForApp(id, platform = process.platform) {
|
|
|
186
216
|
if (mac) {
|
|
187
217
|
return [
|
|
188
218
|
"/Applications/Antigravity IDE.app/Contents/Resources/app/bin/antigravity-ide",
|
|
189
|
-
join(
|
|
219
|
+
join(
|
|
220
|
+
homedir(),
|
|
221
|
+
"Applications",
|
|
222
|
+
"Antigravity IDE.app",
|
|
223
|
+
"Contents",
|
|
224
|
+
"Resources",
|
|
225
|
+
"app",
|
|
226
|
+
"bin",
|
|
227
|
+
"antigravity-ide"
|
|
228
|
+
)
|
|
190
229
|
];
|
|
191
230
|
}
|
|
192
231
|
if (windows) {
|
|
@@ -205,15 +244,9 @@ function fallbackPathsForApp(id, platform = process.platform) {
|
|
|
205
244
|
];
|
|
206
245
|
}
|
|
207
246
|
if (windows) {
|
|
208
|
-
return [
|
|
209
|
-
join(localAppData, "Programs", "Antigravity", "Antigravity.exe")
|
|
210
|
-
];
|
|
247
|
+
return [join(localAppData, "Programs", "Antigravity", "Antigravity.exe")];
|
|
211
248
|
}
|
|
212
|
-
return [
|
|
213
|
-
"/opt/antigravity/antigravity",
|
|
214
|
-
"/usr/local/bin/antigravity",
|
|
215
|
-
"/usr/bin/antigravity"
|
|
216
|
-
];
|
|
249
|
+
return ["/opt/antigravity/antigravity", "/usr/local/bin/antigravity", "/usr/bin/antigravity"];
|
|
217
250
|
case "claude-app":
|
|
218
251
|
if (mac) {
|
|
219
252
|
return [
|
|
@@ -251,8 +284,8 @@ function getSupportedApp(id) {
|
|
|
251
284
|
}
|
|
252
285
|
function detectApp(id) {
|
|
253
286
|
const override = getAppPathOverride(id);
|
|
254
|
-
if (override) {
|
|
255
|
-
return
|
|
287
|
+
if (override && existsSync(override)) {
|
|
288
|
+
return { installed: true, path: override, pathSource: "override" };
|
|
256
289
|
}
|
|
257
290
|
const resolvedPath = findBinaryOnPath(id, FALLBACKS[id] ?? [], { verifyWhichResult: true });
|
|
258
291
|
if (resolvedPath) {
|
|
@@ -278,19 +311,23 @@ function getTerminalLaunchCommand(binPath, args, opts = {}) {
|
|
|
278
311
|
const dir2 = mkdtempSync(join(tmpdir(), "anygate-launch-"));
|
|
279
312
|
const scriptPath2 = join(dir2, "launch.command");
|
|
280
313
|
const displayCommand = opts.displayCommand ?? [binPath, ...args].join(" ");
|
|
281
|
-
writeFileSync(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
314
|
+
writeFileSync(
|
|
315
|
+
scriptPath2,
|
|
316
|
+
[
|
|
317
|
+
"#!/bin/sh",
|
|
318
|
+
`trap 'rm -f "$0"; rmdir "$(dirname "$0")" 2>/dev/null' EXIT`,
|
|
319
|
+
"clear",
|
|
320
|
+
opts.cwd ? `cd ${quoteShellArg(opts.cwd)} || exit 1` : "",
|
|
321
|
+
`printf '%s\\n\\n' ${quoteShellArg(`$ ${displayCommand}`)}`,
|
|
322
|
+
fullCmd,
|
|
323
|
+
"status=$?",
|
|
324
|
+
'printf "\\nanygate session exited with code %s. Press Return to close this window. " "$status"',
|
|
325
|
+
"read _",
|
|
326
|
+
'exit "$status"',
|
|
327
|
+
""
|
|
328
|
+
].join("\n"),
|
|
329
|
+
{ encoding: "utf8", mode: 448 }
|
|
330
|
+
);
|
|
294
331
|
chmodSync(scriptPath2, 448);
|
|
295
332
|
return `open -a Terminal ${quoteShellArg(scriptPath2)}`;
|
|
296
333
|
}
|
|
@@ -300,12 +337,10 @@ function getTerminalLaunchCommand(binPath, args, opts = {}) {
|
|
|
300
337
|
}
|
|
301
338
|
const dir = mkdtempSync(join(tmpdir(), "anygate-launch-"));
|
|
302
339
|
const scriptPath = join(dir, "launch.sh");
|
|
303
|
-
writeFileSync(scriptPath, [
|
|
304
|
-
"
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
""
|
|
308
|
-
].join("\n"), { encoding: "utf8", mode: 448 });
|
|
340
|
+
writeFileSync(scriptPath, ["#!/bin/sh", runCmd, "exec sh", ""].join("\n"), {
|
|
341
|
+
encoding: "utf8",
|
|
342
|
+
mode: 448
|
|
343
|
+
});
|
|
309
344
|
chmodSync(scriptPath, 448);
|
|
310
345
|
const scriptArg = quoteShellArg(scriptPath);
|
|
311
346
|
return `x-terminal-emulator -e sh ${scriptArg} || gnome-terminal -- sh ${scriptArg} || xterm -e sh ${scriptArg}`;
|
|
@@ -326,6 +361,8 @@ function getGatewayLaunchCommand(appId, options = {}) {
|
|
|
326
361
|
}
|
|
327
362
|
if (options.favoritesCatalog) {
|
|
328
363
|
args.push("--favorites");
|
|
364
|
+
} else if (options.allModels && options.providerId) {
|
|
365
|
+
args.push("--provider", options.providerId, "--all-models");
|
|
329
366
|
} else if (options.providerId && options.modelId) {
|
|
330
367
|
args.push("--provider", options.providerId, "--model", options.modelId);
|
|
331
368
|
} else if (options.providerId || options.modelId) {
|
|
@@ -355,21 +392,20 @@ function getSupportedApps() {
|
|
|
355
392
|
}
|
|
356
393
|
|
|
357
394
|
// src/ui/api.ts
|
|
358
|
-
init_config();
|
|
359
395
|
import { exec } from "child_process";
|
|
360
396
|
import { promisify } from "util";
|
|
361
397
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
362
398
|
import { randomUUID } from "crypto";
|
|
363
399
|
|
|
364
400
|
// src/ui/server-control.ts
|
|
365
|
-
init_config();
|
|
366
401
|
var running = null;
|
|
367
402
|
var startInFlight = null;
|
|
368
403
|
var SAVED_PASSWORD_CACHE_TTL_MS = 3e4;
|
|
369
404
|
var hasSavedPasswordCache = null;
|
|
370
405
|
async function hasSavedPasswordCached() {
|
|
371
406
|
const now = Date.now();
|
|
372
|
-
if (hasSavedPasswordCache && hasSavedPasswordCache.expiresAt > now)
|
|
407
|
+
if (hasSavedPasswordCache && hasSavedPasswordCache.expiresAt > now)
|
|
408
|
+
return hasSavedPasswordCache.value;
|
|
373
409
|
const value = Boolean(await getSavedServerPassword());
|
|
374
410
|
hasSavedPasswordCache = { value, expiresAt: now + SAVED_PASSWORD_CACHE_TTL_MS };
|
|
375
411
|
return value;
|
|
@@ -384,9 +420,12 @@ function buildModelRows(models, gateway) {
|
|
|
384
420
|
}
|
|
385
421
|
const rows = [];
|
|
386
422
|
for (const [providerLabel, groupModels] of groups) {
|
|
387
|
-
for (const row of buildDedupedModelRows(groupModels, gateway))
|
|
423
|
+
for (const row of buildDedupedModelRows(groupModels, gateway))
|
|
424
|
+
rows.push({ providerLabel, ...row });
|
|
388
425
|
}
|
|
389
|
-
return rows.sort(
|
|
426
|
+
return rows.sort(
|
|
427
|
+
(a, b) => a.providerLabel.localeCompare(b.providerLabel) || a.name.localeCompare(b.name)
|
|
428
|
+
);
|
|
390
429
|
}
|
|
391
430
|
async function buildSavedConfig() {
|
|
392
431
|
return {
|
|
@@ -416,11 +455,13 @@ async function getServerStatus() {
|
|
|
416
455
|
models: modelRows
|
|
417
456
|
};
|
|
418
457
|
if (config.listenMode === "network") {
|
|
419
|
-
payload.networkUrls = getLocalIps().map(
|
|
420
|
-
name,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
458
|
+
payload.networkUrls = getLocalIps().map(
|
|
459
|
+
({ name, address }) => ({
|
|
460
|
+
name,
|
|
461
|
+
anthropicUrl: `http://${address}:${handle.port}/anthropic`,
|
|
462
|
+
openaiUrl: `http://${address}:${handle.port}/openai/v1`
|
|
463
|
+
})
|
|
464
|
+
);
|
|
424
465
|
payload.apiKey = serverPassword ?? void 0;
|
|
425
466
|
} else {
|
|
426
467
|
payload.apiKey = "any non-empty value";
|
|
@@ -428,7 +469,8 @@ async function getServerStatus() {
|
|
|
428
469
|
return payload;
|
|
429
470
|
}
|
|
430
471
|
function startGatewayServer(req) {
|
|
431
|
-
if (running)
|
|
472
|
+
if (running)
|
|
473
|
+
return Promise.resolve({ ok: false, error: "Server is already running. Stop it first." });
|
|
432
474
|
if (startInFlight) return startInFlight;
|
|
433
475
|
startInFlight = doStartGatewayServer(req).finally(() => {
|
|
434
476
|
startInFlight = null;
|
|
@@ -441,7 +483,10 @@ async function doStartGatewayServer(req) {
|
|
|
441
483
|
}
|
|
442
484
|
const apiKey = await resolveServerUpstreamApiKey();
|
|
443
485
|
if (!apiKey) {
|
|
444
|
-
return {
|
|
486
|
+
return {
|
|
487
|
+
ok: false,
|
|
488
|
+
error: "No providers configured. Add a provider in Providers & Keys first."
|
|
489
|
+
};
|
|
445
490
|
}
|
|
446
491
|
let serverPassword = null;
|
|
447
492
|
if (req.listenMode === "network") {
|
|
@@ -463,13 +508,19 @@ async function doStartGatewayServer(req) {
|
|
|
463
508
|
try {
|
|
464
509
|
models = await loadServerModels();
|
|
465
510
|
} catch (err) {
|
|
466
|
-
return {
|
|
511
|
+
return {
|
|
512
|
+
ok: false,
|
|
513
|
+
error: `Failed to load models: ${err instanceof Error ? err.message : String(err)}`
|
|
514
|
+
};
|
|
467
515
|
}
|
|
468
516
|
if (req.exposedProviders) models = filterServerModelsByProviders(models, req.exposedProviders);
|
|
469
517
|
if (req.favoritesOnly) {
|
|
470
518
|
const favorites = loadPreferences().favoriteModels ?? [];
|
|
471
519
|
if (favorites.length === 0) {
|
|
472
|
-
return {
|
|
520
|
+
return {
|
|
521
|
+
ok: false,
|
|
522
|
+
error: "No favorite models configured. Add favorites in the Favorites tab first."
|
|
523
|
+
};
|
|
473
524
|
}
|
|
474
525
|
models = filterServerModelsByFavorites(models, favorites).slice(0, MAX_MODEL_CATALOG);
|
|
475
526
|
if (models.length === 0) {
|
|
@@ -483,11 +534,14 @@ async function doStartGatewayServer(req) {
|
|
|
483
534
|
}
|
|
484
535
|
}
|
|
485
536
|
if (models.length === 0) {
|
|
486
|
-
return {
|
|
537
|
+
return {
|
|
538
|
+
ok: false,
|
|
539
|
+
error: "No models to expose. Add providers or adjust the exposed-provider filter."
|
|
540
|
+
};
|
|
487
541
|
}
|
|
488
542
|
setServerFavoritesOnly(req.favoritesOnly);
|
|
489
543
|
setServerFreeModelsOnly(req.freeModelsOnly);
|
|
490
|
-
|
|
544
|
+
setServerExposedProviders(req.exposedProviders ?? []);
|
|
491
545
|
setServerMaskGatewayIds(req.maskGatewayIds);
|
|
492
546
|
setServerListenMode(req.listenMode);
|
|
493
547
|
const host = req.listenMode === "network" ? "0.0.0.0" : "127.0.0.1";
|
|
@@ -532,6 +586,94 @@ async function stopGatewayServer() {
|
|
|
532
586
|
return { ok: true, stopped: false };
|
|
533
587
|
}
|
|
534
588
|
|
|
589
|
+
// src/services/doctor.ts
|
|
590
|
+
import pc from "picocolors";
|
|
591
|
+
import { createServer } from "net";
|
|
592
|
+
function nodeMajor() {
|
|
593
|
+
const raw = process.versions.node.split(".")[0] ?? "0";
|
|
594
|
+
return Number.parseInt(raw, 10) || 0;
|
|
595
|
+
}
|
|
596
|
+
function checkPortFree(port) {
|
|
597
|
+
return new Promise((resolve) => {
|
|
598
|
+
const server = createServer();
|
|
599
|
+
server.once("error", () => resolve(false));
|
|
600
|
+
server.listen(port, () => {
|
|
601
|
+
server.close(() => resolve(true));
|
|
602
|
+
});
|
|
603
|
+
const timer = setTimeout(() => resolve(true), 1500);
|
|
604
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
async function collectDoctorReport(opts = {}) {
|
|
608
|
+
const checks = [];
|
|
609
|
+
const major = nodeMajor();
|
|
610
|
+
checks.push({
|
|
611
|
+
id: "node",
|
|
612
|
+
label: "Node.js version",
|
|
613
|
+
ok: major >= 18,
|
|
614
|
+
detail: `v${process.versions.node} (requires \u2265 18)`,
|
|
615
|
+
critical: true
|
|
616
|
+
});
|
|
617
|
+
let keyringOk = false;
|
|
618
|
+
let keyringDetail = "";
|
|
619
|
+
const platform = process.platform;
|
|
620
|
+
if (platform === "darwin") {
|
|
621
|
+
keyringOk = true;
|
|
622
|
+
keyringDetail = "macOS Keychain Service";
|
|
623
|
+
} else if (platform === "win32") {
|
|
624
|
+
keyringOk = true;
|
|
625
|
+
keyringDetail = "Windows Credential Manager";
|
|
626
|
+
} else if (platform === "linux") {
|
|
627
|
+
keyringOk = await isSecretServiceAvailable();
|
|
628
|
+
keyringDetail = keyringOk ? "Secret Service (GNOME Keyring / KWallet)" : "Secret Service daemon unreachable";
|
|
629
|
+
} else {
|
|
630
|
+
keyringDetail = `Unsupported platform (${platform})`;
|
|
631
|
+
}
|
|
632
|
+
checks.push({
|
|
633
|
+
id: "keychain",
|
|
634
|
+
label: "Secure credential storage",
|
|
635
|
+
ok: keyringOk,
|
|
636
|
+
detail: keyringDetail,
|
|
637
|
+
critical: false
|
|
638
|
+
});
|
|
639
|
+
const storedKey = await readFromCredentialStore();
|
|
640
|
+
checks.push({
|
|
641
|
+
id: "opencode-key",
|
|
642
|
+
label: "OpenCode API key",
|
|
643
|
+
ok: Boolean(storedKey || process.env["OPENCODE_API_KEY"]),
|
|
644
|
+
detail: storedKey ? "Configured in secure store" : process.env["OPENCODE_API_KEY"] ? "Configured via process environment" : "Not set (run `anygate --setup`)",
|
|
645
|
+
critical: false
|
|
646
|
+
});
|
|
647
|
+
const conflicts = detectConflicts();
|
|
648
|
+
const conflictNames = conflicts.map((c) => c.name);
|
|
649
|
+
checks.push({
|
|
650
|
+
id: "env-conflicts",
|
|
651
|
+
label: "Environment variable conflicts",
|
|
652
|
+
ok: conflicts.length === 0,
|
|
653
|
+
detail: conflicts.length === 0 ? "Clean" : `Found ${conflicts.length} conflicting var(s): ${conflictNames.join(", ")}`,
|
|
654
|
+
critical: false
|
|
655
|
+
});
|
|
656
|
+
const portFree = await checkPortFree(GATEWAY_PORT);
|
|
657
|
+
const ownedByUs = !portFree && Boolean(opts.gatewayRunning);
|
|
658
|
+
checks.push({
|
|
659
|
+
id: "gateway-port",
|
|
660
|
+
label: `Local gateway port (${GATEWAY_PORT})`,
|
|
661
|
+
ok: portFree || ownedByUs,
|
|
662
|
+
detail: portFree ? "Available" : ownedByUs ? "In use by the anygate gateway" : "In use by another process",
|
|
663
|
+
critical: false
|
|
664
|
+
});
|
|
665
|
+
return {
|
|
666
|
+
ok: !checks.some((c) => c.critical && !c.ok),
|
|
667
|
+
checks,
|
|
668
|
+
nodeVersion: process.versions.node,
|
|
669
|
+
keychain: { available: keyringOk, note: keyringDetail },
|
|
670
|
+
conflictingEnvVars: conflictNames,
|
|
671
|
+
gatewayPort: GATEWAY_PORT,
|
|
672
|
+
gatewayPortAvailable: portFree,
|
|
673
|
+
gatewayPortOwnedByAnygate: ownedByUs
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
535
677
|
// src/ui/api.ts
|
|
536
678
|
var execAsync = promisify(exec);
|
|
537
679
|
var MODELS_TIMEOUT_MS = 3e4;
|
|
@@ -569,6 +711,14 @@ function traceUi(opts, message) {
|
|
|
569
711
|
writeSecureLogLine(opts.traceLogPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}`);
|
|
570
712
|
}
|
|
571
713
|
function notifyServerLifecycle(opts, event) {
|
|
714
|
+
emitAppEvent(
|
|
715
|
+
event.type === "started" ? {
|
|
716
|
+
type: "server",
|
|
717
|
+
running: true,
|
|
718
|
+
listenMode: event.listenMode,
|
|
719
|
+
modelCount: event.modelCount
|
|
720
|
+
} : { type: "server", running: false }
|
|
721
|
+
);
|
|
572
722
|
try {
|
|
573
723
|
opts.onServerLifecycle?.(event);
|
|
574
724
|
} catch {
|
|
@@ -607,9 +757,9 @@ function handleUiApiRequest(req, res, opts = {}) {
|
|
|
607
757
|
handleAddCustomProvider(req, res);
|
|
608
758
|
} else if (url === "/api/providers/delete" && req.method === "POST") {
|
|
609
759
|
handleDeleteProvider(req, res);
|
|
610
|
-
} else if (url === "/api/providers/auth/start" && req.method === "POST") {
|
|
760
|
+
} else if ((url === "/api/providers/oauth/start" || url === "/api/providers/auth/start") && req.method === "POST") {
|
|
611
761
|
handleOAuthStart(req, res);
|
|
612
|
-
} else if (url.startsWith("/api/providers/auth/status") && req.method === "GET") {
|
|
762
|
+
} else if ((url.startsWith("/api/providers/oauth/status") || url.startsWith("/api/providers/auth/status")) && req.method === "GET") {
|
|
613
763
|
handleOAuthStatus(req, res);
|
|
614
764
|
} else if (url.startsWith("/auth/callback") && req.method === "GET") {
|
|
615
765
|
handleOAuthCallback(req, res);
|
|
@@ -629,12 +779,111 @@ function handleUiApiRequest(req, res, opts = {}) {
|
|
|
629
779
|
handleStartServer(req, res, opts);
|
|
630
780
|
} else if (url === "/api/server/stop" && req.method === "POST") {
|
|
631
781
|
handleStopServer(res, opts);
|
|
782
|
+
} else if (url === "/api/events" && req.method === "GET") {
|
|
783
|
+
handleEventStream(req, res);
|
|
784
|
+
} else if (url === "/api/presets" && req.method === "GET") {
|
|
785
|
+
handleGetPresets(res);
|
|
786
|
+
} else if (url === "/api/presets" && req.method === "POST") {
|
|
787
|
+
handleSavePresets(req, res);
|
|
788
|
+
} else if (url === "/api/health" && req.method === "GET") {
|
|
789
|
+
handleGetHealth(res);
|
|
632
790
|
} else if (url.startsWith("/api/analytics") && req.method === "GET") {
|
|
633
791
|
handleGetAnalytics(res, req);
|
|
634
792
|
} else {
|
|
635
793
|
sendJson(res, 404, { error: "Not found" });
|
|
636
794
|
}
|
|
637
795
|
}
|
|
796
|
+
var SSE_KEEPALIVE_MS = 25e3;
|
|
797
|
+
function handleEventStream(req, res) {
|
|
798
|
+
res.writeHead(200, {
|
|
799
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
800
|
+
"Cache-Control": "no-cache, no-transform",
|
|
801
|
+
Connection: "keep-alive",
|
|
802
|
+
// Defeats proxy buffering that would otherwise delay events.
|
|
803
|
+
"X-Accel-Buffering": "no"
|
|
804
|
+
});
|
|
805
|
+
const send = (event) => {
|
|
806
|
+
if (!res.writableEnded) res.write(`data: ${JSON.stringify(event)}
|
|
807
|
+
|
|
808
|
+
`);
|
|
809
|
+
};
|
|
810
|
+
res.write(": connected\n\n");
|
|
811
|
+
const unsubscribe = subscribeToAppEvents(send);
|
|
812
|
+
const keepalive = setInterval(() => {
|
|
813
|
+
if (!res.writableEnded) res.write(": keepalive\n\n");
|
|
814
|
+
}, SSE_KEEPALIVE_MS);
|
|
815
|
+
if (typeof keepalive.unref === "function") keepalive.unref();
|
|
816
|
+
const cleanup = () => {
|
|
817
|
+
clearInterval(keepalive);
|
|
818
|
+
unsubscribe();
|
|
819
|
+
};
|
|
820
|
+
req.on("close", cleanup);
|
|
821
|
+
req.on("error", cleanup);
|
|
822
|
+
res.on("close", cleanup);
|
|
823
|
+
}
|
|
824
|
+
function sanitizePreset(raw) {
|
|
825
|
+
if (!raw || typeof raw !== "object") return null;
|
|
826
|
+
const p2 = raw;
|
|
827
|
+
const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
828
|
+
const id = str(p2["id"]);
|
|
829
|
+
const appId = str(p2["appId"]);
|
|
830
|
+
if (!id || !appId) return null;
|
|
831
|
+
const flags = Array.isArray(p2["flags"]) ? p2["flags"].filter((f) => typeof f === "string") : void 0;
|
|
832
|
+
const preset = { id, appId };
|
|
833
|
+
const providerId = str(p2["providerId"]);
|
|
834
|
+
const modelId = str(p2["modelId"]);
|
|
835
|
+
const folder = str(p2["folder"]);
|
|
836
|
+
const label = str(p2["label"]);
|
|
837
|
+
if (providerId) preset.providerId = providerId;
|
|
838
|
+
if (modelId) preset.modelId = modelId;
|
|
839
|
+
if (folder) preset.folder = folder;
|
|
840
|
+
if (label) preset.label = label;
|
|
841
|
+
if (flags?.length) preset.flags = flags;
|
|
842
|
+
return preset;
|
|
843
|
+
}
|
|
844
|
+
function handleGetPresets(res) {
|
|
845
|
+
try {
|
|
846
|
+
sendJson(res, 200, { presets: loadLaunchPresets() });
|
|
847
|
+
} catch (err) {
|
|
848
|
+
sendJson(res, 500, { error: String(err) });
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async function handleSavePresets(req, res) {
|
|
852
|
+
try {
|
|
853
|
+
const body = JSON.parse(await readBody(req));
|
|
854
|
+
if (!Array.isArray(body.presets)) {
|
|
855
|
+
sendJson(res, 400, { error: "presets must be an array" });
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const seen = /* @__PURE__ */ new Map();
|
|
859
|
+
for (const raw of body.presets) {
|
|
860
|
+
const preset = sanitizePreset(raw);
|
|
861
|
+
if (preset) seen.set(preset.id, preset);
|
|
862
|
+
}
|
|
863
|
+
sendJson(res, 200, { ok: true, presets: saveLaunchPresets([...seen.values()]) });
|
|
864
|
+
} catch (err) {
|
|
865
|
+
sendJson(res, 500, { error: String(err) });
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
async function handleGetHealth(res) {
|
|
869
|
+
try {
|
|
870
|
+
const gatewayRunning = (await getServerStatus()).running;
|
|
871
|
+
const report = await collectDoctorReport({ gatewayRunning });
|
|
872
|
+
sendJson(res, 200, {
|
|
873
|
+
ok: report.ok,
|
|
874
|
+
checks: report.checks,
|
|
875
|
+
nodeVersion: report.nodeVersion,
|
|
876
|
+
keychain: report.keychain,
|
|
877
|
+
conflictingEnvVars: report.conflictingEnvVars,
|
|
878
|
+
gatewayPort: report.gatewayPort,
|
|
879
|
+
// Busy-but-ours counts as available to the UI: nothing is blocking a start.
|
|
880
|
+
port17645Available: report.gatewayPortAvailable || report.gatewayPortOwnedByAnygate,
|
|
881
|
+
gatewayPortOwnedByAnygate: report.gatewayPortOwnedByAnygate
|
|
882
|
+
});
|
|
883
|
+
} catch (err) {
|
|
884
|
+
sendJson(res, 500, { error: String(err) });
|
|
885
|
+
}
|
|
886
|
+
}
|
|
638
887
|
async function handleGetUpdateStatus(res) {
|
|
639
888
|
sendJson(res, 200, await checkForUpdates());
|
|
640
889
|
}
|
|
@@ -650,7 +899,8 @@ async function handlePostConfig(req, res) {
|
|
|
650
899
|
const body = JSON.parse(await readBody(req));
|
|
651
900
|
const update = {};
|
|
652
901
|
if (Array.isArray(body.favoriteModels)) update.favoriteModels = body.favoriteModels;
|
|
653
|
-
if (Array.isArray(body.antigravityCliFavoriteModels))
|
|
902
|
+
if (Array.isArray(body.antigravityCliFavoriteModels))
|
|
903
|
+
update.antigravityCliFavoriteModels = body.antigravityCliFavoriteModels;
|
|
654
904
|
if (Object.keys(update).length > 0) savePreferences(update);
|
|
655
905
|
sendJson(res, 200, { ok: true });
|
|
656
906
|
} catch (err) {
|
|
@@ -671,7 +921,9 @@ async function handleGetModels(res) {
|
|
|
671
921
|
try {
|
|
672
922
|
const catalog = await fetchModelsWithTimeout();
|
|
673
923
|
const registry = loadRegistry();
|
|
674
|
-
const rawCountById = new Map(
|
|
924
|
+
const rawCountById = new Map(
|
|
925
|
+
registry.providers.map((p2) => [p2.id, p2.modelsCache?.models.length ?? 0])
|
|
926
|
+
);
|
|
675
927
|
const providers = catalog.map((p2) => ({
|
|
676
928
|
id: p2.id,
|
|
677
929
|
name: p2.name,
|
|
@@ -704,7 +956,11 @@ async function handleGetModels(res) {
|
|
|
704
956
|
providers.push({
|
|
705
957
|
id: rp.id,
|
|
706
958
|
name: rp.name,
|
|
707
|
-
favoriteName: favoriteProviderDisplayName({
|
|
959
|
+
favoriteName: favoriteProviderDisplayName({
|
|
960
|
+
id: rp.id,
|
|
961
|
+
name: rp.name,
|
|
962
|
+
authType: rp.authType
|
|
963
|
+
}),
|
|
708
964
|
hasKey: true,
|
|
709
965
|
freeAccess: false,
|
|
710
966
|
authType: "oauth",
|
|
@@ -1030,16 +1286,29 @@ async function handlePostKeys(req, res) {
|
|
|
1030
1286
|
}
|
|
1031
1287
|
}
|
|
1032
1288
|
var CUSTOM_TEMPLATES = [
|
|
1033
|
-
{
|
|
1034
|
-
|
|
1289
|
+
{
|
|
1290
|
+
id: "__custom_openai__",
|
|
1291
|
+
name: "Custom OpenAI-compatible",
|
|
1292
|
+
signupUrl: null,
|
|
1293
|
+
authType: "api",
|
|
1294
|
+
custom: true
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
id: "__custom_anthropic__",
|
|
1298
|
+
name: "Custom Anthropic-compatible",
|
|
1299
|
+
signupUrl: null,
|
|
1300
|
+
authType: "api",
|
|
1301
|
+
custom: true
|
|
1302
|
+
}
|
|
1035
1303
|
];
|
|
1036
1304
|
function handleGetTemplates(res) {
|
|
1037
1305
|
const registry = loadRegistry();
|
|
1038
1306
|
const configured = new Set(registry.providers.map((p2) => p2.id));
|
|
1039
|
-
const apiTemplates =
|
|
1307
|
+
const apiTemplates = listAddableTemplates(configured).map((t) => ({
|
|
1040
1308
|
id: t.id,
|
|
1041
1309
|
name: t.name,
|
|
1042
1310
|
signupUrl: t.signupUrl ?? null,
|
|
1311
|
+
signupNote: t.signupNote ?? null,
|
|
1043
1312
|
authType: t.authType,
|
|
1044
1313
|
anonymousFreeModels: t.anonymousFreeModels ?? false,
|
|
1045
1314
|
urlPrompt: t.urlPrompt ?? null,
|
|
@@ -1098,8 +1367,8 @@ async function handleAddProvider(req, res) {
|
|
|
1098
1367
|
sendJson(res, 400, { error: "templateId required" });
|
|
1099
1368
|
return;
|
|
1100
1369
|
}
|
|
1101
|
-
const { listSupportedTemplates
|
|
1102
|
-
const template =
|
|
1370
|
+
const { listSupportedTemplates } = await import("./provider-templates-336QE7ZV.js");
|
|
1371
|
+
const template = listSupportedTemplates().find((t) => t.id === templateId);
|
|
1103
1372
|
if (!template) {
|
|
1104
1373
|
sendJson(res, 404, { error: `Template '${templateId}' not found` });
|
|
1105
1374
|
return;
|
|
@@ -1109,22 +1378,26 @@ async function handleAddProvider(req, res) {
|
|
|
1109
1378
|
sendJson(res, 400, { error: "key must be a non-empty string" });
|
|
1110
1379
|
return;
|
|
1111
1380
|
}
|
|
1112
|
-
const keyText =
|
|
1381
|
+
const keyText = rawKey;
|
|
1113
1382
|
let baseUrlOverride;
|
|
1114
1383
|
if (template.urlPrompt) {
|
|
1115
|
-
baseUrlOverride = typeof baseUrl === "string" ? baseUrl.trim() : "";
|
|
1384
|
+
baseUrlOverride = (typeof baseUrl === "string" ? baseUrl.trim() : "") || (template.defaultBaseUrl ?? "");
|
|
1116
1385
|
if (!baseUrlOverride) {
|
|
1117
1386
|
sendJson(res, 400, { error: "baseUrl required" });
|
|
1118
1387
|
return;
|
|
1119
1388
|
}
|
|
1120
1389
|
const usesHttp = /^http:\/\//i.test(baseUrlOverride);
|
|
1121
|
-
const valid = await validateCustomEndpointUrl(baseUrlOverride, {
|
|
1390
|
+
const valid = await validateCustomEndpointUrl(baseUrlOverride, {
|
|
1391
|
+
allowInsecureLocal: usesHttp
|
|
1392
|
+
});
|
|
1122
1393
|
if (!valid.ok) {
|
|
1123
1394
|
sendJson(res, 400, { error: valid.error ?? "Invalid URL", hint: valid.hint });
|
|
1124
1395
|
return;
|
|
1125
1396
|
}
|
|
1126
1397
|
}
|
|
1127
|
-
const result = await addProviderFromTemplate(template, keyText, {
|
|
1398
|
+
const result = await addProviderFromTemplate(template, keyText, {
|
|
1399
|
+
baseUrl: baseUrlOverride
|
|
1400
|
+
});
|
|
1128
1401
|
if (result.added) {
|
|
1129
1402
|
sendJson(res, 200, { ok: true, name: template.name, count: result.modelCount ?? 0 });
|
|
1130
1403
|
} else {
|
|
@@ -1152,7 +1425,11 @@ async function handleRefreshAll(res) {
|
|
|
1152
1425
|
reason: r.reason
|
|
1153
1426
|
};
|
|
1154
1427
|
});
|
|
1155
|
-
sendJson(res, 200, {
|
|
1428
|
+
sendJson(res, 200, {
|
|
1429
|
+
ok: true,
|
|
1430
|
+
providers: summary,
|
|
1431
|
+
total: summary.reduce((n, p2) => n + p2.count, 0)
|
|
1432
|
+
});
|
|
1156
1433
|
} catch (err) {
|
|
1157
1434
|
sendJson(res, 500, { ok: false, error: String(err) });
|
|
1158
1435
|
}
|
|
@@ -1215,14 +1492,21 @@ async function handleOAuthStart(req, res) {
|
|
|
1215
1492
|
const body = JSON.parse(await readBody(req));
|
|
1216
1493
|
const { providerId } = body;
|
|
1217
1494
|
if (!providerId || !NATIVE_OAUTH_PROVIDER_IDS.has(providerId)) {
|
|
1218
|
-
sendJson(res, 400, {
|
|
1495
|
+
sendJson(res, 400, {
|
|
1496
|
+
error: `providerId must be one of: ${[...NATIVE_OAUTH_PROVIDER_IDS].join(", ")}`
|
|
1497
|
+
});
|
|
1219
1498
|
return;
|
|
1220
1499
|
}
|
|
1221
1500
|
const sessionId = randomUUID();
|
|
1222
1501
|
if (providerId === "xai-oauth") {
|
|
1223
1502
|
const device2 = await requestXaiDeviceCode();
|
|
1224
1503
|
const url2 = device2.verification_uri_complete ?? device2.verification_uri;
|
|
1225
|
-
const session2 = {
|
|
1504
|
+
const session2 = {
|
|
1505
|
+
status: "pending",
|
|
1506
|
+
url: url2,
|
|
1507
|
+
userCode: device2.user_code,
|
|
1508
|
+
providerId
|
|
1509
|
+
};
|
|
1226
1510
|
oauthSessions.set(sessionId, session2);
|
|
1227
1511
|
pollXaiDeviceCodeToken(device2).then(async (tokens) => {
|
|
1228
1512
|
await saveNativeOAuthCredential(providerId, tokens);
|
|
@@ -1237,7 +1521,12 @@ async function handleOAuthStart(req, res) {
|
|
|
1237
1521
|
if (providerId === "github-copilot") {
|
|
1238
1522
|
const device2 = await requestGithubDeviceCode();
|
|
1239
1523
|
const url2 = device2.verification_uri;
|
|
1240
|
-
const session2 = {
|
|
1524
|
+
const session2 = {
|
|
1525
|
+
status: "pending",
|
|
1526
|
+
url: url2,
|
|
1527
|
+
userCode: device2.user_code,
|
|
1528
|
+
providerId
|
|
1529
|
+
};
|
|
1241
1530
|
oauthSessions.set(sessionId, session2);
|
|
1242
1531
|
pollGithubDeviceCodeToken(device2).then(async (tokens) => {
|
|
1243
1532
|
await saveNativeOAuthCredential(providerId, tokens);
|
|
@@ -1389,7 +1678,7 @@ var AGY_APP_IDS = /* @__PURE__ */ new Set(["antigravity", "agy", "antigravity-id
|
|
|
1389
1678
|
async function handleLaunchApp(req, res, opts) {
|
|
1390
1679
|
try {
|
|
1391
1680
|
const body = JSON.parse(await readBody(req));
|
|
1392
|
-
const { appId, favorites, favoritesCatalog, cwd } = body;
|
|
1681
|
+
const { appId, favorites, favoritesCatalog, allModels, cwd } = body;
|
|
1393
1682
|
let { providerId, modelId } = body;
|
|
1394
1683
|
if (!appId) {
|
|
1395
1684
|
sendJson(res, 400, { error: "Missing appId" });
|
|
@@ -1404,14 +1693,22 @@ async function handleLaunchApp(req, res, opts) {
|
|
|
1404
1693
|
sendJson(res, 400, { error: `App ${appId} is not installed on this system.` });
|
|
1405
1694
|
return;
|
|
1406
1695
|
}
|
|
1407
|
-
if (
|
|
1408
|
-
sendJson(res, 400, { error: "
|
|
1696
|
+
if (allModels && !providerId) {
|
|
1697
|
+
sendJson(res, 400, { error: "providerId is required when allModels is true." });
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
if (!allModels && !favorites && (providerId || modelId) && (!providerId || !modelId)) {
|
|
1701
|
+
sendJson(res, 400, {
|
|
1702
|
+
error: "Both providerId and modelId are required to launch a specific anygate model."
|
|
1703
|
+
});
|
|
1409
1704
|
return;
|
|
1410
1705
|
}
|
|
1411
1706
|
const fullCatalog = Boolean(favoritesCatalog);
|
|
1412
1707
|
if (fullCatalog) {
|
|
1413
1708
|
providerId = void 0;
|
|
1414
1709
|
modelId = void 0;
|
|
1710
|
+
} else if (allModels) {
|
|
1711
|
+
modelId = void 0;
|
|
1415
1712
|
} else if (favorites && !providerId && !modelId) {
|
|
1416
1713
|
const prefs = loadPreferences();
|
|
1417
1714
|
const favList = AGY_APP_IDS.has(appId) ? prefs.antigravityCliFavoriteModels ?? [] : prefs.favoriteModels ?? [];
|
|
@@ -1436,13 +1733,14 @@ async function handleLaunchApp(req, res, opts) {
|
|
|
1436
1733
|
const launchCmd = getGatewayLaunchCommand(appId, {
|
|
1437
1734
|
providerId,
|
|
1438
1735
|
modelId,
|
|
1736
|
+
allModels: Boolean(allModels) && Boolean(providerId),
|
|
1439
1737
|
favoritesCatalog: fullCatalog,
|
|
1440
1738
|
cwd: launchFolder,
|
|
1441
1739
|
trace: opts.trace
|
|
1442
1740
|
});
|
|
1443
1741
|
traceUi(
|
|
1444
1742
|
opts,
|
|
1445
|
-
`launch app=${appId} provider=${providerId ?? ""} model=${modelId ?? ""} favorites=${Boolean(favorites)} catalog=${fullCatalog} cwd=${launchFolder ?? ""} command=${launchCmd}`
|
|
1743
|
+
`launch app=${appId} provider=${providerId ?? ""} model=${modelId ?? ""} allModels=${Boolean(allModels)} favorites=${Boolean(favorites)} catalog=${fullCatalog} cwd=${launchFolder ?? ""} command=${launchCmd}`
|
|
1446
1744
|
);
|
|
1447
1745
|
exec(launchCmd, (err) => {
|
|
1448
1746
|
if (err) {
|
|
@@ -1464,7 +1762,9 @@ async function handleSetAppPath(req, res) {
|
|
|
1464
1762
|
return;
|
|
1465
1763
|
}
|
|
1466
1764
|
if (path !== null && (typeof path !== "string" || !path.trim())) {
|
|
1467
|
-
sendJson(res, 400, {
|
|
1765
|
+
sendJson(res, 400, {
|
|
1766
|
+
error: "path must be a non-empty string, or null to clear the override."
|
|
1767
|
+
});
|
|
1468
1768
|
return;
|
|
1469
1769
|
}
|
|
1470
1770
|
const trimmed = typeof path === "string" ? path.trim() : null;
|
|
@@ -1595,12 +1895,16 @@ async function handleBrowseFolder(res) {
|
|
|
1595
1895
|
const { stdout } = await execAsync(`powershell -NoProfile -Sta -EncodedCommand ${encoded}`);
|
|
1596
1896
|
resultPath = stdout.trim();
|
|
1597
1897
|
} catch (err) {
|
|
1598
|
-
sendJson(res, 500, {
|
|
1898
|
+
sendJson(res, 500, {
|
|
1899
|
+
error: `Failed to open folder picker: ${err instanceof Error ? err.message : String(err)}`
|
|
1900
|
+
});
|
|
1599
1901
|
return;
|
|
1600
1902
|
}
|
|
1601
1903
|
} else {
|
|
1602
1904
|
try {
|
|
1603
|
-
const { stdout } = await execAsync(
|
|
1905
|
+
const { stdout } = await execAsync(
|
|
1906
|
+
'zenity --file-selection --directory --title="Select launch folder"'
|
|
1907
|
+
);
|
|
1604
1908
|
resultPath = stdout.trim();
|
|
1605
1909
|
} catch {
|
|
1606
1910
|
try {
|
|
@@ -1679,7 +1983,10 @@ function checkExistingServer() {
|
|
|
1679
1983
|
let processExists = false;
|
|
1680
1984
|
if (isWindows2) {
|
|
1681
1985
|
try {
|
|
1682
|
-
const output = execSync(`tasklist /FI "PID eq ${pid}"`, {
|
|
1986
|
+
const output = execSync(`tasklist /FI "PID eq ${pid}"`, {
|
|
1987
|
+
encoding: "utf8",
|
|
1988
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
1989
|
+
});
|
|
1683
1990
|
processExists = output.includes(String(pid));
|
|
1684
1991
|
} catch {
|
|
1685
1992
|
processExists = false;
|
|
@@ -1718,7 +2025,7 @@ async function runUiCommand(opts = {}) {
|
|
|
1718
2025
|
const existing = checkExistingServer();
|
|
1719
2026
|
if (existing) {
|
|
1720
2027
|
console.log(`
|
|
1721
|
-
${
|
|
2028
|
+
${pc2.bold("anygate UI")} already running at ${pc2.cyan(existing)}
|
|
1722
2029
|
`);
|
|
1723
2030
|
return 0;
|
|
1724
2031
|
}
|
|
@@ -1729,7 +2036,7 @@ async function runUiCommand(opts = {}) {
|
|
|
1729
2036
|
const traceLogPath = opts.trace ? getUiDebugLogPath() : void 0;
|
|
1730
2037
|
const trace = traceLogPath ? makeTraceLogger(traceLogPath) : void 0;
|
|
1731
2038
|
trace?.("ui server starting");
|
|
1732
|
-
const server =
|
|
2039
|
+
const server = createServer2((req, res) => {
|
|
1733
2040
|
const url2 = req.url ?? "/";
|
|
1734
2041
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
1735
2042
|
if (isUiApiRoute(url2)) {
|
|
@@ -1796,12 +2103,14 @@ async function runUiCommand(opts = {}) {
|
|
|
1796
2103
|
process.on("SIGTERM", () => {
|
|
1797
2104
|
void handleSignal("SIGTERM");
|
|
1798
2105
|
});
|
|
1799
|
-
console.log(
|
|
1800
|
-
|
|
1801
|
-
${
|
|
1802
|
-
|
|
2106
|
+
console.log(
|
|
2107
|
+
`
|
|
2108
|
+
${pc2.bold("anygate UI")} ${pc2.cyan(url)}
|
|
2109
|
+
${pc2.dim("Press Ctrl+C to stop")}
|
|
2110
|
+
`
|
|
2111
|
+
);
|
|
1803
2112
|
if (traceLogPath) {
|
|
1804
|
-
console.log(` ${
|
|
2113
|
+
console.log(` ${pc2.dim(`Trace log: ${traceLogPath}`)}
|
|
1805
2114
|
`);
|
|
1806
2115
|
trace?.(`ui server listening ${url}`);
|
|
1807
2116
|
}
|
|
@@ -1822,4 +2131,4 @@ export {
|
|
|
1822
2131
|
resolveUiShutdownDecision,
|
|
1823
2132
|
runUiCommand
|
|
1824
2133
|
};
|
|
1825
|
-
//# sourceMappingURL=command-
|
|
2134
|
+
//# sourceMappingURL=command-XIDZGWNR.js.map
|