@jacobbd/relay-ai 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -196,9 +196,10 @@ import {
196
196
  updateCustomEndpointProvider,
197
197
  upstreamHttpStatus,
198
198
  validateCustomEndpointUrl,
199
+ waitForCodexAppQuit,
199
200
  writeSecureLogLine,
200
201
  zenRegistryStub
201
- } from "./chunk-PYJQMEJD.js";
202
+ } from "./chunk-BJ4AE3PS.js";
202
203
  import {
203
204
  filterTemplates,
204
205
  getTemplateById,
@@ -5574,7 +5575,7 @@ function printCodexAppSessionPanel(opts) {
5574
5575
  `${pc6.bold("Provider")} ${fmtProvider(opts.providerName)}`,
5575
5576
  "",
5576
5577
  `${pc6.yellow(pc6.bold("Keep this terminal open"))}${pc6.white(" while you use Codex.")}`,
5577
- `${pc6.white("Press ")}${pc6.bold(pc6.red("Ctrl+C"))}${pc6.white(" to stop the proxy and restore ")}${fmtCommand("~/.codex/config.toml")}${pc6.white(".")}`,
5578
+ `${pc6.white("Press ")}${pc6.bold(pc6.red("Ctrl+C"))}${pc6.white(" to close ChatGPT Desktop, restore ")}${fmtCommand("~/.codex/config.toml")}${pc6.white(", and stop the proxy.")}`,
5578
5579
  `${pc6.dim("Codex may show ")}${pc6.yellow('"Custom"')}${pc6.dim(" if the desktop picker cannot resolve registry models \u2014 check the terminal line above. After restart, pick your model from the picker if it appears.")}`,
5579
5580
  `${pc6.dim("If Codex asks you to sign in after restart: choose API key and enter any character \u2014 that unlocks the model picker for registry providers.")}`,
5580
5581
  `${pc6.dim("Stuck? Run ")}${fmtCommand(opts.restoreCommand)}${pc6.dim(".")}`
@@ -11608,6 +11609,23 @@ function waitForShutdown2() {
11608
11609
  });
11609
11610
  }
11610
11611
 
11612
+ // src/codex/app-shutdown.ts
11613
+ async function shutdownCodexAppSession(dependencies) {
11614
+ if (dependencies.isAppRunning()) {
11615
+ dependencies.quitApp();
11616
+ const exited = await dependencies.waitForAppExit();
11617
+ if (!exited) {
11618
+ throw new Error(
11619
+ "ChatGPT Desktop did not exit after graceful shutdown; refusing to restore config until Desktop exits. Close Desktop, then run relay-ai codex-app --restore."
11620
+ );
11621
+ }
11622
+ }
11623
+ const result = dependencies.restoreOverlay();
11624
+ if (result.liveSession) throw new Error(result.message);
11625
+ dependencies.closeResources();
11626
+ return result;
11627
+ }
11628
+
11611
11629
  // src/codex-app.ts
