flockbay 0.10.17 → 0.10.20

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.
@@ -614,6 +614,14 @@ async function main() {
614
614
  "Unreal Editor: Launch Project",
615
615
  "Launch Unreal Editor for a given .uproject (no auto-restart). If the editor later crashes or becomes unreachable, Flockbay will abort the current agent run and report it in the chat."
616
616
  );
617
+ forwardTool(
618
+ "unreal_editor_relaunch_last",
619
+ {
620
+ extraArgs: z.z.array(z.z.string()).optional().describe("Optional replacement UnrealEditor command-line args (advanced).")
621
+ },
622
+ "Unreal Editor: Relaunch Last Project",
623
+ "Relaunch the last Unreal project previously launched via unreal_editor_launch in this session (no auto-restart). Use this after a crash once you\u2019ve fixed files."
624
+ );
617
625
  forwardTool(
618
626
  "unreal_headless_screenshot",
619
627
  {
@@ -612,6 +612,14 @@ async function main() {
612
612
  "Unreal Editor: Launch Project",
613
613
  "Launch Unreal Editor for a given .uproject (no auto-restart). If the editor later crashes or becomes unreachable, Flockbay will abort the current agent run and report it in the chat."
614
614
  );
615
+ forwardTool(
616
+ "unreal_editor_relaunch_last",
617
+ {
618
+ extraArgs: z.array(z.string()).optional().describe("Optional replacement UnrealEditor command-line args (advanced).")
619
+ },
620
+ "Unreal Editor: Relaunch Last Project",
621
+ "Relaunch the last Unreal project previously launched via unreal_editor_launch in this session (no auto-restart). Use this after a crash once you\u2019ve fixed files."
622
+ );
615
623
  forwardTool(
616
624
  "unreal_headless_screenshot",
617
625
  {
@@ -1,14 +1,14 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir } from 'node:os';
3
3
  import { randomUUID, createCipheriv, randomBytes } from 'node:crypto';
4
- import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as getLatestDaemonLog } from './types-DuhcLxar.mjs';
4
+ import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as getLatestDaemonLog, x as normalizeServerUrlForNode } from './types-C4QeUggl.mjs';
5
5
  import { spawn, execFileSync, execSync } from 'node:child_process';
6
6
  import path, { resolve, join, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
8
8
  import * as fs from 'node:fs';
9
9
  import fs__default, { existsSync, readFileSync, mkdirSync, readdirSync, accessSync, constants, statSync, createReadStream, writeFileSync, unlinkSync } from 'node:fs';
10
10
  import process$1 from 'node:process';
11
- import fs$1, { readFile, access as access$1, mkdir, stat, readdir } from 'node:fs/promises';
11
+ import fs$1, { readFile, access as access$1, mkdir, readdir, stat } from 'node:fs/promises';
12
12
  import fs$2, { watch, access } from 'fs/promises';
13
13
  import { useStdout, useInput, Box, Text, render } from 'ink';
14
14
  import React, { useState, useRef, useEffect, useCallback } from 'react';
@@ -4581,7 +4581,13 @@ async function checkIfDaemonRunningAndCleanupStaleState() {
4581
4581
  return false;
4582
4582
  }
4583
4583
  }
4584
- return false;
4584
+ const lockPid = readDaemonLockPid();
4585
+ if (!lockPid) return false;
4586
+ if (!isProcessAlive(lockPid)) {
4587
+ await cleanupDaemonState();
4588
+ return false;
4589
+ }
4590
+ return true;
4585
4591
  }
