@jacobbd/relay-ai 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-MVBA7ABV.js → chunk-EJONCU3B.js} +4 -4
- package/dist/chunk-EJONCU3B.js.map +1 -0
- package/dist/{chunk-SV2Y6OCD.js → chunk-I3I5LKZI.js} +238 -318
- package/dist/chunk-I3I5LKZI.js.map +1 -0
- package/dist/cli.js +341 -221
- package/dist/cli.js.map +1 -1
- package/dist/{provider-templates-6XYKAZB5.js → provider-templates-BPGB5V2L.js} +2 -2
- package/dist/ui/public/app.js +94 -13
- package/dist/ui/public/style.css +31 -0
- package/dist/{ui-command-DJZIIIWC.js → ui-command-GNCQS7F7.js} +33 -15
- package/dist/{ui-command-DJZIIIWC.js.map → ui-command-GNCQS7F7.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-MVBA7ABV.js.map +0 -1
- package/dist/chunk-SV2Y6OCD.js.map +0 -1
- /package/dist/{provider-templates-6XYKAZB5.js.map → provider-templates-BPGB5V2L.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -11,9 +11,8 @@ import {
|
|
|
11
11
|
VERSION,
|
|
12
12
|
VERTEX_ANTHROPIC_NPM,
|
|
13
13
|
addCustomEndpointProvider,
|
|
14
|
-
|
|
14
|
+
addOpencodeCloudFromApiKey,
|
|
15
15
|
addProviderFromTemplate,
|
|
16
|
-
addZenRegistryStub,
|
|
17
16
|
aliasModelId,
|
|
18
17
|
appendCodexBodyDump,
|
|
19
18
|
authenticateProvider,
|
|
@@ -47,12 +46,10 @@ import {
|
|
|
47
46
|
favoriteProviderDisplayName,
|
|
48
47
|
fetchAnthropicModels,
|
|
49
48
|
fetchProviderCatalog,
|
|
50
|
-
fetchRawOpencodeProviders,
|
|
51
49
|
fetchTemplateModels,
|
|
52
50
|
filterServerModelsByFavorites,
|
|
53
51
|
findBinaryOnPath,
|
|
54
52
|
findClaudeBinary,
|
|
55
|
-
findOpencodeBinary,
|
|
56
53
|
fmtCommand,
|
|
57
54
|
fmtCount,
|
|
58
55
|
fmtEnabledStar,
|
|
@@ -91,7 +88,6 @@ import {
|
|
|
91
88
|
loadPreferences,
|
|
92
89
|
loadRegistry,
|
|
93
90
|
loadServerModels,
|
|
94
|
-
localProviderToRegistry,
|
|
95
91
|
logActiveModel,
|
|
96
92
|
logConnected,
|
|
97
93
|
logProxy,
|
|
@@ -171,14 +167,14 @@ import {
|
|
|
171
167
|
validateCustomEndpointUrl,
|
|
172
168
|
writeSecureLogLine,
|
|
173
169
|
zenRegistryStub
|
|
174
|
-
} from "./chunk-
|
|
170
|
+
} from "./chunk-I3I5LKZI.js";
|
|
175
171
|
import {
|
|
176
172
|
filterTemplates,
|
|
177
173
|
init_provider_templates,
|
|
178
174
|
listAddableTemplates,
|
|
179
175
|
listSupportedTemplates,
|
|
180
176
|
listVisibleOAuthTemplates
|
|
181
|
-
} from "./chunk-
|
|
177
|
+
} from "./chunk-EJONCU3B.js";
|
|
182
178
|
|
|
183
179
|
// src/cli.ts
|
|
184
180
|
import pc12 from "picocolors";
|
|
@@ -190,6 +186,144 @@ import { fileURLToPath } from "url";
|
|
|
190
186
|
import pc from "picocolors";
|
|
191
187
|
import * as p2 from "@clack/prompts";
|
|
192
188
|
|
|
189
|
+
// src/opencode-serve.ts
|
|
190
|
+
import { execSync, spawn } from "child_process";
|
|
191
|
+
import { existsSync } from "fs";
|
|
192
|
+
import { homedir } from "os";
|
|
193
|
+
import { join } from "path";
|
|
194
|
+
var isWindows = process.platform === "win32";
|
|
195
|
+
var OPENCODE_FALLBACK_PATHS = isWindows ? [
|
|
196
|
+
join(process.env["APPDATA"] ?? homedir(), "npm", "opencode.cmd"),
|
|
197
|
+
join(process.env["APPDATA"] ?? homedir(), "npm", "opencode"),
|
|
198
|
+
join(homedir(), "AppData", "Roaming", "npm", "opencode.cmd")
|
|
199
|
+
] : [
|
|
200
|
+
join(homedir(), ".opencode", "bin", "opencode"),
|
|
201
|
+
join(homedir(), ".local", "bin", "opencode"),
|
|
202
|
+
join(homedir(), ".npm", "bin", "opencode"),
|
|
203
|
+
"/usr/local/bin/opencode",
|
|
204
|
+
"/opt/homebrew/bin/opencode"
|
|
205
|
+
];
|
|
206
|
+
function findOpencodeBinary() {
|
|
207
|
+
try {
|
|
208
|
+
const result = execSync(isWindows ? "where.exe opencode" : "which opencode", {
|
|
209
|
+
encoding: "utf8",
|
|
210
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
211
|
+
});
|
|
212
|
+
const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
|
|
213
|
+
const path2 = (isWindows ? lines.find((l) => l.toLowerCase().endsWith(".cmd")) : null) ?? lines[0];
|
|
214
|
+
if (path2) return path2;
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
for (const path2 of OPENCODE_FALLBACK_PATHS) {
|
|
218
|
+
if (existsSync(path2)) return path2;
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
async function fetchRawOpencodeProviders() {
|
|
223
|
+
const binary = findOpencodeBinary();
|
|
224
|
+
if (!binary) return null;
|
|
225
|
+
return new Promise((resolve2) => {
|
|
226
|
+
let child = null;
|
|
227
|
+
let settled = false;
|
|
228
|
+
const TIMEOUT_MS = 1e4;
|
|
229
|
+
const finish = (value) => {
|
|
230
|
+
if (settled) return;
|
|
231
|
+
settled = true;
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
try {
|
|
234
|
+
child?.kill();
|
|
235
|
+
} catch {
|
|
236
|
+
}
|
|
237
|
+
resolve2(value);
|
|
238
|
+
};
|
|
239
|
+
const timer = setTimeout(() => {
|
|
240
|
+
finish(null);
|
|
241
|
+
}, TIMEOUT_MS);
|
|
242
|
+
try {
|
|
243
|
+
child = isWindows ? spawn("cmd.exe", ["/c", binary, "serve", "--port", "0"], { stdio: ["pipe", "pipe", "pipe"] }) : spawn(binary, ["serve", "--port", "0"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
244
|
+
} catch {
|
|
245
|
+
finish(null);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const portRegex = /opencode server listening on http:\/\/127\.0\.0\.1:(\d+)/;
|
|
249
|
+
let portFound = false;
|
|
250
|
+
let stdoutBuf = "";
|
|
251
|
+
const onData = (chunk) => {
|
|
252
|
+
if (portFound) return;
|
|
253
|
+
stdoutBuf += chunk.toString();
|
|
254
|
+
const match = portRegex.exec(stdoutBuf);
|
|
255
|
+
if (!match) return;
|
|
256
|
+
portFound = true;
|
|
257
|
+
const port = match[1];
|
|
258
|
+
fetch(`http://127.0.0.1:${port}/config/providers`).then((res) => res.json()).then((data) => {
|
|
259
|
+
const raw = data.providers;
|
|
260
|
+
if (!Array.isArray(raw)) {
|
|
261
|
+
finish(null);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
finish(raw);
|
|
265
|
+
}).catch(() => {
|
|
266
|
+
finish(null);
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
child.stdout?.on("data", onData);
|
|
270
|
+
child.stderr?.on("data", onData);
|
|
271
|
+
child.on("error", () => {
|
|
272
|
+
finish(null);
|
|
273
|
+
});
|
|
274
|
+
child.on("exit", () => {
|
|
275
|
+
if (!settled) finish(null);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/registry/convert.ts
|
|
281
|
+
function modelToCached(model) {
|
|
282
|
+
return {
|
|
283
|
+
id: model.id,
|
|
284
|
+
name: model.name,
|
|
285
|
+
upstreamModelId: model.upstreamModelId,
|
|
286
|
+
family: model.family,
|
|
287
|
+
brand: model.brand,
|
|
288
|
+
contextWindow: model.contextWindow,
|
|
289
|
+
cost: model.cost,
|
|
290
|
+
isFree: model.isFree,
|
|
291
|
+
freeStatus: model.freeStatus,
|
|
292
|
+
modelFormat: model.modelFormat,
|
|
293
|
+
npm: model.npm,
|
|
294
|
+
apiUrl: model.apiBaseUrl,
|
|
295
|
+
supportedParameters: model.supportedParameters,
|
|
296
|
+
reasoning: model.reasoning,
|
|
297
|
+
interleavedReasoningField: model.interleavedReasoningField,
|
|
298
|
+
useResponsesLite: model.useResponsesLite,
|
|
299
|
+
preferWebSockets: model.preferWebSockets
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function localProviderToRegistry(provider, opts) {
|
|
303
|
+
if (!isValidProviderId(provider.id)) return null;
|
|
304
|
+
if (provider.models.length === 0) return null;
|
|
305
|
+
const first = provider.models[0];
|
|
306
|
+
const apiUrl = (first.apiBaseUrl ?? first.baseUrl)?.trim();
|
|
307
|
+
const authType = opts?.authType ?? "api";
|
|
308
|
+
return {
|
|
309
|
+
id: provider.id,
|
|
310
|
+
templateId: opts?.templateId ?? provider.id,
|
|
311
|
+
name: provider.name,
|
|
312
|
+
enabled: true,
|
|
313
|
+
authRef: opts?.authRef ?? `keyring:provider:${provider.id}`,
|
|
314
|
+
authType,
|
|
315
|
+
api: {
|
|
316
|
+
npm: first.npm,
|
|
317
|
+
...apiUrl ? { url: apiUrl } : {}
|
|
318
|
+
},
|
|
319
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
320
|
+
modelsCache: {
|
|
321
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
322
|
+
models: provider.models.map(modelToCached)
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
193
327
|
// src/registry/validate-import-key.ts
|
|
194
328
|
function reject(reason, detail) {
|
|
195
329
|
return { canImport: false, reason, detail };
|
|
@@ -399,23 +533,23 @@ async function importFromOpencode(options = {}) {
|
|
|
399
533
|
|
|
400
534
|
// src/key-setup.ts
|
|
401
535
|
import * as p from "@clack/prompts";
|
|
402
|
-
import { appendFileSync, readFileSync, existsSync } from "fs";
|
|
403
|
-
import { homedir } from "os";
|
|
536
|
+
import { appendFileSync, readFileSync, existsSync as existsSync2 } from "fs";
|
|
537
|
+
import { homedir as homedir2 } from "os";
|
|
404
538
|
import { spawnSync } from "child_process";
|
|
405
539
|
function detectShellProfile() {
|
|
406
540
|
const shell = process.env["SHELL"] ?? "";
|
|
407
541
|
if (process.platform === "darwin") {
|
|
408
|
-
if (shell.includes("zsh")) return { display: "~/.zshrc", path: `${
|
|
409
|
-
if (shell.includes("bash")) return { display: "~/.bash_profile", path: `${
|
|
410
|
-
return { display: "~/.profile", path: `${
|
|
542
|
+
if (shell.includes("zsh")) return { display: "~/.zshrc", path: `${homedir2()}/.zshrc` };
|
|
543
|
+
if (shell.includes("bash")) return { display: "~/.bash_profile", path: `${homedir2()}/.bash_profile` };
|
|
544
|
+
return { display: "~/.profile", path: `${homedir2()}/.profile` };
|
|
411
545
|
}
|
|
412
546
|
if (process.platform === "linux") {
|
|
413
|
-
if (shell.includes("zsh")) return { display: "~/.zshrc", path: `${
|
|
414
|
-
if (shell.includes("bash")) return { display: "~/.bashrc", path: `${
|
|
415
|
-
return { display: "~/.profile", path: `${
|
|
547
|
+
if (shell.includes("zsh")) return { display: "~/.zshrc", path: `${homedir2()}/.zshrc` };
|
|
548
|
+
if (shell.includes("bash")) return { display: "~/.bashrc", path: `${homedir2()}/.bashrc` };
|
|
549
|
+
return { display: "~/.profile", path: `${homedir2()}/.profile` };
|
|
416
550
|
}
|
|
417
|
-
if (shell.includes("bash")) return { display: "~/.bashrc", path: `${
|
|
418
|
-
return { display: "~/.profile", path: `${
|
|
551
|
+
if (shell.includes("bash")) return { display: "~/.bashrc", path: `${homedir2()}/.bashrc` };
|
|
552
|
+
return { display: "~/.profile", path: `${homedir2()}/.profile` };
|
|
419
553
|
}
|
|
420
554
|
async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
421
555
|
if (!simulate) {
|
|
@@ -423,7 +557,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
423
557
|
if (existing) return existing;
|
|
424
558
|
}
|
|
425
559
|
const isMac = process.platform === "darwin";
|
|
426
|
-
const
|
|
560
|
+
const isWindows5 = process.platform === "win32";
|
|
427
561
|
const isLinux = process.platform === "linux";
|
|
428
562
|
if (simulate) {
|
|
429
563
|
printDryRunPanel();
|
|
@@ -437,7 +571,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
437
571
|
};
|
|
438
572
|
const storedKey = await readFromCredentialStore(keyDiag);
|
|
439
573
|
if (storedKey) {
|
|
440
|
-
const storeName = isMac ? "macOS Keychain" :
|
|
574
|
+
const storeName = isMac ? "macOS Keychain" : isWindows5 ? "Windows Credential Manager" : "Secret Service";
|
|
441
575
|
p.log.success(`Found key in ${storeName}`);
|
|
442
576
|
process.env["OPENCODE_API_KEY"] = storedKey;
|
|
443
577
|
return storedKey;
|
|
@@ -467,7 +601,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
467
601
|
{ value: "session", label: "This session only", hint: "Not saved anywhere \u2014 you'll be asked again next time" }
|
|
468
602
|
];
|
|
469
603
|
}
|
|
470
|
-
if (
|
|
604
|
+
if (isWindows5) {
|
|
471
605
|
return [
|
|
472
606
|
{ value: "credential-manager", label: "Windows Credential Manager", hint: "Key stored securely; relay-ai reads it automatically next time" },
|
|
473
607
|
{ value: "setx", label: "Persistent environment variable (plaintext)", hint: "Runs setx \u2014 key visible in System Properties \u2192 Environment Variables" },
|
|
@@ -489,7 +623,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
489
623
|
const saveChoice = await p.select({
|
|
490
624
|
message: "Where should we save the key?",
|
|
491
625
|
options: saveOptions,
|
|
492
|
-
initialValue: isMac ? "keychain" :
|
|
626
|
+
initialValue: isMac ? "keychain" : isWindows5 ? "credential-manager" : secretServiceAvailable ? "secret-service" : "profile"
|
|
493
627
|
});
|
|
494
628
|
if (p.isCancel(saveChoice)) {
|
|
495
629
|
p.cancel("Cancelled.");
|
|
@@ -516,7 +650,7 @@ async function resolveOrCollectApiKey(simulate = false, trace = false) {
|
|
|
516
650
|
if (await saveToCredentialStore(trimmedKey)) {
|
|
517
651
|
try {
|
|
518
652
|
const autoLoadLine = `export OPENCODE_API_KEY="$(security find-generic-password -s relay-ai -a ${GLOBAL_OPENCODE_KEYRING_ACCOUNT} -w 2>/dev/null)"`;
|
|
519
|
-
const existing =
|
|
653
|
+
const existing = existsSync2(path2) ? readFileSync(path2, "utf8") : "";
|
|
520
654
|
if (!existing.includes(autoLoadLine)) {
|
|
521
655
|
appendFileSync(path2, `
|
|
522
656
|
# relay-ai: load API key from macOS Keychain
|
|
@@ -553,7 +687,7 @@ ${autoLoadLine}
|
|
|
553
687
|
}
|
|
554
688
|
} else if (saveChoice === "profile") {
|
|
555
689
|
try {
|
|
556
|
-
if (!
|
|
690
|
+
if (!existsSync2(path2)) appendFileSync(path2, "");
|
|
557
691
|
const escapedKey = trimmedKey.replace(/'/g, "'\\''");
|
|
558
692
|
appendFileSync(path2, `
|
|
559
693
|
export OPENCODE_API_KEY='${escapedKey}'
|
|
@@ -592,14 +726,14 @@ async function runFirstRunWizard(trace = false) {
|
|
|
592
726
|
{
|
|
593
727
|
value: "providers",
|
|
594
728
|
label: pc.cyan("Set up your own AI provider"),
|
|
595
|
-
hint:
|
|
729
|
+
hint: "Add Groq, Mistral, OpenAI, \u2026 with relay-ai providers"
|
|
596
730
|
}
|
|
597
731
|
];
|
|
598
732
|
if (hasOpencode) {
|
|
599
733
|
options.push({
|
|
600
734
|
value: "import",
|
|
601
|
-
label: pc.cyan("
|
|
602
|
-
hint: "
|
|
735
|
+
label: pc.cyan("Import from OpenCode CLI"),
|
|
736
|
+
hint: "Optional one-time import of providers you already configured"
|
|
603
737
|
});
|
|
604
738
|
}
|
|
605
739
|
const choice = await p2.select({
|
|
@@ -618,26 +752,20 @@ async function runFirstRunWizard(trace = false) {
|
|
|
618
752
|
p2.log.success("OpenCode Zen ready \u2014 picking a model next.");
|
|
619
753
|
return "continue";
|
|
620
754
|
}
|
|
621
|
-
if (choice === "
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
755
|
+
if (choice === "providers") {
|
|
756
|
+
p2.log.info(`Add providers with ${pc.cyan("relay-ai providers add")}, then run ${pc.cyan("relay-ai claude")} again.`);
|
|
757
|
+
if (hasOpencode) {
|
|
758
|
+
p2.log.info(`Optional: ${pc.cyan("relay-ai providers import")} to pull an existing OpenCode CLI config.`);
|
|
625
759
|
}
|
|
760
|
+
return "cancel";
|
|
761
|
+
}
|
|
762
|
+
if (choice === "import") {
|
|
626
763
|
if (!hasOpencode) {
|
|
627
|
-
p2.log.
|
|
628
|
-
p2.log.info("Quick start with Zen is the fastest path if you have an OpenCode API key.");
|
|
629
|
-
const retry = await p2.select({
|
|
630
|
-
message: "What next?",
|
|
631
|
-
options: [
|
|
632
|
-
{ value: "zen", label: "Quick start with OpenCode Zen", hint: "" },
|
|
633
|
-
{ value: "cancel", label: "Cancel", hint: "" }
|
|
634
|
-
]
|
|
635
|
-
});
|
|
636
|
-
if (p2.isCancel(retry) || retry === "cancel") return "cancel";
|
|
764
|
+
p2.log.error("OpenCode CLI not found. Install from https://opencode.ai \u2014 or use Quick start / providers add instead.");
|
|
637
765
|
return runFirstRunWizard(trace);
|
|
638
766
|
}
|
|
639
767
|
const spinner9 = p2.spinner();
|
|
640
|
-
spinner9.start("Importing from OpenCode...");
|
|
768
|
+
spinner9.start("Importing from OpenCode CLI...");
|
|
641
769
|
const result = await importFromOpencode();
|
|
642
770
|
spinner9.stop("");
|
|
643
771
|
if (result.error) {
|
|
@@ -645,7 +773,7 @@ async function runFirstRunWizard(trace = false) {
|
|
|
645
773
|
return runFirstRunWizard(trace);
|
|
646
774
|
}
|
|
647
775
|
if (result.imported.length === 0) {
|
|
648
|
-
p2.log.warn("No providers imported.
|
|
776
|
+
p2.log.warn("No providers imported. Add providers with relay-ai providers add, or Quick start with Zen.");
|
|
649
777
|
return runFirstRunWizard(trace);
|
|
650
778
|
}
|
|
651
779
|
p2.log.success(
|
|
@@ -1113,7 +1241,7 @@ function parseProvidersArgs(args) {
|
|
|
1113
1241
|
}
|
|
1114
1242
|
}
|
|
1115
1243
|
if (positional.length !== 1) {
|
|
1116
|
-
return { subcommand: "auth", showHelp: false, error: "Usage: relay-ai providers auth <id>
|
|
1244
|
+
return { subcommand: "auth", showHelp: false, error: "Usage: relay-ai providers auth <id>" };
|
|
1117
1245
|
}
|
|
1118
1246
|
return { subcommand: "auth", showHelp: false, removeId: positional[0], authMethod };
|
|
1119
1247
|
}
|
|
@@ -1139,12 +1267,12 @@ ${pc4.bold("Usage:")}
|
|
|
1139
1267
|
relay-ai providers list
|
|
1140
1268
|
relay-ai providers remove <id>
|
|
1141
1269
|
relay-ai providers refresh-models [id]
|
|
1142
|
-
relay-ai providers auth <id>
|
|
1270
|
+
relay-ai providers auth <id>
|
|
1143
1271
|
|
|
1144
1272
|
${pc4.bold("Subcommands:")}
|
|
1145
1273
|
(none) Provider hub wizard ${pc4.dim("[Phase 1.1]")}
|
|
1146
1274
|
add Add a provider (Groq, Mistral, Together AI, \u2026) ${pc4.dim("[Phase 1.1]")}
|
|
1147
|
-
import
|
|
1275
|
+
import Optional one-time import from OpenCode CLI ${pc4.dim("[Phase 1.0]")}
|
|
1148
1276
|
auth Sign in with OAuth (GitHub Copilot, xAI, OpenAI)
|
|
1149
1277
|
list Show configured providers ${pc4.dim("[Phase 1.0]")}
|
|
1150
1278
|
remove Remove a provider by id ${pc4.dim("[Phase 1.1]")}
|
|
@@ -1392,25 +1520,17 @@ async function runTemplateAddFlow() {
|
|
|
1392
1520
|
await migrateGlobalOpencodeCredential();
|
|
1393
1521
|
const spinner10 = p5.spinner();
|
|
1394
1522
|
spinner10.start(`Adding ${template.name}...`);
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
if (!
|
|
1398
|
-
|
|
1399
|
-
p5.log.
|
|
1523
|
+
const result2 = await addOpencodeCloudFromApiKey(apiKey2);
|
|
1524
|
+
spinner10.stop("");
|
|
1525
|
+
if (!result2.added) {
|
|
1526
|
+
p5.log.warn(result2.error ?? "OpenCode Zen / Go is already configured.");
|
|
1527
|
+
if (result2.hint) p5.log.info(result2.hint);
|
|
1400
1528
|
return 0;
|
|
1401
1529
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
await refreshProviderModels("zen", apiKey2, registry),
|
|
1405
|
-
await refreshProviderModels("go", apiKey2, registry)
|
|
1406
|
-
];
|
|
1407
|
-
spinner10.stop("");
|
|
1408
|
-
const modelCount = refreshResults.reduce((total, result2) => total + (result2.modelCount ?? 0), 0);
|
|
1409
|
-
const failed = refreshResults.filter((result2) => !result2.ok);
|
|
1410
|
-
if (failed.length === 0) {
|
|
1411
|
-
p5.log.success(`Added ${template.name} \u2014 ${fmtCount(modelCount, "model")} updated.`);
|
|
1530
|
+
if (result2.hint) {
|
|
1531
|
+
p5.log.warn(`Added ${template.name}. ${result2.hint}`);
|
|
1412
1532
|
} else {
|
|
1413
|
-
p5.log.
|
|
1533
|
+
p5.log.success(`Added ${template.name} \u2014 ${fmtCount(result2.modelCount ?? 0, "model")} updated.`);
|
|
1414
1534
|
}
|
|
1415
1535
|
return 0;
|
|
1416
1536
|
}
|
|
@@ -3558,7 +3678,7 @@ data: ${JSON.stringify({ error: { message: `Unknown model: ${modelId}` } })}
|
|
|
3558
3678
|
}
|
|
3559
3679
|
|
|
3560
3680
|
// src/codex/profile.ts
|
|
3561
|
-
import { join as
|
|
3681
|
+
import { join as join3 } from "path";
|
|
3562
3682
|
|
|
3563
3683
|
// src/codex/routing.ts
|
|
3564
3684
|
function codexCompatibleProviders(providers, agent = "codex") {
|
|
@@ -3633,7 +3753,7 @@ function codexProviderEnvKey(providerId) {
|
|
|
3633
3753
|
// src/codex/session.ts
|
|
3634
3754
|
import {
|
|
3635
3755
|
copyFileSync,
|
|
3636
|
-
existsSync as
|
|
3756
|
+
existsSync as existsSync3,
|
|
3637
3757
|
mkdirSync,
|
|
3638
3758
|
readdirSync,
|
|
3639
3759
|
readFileSync as readFileSync2,
|
|
@@ -3643,36 +3763,36 @@ import {
|
|
|
3643
3763
|
unlinkSync,
|
|
3644
3764
|
writeFileSync
|
|
3645
3765
|
} from "fs";
|
|
3646
|
-
import { homedir as
|
|
3647
|
-
import { basename, dirname, join } from "path";
|
|
3766
|
+
import { homedir as homedir3 } from "os";
|
|
3767
|
+
import { basename, dirname, join as join2 } from "path";
|
|
3648
3768
|
var CODEX_PROFILE_NAME = "relay-ai-launch";
|
|
3649
3769
|
var STALE_SESSION_MS = 5 * 60 * 1e3;
|
|
3650
3770
|
var MAX_BACKUPS = 5;
|
|
3651
3771
|
function getCodexHome() {
|
|
3652
|
-
return
|
|
3772
|
+
return join2(homedir3(), ".codex");
|
|
3653
3773
|
}
|
|
3654
3774
|
function getCodexProfilePath() {
|
|
3655
|
-
return
|
|
3775
|
+
return join2(getCodexHome(), `${CODEX_PROFILE_NAME}.config.toml`);
|
|
3656
3776
|
}
|
|
3657
3777
|
function getRelayAiCodexDir(env = process.env) {
|
|
3658
|
-
return
|
|
3778
|
+
return join2(getAppHome(env), "codex");
|
|
3659
3779
|
}
|
|
3660
3780
|
function getSessionLockPath(env = process.env) {
|
|
3661
|
-
return
|
|
3781
|
+
return join2(getRelayAiCodexDir(env), "session.json");
|
|
3662
3782
|
}
|
|
3663
3783
|
function getBackupsDir(env = process.env) {
|
|
3664
|
-
return
|
|
3784
|
+
return join2(getRelayAiCodexDir(env), "backups");
|
|
3665
3785
|
}
|
|
3666
3786
|
function getCatalogPath(providerId, env = process.env) {
|
|
3667
|
-
return
|
|
3787
|
+
return join2(getRelayAiCodexDir(env), `models-${providerId}.json`);
|
|
3668
3788
|
}
|
|
3669
3789
|
function ownedOverlayPaths(env = process.env) {
|
|
3670
3790
|
const paths = [getCodexProfilePath(), getSessionLockPath(env)];
|
|
3671
3791
|
const codexDir = getRelayAiCodexDir(env);
|
|
3672
|
-
if (
|
|
3792
|
+
if (existsSync3(codexDir)) {
|
|
3673
3793
|
for (const name of readdirSync(codexDir)) {
|
|
3674
3794
|
if (name.startsWith("models-") && name.endsWith(".json")) {
|
|
3675
|
-
paths.push(
|
|
3795
|
+
paths.push(join2(codexDir, name));
|
|
3676
3796
|
}
|
|
3677
3797
|
}
|
|
3678
3798
|
}
|
|
@@ -3685,17 +3805,17 @@ function atomicWriteFile(path2, content) {
|
|
|
3685
3805
|
renameSync(tmp, path2);
|
|
3686
3806
|
}
|
|
3687
3807
|
function rotateBackups(filePath, env = process.env) {
|
|
3688
|
-
if (!
|
|
3808
|
+
if (!existsSync3(filePath)) return;
|
|
3689
3809
|
const backupsDir = getBackupsDir(env);
|
|
3690
3810
|
mkdirSync(backupsDir, { recursive: true });
|
|
3691
3811
|
const base = basename(filePath);
|
|
3692
3812
|
const stamp = Date.now();
|
|
3693
|
-
const backupPath =
|
|
3813
|
+
const backupPath = join2(backupsDir, `${base}.${stamp}.bak`);
|
|
3694
3814
|
copyFileSync(filePath, backupPath);
|
|
3695
|
-
const backups = readdirSync(backupsDir).filter((n) => n.startsWith(`${base}.`) && n.endsWith(".bak")).map((n) => ({ name: n, mtime: statSync(
|
|
3815
|
+
const backups = readdirSync(backupsDir).filter((n) => n.startsWith(`${base}.`) && n.endsWith(".bak")).map((n) => ({ name: n, mtime: statSync(join2(backupsDir, n)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
3696
3816
|
for (const old of backups.slice(MAX_BACKUPS)) {
|
|
3697
3817
|
try {
|
|
3698
|
-
unlinkSync(
|
|
3818
|
+
unlinkSync(join2(backupsDir, old.name));
|
|
3699
3819
|
} catch {
|
|
3700
3820
|
}
|
|
3701
3821
|
}
|
|
@@ -3706,7 +3826,7 @@ function writeOverlayFile(path2, content, env = process.env) {
|
|
|
3706
3826
|
}
|
|
3707
3827
|
function readSessionLock(env = process.env) {
|
|
3708
3828
|
const path2 = getSessionLockPath(env);
|
|
3709
|
-
if (!
|
|
3829
|
+
if (!existsSync3(path2)) return null;
|
|
3710
3830
|
try {
|
|
3711
3831
|
const parsed = JSON.parse(readFileSync2(path2, "utf8"));
|
|
3712
3832
|
if (typeof parsed.pid === "number" && typeof parsed.startedAt === "string") return parsed;
|
|
@@ -3735,7 +3855,7 @@ function isConcurrentSession(lock) {
|
|
|
3735
3855
|
function restoreCodexOverlay(env = process.env) {
|
|
3736
3856
|
const removed = [];
|
|
3737
3857
|
for (const path2 of ownedOverlayPaths(env)) {
|
|
3738
|
-
if (!
|
|
3858
|
+
if (!existsSync3(path2)) continue;
|
|
3739
3859
|
try {
|
|
3740
3860
|
rmSync(path2, { force: true });
|
|
3741
3861
|
removed.push(path2);
|
|
@@ -3745,7 +3865,7 @@ function restoreCodexOverlay(env = process.env) {
|
|
|
3745
3865
|
return removed;
|
|
3746
3866
|
}
|
|
3747
3867
|
function remainingOverlayPaths(env = process.env) {
|
|
3748
|
-
return ownedOverlayPaths(env).filter((p15) =>
|
|
3868
|
+
return ownedOverlayPaths(env).filter((p15) => existsSync3(p15));
|
|
3749
3869
|
}
|
|
3750
3870
|
function recoverInterruptedCodexSession(env = process.env) {
|
|
3751
3871
|
const before = remainingOverlayPaths(env);
|
|
@@ -3822,21 +3942,21 @@ function getCatalogOutputPath(providerId) {
|
|
|
3822
3942
|
return getCatalogPath(providerId);
|
|
3823
3943
|
}
|
|
3824
3944
|
function getFavoritesCatalogPath() {
|
|
3825
|
-
return
|
|
3945
|
+
return join3(getRelayAiCodexDir(), "models-favorites.json");
|
|
3826
3946
|
}
|
|
3827
3947
|
function getFavoritesAppCatalogPath() {
|
|
3828
|
-
return
|
|
3948
|
+
return join3(getRelayAiCodexDir(), "app-models-favorites.json");
|
|
3829
3949
|
}
|
|
3830
3950
|
function profileName() {
|
|
3831
3951
|
return CODEX_PROFILE_NAME;
|
|
3832
3952
|
}
|
|
3833
3953
|
|
|
3834
3954
|
// src/codex/launch.ts
|
|
3835
|
-
import { execFileSync, execSync, spawn } from "child_process";
|
|
3836
|
-
import { existsSync as
|
|
3837
|
-
import { homedir as
|
|
3838
|
-
import { join as
|
|
3839
|
-
var
|
|
3955
|
+
import { execFileSync, execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
3956
|
+
import { existsSync as existsSync4 } from "fs";
|
|
3957
|
+
import { homedir as homedir4 } from "os";
|
|
3958
|
+
import { join as join4 } from "path";
|
|
3959
|
+
var isWindows2 = process.platform === "win32";
|
|
3840
3960
|
var CODEX_CI_ENV_VARS = [
|
|
3841
3961
|
"CI",
|
|
3842
3962
|
"CODEX_CI",
|
|
@@ -3855,33 +3975,33 @@ function stripCodexInheritedEnv(env) {
|
|
|
3855
3975
|
}
|
|
3856
3976
|
return out;
|
|
3857
3977
|
}
|
|
3858
|
-
var CODEX_FALLBACK_PATHS =
|
|
3859
|
-
|
|
3860
|
-
|
|
3978
|
+
var CODEX_FALLBACK_PATHS = isWindows2 ? [
|
|
3979
|
+
join4(process.env["APPDATA"] ?? homedir4(), "npm", "codex.cmd"),
|
|
3980
|
+
join4(process.env["APPDATA"] ?? homedir4(), "npm", "codex")
|
|
3861
3981
|
] : [
|
|
3862
|
-
|
|
3863
|
-
|
|
3982
|
+
join4(homedir4(), ".local", "bin", "codex"),
|
|
3983
|
+
join4(homedir4(), ".npm", "bin", "codex"),
|
|
3864
3984
|
"/usr/local/bin/codex",
|
|
3865
3985
|
"/opt/homebrew/bin/codex"
|
|
3866
3986
|
];
|
|
3867
3987
|
function findCodexBinary() {
|
|
3868
3988
|
const override = getAppPathOverride("codex");
|
|
3869
|
-
if (override) return selectCodexBinary([override],
|
|
3989
|
+
if (override) return selectCodexBinary([override], existsSync4, canRunCodexBinary);
|
|
3870
3990
|
const candidates = [];
|
|
3871
3991
|
try {
|
|
3872
|
-
const result =
|
|
3992
|
+
const result = execSync2(isWindows2 ? "where.exe codex" : "which codex", {
|
|
3873
3993
|
encoding: "utf8",
|
|
3874
3994
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3875
3995
|
});
|
|
3876
3996
|
const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3877
|
-
if (
|
|
3997
|
+
if (isWindows2) {
|
|
3878
3998
|
candidates.push(...lines.filter((l) => l.toLowerCase().endsWith(".cmd")));
|
|
3879
3999
|
}
|
|
3880
4000
|
candidates.push(...lines);
|
|
3881
4001
|
} catch {
|
|
3882
4002
|
}
|
|
3883
4003
|
candidates.push(...CODEX_FALLBACK_PATHS);
|
|
3884
|
-
return selectCodexBinary(candidates,
|
|
4004
|
+
return selectCodexBinary(candidates, existsSync4, canRunCodexBinary);
|
|
3885
4005
|
}
|
|
3886
4006
|
function selectCodexBinary(candidates, exists, canRun) {
|
|
3887
4007
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3898,7 +4018,7 @@ function canRunCodexBinary(path2) {
|
|
|
3898
4018
|
encoding: "utf8",
|
|
3899
4019
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3900
4020
|
timeout: 5e3,
|
|
3901
|
-
shell:
|
|
4021
|
+
shell: isWindows2
|
|
3902
4022
|
});
|
|
3903
4023
|
return true;
|
|
3904
4024
|
} catch {
|
|
@@ -3933,10 +4053,10 @@ function launchCodex(modelId, env, extraArgs) {
|
|
|
3933
4053
|
return new Promise((resolve2) => {
|
|
3934
4054
|
const codexPath = findCodexBinary();
|
|
3935
4055
|
const args = ["--profile", profileName(), "-m", modelId, ...ensureCodexSandboxArgs(extraArgs)];
|
|
3936
|
-
const child =
|
|
4056
|
+
const child = spawn2(codexPath, args, {
|
|
3937
4057
|
stdio: "inherit",
|
|
3938
4058
|
env,
|
|
3939
|
-
shell:
|
|
4059
|
+
shell: isWindows2
|
|
3940
4060
|
});
|
|
3941
4061
|
const forward = (signal) => {
|
|
3942
4062
|
child.kill(signal);
|
|
@@ -5133,24 +5253,24 @@ import pc8 from "picocolors";
|
|
|
5133
5253
|
import * as p10 from "@clack/prompts";
|
|
5134
5254
|
|
|
5135
5255
|
// src/gemini/launch.ts
|
|
5136
|
-
import { spawn as
|
|
5137
|
-
import { existsSync as
|
|
5138
|
-
import { homedir as
|
|
5139
|
-
import { join as
|
|
5140
|
-
var
|
|
5256
|
+
import { spawn as spawn3 } from "child_process";
|
|
5257
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
5258
|
+
import { homedir as homedir5, tmpdir } from "os";
|
|
5259
|
+
import { join as join5 } from "path";
|
|
5260
|
+
var isWindows3 = process.platform === "win32";
|
|
5141
5261
|
var GEMINI_API_KEY_AUTH_TYPE = "gemini-api-key";
|
|
5142
|
-
var GEMINI_FALLBACK_PATHS =
|
|
5143
|
-
|
|
5144
|
-
|
|
5262
|
+
var GEMINI_FALLBACK_PATHS = isWindows3 ? [
|
|
5263
|
+
join5(process.env["APPDATA"] ?? homedir5(), "npm", "gemini.cmd"),
|
|
5264
|
+
join5(process.env["APPDATA"] ?? homedir5(), "npm", "gemini")
|
|
5145
5265
|
] : [
|
|
5146
|
-
|
|
5147
|
-
|
|
5266
|
+
join5(homedir5(), ".local", "bin", "gemini"),
|
|
5267
|
+
join5(homedir5(), ".npm", "bin", "gemini"),
|
|
5148
5268
|
"/usr/local/bin/gemini",
|
|
5149
5269
|
"/opt/homebrew/bin/gemini"
|
|
5150
5270
|
];
|
|
5151
5271
|
function findGeminiBinary() {
|
|
5152
5272
|
const override = getAppPathOverride("gemini");
|
|
5153
|
-
if (override) return
|
|
5273
|
+
if (override) return existsSync5(override) ? override : null;
|
|
5154
5274
|
return findBinaryOnPath("gemini", GEMINI_FALLBACK_PATHS);
|
|
5155
5275
|
}
|
|
5156
5276
|
function buildGeminiChildEnv(proxyPort, proxyToken) {
|
|
@@ -5165,7 +5285,7 @@ function buildGeminiChildEnv(proxyPort, proxyToken) {
|
|
|
5165
5285
|
return env;
|
|
5166
5286
|
}
|
|
5167
5287
|
function createGeminiCliHomeOverlay() {
|
|
5168
|
-
const cliHome = mkdtempSync(
|
|
5288
|
+
const cliHome = mkdtempSync(join5(tmpdir(), "relay-ai-gemini-"));
|
|
5169
5289
|
const settings = {
|
|
5170
5290
|
security: {
|
|
5171
5291
|
auth: {
|
|
@@ -5173,9 +5293,9 @@ function createGeminiCliHomeOverlay() {
|
|
|
5173
5293
|
}
|
|
5174
5294
|
}
|
|
5175
5295
|
};
|
|
5176
|
-
const geminiDir =
|
|
5296
|
+
const geminiDir = join5(cliHome, ".gemini");
|
|
5177
5297
|
mkdirSync2(geminiDir);
|
|
5178
|
-
writeFileSync2(
|
|
5298
|
+
writeFileSync2(join5(geminiDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
|
|
5179
5299
|
`, {
|
|
5180
5300
|
encoding: "utf8",
|
|
5181
5301
|
mode: 384
|
|
@@ -5199,10 +5319,10 @@ function prepareGeminiChildEnv(proxyPort, proxyToken) {
|
|
|
5199
5319
|
function launchGemini(geminiPath, modelId, env, extraArgs) {
|
|
5200
5320
|
return new Promise((resolve2) => {
|
|
5201
5321
|
const args = ["-m", modelId, ...extraArgs];
|
|
5202
|
-
const child =
|
|
5322
|
+
const child = spawn3(geminiPath, args, {
|
|
5203
5323
|
stdio: "inherit",
|
|
5204
5324
|
env,
|
|
5205
|
-
shell:
|
|
5325
|
+
shell: isWindows3
|
|
5206
5326
|
});
|
|
5207
5327
|
const onSigInt = () => child.kill("SIGINT");
|
|
5208
5328
|
const onSigTerm = () => child.kill("SIGTERM");
|
|
@@ -8653,26 +8773,26 @@ async function resolveAntigravityLaunchRoutes(opts) {
|
|
|
8653
8773
|
}
|
|
8654
8774
|
|
|
8655
8775
|
// src/antigravity/launch-cli.ts
|
|
8656
|
-
import { execFileSync as execFileSync2, execSync as
|
|
8657
|
-
import { existsSync as
|
|
8658
|
-
import { homedir as
|
|
8659
|
-
import { join as
|
|
8660
|
-
var
|
|
8661
|
-
var FALLBACK_PATHS =
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8776
|
+
import { execFileSync as execFileSync2, execSync as execSync3, spawn as spawn4 } from "child_process";
|
|
8777
|
+
import { existsSync as existsSync6 } from "fs";
|
|
8778
|
+
import { homedir as homedir6 } from "os";
|
|
8779
|
+
import { join as join6 } from "path";
|
|
8780
|
+
var isWindows4 = process.platform === "win32";
|
|
8781
|
+
var FALLBACK_PATHS = isWindows4 ? [
|
|
8782
|
+
join6(process.env["APPDATA"] ?? homedir6(), "npm", "agy.cmd"),
|
|
8783
|
+
join6(process.env["APPDATA"] ?? homedir6(), "npm", "agy"),
|
|
8784
|
+
join6(homedir6(), "AppData", "Roaming", "npm", "agy.cmd")
|
|
8665
8785
|
] : [
|
|
8666
|
-
|
|
8667
|
-
|
|
8786
|
+
join6(homedir6(), ".local", "bin", "agy"),
|
|
8787
|
+
join6(homedir6(), ".npm", "bin", "agy"),
|
|
8668
8788
|
"/usr/local/bin/agy",
|
|
8669
8789
|
"/opt/homebrew/bin/agy"
|
|
8670
8790
|
];
|
|
8671
8791
|
function findAntigravityCliBinary() {
|
|
8672
8792
|
const override = getAppPathOverride("agy");
|
|
8673
|
-
if (override) return
|
|
8793
|
+
if (override) return existsSync6(override) ? override : null;
|
|
8674
8794
|
try {
|
|
8675
|
-
const result =
|
|
8795
|
+
const result = execSync3(isWindows4 ? "where.exe agy" : "which agy", {
|
|
8676
8796
|
encoding: "utf8",
|
|
8677
8797
|
stdio: ["pipe", "pipe", "pipe"]
|
|
8678
8798
|
});
|
|
@@ -8681,7 +8801,7 @@ function findAntigravityCliBinary() {
|
|
|
8681
8801
|
} catch {
|
|
8682
8802
|
}
|
|
8683
8803
|
for (const path2 of FALLBACK_PATHS) {
|
|
8684
|
-
if (
|
|
8804
|
+
if (existsSync6(path2)) return path2;
|
|
8685
8805
|
}
|
|
8686
8806
|
return null;
|
|
8687
8807
|
}
|
|
@@ -8711,10 +8831,10 @@ function launchAntigravityCli(env, extraArgs) {
|
|
|
8711
8831
|
resolve2(127);
|
|
8712
8832
|
return;
|
|
8713
8833
|
}
|
|
8714
|
-
const child =
|
|
8834
|
+
const child = spawn4(binaryPath, extraArgs, {
|
|
8715
8835
|
stdio: "inherit",
|
|
8716
8836
|
env,
|
|
8717
|
-
shell:
|
|
8837
|
+
shell: isWindows4
|
|
8718
8838
|
});
|
|
8719
8839
|
const forward = (signal) => {
|
|
8720
8840
|
child.kill(signal);
|
|
@@ -8740,10 +8860,10 @@ function launchAntigravityCli(env, extraArgs) {
|
|
|
8740
8860
|
}
|
|
8741
8861
|
|
|
8742
8862
|
// src/antigravity/launch-ide.ts
|
|
8743
|
-
import { execFileSync as execFileSync3, execSync as
|
|
8744
|
-
import { existsSync as
|
|
8745
|
-
import { homedir as
|
|
8746
|
-
import { join as
|
|
8863
|
+
import { execFileSync as execFileSync3, execSync as execSync4, spawn as spawn5 } from "child_process";
|
|
8864
|
+
import { existsSync as existsSync7 } from "fs";
|
|
8865
|
+
import { homedir as homedir7 } from "os";
|
|
8866
|
+
import { join as join7 } from "path";
|
|
8747
8867
|
|
|
8748
8868
|
// src/antigravity/ide-profile.ts
|
|
8749
8869
|
import fs from "fs";
|
|
@@ -8781,7 +8901,7 @@ function sleep(ms) {
|
|
|
8781
8901
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
8782
8902
|
}
|
|
8783
8903
|
function runPowerShell(script) {
|
|
8784
|
-
return
|
|
8904
|
+
return execSync4(`powershell.exe -NoProfile -Command ${JSON.stringify(script)}`, {
|
|
8785
8905
|
encoding: "utf8",
|
|
8786
8906
|
stdio: ["pipe", "pipe", "pipe"]
|
|
8787
8907
|
}).trim();
|
|
@@ -8896,32 +9016,32 @@ function quitAntigravityAppGracefully() {
|
|
|
8896
9016
|
}
|
|
8897
9017
|
function findAntigravityAppBinary() {
|
|
8898
9018
|
const override = getAppPathOverride("antigravity");
|
|
8899
|
-
if (override) return
|
|
9019
|
+
if (override) return existsSync7(override) ? override : null;
|
|
8900
9020
|
if (process.platform === "win32") {
|
|
8901
|
-
const localAppData = process.env["LOCALAPPDATA"] ??
|
|
8902
|
-
const winPath =
|
|
8903
|
-
return
|
|
9021
|
+
const localAppData = process.env["LOCALAPPDATA"] ?? join7(homedir7(), "AppData", "Local");
|
|
9022
|
+
const winPath = join7(localAppData, "Programs", "Antigravity", "Antigravity.exe");
|
|
9023
|
+
return existsSync7(winPath) ? winPath : null;
|
|
8904
9024
|
}
|
|
8905
9025
|
if (process.platform !== "darwin") return null;
|
|
8906
9026
|
const defaultPath = "/Applications/Antigravity.app/Contents/MacOS/Antigravity";
|
|
8907
|
-
if (
|
|
8908
|
-
const homePath =
|
|
8909
|
-
if (
|
|
9027
|
+
if (existsSync7(defaultPath)) return defaultPath;
|
|
9028
|
+
const homePath = join7(homedir7(), "Applications", "Antigravity.app", "Contents", "MacOS", "Antigravity");
|
|
9029
|
+
if (existsSync7(homePath)) return homePath;
|
|
8910
9030
|
return null;
|
|
8911
9031
|
}
|
|
8912
9032
|
function findAntigravityIdeBinary() {
|
|
8913
9033
|
const override = getAppPathOverride("antigravity-ide");
|
|
8914
|
-
if (override) return
|
|
9034
|
+
if (override) return existsSync7(override) ? override : null;
|
|
8915
9035
|
if (process.platform === "win32") {
|
|
8916
|
-
const localAppData = process.env["LOCALAPPDATA"] ??
|
|
8917
|
-
const winPath =
|
|
8918
|
-
return
|
|
9036
|
+
const localAppData = process.env["LOCALAPPDATA"] ?? join7(homedir7(), "AppData", "Local");
|
|
9037
|
+
const winPath = join7(localAppData, "Programs", "Antigravity IDE", "Antigravity IDE.exe");
|
|
9038
|
+
return existsSync7(winPath) ? winPath : null;
|
|
8919
9039
|
}
|
|
8920
9040
|
if (process.platform !== "darwin") return null;
|
|
8921
9041
|
const defaultPath = "/Applications/Antigravity IDE.app/Contents/Resources/app/bin/antigravity-ide";
|
|
8922
|
-
if (
|
|
8923
|
-
const homePath =
|
|
8924
|
-
if (
|
|
9042
|
+
if (existsSync7(defaultPath)) return defaultPath;
|
|
9043
|
+
const homePath = join7(homedir7(), "Applications", "Antigravity IDE.app", "Contents", "Resources", "app", "bin", "antigravity-ide");
|
|
9044
|
+
if (existsSync7(homePath)) return homePath;
|
|
8925
9045
|
return null;
|
|
8926
9046
|
}
|
|
8927
9047
|
function launchAntigravityApp(env, profileDir, gatewayUrl, extraArgs) {
|
|
@@ -8944,7 +9064,7 @@ function launchAntigravityApp(env, profileDir, gatewayUrl, extraArgs) {
|
|
|
8944
9064
|
`--user-data-dir=${profileDir}`,
|
|
8945
9065
|
...extraArgs
|
|
8946
9066
|
];
|
|
8947
|
-
const child =
|
|
9067
|
+
const child = spawn5(binaryPath, args, {
|
|
8948
9068
|
stdio: "inherit",
|
|
8949
9069
|
env
|
|
8950
9070
|
});
|
|
@@ -8970,13 +9090,13 @@ function launchAntigravityIde(env, profileDir, gatewayUrl, extraArgs) {
|
|
|
8970
9090
|
return;
|
|
8971
9091
|
}
|
|
8972
9092
|
prepareIdeProfile(profileDir, gatewayUrl);
|
|
8973
|
-
const relayExtensionsDir =
|
|
9093
|
+
const relayExtensionsDir = join7(homedir7(), ".relay-ai", "antigravity", "extensions");
|
|
8974
9094
|
const args = [
|
|
8975
9095
|
`--user-data-dir=${profileDir}`,
|
|
8976
9096
|
`--extensions-dir=${relayExtensionsDir}`,
|
|
8977
9097
|
...extraArgs
|
|
8978
9098
|
];
|
|
8979
|
-
const child =
|
|
9099
|
+
const child = spawn5(binaryPath, args, {
|
|
8980
9100
|
stdio: "inherit",
|
|
8981
9101
|
env
|
|
8982
9102
|
});
|
|
@@ -8991,8 +9111,8 @@ function launchAntigravityIde(env, profileDir, gatewayUrl, extraArgs) {
|
|
|
8991
9111
|
}
|
|
8992
9112
|
|
|
8993
9113
|
// src/antigravity.ts
|
|
8994
|
-
import { homedir as
|
|
8995
|
-
import { join as
|
|
9114
|
+
import { homedir as homedir8 } from "os";
|
|
9115
|
+
import { join as join8 } from "path";
|
|
8996
9116
|
var SHUTDOWN_DRAIN_MS = 500;
|
|
8997
9117
|
var AGY_FAVORITES_PROVIDER_ID = "__relay_agy_favorites__";
|
|
8998
9118
|
var AGY_FAVORITES_PROVIDER_LABEL = "\u2605 Antigravity CLI Favorites";
|
|
@@ -9275,7 +9395,7 @@ async function runAntigravityAppCommand(childArgs, trace = false, boot) {
|
|
|
9275
9395
|
trace,
|
|
9276
9396
|
boot,
|
|
9277
9397
|
async (env, _routes, gatewayHandle) => {
|
|
9278
|
-
const profileDir =
|
|
9398
|
+
const profileDir = join8(homedir8(), ".relay-ai", "antigravity", "app-profile");
|
|
9279
9399
|
if (isAntigravityAppRunning(profileDir)) {
|
|
9280
9400
|
const restart = await p11.confirm({
|
|
9281
9401
|
message: "Restart Antigravity to apply this Relay gateway?",
|
|
@@ -9323,7 +9443,7 @@ async function runAntigravityIdeCommand(childArgs, trace = false, boot) {
|
|
|
9323
9443
|
trace,
|
|
9324
9444
|
boot,
|
|
9325
9445
|
async (env, _routes, gatewayHandle) => {
|
|
9326
|
-
const profileDir =
|
|
9446
|
+
const profileDir = join8(homedir8(), ".relay-ai", "antigravity", "profile");
|
|
9327
9447
|
if (isAntigravityIdeRunning(profileDir)) {
|
|
9328
9448
|
const restart = await p11.confirm({
|
|
9329
9449
|
message: "Restart Antigravity IDE to apply this Relay gateway?",
|
|
@@ -9455,14 +9575,14 @@ async function buildCodexAppProviderCatalogRoutes(provider, apiKey, selectedMode
|
|
|
9455
9575
|
}
|
|
9456
9576
|
|
|
9457
9577
|
// src/codex/app-config.ts
|
|
9458
|
-
import { existsSync as
|
|
9459
|
-
import { dirname as dirname2, join as
|
|
9578
|
+
import { existsSync as existsSync8, readFileSync as readFileSync3, rmSync as rmSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
9579
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
9460
9580
|
import { parse, stringify } from "smol-toml";
|
|
9461
9581
|
function getCodexConfigPath() {
|
|
9462
|
-
return
|
|
9582
|
+
return join9(getCodexHome(), "config.toml");
|
|
9463
9583
|
}
|
|
9464
9584
|
function getCodexAppSidecarProfilePath() {
|
|
9465
|
-
return
|
|
9585
|
+
return join9(getCodexHome(), `${CODEX_APP_PROVIDER_ID}.config.toml`);
|
|
9466
9586
|
}
|
|
9467
9587
|
function asRecord(value) {
|
|
9468
9588
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
@@ -9485,7 +9605,7 @@ function applyRestoreNumber(config, key, had, value) {
|
|
|
9485
9605
|
}
|
|
9486
9606
|
}
|
|
9487
9607
|
function readCodexConfigText(path2 = getCodexConfigPath()) {
|
|
9488
|
-
if (!
|
|
9608
|
+
if (!existsSync8(path2)) return "";
|
|
9489
9609
|
return readFileSync3(path2, "utf8");
|
|
9490
9610
|
}
|
|
9491
9611
|
function parseCodexConfig(text4) {
|
|
@@ -9650,13 +9770,13 @@ function restoreConfigFromState(state, configPath = getCodexConfigPath()) {
|
|
|
9650
9770
|
applyRestoreNumber(config, "model_context_window", state.hadModelContextWindow ?? false, state.modelContextWindow);
|
|
9651
9771
|
applyRestoreNumber(config, "model_auto_compact_token_limit", state.hadModelAutoCompactTokenLimit ?? false, state.modelAutoCompactTokenLimit);
|
|
9652
9772
|
const sidecar = getCodexAppSidecarProfilePath();
|
|
9653
|
-
if (
|
|
9773
|
+
if (existsSync8(sidecar)) {
|
|
9654
9774
|
try {
|
|
9655
9775
|
rmSync3(sidecar, { force: true });
|
|
9656
9776
|
} catch {
|
|
9657
9777
|
}
|
|
9658
9778
|
}
|
|
9659
|
-
const hadFile =
|
|
9779
|
+
const hadFile = existsSync8(configPath);
|
|
9660
9780
|
const empty = Object.keys(config).length === 0 || Object.keys(config).length === 1 && "model_providers" in config && Object.keys(asRecord(config.model_providers)).length === 0;
|
|
9661
9781
|
if (!hadFile && empty) return false;
|
|
9662
9782
|
if (empty) {
|
|
@@ -9677,25 +9797,25 @@ function previewAppConfigToml(spec) {
|
|
|
9677
9797
|
// src/codex/app-session.ts
|
|
9678
9798
|
import {
|
|
9679
9799
|
copyFileSync as copyFileSync2,
|
|
9680
|
-
existsSync as
|
|
9800
|
+
existsSync as existsSync9,
|
|
9681
9801
|
mkdirSync as mkdirSync4,
|
|
9682
9802
|
readdirSync as readdirSync2,
|
|
9683
9803
|
readFileSync as readFileSync4,
|
|
9684
9804
|
rmSync as rmSync4
|
|
9685
9805
|
} from "fs";
|
|
9686
|
-
import { basename as basename2, join as
|
|
9806
|
+
import { basename as basename2, join as join10 } from "path";
|
|
9687
9807
|
function getAppSessionLockPath(env = process.env) {
|
|
9688
|
-
return
|
|
9808
|
+
return join10(getRelayAiCodexDir(env), "session-app.json");
|
|
9689
9809
|
}
|
|
9690
9810
|
function getAppRestoreStatePath(env = process.env) {
|
|
9691
|
-
return
|
|
9811
|
+
return join10(getRelayAiCodexDir(env), "app-restore-state.json");
|
|
9692
9812
|
}
|
|
9693
9813
|
function getAppCatalogPath(providerId, env = process.env) {
|
|
9694
|
-
return
|
|
9814
|
+
return join10(getRelayAiCodexDir(env), `app-models-${providerId}.json`);
|
|
9695
9815
|
}
|
|
9696
9816
|
function readAppSessionLock(env = process.env) {
|
|
9697
9817
|
const path2 = getAppSessionLockPath(env);
|
|
9698
|
-
if (!
|
|
9818
|
+
if (!existsSync9(path2)) return null;
|
|
9699
9819
|
try {
|
|
9700
9820
|
const parsed = JSON.parse(readFileSync4(path2, "utf8"));
|
|
9701
9821
|
if (typeof parsed.pid === "number" && typeof parsed.startedAt === "string") return parsed;
|
|
@@ -9709,11 +9829,11 @@ function writeAppSessionLock(lock, env = process.env) {
|
|
|
9709
9829
|
}
|
|
9710
9830
|
function clearAppSessionLock(env = process.env) {
|
|
9711
9831
|
const path2 = getAppSessionLockPath(env);
|
|
9712
|
-
if (
|
|
9832
|
+
if (existsSync9(path2)) rmSync4(path2, { force: true });
|
|
9713
9833
|
}
|
|
9714
9834
|
function readAppRestoreState(env = process.env) {
|
|
9715
9835
|
const path2 = getAppRestoreStatePath(env);
|
|
9716
|
-
if (!
|
|
9836
|
+
if (!existsSync9(path2)) return null;
|
|
9717
9837
|
try {
|
|
9718
9838
|
return JSON.parse(readFileSync4(path2, "utf8"));
|
|
9719
9839
|
} catch {
|
|
@@ -9727,16 +9847,16 @@ function writeAppRestoreState(state, env = process.env) {
|
|
|
9727
9847
|
}
|
|
9728
9848
|
function clearAppRestoreState(env = process.env) {
|
|
9729
9849
|
const path2 = getAppRestoreStatePath(env);
|
|
9730
|
-
if (
|
|
9850
|
+
if (existsSync9(path2)) rmSync4(path2, { force: true });
|
|
9731
9851
|
}
|
|
9732
9852
|
function backupConfigToml(env = process.env) {
|
|
9733
9853
|
const configPath = getCodexConfigPath();
|
|
9734
|
-
if (!
|
|
9854
|
+
if (!existsSync9(configPath)) return void 0;
|
|
9735
9855
|
rotateBackups(configPath, env);
|
|
9736
9856
|
const backupsDir = getBackupsDir(env);
|
|
9737
9857
|
mkdirSync4(backupsDir, { recursive: true });
|
|
9738
9858
|
const base = basename2(configPath);
|
|
9739
|
-
const backupPath =
|
|
9859
|
+
const backupPath = join10(backupsDir, `${base}.${Date.now()}.bak`);
|
|
9740
9860
|
copyFileSync2(configPath, backupPath);
|
|
9741
9861
|
return backupPath;
|
|
9742
9862
|
}
|
|
@@ -9752,8 +9872,8 @@ function saveAppRestoreStateBeforePatch(env = process.env) {
|
|
|
9752
9872
|
}
|
|
9753
9873
|
function ownedAppCatalogPaths(env = process.env) {
|
|
9754
9874
|
const codexDir = getRelayAiCodexDir(env);
|
|
9755
|
-
if (!
|
|
9756
|
-
return readdirSync2(codexDir).filter((n) => n.startsWith("app-models-") && n.endsWith(".json")).map((n) =>
|
|
9875
|
+
if (!existsSync9(codexDir)) return [];
|
|
9876
|
+
return readdirSync2(codexDir).filter((n) => n.startsWith("app-models-") && n.endsWith(".json")).map((n) => join10(codexDir, n));
|
|
9757
9877
|
}
|
|
9758
9878
|
function removeAppCatalogs(env = process.env) {
|
|
9759
9879
|
const removed = [];
|
|
@@ -9785,7 +9905,7 @@ function restoreCodexAppOverlay(env = process.env) {
|
|
|
9785
9905
|
}
|
|
9786
9906
|
if (restoreState) {
|
|
9787
9907
|
restoreConfigFromState(restoreState);
|
|
9788
|
-
} else if (lock?.backupPath &&
|
|
9908
|
+
} else if (lock?.backupPath && existsSync9(lock.backupPath)) {
|
|
9789
9909
|
copyFileSync2(lock.backupPath, getCodexConfigPath());
|
|
9790
9910
|
}
|
|
9791
9911
|
removeAppCatalogs(env);
|
|
@@ -10393,25 +10513,25 @@ import pc11 from "picocolors";
|
|
|
10393
10513
|
import * as p13 from "@clack/prompts";
|
|
10394
10514
|
|
|
10395
10515
|
// src/claude-desktop/app-config.ts
|
|
10396
|
-
import { existsSync as
|
|
10397
|
-
import { homedir as
|
|
10398
|
-
import { join as
|
|
10516
|
+
import { existsSync as existsSync10, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
10517
|
+
import { homedir as homedir9 } from "os";
|
|
10518
|
+
import { join as join11, dirname as dirname3 } from "path";
|
|
10399
10519
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
10400
10520
|
function getClaudeDesktopHome() {
|
|
10401
10521
|
if (process.platform === "win32") {
|
|
10402
|
-
return
|
|
10522
|
+
return join11(process.env.LOCALAPPDATA || join11(homedir9(), "AppData", "Local"), "Claude-3p");
|
|
10403
10523
|
}
|
|
10404
|
-
return
|
|
10524
|
+
return join11(homedir9(), "Library", "Application Support", "Claude-3p");
|
|
10405
10525
|
}
|
|
10406
10526
|
function getConfigLibraryPath() {
|
|
10407
|
-
return
|
|
10527
|
+
return join11(getClaudeDesktopHome(), "configLibrary");
|
|
10408
10528
|
}
|
|
10409
10529
|
function getMetaJsonPath() {
|
|
10410
|
-
return
|
|
10530
|
+
return join11(getConfigLibraryPath(), "_meta.json");
|
|
10411
10531
|
}
|
|
10412
10532
|
function readMetaJson() {
|
|
10413
10533
|
const metaPath = getMetaJsonPath();
|
|
10414
|
-
if (!
|
|
10534
|
+
if (!existsSync10(metaPath)) return null;
|
|
10415
10535
|
try {
|
|
10416
10536
|
return JSON.parse(readFileSync5(metaPath, "utf8"));
|
|
10417
10537
|
} catch {
|
|
@@ -10435,7 +10555,7 @@ function buildRelayAiConfig(proxyPort) {
|
|
|
10435
10555
|
}
|
|
10436
10556
|
function writeRelayAiConfig(proxyPort) {
|
|
10437
10557
|
const uuid = randomUUID2();
|
|
10438
|
-
const configPath =
|
|
10558
|
+
const configPath = join11(getConfigLibraryPath(), `${uuid}.json`);
|
|
10439
10559
|
const config = buildRelayAiConfig(proxyPort);
|
|
10440
10560
|
mkdirSync5(dirname3(configPath), { recursive: true });
|
|
10441
10561
|
writeFileSync4(configPath, `${JSON.stringify(config, null, 2)}
|
|
@@ -10450,14 +10570,14 @@ function writeRelayAiConfig(proxyPort) {
|
|
|
10450
10570
|
}
|
|
10451
10571
|
|
|
10452
10572
|
// src/claude-desktop/app-session.ts
|
|
10453
|
-
import { existsSync as
|
|
10454
|
-
import { join as
|
|
10573
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6, rmSync as rmSync5, writeFileSync as writeFileSync5, copyFileSync as copyFileSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
10574
|
+
import { join as join12 } from "path";
|
|
10455
10575
|
function getSessionLockPath2() {
|
|
10456
|
-
return
|
|
10576
|
+
return join12(getClaudeDesktopHome(), ".relay-ai.lock");
|
|
10457
10577
|
}
|
|
10458
10578
|
function readSessionLock2() {
|
|
10459
10579
|
const path2 = getSessionLockPath2();
|
|
10460
|
-
if (!
|
|
10580
|
+
if (!existsSync11(path2)) return null;
|
|
10461
10581
|
try {
|
|
10462
10582
|
const parsed = JSON.parse(readFileSync6(path2, "utf8"));
|
|
10463
10583
|
if (typeof parsed.pid === "number" && typeof parsed.startedAt === "string") return parsed;
|
|
@@ -10482,21 +10602,21 @@ function isProcessAlive3(pid) {
|
|
|
10482
10602
|
function backupMetaJson() {
|
|
10483
10603
|
const metaPath = getMetaJsonPath();
|
|
10484
10604
|
const backupPath = `${metaPath}.bak`;
|
|
10485
|
-
if (
|
|
10605
|
+
if (existsSync11(metaPath)) {
|
|
10486
10606
|
copyFileSync3(metaPath, backupPath);
|
|
10487
10607
|
}
|
|
10488
10608
|
}
|
|
10489
10609
|
function restoreMetaJson() {
|
|
10490
10610
|
const metaPath = getMetaJsonPath();
|
|
10491
10611
|
const backupPath = `${metaPath}.bak`;
|
|
10492
|
-
if (
|
|
10612
|
+
if (existsSync11(backupPath)) {
|
|
10493
10613
|
copyFileSync3(backupPath, metaPath);
|
|
10494
10614
|
unlinkSync2(backupPath);
|
|
10495
10615
|
}
|
|
10496
10616
|
}
|
|
10497
10617
|
function removeRelayAiConfig(uuid) {
|
|
10498
|
-
const configPath =
|
|
10499
|
-
if (
|
|
10618
|
+
const configPath = join12(getConfigLibraryPath(), `${uuid}.json`);
|
|
10619
|
+
if (existsSync11(configPath)) {
|
|
10500
10620
|
try {
|
|
10501
10621
|
rmSync5(configPath, { force: true });
|
|
10502
10622
|
} catch {
|
|
@@ -10844,17 +10964,17 @@ ${pc11.bold("Claude Desktop 3P Mode Active")}`);
|
|
|
10844
10964
|
}
|
|
10845
10965
|
|
|
10846
10966
|
// src/ai-doc.ts
|
|
10847
|
-
import { existsSync as
|
|
10848
|
-
import { homedir as
|
|
10849
|
-
import { join as
|
|
10967
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
10968
|
+
import { homedir as homedir10 } from "os";
|
|
10969
|
+
import { join as join13 } from "path";
|
|
10850
10970
|
var SKILL_DIR_NAME = "relay-ai-cli";
|
|
10851
10971
|
var SKILL_INSTALL_DIRS = [
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10972
|
+
join13(getAppHome(), "skills"),
|
|
10973
|
+
join13(homedir10(), ".claude", "skills"),
|
|
10974
|
+
join13(homedir10(), ".agents", "skills"),
|
|
10975
|
+
join13(homedir10(), ".codex", "skills"),
|
|
10976
|
+
join13(homedir10(), ".cursor", "skills"),
|
|
10977
|
+
join13(homedir10(), ".cursor", "skills-cursor")
|
|
10858
10978
|
];
|
|
10859
10979
|
function parseSkillVersion(content) {
|
|
10860
10980
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
@@ -10868,8 +10988,8 @@ function parseSkillVersion(content) {
|
|
|
10868
10988
|
return null;
|
|
10869
10989
|
}
|
|
10870
10990
|
function readInstalledSkillVersion(skillDir) {
|
|
10871
|
-
const skillPath =
|
|
10872
|
-
if (!
|
|
10991
|
+
const skillPath = join13(skillDir, "SKILL.md");
|
|
10992
|
+
if (!existsSync12(skillPath)) return null;
|
|
10873
10993
|
try {
|
|
10874
10994
|
const head = readFileSync7(skillPath, "utf-8").slice(0, 1024);
|
|
10875
10995
|
return parseSkillVersion(head.includes("---", 4) ? head : `${head}
|
|
@@ -10881,8 +11001,8 @@ function readInstalledSkillVersion(skillDir) {
|
|
|
10881
11001
|
}
|
|
10882
11002
|
function skillInstallTargets() {
|
|
10883
11003
|
return SKILL_INSTALL_DIRS.map((dir) => {
|
|
10884
|
-
const skillDir =
|
|
10885
|
-
return { skillDir, skillPath:
|
|
11004
|
+
const skillDir = join13(dir, SKILL_DIR_NAME);
|
|
11005
|
+
return { skillDir, skillPath: join13(skillDir, "SKILL.md") };
|
|
10886
11006
|
});
|
|
10887
11007
|
}
|
|
10888
11008
|
function formatProviderModels(provider) {
|
|
@@ -11168,7 +11288,7 @@ OPENAI CODEX CLI
|
|
|
11168
11288
|
PROVIDERS REGISTRY
|
|
11169
11289
|
relay-ai providers interactive hub
|
|
11170
11290
|
relay-ai providers add add Groq, Mistral, OpenAI, custom URL, \u2026
|
|
11171
|
-
relay-ai providers import one-time import from OpenCode
|
|
11291
|
+
relay-ai providers import optional one-time import from OpenCode CLI
|
|
11172
11292
|
relay-ai providers list show provider ids and model counts
|
|
11173
11293
|
relay-ai providers remove <id>
|
|
11174
11294
|
relay-ai providers refresh-models [id]
|
|
@@ -11501,7 +11621,7 @@ function buildHttpProxyChildEnv(baseEnv, proxyUrl, caCertPath) {
|
|
|
11501
11621
|
import { randomBytes, randomUUID as randomUUID3 } from "crypto";
|
|
11502
11622
|
import {
|
|
11503
11623
|
chmodSync,
|
|
11504
|
-
existsSync as
|
|
11624
|
+
existsSync as existsSync13,
|
|
11505
11625
|
mkdirSync as mkdirSync7,
|
|
11506
11626
|
readFileSync as readFileSync8,
|
|
11507
11627
|
readdirSync as readdirSync3,
|
|
@@ -11509,7 +11629,7 @@ import {
|
|
|
11509
11629
|
statSync as statSync2,
|
|
11510
11630
|
writeFileSync as writeFileSync7
|
|
11511
11631
|
} from "fs";
|
|
11512
|
-
import { dirname as dirname4, join as
|
|
11632
|
+
import { dirname as dirname4, join as join14, resolve } from "path";
|
|
11513
11633
|
import forge from "node-forge";
|
|
11514
11634
|
var SESSION_ROOT = "http-proxy-sessions";
|
|
11515
11635
|
var OWNER_FILE = "owner.pid";
|
|
@@ -11528,13 +11648,13 @@ function processIsRunning(pid) {
|
|
|
11528
11648
|
}
|
|
11529
11649
|
}
|
|
11530
11650
|
function cleanupStaleHttpProxySessions(appHome = getAppHome()) {
|
|
11531
|
-
const root =
|
|
11532
|
-
if (!
|
|
11651
|
+
const root = join14(appHome, SESSION_ROOT);
|
|
11652
|
+
if (!existsSync13(root)) return;
|
|
11533
11653
|
for (const name of readdirSync3(root)) {
|
|
11534
|
-
const sessionDir =
|
|
11654
|
+
const sessionDir = join14(root, name);
|
|
11535
11655
|
try {
|
|
11536
11656
|
if (!statSync2(sessionDir).isDirectory()) continue;
|
|
11537
|
-
const pid = Number(readFileSync8(
|
|
11657
|
+
const pid = Number(readFileSync8(join14(sessionDir, OWNER_FILE), "utf8").trim());
|
|
11538
11658
|
if (!processIsRunning(pid)) rmSync6(sessionDir, { recursive: true, force: true });
|
|
11539
11659
|
} catch {
|
|
11540
11660
|
rmSync6(sessionDir, { recursive: true, force: true });
|
|
@@ -11543,13 +11663,13 @@ function cleanupStaleHttpProxySessions(appHome = getAppHome()) {
|
|
|
11543
11663
|
}
|
|
11544
11664
|
function createHttpProxyCertificates(appHome = getAppHome()) {
|
|
11545
11665
|
cleanupStaleHttpProxySessions(appHome);
|
|
11546
|
-
const root =
|
|
11666
|
+
const root = join14(appHome, SESSION_ROOT);
|
|
11547
11667
|
mkdirSync7(root, { recursive: true, mode: 448 });
|
|
11548
11668
|
chmodSync(root, 448);
|
|
11549
|
-
const sessionDir =
|
|
11669
|
+
const sessionDir = join14(root, randomUUID3());
|
|
11550
11670
|
mkdirSync7(sessionDir, { mode: 448 });
|
|
11551
11671
|
chmodSync(sessionDir, 448);
|
|
11552
|
-
writeFileSync7(
|
|
11672
|
+
writeFileSync7(join14(sessionDir, OWNER_FILE), `${process.pid}
|
|
11553
11673
|
`, { mode: 384 });
|
|
11554
11674
|
try {
|
|
11555
11675
|
const caKeys = forge.pki.rsa.generateKeyPair(2048);
|
|
@@ -11584,7 +11704,7 @@ function createHttpProxyCertificates(appHome = getAppHome()) {
|
|
|
11584
11704
|
]);
|
|
11585
11705
|
server.sign(caKeys.privateKey, forge.md.sha256.create());
|
|
11586
11706
|
const caCert = forge.pki.certificateToPem(ca);
|
|
11587
|
-
const caCertPath =
|
|
11707
|
+
const caCertPath = join14(sessionDir, "relay-ai-ca.pem");
|
|
11588
11708
|
writeFileSync7(caCertPath, caCert, { encoding: "utf8", mode: 384 });
|
|
11589
11709
|
chmodSync(caCertPath, 384);
|
|
11590
11710
|
let cleaned = false;
|
|
@@ -11630,7 +11750,7 @@ function createHttpProxyCaBundle(relayCaCertPath, additionalCaCertPath) {
|
|
|
11630
11750
|
const relayCa = readFileSync8(relayCaCertPath, "utf8").trimEnd();
|
|
11631
11751
|
const additionalCa = readFileSync8(additionalCaCertPath, "utf8").trim();
|
|
11632
11752
|
if (!additionalCa) return relayCaCertPath;
|
|
11633
|
-
const combinedPath =
|
|
11753
|
+
const combinedPath = join14(dirname4(relayCaCertPath), "combined-ca.pem");
|
|
11634
11754
|
writeFileSync7(
|
|
11635
11755
|
combinedPath,
|
|
11636
11756
|
`${relayCa}
|
|
@@ -13479,7 +13599,7 @@ Options:
|
|
|
13479
13599
|
--trace Write debug logs under ~/.relay-ai/logs/`);
|
|
13480
13600
|
return 0;
|
|
13481
13601
|
}
|
|
13482
|
-
const { runUiCommand } = await import("./ui-command-
|
|
13602
|
+
const { runUiCommand } = await import("./ui-command-GNCQS7F7.js");
|
|
13483
13603
|
return runUiCommand({ trace: parsed.trace, serverMode: parsed.uiServerMode });
|
|
13484
13604
|
}
|
|
13485
13605
|
if (parsed.command === "models") {
|