11612
11630
  function codexProxyRouteToCodexRoute(route, fallbackProviderId) {
11613
11631
  return {
@@ -11648,22 +11666,6 @@ async function waitForShutdownWithConfirm(assumeYes = false) {
11648
11666
  if (p12.isCancel(choice) || choice === "yes") return signal;
11649
11667
  }
11650
11668
  }
11651
- function unattendedShutdownClosesApp(assumeYes, signal) {
11652
- return assumeYes && signal !== "sigint";
11653
- }
11654
- async function maybeCloseRunningCodexApp(assumeYes = false) {
11655
- if (!isCodexAppRunning()) return;
11656
- if (assumeYes) {
11657
- p12.log.step("Stopping ChatGPT Desktop...");
11658
- quitCodexAppGracefully();
11659
- return;
11660
- }
11661
- const shouldClose = await p12.confirm({ message: "ChatGPT Desktop is still running. Close it?" });
11662
- if (shouldClose && !p12.isCancel(shouldClose)) {
11663
- p12.log.step("Stopping ChatGPT Desktop...");
11664
- quitCodexAppGracefully();
11665
- }
11666
- }
11667
11669
  function codexAppHelpText() {
11668
11670
  return `${pc10.bold("relay-ai codex-app")} \u2014 launch the ChatGPT desktop app (Codex mode) with your registry providers
11669
11671
  ${pc10.dim('(OpenAI merged the Codex app into ChatGPT desktop on 2026-07-09; "chatgpt" is an alias for this command)')}
@@ -11697,7 +11699,7 @@ ${pc10.bold("Platforms:")}
11697
11699
  macOS, Windows, and Linux (ChatGPT desktop app preview).
11698
11700
 
11699
11701
  ${pc10.bold("Cleanup:")}
11700
- Ctrl+C stops the proxy and restores your previous Codex config.
11702
+ Ctrl+C closes ChatGPT Desktop, restores your previous Codex config, and stops the proxy.
11701
11703
  After crash: relay-ai codex-app --restore
11702
11704
 
11703
11705
  ${pc10.bold("Preview (no writes):")}
@@ -11795,6 +11797,25 @@ async function runCodexAppVertexLaunch(configOnly, trace = false) {
11795
11797
  }
11796
11798
  let proxyHandle = null;
11797
11799
  let sessionActive = false;
11800
+ let shutdownFailed = false;
11801
+ let resourcesClosed = false;
11802
+ const closeResources = () => {
11803
+ if (resourcesClosed) return;
11804
+ resourcesClosed = true;
11805
+ proxyHandle?.close();
11806
+ };
11807
+ const restoreOverlay = () => {
11808
+ const result = restoreCodexAppOverlay();
11809
+ if (!result.liveSession) sessionActive = false;
11810
+ return result;
11811
+ };
11812
+ const restoreOverlaySafely = () => {
11813
+ try {
11814
+ restoreOverlay();
11815
+ } catch (err) {
11816
+ p12.log.error(String(err instanceof Error ? err.message : err));
11817
+ }
11818
+ };
11798
11819
  try {
11799
11820
  proxyHandle = await startCodexProxy(
11800
11821
  vertexModels.map((m) => ({
@@ -11851,15 +11872,27 @@ async function runCodexAppVertexLaunch(configOnly, trace = false) {
11851
11872
  codexAppOutro(selectedEntry.display_name);
11852
11873
  await waitForShutdownWithConfirm();
11853
11874
  console.log("");
11854
- if (sessionActive) {
11855
- restoreCodexAppOverlay();
11856
- sessionActive = false;
11875
+ try {
11876
+ const result = await shutdownCodexAppSession({
11877
+ isAppRunning: isCodexAppRunning,
11878
+ quitApp: quitCodexAppGracefully,
11879
+ waitForAppExit: () => waitForCodexAppQuit(),
11880
+ restoreOverlay,
11881
+ closeResources
11882
+ });
11883
+ p12.log.success(result.message);
11884
+ return 0;
11885
+ } catch (err) {
11886
+ shutdownFailed = true;
11887
+ p12.log.error(String(err instanceof Error ? err.message : err));
11888
+ return 1;
11857
11889
  }
11858
- await maybeCloseRunningCodexApp();
11859
- return 0;
11860
11890
  } finally {
11861
- proxyHandle?.close();
11862
- if (sessionActive) restoreCodexAppOverlay();
11891
+ if (sessionActive && !isCodexAppRunning()) restoreOverlaySafely();
11892
+ closeResources();
11893
+ if (sessionActive && !shutdownFailed) {
11894
+ p12.log.error("ChatGPT Desktop is still running; config restoration was skipped. Close Desktop, then run relay-ai codex-app --restore.");
11895
+ }
11863
11896
  }
11864
11897
  }
11865
11898
  async function runCodexAppCommand(args, opts = {}) {
@@ -12073,6 +12106,27 @@ Mixed Codex App mode is unavailable: ${err instanceof Error ? err.message : err}
12073
12106
  }
12074
12107
  let proxyHandle = null;
12075
12108
  let sessionActive = false;
12109
+ let shutdownFailed = false;
12110
+ let resourcesClosed = false;
12111
+ const closeResources = () => {
12112
+ if (resourcesClosed) return;
12113
+ resourcesClosed = true;
12114
+ proxyHandle?.close();
12115
+ cloudCodeBackend?.handle.close();
12116
+ cloudCodeBackendFav?.handle.close();
12117
+ };
12118
+ const restoreOverlay = () => {
12119
+ const result = restoreCodexAppOverlay();
12120
+ if (!result.liveSession) sessionActive = false;
12121
+ return result;
12122
+ };
12123
+ const restoreOverlaySafely = () => {
12124
+ try {
12125
+ restoreOverlay();
12126
+ } catch (err) {
12127
+ p12.log.error(String(err instanceof Error ? err.message : err));
12128
+ }
12129
+ };
12076
12130
  try {
12077
12131
  const catalogPath = mixedPlan ? join13(getRelayAiCodexDir(), "app-models-mixed.json") : favoritesActive && resolvedFavorites.length > 0 ? getFavoritesAppCatalogPath() : getAppCatalogPath(route.providerId);
12078
12132
  const activeRoute = mixedPlan ? {
@@ -12249,31 +12303,30 @@ Mixed Codex App mode is unavailable: ${err instanceof Error ? err.message : err}
12249
12303
  restoreCommand: "relay-ai codex-app --restore"
12250
12304
  });
12251
12305
  codexAppOutro(modelLabel);
12252
- const shutdownSignal = await waitForShutdownWithConfirm(opts.assumeYes);
12306
+ await waitForShutdownWithConfirm(opts.assumeYes);
12253
12307
  if (trace) printTraceLog(debugLogPath);
12254
12308
  console.log("");
12255
- if (sessionActive) {
12256
- restoreCodexAppOverlay();
12257
- sessionActive = false;
12258
- }
12259
- if (unattendedShutdownClosesApp(Boolean(opts.assumeYes), shutdownSignal)) {
12260
- if (isCodexAppRunning()) {
12261
- p12.log.step("Stopping ChatGPT Desktop after unattended Relay shutdown...");
12262
- quitCodexAppGracefully();
12263
- }
12264
- } else {
12265
- await maybeCloseRunningCodexApp(opts.assumeYes);
12309
+ try {
12310
+ const result = await shutdownCodexAppSession({
12311
+ isAppRunning: isCodexAppRunning,
12312
+ quitApp: quitCodexAppGracefully,
12313
+ waitForAppExit: () => waitForCodexAppQuit(),
12314
+ restoreOverlay,
12315
+ closeResources
12316
+ });
12317
+ p12.log.success(result.message);
12318
+ return 0;
12319
+ } catch (err) {
12320
+ shutdownFailed = true;
12321
+ p12.log.error(String(err instanceof Error ? err.message : err));
12322
+ return 1;
12266
12323
  }
12267
- return 0;
12268
12324
  } finally {
12269
- proxyHandle?.close();
12270
- if (cloudCodeBackend) {
12271
- cloudCodeBackend.handle.close();
12272
- }
12273
- if (cloudCodeBackendFav) {
12274
- cloudCodeBackendFav.handle.close();
12325
+ if (sessionActive && !isCodexAppRunning()) restoreOverlaySafely();
12326
+ closeResources();
12327
+ if (sessionActive && !shutdownFailed) {
12328
+ p12.log.error("ChatGPT Desktop is still running; config restoration was skipped. Close Desktop, then run relay-ai codex-app --restore.");
12275
12329
  }
12276
- if (sessionActive) restoreCodexAppOverlay();
12277
12330
  }
12278
12331
  }
12279
12332
 
@@ -15739,7 +15792,7 @@ Options:
15739
15792
  --trace Write debug logs under ~/.relay-ai/logs/`);
15740
15793
  return 0;
15741
15794
  }
15742
- const { runUiCommand } = await import("./ui-command-NYYLGTCD.js");
15795
+ const { runUiCommand } = await import("./ui-command-NM4MNZLO.js");
15743
15796
  return runUiCommand({ trace: parsed.trace, serverMode: parsed.uiServerMode });
15744
15797
  }
15745
15798
  if (parsed.command === "models") {