flockbay 0.10.31 → 0.10.32

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.
@@ -1,9 +1,11 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
- import os, { homedir } from 'node:os';
2
+ import * as os from 'node:os';
3
+ import os__default, { homedir } from 'node:os';
3
4
  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 buildAndInstallUnrealMcpPlugin, x as getLatestDaemonLog, y as normalizeServerUrlForNode } from './types-BOWEIn3h.mjs';
5
+ 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 buildAndInstallUnrealMcpPlugin, x as getLatestDaemonLog, y as normalizeServerUrlForNode } from './types-6KOeU7L8.mjs';
5
6
  import { spawn, execFileSync, execSync } from 'node:child_process';
6
- import path, { resolve, join, dirname } from 'node:path';
7
+ import * as path from 'node:path';
8
+ import path__default, { resolve, join, dirname } from 'node:path';
7
9
  import { createInterface } from 'node:readline';
8
10
  import * as fs from 'node:fs';
9
11
  import fs__default, { existsSync, readFileSync, mkdirSync, readdirSync, accessSync, constants, statSync, createReadStream, writeFileSync, unlinkSync } from 'node:fs';
@@ -2009,9 +2011,9 @@ function resolveCandidatePath(candidate, cwd) {
2009
2011
  if (!raw) return raw;
2010
2012
  if (raw.startsWith("~/")) {
2011
2013
  const home = process.env.HOME || process.env.USERPROFILE || "";
2012
- if (home) return path.join(home, raw.slice(2));
2014
+ if (home) return path__default.join(home, raw.slice(2));
2013
2015
  }
2014
- return path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
2016
+ return path__default.isAbsolute(raw) ? raw : path__default.resolve(cwd, raw);
2015
2017
  }
