@jacobbd/relay-ai 0.9.5 → 0.9.6

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.
@@ -11,7 +11,7 @@ import { join } from "path";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@jacobbd/relay-ai",
14
- version: "0.9.5",
14
+ version: "0.9.6",
15
15
  publishConfig: {
16
16
  access: "public"
17
17
  },
@@ -12888,6 +12888,7 @@ ${pc6.bold("Usage:")}
12888
12888
  relay-ai providers auth openai-oauth
12889
12889
  relay-ai providers auth github-copilot
12890
12890
  relay-ai providers auth cline-pass
12891
+ relay-ai providers auth antigravity
12891
12892
 
12892
12893
  ${pc6.bold("Device code (works on SSH/VPS):")}
12893
12894
  xai-oauth SuperGrok / X Premium (device code at x.ai/device)
@@ -12895,11 +12896,14 @@ ${pc6.bold("Device code (works on SSH/VPS):")}
12895
12896
  github-copilot GitHub Copilot Free or paid (device code at github.com/login/device)
12896
12897
  cline-pass ClinePass account (device code at app.cline.bot)
12897
12898
 
12899
+ ${pc6.bold("Browser sign-in:")}
12900
+ antigravity Google Cloud Code Assist OAuth (opens Google sign-in)
12901
+
12898
12902
  ${pc6.dim("OpenCode CLI configs: use")} relay-ai providers import${pc6.dim(" (optional one-time migration).")}`;
12899
12903
  }
12900
12904
 
12901
12905
  // src/codex/app-launch.ts
12902
- import { execSync as execSync2, spawn as spawn3 } from "child_process";
12906
+ import { execFileSync as execFileSync3, execSync as execSync2, spawn as spawn3 } from "child_process";
12903
12907
  import { copyFileSync as copyFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync8, readdirSync as readdirSync2, realpathSync, statSync as statSync3 } from "fs";
12904
12908
  import { homedir as homedir7 } from "os";
12905
12909
  import { dirname as dirname5, join as join12, win32 as winPath } from "path";
@@ -13136,6 +13140,51 @@ function darwinIsRunning() {
13136
13140
  }
13137
13141
  });
13138
13142
  }
13143
+ function pgrepExact(names) {
13144
+ const pids = /* @__PURE__ */ new Set();
13145
+ for (const name of names) {
13146
+ try {
13147
+ for (const raw of run(`pgrep -x ${JSON.stringify(name)}`).split(/\s+/)) {
13148
+ const pid = Number.parseInt(raw, 10);
13149
+ if (Number.isFinite(pid) && pid > 0 && pid !== process.pid) pids.add(pid);
13150
+ }
13151
+ } catch {
13152
+ }
13153
+ }
13154
+ return [...pids];
13155
+ }
13156
+ function darwinMainExecutableCandidates(appPath) {
13157
+ return DARWIN_APP_NAMES.map((name) => join12(appPath, "Contents", "MacOS", name));
13158
+ }
13159
+ function darwinMainPidsFromProcessList(processList, commands, currentPid = process.pid) {
13160
+ const pids = /* @__PURE__ */ new Set();
13161
+ for (const line of processList.split("\n")) {
13162
+ const match = line.match(/^\s*(\d+)\s+(.+?)\s*$/);
13163
+ if (!match) continue;
13164
+ const pid = Number.parseInt(match[1], 10);
13165
+ const command = match[2];
13166
+ if (Number.isFinite(pid) && pid > 0 && pid !== currentPid && commands.some((candidate) => command === candidate || command.startsWith(`${candidate} `))) {
13167
+ pids.add(pid);
13168
+ }
13169
+ }
13170
+ return [...pids];
13171
+ }
13172
+ function darwinMatchingPids() {
13173
+ const appPath = findCodexApp("darwin");
13174
+ if (!appPath) return [];
13175
+ try {
13176
+ const processList = execFileSync3("ps", ["-axo", "pid=,command="], {
13177
+ encoding: "utf8",
13178
+ stdio: ["pipe", "pipe", "pipe"]
13179
+ });
13180
+ return darwinMainPidsFromProcessList(
13181
+ processList,
13182
+ darwinMainExecutableCandidates(appPath)
13183
+ );
13184
+ } catch {
13185
+ return [];
13186
+ }
13187
+ }
13139
13188
  function linuxIsRunning() {
13140
13189
  for (const name of ["ChatGPT", "chatgpt"]) {
13141
13190
  try {
@@ -13145,6 +13194,9 @@ function linuxIsRunning() {
13145
13194
  }
13146
13195
  return false;
13147
13196
  }
13197
+ function linuxMatchingPids() {
13198
+ return pgrepExact(["ChatGPT", "chatgpt"]);
13199
+ }
13148
13200
  function winMatchingPids() {
13149
13201
  try {
13150
13202
  const nameFilter = WIN_APP_NAMES.map((name) => `Name = '${name}.exe'`).join(" OR ");
@@ -13173,21 +13225,30 @@ function isCodexAppRunning() {
13173
13225
  if (process.platform === "linux") return linuxIsRunning();
13174
13226
  return false;
13175
13227
  }
13228
+ function codexAppMainPids(platform = process.platform) {
13229
+ if (platform === "darwin") return darwinMatchingPids();
13230
+ if (platform === "win32") return winMatchingPids();
13231
+ if (platform === "linux") return linuxMatchingPids();
13232
+ return [];
13233
+ }
13234
+ function pidIsAlive(pid) {
13235
+ try {
13236
+ process.kill(pid, 0);
13237
+ return true;
13238
+ } catch (err) {
13239
+ return err.code === "EPERM";
13240
+ }
13241
+ }
13176
13242
  function sleep(ms) {
13177
13243
  return new Promise((resolve) => setTimeout(resolve, ms));
13178
13244
  }
13179
- async function waitForQuit(timeoutMs) {
13245
+ async function waitForOriginalCodexPids(originalPids, timeoutMs, alive = pidIsAlive) {
13180
13246
  const deadline = Date.now() + timeoutMs;
13181
13247
  while (Date.now() < deadline) {
13182
- if (process.platform === "win32") {
13183
- if (winMatchingPids().length === 0) return true;
13184
- } else if (process.platform === "linux" ? !linuxIsRunning() : !darwinIsRunning()) {
13185
- return true;
13186
- }
13248
+ if (originalPids.every((pid) => !alive(pid))) return true;
13187
13249
  await sleep(200);
13188
13250
  }
13189
- if (process.platform === "win32") return winMatchingPids().length === 0;
13190
- return process.platform === "linux" ? !linuxIsRunning() : !darwinIsRunning();
13251
+ return originalPids.every((pid) => !alive(pid));
13191
13252
  }
13192
13253
  function openCodexAppAt(path) {
13193
13254
  if (process.platform === "darwin") {
@@ -13219,12 +13280,11 @@ function openCodexApp() {
13219
13280
  }
13220
13281
  openCodexAppAt(path);
13221
13282
  }
13283
+ function darwinQuitAppleScript() {
13284
+ return `tell application id "${CODEX_BUNDLE_ID}" to quit`;
13285
+ }
13222
13286
  function darwinQuit() {
13223
- try {
13224
- execSync2(`osascript -e 'tell application "Codex" to quit'`, { stdio: "pipe" });
13225
- } catch {
13226
- execSync2(`osascript -e 'tell application id "${CODEX_BUNDLE_ID}" to quit'`, { stdio: "pipe" });
13227
- }
13287
+ execFileSync3("osascript", ["-e", darwinQuitAppleScript()], { stdio: "pipe" });
13228
13288
  }
13229
13289
  function winQuitGraceful() {
13230
13290
  const nameFilter = WIN_APP_NAMES.map((name) => `'${name}'`).join(",");
@@ -13246,13 +13306,19 @@ function quitCodexAppGracefully() {
13246
13306
  else if (process.platform === "win32") winQuitGraceful();
13247
13307
  else if (process.platform === "linux") linuxQuitGraceful();
13248
13308
  }
13249
- function winForceQuit() {
13250
- const pids = winMatchingPids();
13309
+ function winForceQuit(pids = winMatchingPids()) {
13251
13310
  if (pids.length === 0) return;
13252
13311
  runPowerShell(`Stop-Process -Id ${pids.join(",")} -Force -ErrorAction SilentlyContinue`);
13253
13312
  }
13313
+ function restartTimeoutAction(platform) {
13314
+ return platform === "win32" ? "force-quit" : "fail-closed";
13315
+ }
13316
+ function gracefulQuitTimeoutMs(platform) {
13317
+ return platform === "darwin" ? 3e4 : 5e3;
13318
+ }
13254
13319
  async function launchOrRestartCodexApp(prompt = "Restart ChatGPT Desktop to apply relay-ai settings?", assumeYes = false) {
13255
13320
  const appPath = findCodexApp();
13321
+ const originalPids = codexAppMainPids();
13256
13322
  if (!isCodexAppRunning()) {
13257
13323
  if (!appPath) {
13258
13324
  throw new Error(
@@ -13262,6 +13328,9 @@ async function launchOrRestartCodexApp(prompt = "Restart ChatGPT Desktop to appl
13262
13328
  openCodexAppAt(appPath);
13263
13329
  return;
13264
13330
  }
13331
+ if (originalPids.length === 0) {
13332
+ throw new Error("ChatGPT Desktop is running but Relay could not identify its main process; refusing an unsafe restart.");
13333
+ }
13265
13334
  if (process.platform === "linux") {
13266
13335
  p6.log.info("Restarting ChatGPT Desktop to apply relay-ai settings...");
13267
13336
  linuxQuitGraceful();
@@ -13277,10 +13346,18 @@ async function launchOrRestartCodexApp(prompt = "Restart ChatGPT Desktop to appl
13277
13346
  if (process.platform === "darwin") darwinQuit();
13278
13347
  else if (process.platform === "win32") winQuitGraceful();
13279
13348
  }
13280
- if (!await waitForQuit(5e3)) {
13281
- if (process.platform === "win32") winForceQuit();
13282
- await waitForQuit(5e3);
13349
+ const gracefulTimeout = gracefulQuitTimeoutMs(process.platform);
13350
+ if (!await waitForOriginalCodexPids(originalPids, gracefulTimeout)) {
13351
+ if (restartTimeoutAction(process.platform) === "force-quit") {
13352
+ winForceQuit(originalPids);
13353
+ if (!await waitForOriginalCodexPids(originalPids, 5e3)) {
13354
+ throw new Error("ChatGPT Desktop did not exit after its force-quit timeout; refusing to launch a duplicate process.");
13355
+ }
13356
+ } else {
13357
+ throw new Error("ChatGPT Desktop did not exit after graceful shutdown; refusing to relaunch or force-quit it.");
13358
+ }
13283
13359
  }
13360
+ if (isCodexAppRunning()) return;
13284
13361
  if (appPath) openCodexAppAt(appPath);
13285
13362
  else openCodexApp();
13286
13363
  }
@@ -13356,7 +13433,7 @@ function linuxWhichClaude() {
13356
13433
  return null;
13357
13434
  }
13358
13435
  }
13359
- function linuxMatchingPids() {
13436
+ function linuxMatchingPids2() {
13360
13437
  try {
13361
13438
  const out = run2("pgrep -x claude-desktop");
13362
13439
  return out.split(/\s+/).map((s) => Number.parseInt(s, 10)).filter((n) => Number.isFinite(n) && n > 0);
@@ -13365,7 +13442,7 @@ function linuxMatchingPids() {
13365
13442
  }
13366
13443
  }
13367
13444
  function linuxMainPid() {
13368
- const pids = linuxMatchingPids();
13445
+ const pids = linuxMatchingPids2();
13369
13446
  for (const pid of pids) {
13370
13447
  try {
13371
13448
  const cmdline = readFileSync12(`/proc/${pid}/cmdline`, "utf8");
@@ -13384,7 +13461,7 @@ function linuxQuit() {
13384
13461
  }
13385
13462
  }
13386
13463
  function linuxForceQuit() {
13387
- for (const pid of linuxMatchingPids()) {
13464
+ for (const pid of linuxMatchingPids2()) {
13388
13465
  try {
13389
13466
  process.kill(pid, "SIGKILL");
13390
13467
  } catch {
@@ -13463,26 +13540,26 @@ function winHasWindow2() {
13463
13540
  function isClaudeAppRunning() {
13464
13541
  if (process.platform === "darwin") return darwinIsRunning2();
13465
13542
  if (process.platform === "win32") return winMatchingPids2().length > 0 || winHasWindow2();
13466
- if (process.platform === "linux") return linuxMatchingPids().length > 0;
13543
+ if (process.platform === "linux") return linuxMatchingPids2().length > 0;
13467
13544
  return false;
13468
13545
  }
13469
13546
  function sleep2(ms) {
13470
13547
  return new Promise((resolve) => setTimeout(resolve, ms));
13471
13548
  }
13472
- async function waitForQuit2(timeoutMs) {
13549
+ async function waitForQuit(timeoutMs) {
13473
13550
  const deadline = Date.now() + timeoutMs;
13474
13551
  while (Date.now() < deadline) {
13475
13552
  if (process.platform === "win32") {
13476
13553
  if (winMatchingPids2().length === 0) return true;
13477
13554
  } else if (process.platform === "linux") {
13478
- if (linuxMatchingPids().length === 0) return true;
13555
+ if (linuxMatchingPids2().length === 0) return true;
13479
13556
  } else if (!darwinIsRunning2()) {
13480
13557
  return true;
13481
13558
  }
13482
13559
  await sleep2(200);
13483
13560
  }
13484
13561
  if (process.platform === "win32") return winMatchingPids2().length === 0;
13485
- if (process.platform === "linux") return linuxMatchingPids().length === 0;
13562
+ if (process.platform === "linux") return linuxMatchingPids2().length === 0;
13486
13563
  return !darwinIsRunning2();
13487
13564
  }
13488
13565
  function openClaudeAppAt(path) {
@@ -13558,10 +13635,10 @@ async function launchOrRestartClaudeApp(prompt = "Restart Claude Desktop to appl
13558
13635
  if (process.platform === "darwin") darwinQuit2();
13559
13636
  else if (process.platform === "win32") winQuitGraceful2();
13560
13637
  }
13561
- if (!await waitForQuit2(5e3)) {
13638
+ if (!await waitForQuit(5e3)) {
13562
13639
  if (process.platform === "win32") winForceQuit2();
13563
13640
  else if (process.platform === "linux") linuxForceQuit();
13564
- await waitForQuit2(5e3);
13641
+ await waitForQuit(5e3);
13565
13642
  }
13566
13643
  if (appPath) openClaudeAppAt(appPath);
13567
13644
  else openClaudeApp();
@@ -13631,6 +13708,7 @@ export {
13631
13708
  getAppHome,
13632
13709
  getConfigPath,
13633
13710
  getProvidersPath,
13711
+ getLogsPath,
13634
13712
  loadPreferences,
13635
13713
  savePreferences,
13636
13714
  getAppPathOverride,
@@ -13818,4 +13896,4 @@ export {
13818
13896
  supportsClaudeTransparentMode,
13819
13897
  buildHttpProxyRoutes
13820
13898
  };
13821
- //# sourceMappingURL=chunk-SCW2TYSG.js.map
13899
+ //# sourceMappingURL=chunk-PYJQMEJD.js.map