4586
4592
  async function isDaemonRunningCurrentCliVersion() {
4587
4593
  logger.debug("[DAEMON CONTROL] Checking if daemon is running same version");
@@ -4637,7 +4643,43 @@ async function stopDaemon() {
4637
4643
  await cleanupDaemonState();
4638
4644
  return;
4639
4645
  }
4640
- logger.debug("No daemon state found");
4646
+ const lockPid = readDaemonLockPid();
4647
+ if (!lockPid) {
4648
+ logger.debug("No daemon state found");
4649
+ return;
4650
+ }
4651
+ if (!isProcessAlive(lockPid)) {
4652
+ logger.debug("[DAEMON RUN] Daemon lock PID not running, cleaning up state");
4653
+ await cleanupDaemonState();
4654
+ return;
4655
+ }
4656
+ const cmd = readProcessCommand(lockPid);
4657
+ const looksLikeDaemon = looksLikeFlockbayDaemonCommand(cmd, configuration.profile);
4658
+ if (!looksLikeDaemon) {
4659
+ logger.debug("[DAEMON RUN] Daemon lock is held by an unexpected process; refusing to kill", {
4660
+ lockPid,
4661
+ cmd: cmd || null
4662
+ });
4663
+ return;
4664
+ }
4665
+ logger.debug(`[DAEMON RUN] Stopping daemon by lock PID ${lockPid} (state file missing)`);
4666
+ try {
4667
+ process.kill(lockPid, "SIGTERM");
4668
+ } catch (error) {
4669
+ logger.debug("[DAEMON RUN] Failed to SIGTERM lock PID", { lockPid, error });
4670
+ }
4671
+ try {
4672
+ await waitForProcessDeath(lockPid, 2e3);
4673
+ } catch {
4674
+ }
4675
+ if (isProcessAlive(lockPid)) {
4676
+ try {
4677
+ process.kill(lockPid, "SIGKILL");
4678
+ } catch (error) {
4679
+ logger.debug("[DAEMON RUN] Failed to SIGKILL lock PID", { lockPid, error });
4680
+ }
4681
+ }
4682
+ await cleanupDaemonState();
4641
4683
  } catch (error) {
4642
4684
  logger.debug("Error stopping daemon", error);
4643
4685
  }
@@ -4654,6 +4696,39 @@ async function waitForProcessDeath(pid, timeout) {
4654
4696
  }
4655
4697
  throw new Error("Process did not die within timeout");
4656
4698
  }
4699
+ function isProcessAlive(pid) {
4700
+ try {
4701
+ process.kill(pid, 0);
4702
+ return true;
4703
+ } catch {
4704
+ return false;
4705
+ }
4706
+ }
4707
+ function readDaemonLockPid() {
4708
+ try {
4709
+ const raw = readFileSync$1(configuration.daemonLockFile, "utf-8").trim();
4710
+ const pid = Number(raw);
4711
+ return Number.isFinite(pid) && pid > 0 ? pid : null;
4712
+ } catch {
4713
+ return null;
4714
+ }
4715
+ }
4716
+ function readProcessCommand(pid) {
4717
+ try {
4718
+ return String(execFileSync("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8" }) || "").trim();
4719
+ } catch {
4720
+ return null;
4721
+ }
4722
+ }
4723
+ function looksLikeFlockbayDaemonCommand(command, profile) {
4724
+ const cmd = String(command || "").trim();
4725
+ if (!cmd) return false;
4726
+ if (!cmd.includes("flockbay")) return false;
4727
+ if (!cmd.includes("daemon")) return false;
4728
+ if (!cmd.includes("start-sync")) return false;
4729
+ if (!cmd.includes("--profile")) return false;
4730
+ return cmd.includes(profile);
4731
+ }
4657
4732
 