2016
2018
  function isImageBlock(block) {
2017
2019
  if (!block || typeof block !== "object") return false;
@@ -2047,7 +2049,7 @@ function extractScreenshotViewsFromText(text, cwd) {
2047
2049
  const token = String(match[1] || "");
2048
2050
  const resolved = resolveCandidatePath(token, cwd);
2049
2051
  if (!resolved) continue;
2050
- if (!resolved.includes(`${path.sep}Saved${path.sep}Screenshots${path.sep}Flockbay${path.sep}`) && !resolved.includes("Saved/Screenshots/Flockbay/") && !resolved.includes("Saved\\Screenshots\\Flockbay\\")) {
2052
+ if (!resolved.includes(`${path__default.sep}Saved${path__default.sep}Screenshots${path__default.sep}Flockbay${path__default.sep}`) && !resolved.includes("Saved/Screenshots/Flockbay/") && !resolved.includes("Saved\\Screenshots\\Flockbay\\")) {
2051
2053
  continue;
2052
2054
  }
2053
2055
  uniqPush(out, seen, resolved);
@@ -2057,7 +2059,7 @@ function extractScreenshotViewsFromText(text, cwd) {
2057
2059
  for (const match of text.matchAll(filenameRe)) {
2058
2060
  const filename = normalizeFilePathToken(String(match[1] || ""));
2059
2061
  if (!filename) continue;
2060
- const rel = path.join("Saved", "Screenshots", "Flockbay", filename);
2062
+ const rel = path__default.join("Saved", "Screenshots", "Flockbay", filename);
2061
2063
  const resolved = resolveCandidatePath(rel, cwd);
2062
2064
  uniqPush(out, seen, resolved);
2063
2065
  }
@@ -2326,7 +2328,7 @@ async function claudeRemote(opts) {
2326
2328
  )) {
2327
2329
  didEmitAuthDiagnostic = true;
2328
2330
  const homeEnv = process.env.HOME ? String(process.env.HOME) : "";
2329
- const homedir = os.homedir();
2331
+ const homedir = os__default.homedir();
2330
2332
  const forcedClaudePath = (process.env.FLOCKBAY_CLAUDE_PATH || process.env.FLOCKBAY_CLAUDE_CLI_PATH || "").trim();
2331
2333
  const pathHead = String(process.env.PATH || "").split(process.platform === "win32" ? ";" : ":").filter(Boolean).slice(0, 8).join(process.platform === "win32" ? ";" : ":");
2332
2334
  const diag = [
@@ -2341,7 +2343,7 @@ async function claudeRemote(opts) {
2341
2343
  "If you have multiple Claude installs, Flockbay remote prefers npm-global, then Homebrew, then native installer.",
2342
2344
  "You can force a specific install by setting `FLOCKBAY_CLAUDE_PATH` to the desired `cli.js` or binary path.",
2343
2345
  "",
2344
- `Diagnostics: user=${os.userInfo().username} platform=${process.platform} pid=${process.pid}`,
2346
+ `Diagnostics: user=${os__default.userInfo().username} platform=${process.platform} pid=${process.pid}`,
2345
2347
  `Diagnostics: HOME(env)=${homeEnv || "(unset)"} os.homedir()=${homedir || "(unknown)"}`,
2346
2348
  `Diagnostics: FLOCKBAY_CLAUDE_PATH=${forcedClaudePath || "(unset)"}`,
2347
2349
  `Diagnostics: PATH(head)=${pathHead || "(unset)"}`,
@@ -2592,11 +2594,11 @@ class PermissionHandler {
2592
2594
  const raw = typeof filePath === "string" ? filePath.trim() : String(filePath ?? "").trim();
2593
2595
  if (!raw) return null;
2594
2596
  let candidate = raw.replace(/\\/g, "/");
2595
- if (path.isAbsolute(candidate)) {
2597
+ if (path__default.isAbsolute(candidate)) {
2596
2598
  const base = String(this.session.path || "").trim();
2597
2599
  if (base) {
2598
- const rel = path.relative(base, candidate);
2599
- if (rel && !rel.startsWith("..") && !path.isAbsolute(rel)) {
2600
+ const rel = path__default.relative(base, candidate);
2601
+ if (rel && !rel.startsWith("..") && !path__default.isAbsolute(rel)) {
2600
2602
  candidate = rel.replace(/\\/g, "/");
2601
2603
  }
2602
2604
  }
@@ -3583,6 +3585,14 @@ function truncateCommitSubject(value, maxLen) {
3583
3585
  if (trimmed.length <= maxLen) return trimmed;
3584
3586
  return `${trimmed.slice(0, Math.max(0, maxLen - 1)).trimEnd()}\u2026`;
3585
3587
  }
3588
+ function normalizeFsPath(p) {
3589
+ const resolved = path.resolve(String(p || ""));
3590
+ const root = path.parse(resolved).root;
3591
+ let normalized = resolved;
3592
+ if (normalized !== root) normalized = normalized.replace(/[\\/]+$/, "");
3593
+ if (process.platform === "win32") normalized = normalized.toLowerCase();
3594
+ return normalized;
3595
+ }
3586
3596
  async function runGit(args, cwd, timeoutMs) {
3587
3597
  const child = spawn("git", args, {
3588
3598
  cwd,
@@ -3627,11 +3637,11 @@ async function runGit(args, cwd, timeoutMs) {
3627
3637
  const exitCode = result.timedOut ? -1 : result.exitCode;
3628
3638
  return { ok: !result.timedOut && exitCode === 0, stdout: out, stderr: err, exitCode };
3629
3639
  }
3630
- async function postJson(path, token, body) {
3640
+ async function postJson(path2, token, body) {
3631
3641
  const base = configuration.serverUrl.replace(/\/+$/, "");
3632
3642
  const timeoutMsRaw = String(process.env.FLOCKBAY_COORDINATION_HTTP_TIMEOUT_MS || "").trim();
3633
3643
  const timeoutMs = Number.isFinite(Number(timeoutMsRaw)) && Number(timeoutMsRaw) > 0 ? Number(timeoutMsRaw) : 7e3;
3634
- const url = `${base}${path}`;
3644
+ const url = `${base}${path2}`;
3635
3645
  const res = await fetch(url, {
3636
3646
  method: "POST",
3637
3647
  headers: {
@@ -3661,6 +3671,26 @@ async function autoFinalizeCoordinationWorkItem(params) {
3661
3671
  if (!inRepo.ok || String(inRepo.stdout || "").trim().toLowerCase() !== "true") {
3662
3672
  return { ok: false, error: "not_a_git_repo" };
3663
3673
  }
3674
+ const topLevel = await runGit(["rev-parse", "--show-toplevel"], cwd, 1e4);
3675
+ if (!topLevel.ok) {
3676
+ return { ok: false, error: topLevel.stderr || topLevel.stdout || "git_show_toplevel_failed" };
3677
+ }
3678
+ const repoRootRaw = String(topLevel.stdout || "").trim().split("\n")[0] || "";
3679
+ const repoRoot = normalizeFsPath(repoRootRaw);
3680
+ const homeDir = normalizeFsPath(os.homedir());
3681
+ const fsRoot = normalizeFsPath(path.parse(repoRootRaw || repoRoot).root);
3682
+ if (repoRoot && repoRoot === homeDir) {
3683
+ return {
3684
+ ok: false,
3685
+ error: `unsafe_git_repo_root: repo root is your home directory (${repoRootRaw || repoRoot}). This usually means there's an accidental .git directory in your home folder. Fix by removing/renaming that .git and initializing git inside your project folder.`
3686
+ };
3687
+ }
3688
+ if (repoRoot && repoRoot === fsRoot) {
3689
+ return {
3690
+ ok: false,
3691
+ error: `unsafe_git_repo_root: repo root is the filesystem root (${repoRootRaw || repoRoot}). Auto-finalize refuses to run to avoid scanning massive folders.`
3692
+ };
3693
+ }
3664
3694
  const porcelain = await runGit(["status", "--porcelain=v1", "-z"], cwd, 2e4);
3665
3695
  if (!porcelain.ok) {
3666
3696
  return { ok: false, error: porcelain.stderr || porcelain.stdout || "git_status_failed" };
@@ -3722,6 +3752,28 @@ async function autoFinalizeCoordinationWorkItem(params) {
3722
3752
 
3723
3753
  async function claudeRemoteLauncher(session) {
3724
3754
  logger.debug("[claudeRemoteLauncher] Starting remote launcher");
3755
+ const coordinationEnabled = Boolean(String(process.env.FLOCKBAY_COORDINATION_WORKSPACE_PROJECT_ID || "").trim() && String(process.env.FLOCKBAY_COORDINATION_WORK_ITEM_ID || "").trim());
3756
+ let lastAutoFinalizeStatus = null;
3757
+ const publishAutoFinalizeStatus = (next) => {
3758
+ if (!coordinationEnabled) return false;
3759
+ if (lastAutoFinalizeStatus && lastAutoFinalizeStatus.status === next.status && lastAutoFinalizeStatus.error === next.error) {
3760
+ return false;
3761
+ }
3762
+ lastAutoFinalizeStatus = next;
3763
+ try {
3764
+ session.client.updateMetadata((metadata) => ({
3765
+ ...metadata || {},
3766
+ coordinationAutoFinalize: {
3767
+ status: next.status,
3768
+ error: next.error,
3769
+ updatedAt: Date.now()
3770
+ }
3771
+ }));
3772
+ } catch (e) {
3773
+ logger.debug("[remote]: Failed to publish coordination auto-finalize status", e);
3774
+ }
3775
+ return true;
3776
+ };
3725
3777
  const isLikelyAuthOrUsageError = (error) => {
3726
3778
  const message = error instanceof Error ? error.message : String(error);
3727
3779
  return /usage limit|quota|rate limit|resource exhausted|resource_exhausted|oauth token has expired|please run \/login|unauthenticated|unauthorized|forbidden|invalid (session )?token|needs authentication|setup-token|status 401|status 403|status 429|\b401\b|\b403\b|\b429\b/i.test(message);
@@ -4015,14 +4067,19 @@ async function claudeRemoteLauncher(session) {
4015
4067
  summary: lastDeliveredMessage?.message ?? null
4016
4068
  });
4017
4069
  if (!finalizeRes.ok) {
4018
- const msg = `Auto-finalize failed: ${finalizeRes.error}`;
4019
- messageBuffer.addMessage(msg, "status");
4020
- session.client.sendSessionEvent({ type: "message", message: msg });
4070
+ const err = String(finalizeRes.error || "").trim() || "auto_finalize_failed";
4071
+ if (publishAutoFinalizeStatus({ status: "error", error: err })) {
4072
+ messageBuffer.addMessage(`Auto-finalize failed: ${err}`, "status");
4073
+ }
4074
+ } else {
4075
+ publishAutoFinalizeStatus({ status: "ok", error: null });
4021
4076
  }
4022
4077
  } catch (err) {
4023
- const msg = `Auto-finalize failed: ${err instanceof Error ? err.message : String(err)}`;
4024
- messageBuffer.addMessage(msg, "status");
4025
- session.client.sendSessionEvent({ type: "message", message: msg });
4078
+ const m = err instanceof Error ? err.message : String(err);
4079
+ const errorMsg = String(m || "").trim() || "auto_finalize_failed";
4080
+ if (publishAutoFinalizeStatus({ status: "error", error: errorMsg })) {
4081
+ messageBuffer.addMessage(`Auto-finalize failed: ${errorMsg}`, "status");
4082
+ }
4026
4083
  }
4027
4084
  }
4028
4085
  if (!pending && session.queue.size() === 0) {
@@ -5148,7 +5205,7 @@ async function loginWithClerkAndPairMachine() {
5148
5205
  console.log(chalk.bold("Flockbay CLI login"));
5149
5206
  console.log(chalk.gray(`Profile: ${configuration.profile}`));
5150
5207
  console.log(chalk.gray(`Server: ${configuration.serverUrl}`));
5151
- console.log(chalk.gray(`Machine: ${machineId} (${os.hostname()})`));
5208
+ console.log(chalk.gray(`Machine: ${machineId} (${os__default.hostname()})`));
5152
5209
  console.log("");
5153
5210
  console.log("Open this link to sign in with Clerk and approve this machine:");
5154
5211
  console.log(approveUrl);
@@ -5244,8 +5301,8 @@ function startUnrealMcpServerForDaemon(options) {
5244
5301
  return { ok: false, errorMessage: `Missing Unreal MCP Python folder: ${pythonDir}` };
5245
5302
  }
5246
5303
  const flockbayHomeDir = options.flockbayHomeDir;
5247
- const runtimeDir = path.join(flockbayHomeDir, "unreal-mcp");
5248
- const logPath = path.join(runtimeDir, "unreal_mcp.log");
5304
+ const runtimeDir = path__default.join(flockbayHomeDir, "unreal-mcp");
5305
+ const logPath = path__default.join(runtimeDir, "unreal_mcp.log");
5249
5306
  try {
5250
5307
  fs__default.mkdirSync(runtimeDir, { recursive: true });
5251
5308
  } catch (err) {
@@ -5253,7 +5310,7 @@ function startUnrealMcpServerForDaemon(options) {
5253
5310
  return { ok: false, errorMessage: `Failed to create runtime folder: ${runtimeDir}
5254
5311
  Error: ${message}` };
5255
5312
  }
5256
- const uvProjectEnv = path.join(runtimeDir, "uv-venv");
5313
+ const uvProjectEnv = path__default.join(runtimeDir, "uv-venv");
5257
5314
  const child = spawn("uv", ["run", "unreal_mcp_server.py"], {
5258
5315
  cwd: pythonDir,
5259
5316
  env: {
@@ -5514,9 +5571,9 @@ async function findNearestUprojectRoot(startDir) {
5514
5571
  if (current.toLowerCase().endsWith(".uproject")) {
5515
5572
  try {
5516
5573
  await fs$1.access(current);
5517
- return path.dirname(current);
5574
+ return path__default.dirname(current);
5518
5575
  } catch {
5519
- current = path.dirname(current);
5576
+ current = path__default.dirname(current);
5520
5577
  }
5521
5578
  }
5522
5579
  for (let i = 0; i < 25; i += 1) {
@@ -5525,7 +5582,7 @@ async function findNearestUprojectRoot(startDir) {
5525
5582
  if (entries.some((name) => name.toLowerCase().endsWith(".uproject"))) return current;
5526
5583
  } catch {
5527
5584
  }
5528
- const parent = path.dirname(current);
5585
+ const parent = path__default.dirname(current);
5529
5586
  if (parent === current) break;
5530
5587
  current = parent;
5531
5588
  }
@@ -5536,7 +5593,7 @@ async function findFirstUprojectFile(projectRoot) {
5536
5593
  const entries = await fs$1.readdir(projectRoot);
5537
5594
  const uprojects = entries.filter((name) => name.toLowerCase().endsWith(".uproject")).sort();
5538
5595
  if (uprojects.length === 0) return null;
5539
- return path.join(projectRoot, uprojects[0]);
5596
+ return path__default.join(projectRoot, uprojects[0]);
5540
5597
  } catch {
5541
5598
  return null;
5542
5599
  }
@@ -6589,9 +6646,9 @@ function targetPlatform() {
6589
6646
  }
6590
6647
  function buildScriptPath(engineRoot) {
6591
6648
  if (process.platform === "win32") {
6592
- return path.join(engineRoot, "Engine", "Build", "BatchFiles", "Build.bat");
6649
+ return path__default.join(engineRoot, "Engine", "Build", "BatchFiles", "Build.bat");
6593
6650
  }
6594
- return path.join(engineRoot, "Engine", "Build", "BatchFiles", "Build.sh");
6651
+ return path__default.join(engineRoot, "Engine", "Build", "BatchFiles", "Build.sh");
6595
6652
  }
6596
6653
  function parseBuildIssuesFromText(text, limit) {
6597
6654
  const issues = [];
@@ -6650,7 +6707,7 @@ async function buildUnrealProject(args) {
6650
6707
  const target = args.target ?? "Editor";
6651
6708
  const timeoutMs = Math.max(3e4, args.timeoutMs ?? 20 * 6e4);
6652
6709
  const issuesLimit = Math.max(1, Math.min(2e3, args.issuesLimit ?? 250));
6653
- if (!uprojectPath || !path.isAbsolute(uprojectPath) || !uprojectPath.toLowerCase().endsWith(".uproject")) {
6710
+ if (!uprojectPath || !path__default.isAbsolute(uprojectPath) || !uprojectPath.toLowerCase().endsWith(".uproject")) {
6654
6711
  return {
6655
6712
  ok: false,
6656
6713
  exitCode: null,
@@ -6687,12 +6744,12 @@ async function buildUnrealProject(args) {
6687
6744
  errorMessage: `Missing Unreal build script: ${script}`
6688
6745
  };
6689
6746
  }
6690
- const projectName = path.basename(uprojectPath).replace(/\.uproject$/i, "");
6747
+ const projectName = path__default.basename(uprojectPath).replace(/\.uproject$/i, "");
6691
6748
  const targetName = target === "Editor" ? `${projectName}Editor` : projectName;
6692
6749
  const platform = targetPlatform();
6693
- const logDir = args.logDir ?? path.join(path.dirname(uprojectPath), "Saved", "Logs", "Flockbay");
6750
+ const logDir = args.logDir ?? path__default.join(path__default.dirname(uprojectPath), "Saved", "Logs", "Flockbay");
6694
6751
  fs__default.mkdirSync(logDir, { recursive: true });
6695
- const logPath = path.join(logDir, `flockbay_build_${Date.now()}.log`);
6752
+ const logPath = path__default.join(logDir, `flockbay_build_${Date.now()}.log`);
6696
6753
  const buildArgs = [
6697
6754
  targetName,
6698
6755
  platform,
@@ -6780,9 +6837,9 @@ async function runUnrealSmokeTest(args) {
6780
6837
  const timeoutMs = Math.max(5e3, args.timeoutMs ?? 3e4);
6781
6838
  const stabilizeMs = Math.max(250, args.stabilizeMs ?? 1500);
6782
6839
  const stopIfPlaying = args.stopIfPlaying ?? true;
6783
- const screenshotDir = path.join(path.dirname(args.uprojectPath), "Saved", "Screenshots", "Flockbay");
6840
+ const screenshotDir = path__default.join(path__default.dirname(args.uprojectPath), "Saved", "Screenshots", "Flockbay");
6784
6841
  await mkdir(screenshotDir, { recursive: true });
6785
- const screenshotPath = path.join(screenshotDir, `Flockbay_smoke_test_${stampForFilename()}.png`);
6842
+ const screenshotPath = path__default.join(screenshotDir, `Flockbay_smoke_test_${stampForFilename()}.png`);
6786
6843
  let started = false;
6787
6844
  let stopped = false;
6788
6845
  try {
@@ -7107,10 +7164,10 @@ async function readUprojectEngineAssociationOrNull(uprojectPath) {
7107
7164
  function isValidEngineRoot(engineRoot) {
7108
7165
  if (!engineRoot) return false;
7109
7166
  if (!existsSync(engineRoot)) return false;
7110
- if (!existsSync(path.join(engineRoot, "Engine"))) return false;
7111
- const buildVersion = path.join(engineRoot, "Engine", "Build", "Build.version");
7167
+ if (!existsSync(path__default.join(engineRoot, "Engine"))) return false;
7168
+ const buildVersion = path__default.join(engineRoot, "Engine", "Build", "Build.version");
7112
7169
  if (existsSync(buildVersion)) return true;
7113
- const editorCmd = process.platform === "darwin" ? path.join(engineRoot, "Engine", "Binaries", "Mac", "UnrealEditor-Cmd") : process.platform === "win32" ? path.join(engineRoot, "Engine", "Binaries", "Win64", "UnrealEditor-Cmd.exe") : process.platform === "linux" ? path.join(engineRoot, "Engine", "Binaries", "Linux", "UnrealEditor-Cmd") : "";
7170
+ const editorCmd = process.platform === "darwin" ? path__default.join(engineRoot, "Engine", "Binaries", "Mac", "UnrealEditor-Cmd") : process.platform === "win32" ? path__default.join(engineRoot, "Engine", "Binaries", "Win64", "UnrealEditor-Cmd.exe") : process.platform === "linux" ? path__default.join(engineRoot, "Engine", "Binaries", "Linux", "UnrealEditor-Cmd") : "";
7114
7171
  if (editorCmd && existsSync(editorCmd)) return true;
7115
7172
  return false;
7116
7173
  }
@@ -7131,7 +7188,7 @@ function engineRootCandidatesForVersion(platform, version) {
7131
7188
  return [];
7132
7189
  }
7133
7190
  async function readEngineRootMajorMinorOrNull(engineRoot) {
7134
- const buildVersionPath = path.join(engineRoot, "Engine", "Build", "Build.version");
7191
+ const buildVersionPath = path__default.join(engineRoot, "Engine", "Build", "Build.version");
7135
7192
  try {
7136
7193
  if (existsSync(buildVersionPath)) {
7137
7194
  const json = await readJsonFile(buildVersionPath);
@@ -7275,7 +7332,7 @@ async function uploadScreenshotViewsForSession(args) {
7275
7332
  const form = new FormData();
7276
7333
  for (const v of args.views) {
7277
7334
  const buf = await readFile(v.path);
7278
- const filename = path.basename(v.path);
7335
+ const filename = path__default.basename(v.path);
7279
7336
  const contentType = (() => {
7280
7337
  const mime = detectImageMimeTypeFromBuffer$1(buf);
7281
7338
  if (mime) return mime;
@@ -7501,7 +7558,7 @@ async function startFlockbayServer(client, options) {
7501
7558
  let best = null;
7502
7559
  for (const name of entries) {
7503
7560
  if (!filter(name)) continue;
7504
- const full = path.join(dir, name);
7561
+ const full = path__default.join(dir, name);
7505
7562
  let st;
7506
7563
  try {
7507
7564
  st = await stat(full);
@@ -7518,12 +7575,12 @@ async function startFlockbayServer(client, options) {
7518
7575
  }
7519
7576
  };
7520
7577
  const findLatestCrashDir = async (projectRoot) => {
7521
- const crashesDir = path.join(projectRoot, "Saved", "Crashes");
7578
+ const crashesDir = path__default.join(projectRoot, "Saved", "Crashes");
7522
7579
  try {
7523
7580
  const entries = await readdir(crashesDir);
7524
7581
  let best = null;
7525
7582
  for (const name of entries) {
7526
- const full = path.join(crashesDir, name);
7583
+ const full = path__default.join(crashesDir, name);
7527
7584
  let st;
7528
7585
  try {
7529
7586
  st = await stat(full);
@@ -7549,10 +7606,10 @@ async function startFlockbayServer(client, options) {
7549
7606
  }
7550
7607
  };
7551
7608
  const gatherCrashDiagnosticsBestEffort = async (uprojectPath) => {
7552
- const projectRoot = path.dirname(uprojectPath);
7609
+ const projectRoot = path__default.dirname(uprojectPath);
7553
7610
  const summary = [];
7554
7611
  const detail = { uprojectPath, projectRoot };
7555
- const latestLog = await findLatestFile(path.join(projectRoot, "Saved", "Logs"), (n) => n.toLowerCase().endsWith(".log"));
7612
+ const latestLog = await findLatestFile(path__default.join(projectRoot, "Saved", "Logs"), (n) => n.toLowerCase().endsWith(".log"));
7556
7613
  if (latestLog) {
7557
7614
  detail.projectLogPath = latestLog;
7558
7615
  const tail = await readFileTail(latestLog, 24e3);
@@ -7579,13 +7636,13 @@ async function startFlockbayServer(client, options) {
7579
7636
  const getUnrealEditorExe = (engineRoot) => {
7580
7637
  const root = engineRoot.trim().replace(/[\\/]+$/, "");
7581
7638
  if (process.platform === "darwin") {
7582
- return path.join(root, "Engine", "Binaries", "Mac", "UnrealEditor.app", "Contents", "MacOS", "UnrealEditor");
7639
+ return path__default.join(root, "Engine", "Binaries", "Mac", "UnrealEditor.app", "Contents", "MacOS", "UnrealEditor");
7583
7640
  }
7584
7641
  if (process.platform === "win32") {
7585
- return path.join(root, "Engine", "Binaries", "Win64", "UnrealEditor.exe");
7642
+ return path__default.join(root, "Engine", "Binaries", "Win64", "UnrealEditor.exe");
7586
7643
  }
7587
7644
  if (process.platform === "linux") {
7588
- return path.join(root, "Engine", "Binaries", "Linux", "UnrealEditor");
7645
+ return path__default.join(root, "Engine", "Binaries", "Linux", "UnrealEditor");
7589
7646
  }
7590
7647
  return "";
7591
7648
  };
@@ -7754,12 +7811,46 @@ Next: fix the issue, then relaunch via unreal_editor_relaunch_last (or unreal_ed
7754
7811
  const exists = await runGit(["show-ref", "--verify", "--quiet", `refs/heads/${candidate}`], args.repoRoot, 1e4);
7755
7812
  if (exists.ok) return candidate;
7756
7813
  }
7814
+ const hasCommit = await runGit(["rev-parse", "--verify", "HEAD"], args.repoRoot, 1e4);
7815
+ if (!hasCommit.ok) {
7816
+ throw new Error(
7817
+ `Coordination requires an initial commit (no local branches exist yet).
7818
+
7819
+ Fix:
7820
+ - Initialize: git init -b main
7821
+ - Add a minimal .gitignore
7822
+ - Commit: git add .gitignore && git commit -m "chore: init coordination"`
7823
+ );
7824
+ }
7757
7825
  const heads = await runGit(["for-each-ref", "--format=%(refname:short)", "refs/heads"], args.repoRoot, 1e4);
7758
7826
  const available = String(heads.stdout || "").split("\n").map((l) => l.trim()).filter(Boolean).slice(0, 20).join(", ");
7759
7827
  throw new Error(
7760
7828
  `Invalid base branch '${"main"}' (no local branch found). Create the branch locally (or rename your default branch). Available local branches: ${available || "(none)"}`
7761
7829
  );
7762
7830
  };
7831
+ const publishCoordinationSetupStatus = (next) => {
7832
+ try {
7833
+ client?.updateMetadata?.((metadata) => ({
7834
+ ...metadata || {},
7835
+ coordinationAutoFinalize: {
7836
+ status: next.status,
7837
+ error: next.error,
7838
+ updatedAt: Date.now()
7839
+ }
7840
+ }));
7841
+ } catch (err) {
7842
+ logger.debug("[flockbayMCP] Failed to publish coordination setup status:", err);
7843
+ }
7844
+ };
7845
+ const classifyCoordinationGitError = (err) => {
7846
+ const message = err instanceof Error ? err.message : String(err || "");
7847
+ const detail = String(message || "").trim() || "coordination_git_error";
7848
+ if (detail.startsWith("Not a git repo")) return { code: "not_a_git_repo", detail };
7849
+ if (detail.startsWith("Coordination requires an initial commit")) return { code: "no_initial_commit", detail };
7850
+ if (detail.startsWith("Invalid base branch")) return { code: "missing_base_branch", detail };
7851
+ if (detail.includes("unsafe_git_repo_root")) return { code: "unsafe_git_repo_root", detail };
7852
+ return { code: "coordination_git_error", detail };
7853
+ };
7763
7854
  const preflightRefreshableFiles = async (args) => {
7764
7855
  const out = [];
7765
7856
  for (const filePath of args.files) {
@@ -7877,7 +7968,7 @@ ${String(st.stdout || "").trim()}`
7877
7968
  };
7878
7969
  const toolResultsArtifactsRoot = () => {
7879
7970
  const sessionDir = readSessionWorkingDirectory();
7880
- return path.join(sessionDir, ".flockbay", "artifacts", "tool-results");
7971
+ return path__default.join(sessionDir, ".flockbay", "artifacts", "tool-results");
7881
7972
  };
7882
7973
  const safePathSegment = (raw) => String(raw || "").trim().replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+/, "").replace(/_+$/, "") || "unknown";
7883
7974
  const coerceTextBlocks = (content) => {
@@ -7893,9 +7984,9 @@ ${String(st.stdout || "").trim()}`
7893
7984
  };
7894
7985
  const writeToolResultArtifact = async (args) => {
7895
7986
  const root = toolResultsArtifactsRoot();
7896
- const toolDir = path.join(root, safePathSegment(args.toolName));
7987
+ const toolDir = path__default.join(root, safePathSegment(args.toolName));
7897
7988
  await mkdir(toolDir, { recursive: true });
7898
- const filePath = path.join(toolDir, `${safePathSegment(args.toolResultId)}.json`);
7989
+ const filePath = path__default.join(toolDir, `${safePathSegment(args.toolResultId)}.json`);
7899
7990
  const payload = {
7900
7991
  kind: "mcp_tool_result",
7901
7992
  toolName: args.toolName,
@@ -7916,7 +8007,9 @@ ${String(st.stdout || "").trim()}`
7916
8007
  const first = texts[0];
7917
8008
  if (first && !/^\s*[{[]/.test(first)) headLines.push(first);
7918
8009
  headLines.push(`Evidence: toolResultId=${args.artifact.id}`);
7919
- headLines.push(`Tip: use tool_result_query/tool_result_read for details (avoid re-reading full tool JSON unless necessary).`);
8010
+ headLines.push(
8011
+ `Tip: use tool_result_query (preferred) to fetch small slices; avoid cat/reading full .flockbay tool-result JSON unless necessary.`
8012
+ );
7920
8013
  const modelContent = [{ type: "text", text: headLines.join("\n") }];
7921
8014
  if (args.passthroughContent && Array.isArray(args.fullResult?.content)) {
7922
8015
  for (const block of args.fullResult.content) {
@@ -7939,24 +8032,21 @@ ${String(st.stdout || "").trim()}`
7939
8032
  };
7940
8033
  const resolveToolResultArtifactPath = async (args) => {
7941
8034
  const root = toolResultsArtifactsRoot();
7942
- const resolvedRoot = path.resolve(root);
8035
+ const resolvedRoot = path__default.resolve(root);
7943
8036
  const toolResultId = String(args.toolResultId || "").trim();
7944
8037
  if (!toolResultId) return { ok: false, error: "Missing toolResultId." };
7945
- const rawPath = String(args.artifactPath || "").trim();
7946
8038
  const toolName = String(args.toolName || "").trim();
7947
8039
  const safeId = safePathSegment(toolResultId);
7948
8040
  let filePath = "";
7949
- if (rawPath) {
7950
- filePath = rawPath;
7951
- } else if (toolName) {
7952
- filePath = path.join(root, safePathSegment(toolName), `${safeId}.json`);
8041
+ if (toolName) {
8042
+ filePath = path__default.join(root, safePathSegment(toolName), `${safeId}.json`);
7953
8043
  } else {
7954
8044
  if (!existsSync(root)) return { ok: false, error: `Tool results root not found: ${root}` };
7955
8045
  const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
7956
8046
  const matches = [];
7957
8047
  for (const entry of entries) {
7958
8048
  if (!entry.isDirectory()) continue;
7959
- const candidate = path.join(root, entry.name, `${safeId}.json`);
8049
+ const candidate = path__default.join(root, entry.name, `${safeId}.json`);
7960
8050
  if (existsSync(candidate)) matches.push(candidate);
7961
8051
  }
7962
8052
  if (matches.length === 0) return { ok: false, error: `tool result not found: ${toolResultId}` };
@@ -7968,8 +8058,8 @@ ${String(st.stdout || "").trim()}`
7968
8058
  }
7969
8059
  filePath = matches[0];
7970
8060
  }
7971
- const resolvedFile = path.resolve(filePath);
7972
- if (!resolvedFile.startsWith(resolvedRoot + path.sep) && resolvedFile !== resolvedRoot) {
8061
+ const resolvedFile = path__default.resolve(filePath);
8062
+ if (!resolvedFile.startsWith(resolvedRoot + path__default.sep) && resolvedFile !== resolvedRoot) {
7973
8063
  return { ok: false, error: `Refusing to read outside tool-results root.` };
7974
8064
  }
7975
8065
  if (!existsSync(resolvedFile)) return { ok: false, error: `tool result artifact not found` };
@@ -8532,15 +8622,13 @@ ${String(st.stdout || "").trim()}`
8532
8622
  description: "Read a previously-stored MCP tool result artifact produced by Flockbay MCP (full tool input/output JSON). Use this when you explicitly need details beyond the default minimal tool observation.",
8533
8623
  inputSchema: {
8534
8624
  toolName: z.string().optional().describe("Tool name (folder under .flockbay/artifacts/tool-results)."),
8535
- toolResultId: z.string().describe("toolResultId from a prior tool observation."),
8536
- artifactPath: z.string().optional().describe("Optional absolute artifact path (advanced).")
8625
+ toolResultId: z.string().describe("toolResultId from a prior tool observation.")
8537
8626
  }
8538
8627
  },
8539
8628
  async (args) => runWithMcpToolCard("tool_result_read", args, async () => {
8540
8629
  const toolName = typeof args?.toolName === "string" ? String(args.toolName).trim() : null;
8541
8630
  const toolResultId = typeof args?.toolResultId === "string" ? String(args.toolResultId).trim() : "";
8542
- const artifactPath = typeof args?.artifactPath === "string" ? String(args.artifactPath).trim() : null;
8543
- const resolved = await resolveToolResultArtifactPath({ toolName, toolResultId, artifactPath });
8631
+ const resolved = await resolveToolResultArtifactPath({ toolName, toolResultId });
8544
8632
  if (!resolved.ok) return textToolResult(resolved.error, true);
8545
8633
  const raw = await readFile(resolved.path, "utf8");
8546
8634
  return {
@@ -8559,18 +8647,16 @@ ${String(st.stdout || "").trim()}`
8559
8647
  inputSchema: {
8560
8648
  toolName: z.string().optional().describe("Tool name (folder under .flockbay/artifacts/tool-results)."),
8561
8649
  toolResultId: z.string().describe("toolResultId from a prior tool observation."),
8562
- artifactPath: z.string().optional().describe("Optional absolute artifact path (advanced)."),
8563
8650
  paths: z.array(z.string()).min(1).describe('JSON pointer paths ("/output/result/location") or dot-paths ("output.result.location").')
8564
8651
  }
8565
8652
  },
8566
8653
  async (args) => runWithMcpToolCard("tool_result_query", args, async () => {
8567
8654
  const toolName = typeof args?.toolName === "string" ? String(args.toolName).trim() : null;
8568
8655
  const toolResultId = typeof args?.toolResultId === "string" ? String(args.toolResultId).trim() : "";
8569
- const artifactPath = typeof args?.artifactPath === "string" ? String(args.artifactPath).trim() : null;
8570
8656
  const paths = Array.isArray(args?.paths) ? args.paths.map((p) => String(p || "").trim()).filter(Boolean) : [];
8571
8657
  if (!toolResultId) return textToolResult("Missing toolResultId.", true);
8572
8658
  if (paths.length === 0) return textToolResult("Missing paths[] (provide one or more JSON paths).", true);
8573
- const resolved = await resolveToolResultArtifactPath({ toolName, toolResultId, artifactPath });
8659
+ const resolved = await resolveToolResultArtifactPath({ toolName, toolResultId });
8574
8660
  if (!resolved.ok) return textToolResult(resolved.error, true);
8575
8661
  let json;
8576
8662
  try {
@@ -8655,8 +8741,29 @@ ${String(st.stdout || "").trim()}`
8655
8741
  return { content: [{ type: "text", text: "Missing files[]" }], isError: true };
8656
8742
  }
8657
8743
  const sessionCwd = readSessionWorkingDirectory();
8658
- const repoRoot = await resolveGitRepoRoot(sessionCwd);
8659
- const baseBranch = await resolveCoordinationBaseBranch({ projectId, repoRoot });
8744
+ let repoRoot = "";
8745
+ let baseBranch = "";
8746
+ try {
8747
+ repoRoot = await resolveGitRepoRoot(sessionCwd);
8748
+ baseBranch = await resolveCoordinationBaseBranch({ projectId, repoRoot });
8749
+ publishCoordinationSetupStatus({ status: "ok", error: null });
8750
+ } catch (err) {
8751
+ const classified = classifyCoordinationGitError(err);
8752
+ publishCoordinationSetupStatus({ status: "error", error: classified.code });
8753
+ return textToolResult(
8754
+ JSON.stringify(
8755
+ {
8756
+ success: false,
8757
+ error: classified.code,
8758
+ detail: classified.detail,
8759
+ hint: classified.code === "not_a_git_repo" ? "Initialize git in this project root (git init -b main) and add an initial commit, then retry." : classified.code === "no_initial_commit" ? "Create an initial commit so a base branch exists, then retry." : classified.code === "missing_base_branch" ? "Create/rename your base branch (main/master) locally, then retry." : "Fix the git repo and retry."
8760
+ },
8761
+ null,
8762
+ 2
8763
+ ),
8764
+ true
8765
+ );
8766
+ }
8660
8767
  const guard = client?.coordinationLeaseGuard;
8661
8768
  const needsRefresh = files.filter((f) => {
8662
8769
  try {
@@ -8890,8 +8997,28 @@ ${String(st.stdout || "").trim()}`
8890
8997
  return { content: [{ type: "text", text: "Missing files[]" }], isError: true };
8891
8998
  }
8892
8999
  const sessionCwd = readSessionWorkingDirectory();
8893
- const repoRoot = await resolveGitRepoRoot(sessionCwd);
8894
- const baseBranch = await resolveCoordinationBaseBranch({ projectId, repoRoot });
9000
+ let repoRoot = "";
9001
+ let baseBranch = "";
9002
+ try {
9003
+ repoRoot = await resolveGitRepoRoot(sessionCwd);
9004
+ baseBranch = await resolveCoordinationBaseBranch({ projectId, repoRoot });
9005
+ publishCoordinationSetupStatus({ status: "ok", error: null });
9006
+ } catch (err) {
9007
+ const classified = classifyCoordinationGitError(err);
9008
+ publishCoordinationSetupStatus({ status: "error", error: classified.code });
9009
+ return textToolResult(
9010
+ JSON.stringify(
9011
+ {
9012
+ success: false,
9013
+ error: classified.code,
9014
+ detail: classified.detail
9015
+ },
9016
+ null,
9017
+ 2
9018
+ ),
9019
+ true
9020
+ );
9021
+ }
8895
9022
  const guard = client?.coordinationLeaseGuard;
8896
9023
  const needsRefresh = files.filter((f) => {
8897
9024
  try {
@@ -9037,10 +9164,10 @@ ${String(st.stdout || "").trim()}`
9037
9164
  if (!p) return p;
9038
9165
  if (p.startsWith("~/")) {
9039
9166
  const home = process.env.HOME || process.env.USERPROFILE || "";
9040
- if (home) return path.join(home, p.slice(2));
9167
+ if (home) return path__default.join(home, p.slice(2));
9041
9168
  }
9042
9169
  const baseDir = readSessionWorkingDirectory();
9043
- return path.isAbsolute(p) ? p : path.resolve(baseDir, p);
9170
+ return path__default.isAbsolute(p) ? p : path__default.resolve(baseDir, p);
9044
9171
  };
9045
9172
  const idsSeen = /* @__PURE__ */ new Set();
9046
9173
  const viewsLocal = [];
@@ -9053,7 +9180,7 @@ ${String(st.stdout || "").trim()}`
9053
9180
  if (!existsSync(abs)) {
9054
9181
  throw new Error(`Image not found: ${abs}`);
9055
9182
  }
9056
- const filename = path.basename(abs);
9183
+ const filename = path__default.basename(abs);
9057
9184
  let id = deriveScreenshotViewIdFromFilename(filename);
9058
9185
  if (!id) id = filename.replace(/\.[^.]+$/, "");
9059
9186
  let unique = id;
@@ -9130,9 +9257,9 @@ ${String(st.stdout || "").trim()}`
9130
9257
  const limit = args.limit ?? 12;
9131
9258
  const includeBase64 = args.includeBase64 ?? false;
9132
9259
  const maxBytesPerImage = args.maxBytesPerImage ?? 25e5;
9133
- const outDir = path.join(path.dirname(uprojectPath), "Saved", "Screenshots", "Flockbay");
9260
+ const outDir = path__default.join(path__default.dirname(uprojectPath), "Saved", "Screenshots", "Flockbay");
9134
9261
  try {
9135
- if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path.isAbsolute(uprojectPath)) {
9262
+ if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path__default.isAbsolute(uprojectPath)) {
9136
9263
  return {
9137
9264
  content: [{ type: "text", text: `Invalid uprojectPath (must be an absolute path to *.uproject): ${String(uprojectPath)}` }],
9138
9265
  isError: true
@@ -9167,7 +9294,7 @@ ${String(st.stdout || "").trim()}`
9167
9294
  }
9168
9295
  const withTimes = await Promise.all(
9169
9296
  candidates.map(async (name) => {
9170
- const fullPath = path.join(outDir, name);
9297
+ const fullPath = path__default.join(outDir, name);
9171
9298
  const st = await stat(fullPath);
9172
9299
  return { name, path: fullPath, mtimeMs: st.mtimeMs };
9173
9300
  })
@@ -9264,7 +9391,7 @@ ${String(st.stdout || "").trim()}`
9264
9391
  const uprojectPath = typeof args?.uprojectPath === "string" ? String(args.uprojectPath).trim() : "";
9265
9392
  const engineRootArg = typeof args?.engineRoot === "string" ? String(args.engineRoot).trim() : "";
9266
9393
  const extraArgs = Array.isArray(args?.extraArgs) ? args.extraArgs : [];
9267
- if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path.isAbsolute(uprojectPath)) {
9394
+ if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path__default.isAbsolute(uprojectPath)) {
9268
9395
  return {
9269
9396
  content: [{ type: "text", text: `Invalid uprojectPath (must be an absolute path to *.uproject): ${String(uprojectPath)}` }],
9270
9397
  isError: true
@@ -9352,7 +9479,7 @@ ${String(st.stdout || "").trim()}`
9352
9479
  const uprojectPath = typeof args?.uprojectPath === "string" ? String(args.uprojectPath).trim() : "";
9353
9480
  const engineRootArg = typeof args?.engineRoot === "string" ? String(args.engineRoot).trim() : "";
9354
9481
  const timeoutMs = typeof args?.timeoutMs === "number" ? args.timeoutMs : void 0;
9355
- if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path.isAbsolute(uprojectPath)) {
9482
+ if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path__default.isAbsolute(uprojectPath)) {
9356
9483
  return {
9357
9484
  content: [{ type: "text", text: `Invalid uprojectPath (must be an absolute path to *.uproject): ${String(uprojectPath)}` }],
9358
9485
  isError: true
@@ -10588,7 +10715,7 @@ ${String(st.stdout || "").trim()}`
10588
10715
  const stabilizeMs = typeof args?.stabilizeMs === "number" ? args.stabilizeMs : void 0;
10589
10716
  const timeoutMs = typeof args?.timeoutMs === "number" ? args.timeoutMs : void 0;
10590
10717
  const stopIfPlaying = typeof args?.stopIfPlaying === "boolean" ? args.stopIfPlaying : void 0;
10591
- if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path.isAbsolute(uprojectPath)) {
10718
+ if (!uprojectPath || !uprojectPath.toLowerCase().endsWith(".uproject") || !path__default.isAbsolute(uprojectPath)) {
10592
10719
  return {
10593
10720
  content: [{ type: "text", text: `Invalid uprojectPath (must be an absolute path to *.uproject): ${String(uprojectPath)}` }],
10594
10721
  isError: true
@@ -10965,7 +11092,7 @@ async function buildProjectCapsule(opts) {
10965
11092
  if (!detection.projectRoot) return null;
10966
11093
  const projectRoot = detection.projectRoot;
10967
11094
  const uprojectFile = detection.uprojectFile;
10968
- const readmePath = path.join(projectRoot, ".flockbay", "README.md");
11095
+ const readmePath = path__default.join(projectRoot, ".flockbay", "README.md");
10969
11096
  const readmeRaw = await readTextFileIfExists(readmePath);
10970
11097
  const maxReadmeChars = typeof opts.maxReadmeChars === "number" ? opts.maxReadmeChars : DEFAULT_MAX_README_CHARS;
10971
11098
  const readme = readmeRaw ? truncateWithNote(readmeRaw, maxReadmeChars) : null;
@@ -11027,14 +11154,14 @@ async function runClaude(credentials, options = {}) {
11027
11154
  let metadata = {
11028
11155
  path: workingDirectory,
11029
11156
  projectRootPath: coordinationProjectRootPath,
11030
- host: os.hostname(),
11157
+ host: os__default.hostname(),
11031
11158
  version: packageJson.version,
11032
- os: os.platform(),
11159
+ os: os__default.platform(),
11033
11160
  machineId,
11034
11161
  workspaceProjectId: coordinationWorkspaceProjectId,
11035
11162
  featureId: coordinationFeatureId,
11036
11163
  workItemId: coordinationWorkItemId,
11037
- homeDir: os.homedir(),
11164
+ homeDir: os__default.homedir(),
11038
11165
  flockbayHomeDir: configuration.flockbayHomeDir,
11039
11166
  flockbayLibDir: projectPath(),
11040
11167
  flockbayToolsDir: resolve(projectPath(), "tools", "unpacked"),
@@ -11966,8 +12093,8 @@ ${authUrl}
11966
12093
  }
11967
12094
 
11968
12095
  async function syncCodexCliAuth(tokens) {
11969
- const authFilePath = path.join(os.homedir(), ".codex", "auth.json");
11970
- const authDir = path.dirname(authFilePath);
12096
+ const authFilePath = path__default.join(os__default.homedir(), ".codex", "auth.json");
12097
+ const authDir = path__default.dirname(authFilePath);
11971
12098
  let previousAccountId;
11972
12099
  let previousApiKey = null;
11973
12100
  try {
@@ -12149,10 +12276,10 @@ async function ensureDaemonRunning({ skipUnreal }) {
12149
12276
  throw new Error("daemon_start_timeout");
12150
12277
  }
12151
12278
  async function createSmokeWorkspaceDir(baseDir) {
12152
- const root = baseDir?.trim() ? path.resolve(baseDir) : path.join(os.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + randomUUID().slice(0, 8));
12279
+ const root = baseDir?.trim() ? path__default.resolve(baseDir) : path__default.join(os__default.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + randomUUID().slice(0, 8));
12153
12280
  await fs$1.mkdir(root, { recursive: true });
12154
12281
  const secret = `SMOKE_SECRET_${randomUUID().slice(0, 8)}`;
12155
- await fs$1.writeFile(path.join(root, "smoke.txt"), `flockbay smoke test
12282
+ await fs$1.writeFile(path__default.join(root, "smoke.txt"), `flockbay smoke test
12156
12283
  SMOKE_SECRET=${secret}
12157
12284
  `, "utf8");
12158
12285
  return { dir: root, secret };
@@ -12485,8 +12612,8 @@ async function handleSmokeTestCommand(args) {
12485
12612
  }
12486
12613
  const allOk = results.every((r) => r.ok);
12487
12614
  if (outPath) {
12488
- const abs = path.resolve(outPath);
12489
- await fs$1.mkdir(path.dirname(abs), { recursive: true });
12615
+ const abs = path__default.resolve(outPath);
12616
+ await fs$1.mkdir(path__default.dirname(abs), { recursive: true });
12490
12617
  await fs$1.writeFile(abs, JSON.stringify({ ok: allOk, results }, null, 2) + "\n", "utf8");
12491
12618
  console.log(chalk.gray(`Wrote: ${abs}`));
12492
12619
  }
@@ -12540,7 +12667,7 @@ async function waitForUnreal(options) {
12540
12667
  };
12541
12668
  }
12542
12669
  function resolveUnrealEditorExe(engineRoot) {
12543
- const exe = process.platform === "win32" ? path.join(engineRoot, "Engine", "Binaries", "Win64", "UnrealEditor.exe") : path.join(engineRoot, "Engine", "Binaries", process.platform === "darwin" ? "Mac" : "Linux", "UnrealEditor");
12670
+ const exe = process.platform === "win32" ? path__default.join(engineRoot, "Engine", "Binaries", "Win64", "UnrealEditor.exe") : path__default.join(engineRoot, "Engine", "Binaries", process.platform === "darwin" ? "Mac" : "Linux", "UnrealEditor");
12544
12671
  return exe;
12545
12672
  }
12546
12673
  async function runRuntimeSmoke(options) {
@@ -12617,10 +12744,10 @@ Expected FriendlyName="Flockbay MCP" CreatedBy="Respaced Inc."`
12617
12744
  await sendUnrealMcpTcpCommand({ type: "play_in_editor_windowed", host: options.host, port: options.port, timeoutMs: Math.max(options.timeoutMs, 2e4) });
12618
12745
  await new Promise((r) => setTimeout(r, 1e3));
12619
12746
  await sendUnrealMcpTcpCommand({ type: "stop_play_in_editor", host: options.host, port: options.port, timeoutMs: Math.max(options.timeoutMs, 2e4) });
12620
- const projectDir = path.dirname(options.projectPath);
12621
- const shotsDir = path.join(projectDir, "Saved", "Screenshots", "Flockbay");
12747
+ const projectDir = path__default.dirname(options.projectPath);
12748
+ const shotsDir = path__default.join(projectDir, "Saved", "Screenshots", "Flockbay");
12622
12749
  ensureDir(shotsDir);
12623
- const shotPath = path.join(shotsDir, `smoke_${Date.now()}.png`);
12750
+ const shotPath = path__default.join(shotsDir, `smoke_${Date.now()}.png`);
12624
12751
  await sendUnrealMcpTcpCommand({
12625
12752
  type: "take_screenshot",
12626
12753
  params: { filepath: shotPath },
@@ -13270,7 +13397,7 @@ ${engineRoot}`, {
13270
13397
  } else if (subcommand === "codex") {
13271
13398
  try {
13272
13399
  await chdirToNearestUprojectRootIfPresent();
13273
- const { runCodex } = await import('./runCodex-Csi1jhMD.mjs');
13400
+ const { runCodex } = await import('./runCodex-F93OWlPh.mjs');
13274
13401
  let startedBy = void 0;
13275
13402
  let sessionId = void 0;
13276
13403
  for (let i = 1; i < args.length; i++) {
@@ -13372,7 +13499,7 @@ ${engineRoot}`, {
13372
13499
  }
13373
13500
  try {
13374
13501
  await chdirToNearestUprojectRootIfPresent();
13375
- const { runGemini } = await import('./runGemini-CsLa2i5F.mjs');
13502
+ const { runGemini } = await import('./runGemini-Cvo7a4eh.mjs');
13376
13503
  let startedBy = void 0;
13377
13504
  let sessionId = void 0;
13378
13505
  for (let i = 1; i < args.length; i++) {