4658
4733
  async function findAllFlockbayProcesses() {
4659
4734
  try {
@@ -4938,8 +5013,8 @@ async function loginWithClerkAndPairMachine() {
4938
5013
  logger.debug("[AUTH] Starting Clerk-based CLI login + machine pairing");
4939
5014
  const settings = await updateSettings(async (s) => {
4940
5015
  const machineId2 = s.machineId || randomUUID();
4941
- const serverUrl2 = s.serverUrl || configuration.serverUrl;
4942
- const webappUrl = s.webappUrl || configuration.webappUrl;
5016
+ const serverUrl2 = configuration.serverUrl;
5017
+ const webappUrl = configuration.webappUrl;
4943
5018
  return { ...s, machineId: machineId2, serverUrl: serverUrl2, webappUrl };
4944
5019
  });
4945
5020
  const serverUrl = configuration.serverUrl.replace(/\/+$/, "");
@@ -7133,7 +7208,8 @@ async function startFlockbayServer(client, options) {
7133
7208
  lastReachableAtMs: 0,
7134
7209
  lastIssueAtMs: 0,
7135
7210
  lastIssueKey: "",
7136
- launched: null
7211
+ launched: null,
7212
+ lastLaunch: null
7137
7213
  };
7138
7214
  const emitIssue = (event) => {
7139
7215
  const key = `${event.kind}:${event.severity}:${event.message}`;
@@ -7158,6 +7234,93 @@ async function startFlockbayServer(client, options) {
7158
7234
  }
7159
7235
  }
7160
7236
  };
7237
+ const tailText = (text, maxChars) => {
7238
+ const t = String(text || "").trim();
7239
+ if (!t) return "";
7240
+ if (t.length <= maxChars) return t;
7241
+ return t.slice(t.length - maxChars);
7242
+ };
7243
+ const findLatestFile = async (dir, filter) => {
7244
+ try {
7245
+ const entries = await readdir(dir);
7246
+ let best = null;
7247
+ for (const name of entries) {
7248
+ if (!filter(name)) continue;
7249
+ const full = path.join(dir, name);
7250
+ let st;
7251
+ try {
7252
+ st = await stat(full);
7253
+ } catch {
7254
+ continue;
7255
+ }
7256
+ if (!st?.isFile?.()) continue;
7257
+ const mtimeMs = Number(st.mtimeMs || 0);
7258
+ if (!best || mtimeMs > best.mtimeMs) best = { path: full, mtimeMs };
7259
+ }
7260
+ return best?.path ?? null;
7261
+ } catch {
7262
+ return null;
7263
+ }
7264
+ };
7265
+ const findLatestCrashDir = async (projectRoot) => {
7266
+ const crashesDir = path.join(projectRoot, "Saved", "Crashes");
7267
+ try {
7268
+ const entries = await readdir(crashesDir);
7269
+ let best = null;
7270
+ for (const name of entries) {
7271
+ const full = path.join(crashesDir, name);
7272
+ let st;
7273
+ try {
7274
+ st = await stat(full);
7275
+ } catch {
7276
+ continue;
7277
+ }
7278
+ if (!st?.isDirectory?.()) continue;
7279
+ const mtimeMs = Number(st.mtimeMs || 0);
7280
+ if (!best || mtimeMs > best.mtimeMs) best = { path: full, mtimeMs };
7281
+ }
7282
+ return best?.path ?? null;
7283
+ } catch {
7284
+ return null;
7285
+ }
7286
+ };
7287
+ const readFileTail = async (filePath, maxBytes) => {
7288
+ try {
7289
+ const buf = await readFile(filePath);
7290
+ const slice = buf.length > maxBytes ? buf.subarray(buf.length - maxBytes) : buf;
7291
+ return slice.toString("utf8");
7292
+ } catch {
7293
+ return null;
7294
+ }
7295
+ };
7296
+ const gatherCrashDiagnosticsBestEffort = async (uprojectPath) => {
7297
+ const projectRoot = path.dirname(uprojectPath);
7298
+ const summary = [];
7299
+ const detail = { uprojectPath, projectRoot };
7300
+ const latestLog = await findLatestFile(path.join(projectRoot, "Saved", "Logs"), (n) => n.toLowerCase().endsWith(".log"));
7301
+ if (latestLog) {
7302
+ detail.projectLogPath = latestLog;
7303
+ const tail = await readFileTail(latestLog, 24e3);
7304
+ if (tail) {
7305
+ detail.projectLogTail = tailText(tail, 12e3);
7306
+ summary.push(`Latest log: ${latestLog}`);
7307
+ }
7308
+ }
7309
+ const latestCrashDir = await findLatestCrashDir(projectRoot);
7310
+ if (latestCrashDir) {
7311
+ detail.latestCrashDir = latestCrashDir;
7312
+ const crashContext = await findLatestFile(latestCrashDir, (n) => n.toLowerCase().includes("crashcontext") && n.toLowerCase().endsWith(".xml"));
7313
+ if (crashContext) {
7314
+ detail.crashContextPath = crashContext;
7315
+ const tail = await readFileTail(crashContext, 24e3);
7316
+ if (tail) {
7317
+ detail.crashContextTail = tailText(tail, 12e3);
7318
+ summary.push(`CrashContext: ${crashContext}`);
7319
+ }
7320
+ }
7321
+ }
7322
+ return { detail, summary };
7323
+ };
7161
7324
  const getUnrealEditorExe = (engineRoot) => {
7162
7325
  const root = engineRoot.trim().replace(/[\\/]+$/, "");
7163
7326
  if (process.platform === "darwin") {
@@ -7213,7 +7376,7 @@ ${res.stderr}`;
7213
7376
  kind: "unreachable",
7214
7377
  severity: "warning",
7215
7378
  detectedAtMs: now,
7216
- message: "Unreal Editor is no longer reachable (it was reachable earlier). It may have crashed or been closed.",
7379
+ message: "Unreal Editor is no longer reachable (it was reachable earlier). It may have crashed or been closed.\nNext: fix the issue, then relaunch via unreal_editor_relaunch_last (if you launched from this session) or unreal_editor_launch.",
7217
7380
  detail: {
7218
7381
  lastReachableAtMs: state.lastReachableAtMs
7219
7382
  }
@@ -7245,20 +7408,35 @@ ${res.stderr}`;
7245
7408
  engineRoot,
7246
7409
  startedAtMs: Date.now()
7247
7410
  };
7411
+ state.lastLaunch = {
7412
+ uprojectPath,
7413
+ engineRoot,
7414
+ extraArgs,
7415
+ startedAtMs: Date.now()
7416
+ };
7248
7417
  child.on("exit", (code, signal) => {
7249
- const now = Date.now();
7250
- const exitCode = typeof code === "number" ? code : null;
7251
- const sig = typeof signal === "string" ? signal : null;
7252
- const isCrash = sig !== null || exitCode !== null && exitCode !== 0;
7253
- state.launched = null;
7254
- if (!isCrash) return;
7255
- emitIssue({
7256
- kind: "process_exit",
7257
- severity: "crash",
7258
- detectedAtMs: now,
7259
- message: `Unreal Editor process exited unexpectedly (code=${exitCode ?? "null"} signal=${sig ?? "null"}).`,
7260
- detail: { exitCode, signal: sig, pid, uprojectPath }
7261
- });
7418
+ void (async () => {
7419
+ const now = Date.now();
7420
+ const exitCode = typeof code === "number" ? code : null;
7421
+ const sig = typeof signal === "string" ? signal : null;
7422
+ const isCrash = sig !== null || exitCode !== null && exitCode !== 0;
7423
+ state.launched = null;
7424
+ if (!isCrash) return;
7425
+ const diag = await gatherCrashDiagnosticsBestEffort(uprojectPath).catch(() => ({ detail: {}, summary: [] }));
7426
+ const msgParts = [
7427
+ `Unreal Editor process exited unexpectedly (code=${exitCode ?? "null"} signal=${sig ?? "null"}).`,
7428
+ `Project: ${uprojectPath}`,
7429
+ ...diag.summary,
7430
+ `Next: fix the issue, then relaunch via unreal_editor_relaunch_last (or unreal_editor_launch).`
7431
+ ];
7432
+ emitIssue({
7433
+ kind: "process_exit",
7434
+ severity: "crash",
7435
+ detectedAtMs: now,
7436
+ message: msgParts.filter(Boolean).join("\n"),
7437
+ detail: { exitCode, signal: sig, pid, uprojectPath, ...diag.detail }
7438
+ });
7439
+ })();
7262
7440
  });
7263
7441
  child.on("error", (err) => {
7264
7442
  const now = Date.now();
@@ -7267,7 +7445,9 @@ ${res.stderr}`;
7267
7445
  kind: "process_exit",
7268
7446
  severity: "crash",
7269
7447
  detectedAtMs: now,
7270
- message: `Failed to launch Unreal Editor: ${err instanceof Error ? err.message : String(err)}`,
7448
+ message: `Failed to launch Unreal Editor: ${err instanceof Error ? err.message : String(err)}
7449
+ Project: ${uprojectPath}
7450
+ Next: fix the issue, then relaunch via unreal_editor_relaunch_last (or unreal_editor_launch).`,
7271
7451
  detail: { pid, uprojectPath }
7272
7452
  });
7273
7453
  });
@@ -7277,6 +7457,12 @@ ${res.stderr}`;
7277
7457
  noteUnrealActivity,
7278
7458
  noteUnrealReachable,
7279
7459
  launchEditor,
7460
+ relaunchLast: async (extraArgs) => {
7461
+ const last = state.lastLaunch;
7462
+ if (!last) throw new Error("No known prior Unreal launch in this session. Use unreal_editor_launch with an explicit uprojectPath.");
7463
+ const mergedArgs = Array.isArray(extraArgs) && extraArgs.length > 0 ? extraArgs.filter((a) => typeof a === "string" && a.trim()) : last.extraArgs;
7464
+ return launchEditor({ uprojectPath: last.uprojectPath, engineRoot: last.engineRoot, extraArgs: mergedArgs });
7465
+ },
7280
7466
  stop: () => {
7281
7467
  try {
7282
7468
  interval.unref();
@@ -8783,6 +8969,32 @@ ${String(st.stdout || "").trim()}`
8783
8969
  isError: false
8784
8970
  };
8785
8971
  }));
8972
+ mcp.registerTool("unreal_editor_relaunch_last", {
8973
+ title: "Unreal Editor: Relaunch Last Project",
8974
+ description: "Relaunch the last Unreal project previously launched via unreal_editor_launch in this session (no auto-restart). Use this after a crash once you\u2019ve fixed files. If it crashes again, Flockbay will abort and report again.",
8975
+ inputSchema: {
8976
+ extraArgs: z.array(z.string()).optional().describe("Optional replacement UnrealEditor command-line args (advanced).")
8977
+ }
8978
+ }, async (args) => runWithMcpToolCard("unreal_editor_relaunch_last", args, async () => {
8979
+ const extraArgs = Array.isArray(args?.extraArgs) ? args.extraArgs : void 0;
8980
+ unrealEditorSupervisor.noteUnrealActivity();
8981
+ try {
8982
+ const launched = await unrealEditorSupervisor.relaunchLast(extraArgs);
8983
+ return {
8984
+ content: [
8985
+ { type: "text", text: `Relaunched Unreal Editor (last project).` },
8986
+ { type: "text", text: JSON.stringify({ pid: launched.pid, exePath: launched.exePath }, null, 2) },
8987
+ { type: "text", text: "Next: wait for the editor to finish loading, then re-run UnrealMCP tools." }
8988
+ ],
8989
+ isError: false
8990
+ };
8991
+ } catch (err) {
8992
+ return {
8993
+ content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
8994
+ isError: true
8995
+ };
8996
+ }
8997
+ }));
8786
8998
  mcp.registerTool("unreal_build_project", {
8787
8999
  title: "Unreal Build Project (UBT)",
8788
9000
  description: "Build the project via Unreal Build Tool (via Engine/Build/BatchFiles/Build.*). Returns structured errors (file/line) and a log path for deep debugging.",
@@ -10208,6 +10420,7 @@ Fix: ${res.hint}` : "";
10208
10420
  "unreal_headless_screenshot",
10209
10421
  "unreal_latest_screenshots",
10210
10422
  "unreal_editor_launch",
10423
+ "unreal_editor_relaunch_last",
10211
10424
  "unreal_build_project",
10212
10425
  "unreal_mcp_command",
10213
10426
  "unreal_mcp_list_capabilities",
@@ -11575,6 +11788,51 @@ async function reauthForCurrentServerKeepingMachineId() {
11575
11788
  await clearCredentials();
11576
11789
  await loginWithClerkAndPairMachine();
11577
11790
  }
11791
+ function isLocalDevServerUrl(url) {
11792
+ try {
11793
+ const u = new URL(String(url || "").trim());
11794
+ const host = u.hostname.toLowerCase();
11795
+ return host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" || host.endsWith(".localhost");
11796
+ } catch {
11797
+ return false;
11798
+ }
11799
+ }
11800
+ async function isServerReachable(url) {
11801
+ const base = String(url || "").trim().replace(/\/+$/, "");
11802
+ if (!base) return false;
11803
+ try {
11804
+ const res = await fetch(`${base}/healthz`, { method: "GET", signal: AbortSignal.timeout(1200) });
11805
+ return res.ok;
11806
+ } catch {
11807
+ return false;
11808
+ }
11809
+ }
11810
+ async function ensureProdServerWhenLocalDevUnreachable() {
11811
+ if ((process.env.FLOCKBAY_SERVER_URL || "").trim()) return;
11812
+ const settings = await readSettings().catch(() => null);
11813
+ const configured = String(settings?.serverUrl || "").trim();
11814
+ if (!configured) return;
11815
+ const normalized = normalizeServerUrlForNode(configured);
11816
+ if (!isLocalDevServerUrl(normalized)) return;
11817
+ const reachable = await isServerReachable(normalized);
11818
+ if (reachable) return;
11819
+ const shouldSwitch = await promptYesNo(
11820
+ `This profile is configured to use a local server (${normalized}), but it isn't reachable.
11821
+
11822
+ Switch this profile to production (https://api.flockbay.com) and re-authenticate?`,
11823
+ { defaultYes: true }
11824
+ );
11825
+ if (!shouldSwitch) return;
11826
+ const nextWebappUrl = String(settings?.webappUrl || "").trim() || "https://flockbay.com";
11827
+ await updateSettings((s) => ({
11828
+ ...s,
11829
+ serverUrl: "https://api.flockbay.com",
11830
+ webappUrl: nextWebappUrl
11831
+ }));
11832
+ configuration.serverUrl = "https://api.flockbay.com";
11833
+ configuration.webappUrl = nextWebappUrl;
11834
+ await reauthForCurrentServerKeepingMachineId();
11835
+ }
11578
11836
  function openUrlBestEffort(url) {
11579
11837
  const u = String(url || "").trim();
11580
11838
  if (!u) return;
@@ -11693,11 +11951,19 @@ async function startDaemonDetachedOrExit(opts) {
11693
11951
  }
11694
11952
  console.error("");
11695
11953
  console.error(chalk.red("Daemon is running but not connected to the server."));
11954
+ console.error(chalk.gray(`Profile: ${configuration.profile}`));
11955
+ console.error(chalk.gray(`Server: ${configuration.serverUrl}`));
11696
11956
  if (typeof status?.connection?.lastHttpUpsertError === "string" && status.connection.lastHttpUpsertError.trim()) {
11697
11957
  console.error(chalk.gray(`Last upsert error: ${status.connection.lastHttpUpsertError.trim()}`));
11698
11958
  }
11699
11959
  if (lastConnectError) console.error(chalk.gray(`Last connect error: ${lastConnectError}`));
11700
- console.error(chalk.gray("Tip: if the backend is restarting, wait a moment and re-run `flockbay start`."));
11960
+ if (isLocalDevServerUrl(configuration.serverUrl)) {
11961
+ console.error(chalk.gray("Tip: if you meant to run against production, set the server URL or use a prod profile:"));
11962
+ console.error(chalk.gray(" FLOCKBAY_SERVER_URL=https://api.flockbay.com flockbay start"));
11963
+ console.error(chalk.gray(" flockbay start --profile prod"));
11964
+ } else {
11965
+ console.error(chalk.gray("Tip: if the backend is restarting, wait a moment and re-run `flockbay start`."));
11966
+ }
11701
11967
  process.exit(1);
11702
11968
  }
11703
11969
  }
@@ -11901,6 +12167,7 @@ async function authAndSetupMachineIfNeeded() {
11901
12167
  return;
11902
12168
  }
11903
12169
  try {
12170
+ await ensureProdServerWhenLocalDevUnreachable();
11904
12171
  await ensureMachineAuthOrLogin();
11905
12172
  const skipUnreal = startArgs.includes("--skip-unreal");
11906
12173
  if (!skipUnreal) {
@@ -11935,7 +12202,7 @@ ${engineRoot}`, {
11935
12202
  } else if (subcommand === "codex") {
11936
12203
  try {
11937
12204
  await chdirToNearestUprojectRootIfPresent();
11938
- const { runCodex } = await import('./runCodex-DudVDqNh.mjs');
12205
+ const { runCodex } = await import('./runCodex-Biis9GFw.mjs');
11939
12206
  let startedBy = void 0;
11940
12207
  let sessionId = void 0;
11941
12208
  for (let i = 1; i < args.length; i++) {
@@ -12030,7 +12297,7 @@ ${engineRoot}`, {
12030
12297
  }
12031
12298
  try {
12032
12299
  await chdirToNearestUprojectRootIfPresent();
12033
- const { runGemini } = await import('./runGemini-Ddu8UCOS.mjs');
12300
+ const { runGemini } = await import('./runGemini-BSH4b0wu.mjs');
12034
12301
  let startedBy = void 0;
12035
12302
  let sessionId = void 0;
12036
12303
  for (let i = 1; i < args.length; i++) {