flockbay 0.10.43 → 0.10.44

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.
@@ -3,7 +3,7 @@
3
3
  import { execFileSync } from 'node:child_process';
4
4
  import { existsSync } from 'node:fs';
5
5
  import { dirname, join } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
7
 
8
8
  // Ensure Node flags to reduce noisy warnings on stdout (which could interfere with MCP).
9
9
  const hasNoWarnings = process.execArgv.includes('--no-warnings');
@@ -25,7 +25,13 @@ function resolveTsxImportArgs() {
25
25
  join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.js'),
26
26
  ];
27
27
  const resolved = candidates.find(existsSync);
28
- return resolved ? ['--import', resolved] : ['--import', 'tsx'];
28
+ return resolved ? ['--import', toNodeSpecifier(resolved)] : ['--import', 'tsx'];
29
+ }
30
+
31
+ function toNodeSpecifier(p) {
32
+ if (process.platform !== 'win32') return p;
33
+ if (!/^[a-zA-Z]:[\\/]/.test(p)) return p;
34
+ return pathToFileURL(p).href;
29
35
  }
30
36
 
31
37
  if (!hasNoWarnings || !hasNoDeprecation || useTsx) {
package/bin/flockbay.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  import { execFileSync } from 'node:child_process';
4
4
  import { existsSync, statSync } from 'node:fs';
5
5
  import { dirname, join } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
7
 
8
8
  // Ensure Node flags to reduce noisy warnings on stdout.
9
9
  const hasNoWarnings = process.execArgv.includes('--no-warnings');
@@ -54,7 +54,13 @@ function resolveTsxImportArgs() {
54
54
  join(projectRoot, 'node_modules', 'tsx', 'dist', 'index.js'),
55
55
  ];
56
56
  const resolved = candidates.find(existsSync);
57
- return resolved ? ['--import', resolved] : ['--import', 'tsx'];
57
+ return resolved ? ['--import', toNodeSpecifier(resolved)] : ['--import', 'tsx'];
58
+ }
59
+
60
+ function toNodeSpecifier(p) {
61
+ if (process.platform !== 'win32') return p;
62
+ if (!/^[a-zA-Z]:[\\/]/.test(p)) return p;
63
+ return pathToFileURL(p).href;
58
64
  }
59
65
 
60
66
  const rewrittenArgs = rewriteTopLevelAliases(process.argv.slice(2));
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
2
2
  import * as os from 'node:os';
3
3
  import os__default, { homedir } from 'node:os';
4
4
  import { randomUUID, createCipheriv, randomBytes, createHash as createHash$1 } from 'node:crypto';
5
- import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-1s9-Oj5w.mjs';
5
+ import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-D8EqTVgB.mjs';
6
6
  import { spawn, execFileSync, execSync } from 'node:child_process';
7
7
  import * as path from 'node:path';
8
8
  import path__default, { resolve, join, dirname } from 'node:path';
@@ -14,7 +14,7 @@ import fs$1, { readFile, access as access$1, mkdir, readdir, stat, writeFile, co
14
14
  import fs$2, { watch, access, mkdir as mkdir$1, writeFile as writeFile$1, rm } from 'fs/promises';
15
15
  import { useStdout, useInput, Box, Text, render } from 'ink';
16
16
  import React, { useState, useRef, useEffect, useCallback } from 'react';
17
- import { fileURLToPath } from 'node:url';
17
+ import { fileURLToPath, pathToFileURL } from 'node:url';
18
18
  import axios from 'axios';
19
19
  import 'socket.io-client';
20
20
  import { spawn as spawn$1, execFileSync as execFileSync$1 } from 'child_process';
@@ -5261,13 +5261,35 @@ function resolveTsxImportArgs(projectRoot) {
5261
5261
  join(projectRoot, "node_modules", "tsx", "dist", "index.js")
5262
5262
  ];
5263
5263
  const resolved = candidates.find(existsSync);
5264
- return resolved ? ["--import", resolved] : ["--import", "tsx"];
5264
+ return resolved ? ["--import", toNodeSpecifier(resolved)] : ["--import", "tsx"];
5265
+ }
5266
+ function toNodeSpecifier(p) {
5267
+ if (process$1.platform !== "win32") return p;
5268
+ if (!/^[a-zA-Z]:[\\/]/.test(p)) return p;
5269
+ return pathToFileURL(p).href;
5265
5270
  }
5266
5271
  function spawnFlockbayCLI(args, options = {}) {
5267
5272
  const projectRoot = projectPath();
5268
5273
  const distEntrypoint = join(projectRoot, "dist", "index.mjs");
5269
5274
  const devEntrypoint = join(projectRoot, "src", "index.ts");
5270
- const entrypoint = existsSync(distEntrypoint) ? distEntrypoint : devEntrypoint;
5275
+ const entrypoint = (() => {
5276
+ const forceSrc = process$1.env.FLOCKBAY_USE_SRC === "1";
5277
+ const forceDist = process$1.env.FLOCKBAY_USE_DIST === "1";
5278
+ const hasDist = existsSync(distEntrypoint);
5279
+ const hasDev = existsSync(devEntrypoint);
5280
+ if (forceSrc && hasDev) return devEntrypoint;
5281
+ if (forceDist && hasDist) return distEntrypoint;
5282
+ if (hasDist && hasDev) {
5283
+ try {
5284
+ const devTime = statSync(devEntrypoint).mtimeMs;
5285
+ const distTime = statSync(distEntrypoint).mtimeMs;
5286
+ if (devTime > distTime) return devEntrypoint;
5287
+ } catch {
5288
+ }
5289
+ return distEntrypoint;
5290
+ }
5291
+ return hasDist ? distEntrypoint : devEntrypoint;
5292
+ })();
5271
5293
  const useTsx = entrypoint.endsWith(".ts");
5272
5294
  const desiredCwd = "cwd" in options && typeof options.cwd === "string" ? options.cwd : process$1.cwd();
5273
5295
  const windowsHide = typeof options?.windowsHide === "boolean" ? Boolean(options.windowsHide) : process$1.platform === "win32";
@@ -5683,12 +5705,14 @@ async function enforceCliVersionPolicy(opts) {
5683
5705
  const policy = await fetchCliVersionPolicy({ serverUrl: opts.serverUrl, timeoutMs: opts.timeoutMs });
5684
5706
  const evaluation = evaluateCliVersion({ currentVersion, policy });
5685
5707
  if (evaluation.status === "update_required") {
5686
- const header = `CLI update required (installed: ${currentVersion}, required: ${evaluation.minimumSupported})`;
5687
- const msg = evaluation.message ? `
5688
- ${evaluation.message}` : "";
5689
- const help = `
5690
- Update: ${evaluation.updateCommand}`;
5691
- throw new Error(`${header}${msg}${help}`);
5708
+ try {
5709
+ opts.onUpdateRequired?.({
5710
+ minimumSupported: evaluation.minimumSupported,
5711
+ updateCommand: evaluation.updateCommand,
5712
+ message: evaluation.message
5713
+ });
5714
+ } catch {
5715
+ }
5692
5716
  }
5693
5717
  if (evaluation.status === "update_available") {
5694
5718
  try {
@@ -5789,6 +5813,14 @@ async function startDaemon() {
5789
5813
  serverUrl: configuration.serverUrl,
5790
5814
  currentVersion: packageJson.version,
5791
5815
  timeoutMs: Number.parseInt(process.env.FLOCKBAY_CLI_VERSION_CHECK_TIMEOUT_MS || "3000", 10) || 3e3,
5816
+ onUpdateRequired: ({ minimumSupported, updateCommand, message }) => {
5817
+ const note = message ? `
5818
+ ${message}` : "";
5819
+ console.error(
5820
+ `CLI update required (installed: ${packageJson.version}, required: ${minimumSupported})${note}
5821
+ Update: ${updateCommand}`
5822
+ );
5823
+ },
5792
5824
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
5793
5825
  const note = message ? `
5794
5826
  ${message}` : "";
@@ -5798,12 +5830,7 @@ Update: ${updateCommand}`);
5798
5830
  });
5799
5831
  } catch (err) {
5800
5832
  const msg = err instanceof Error ? err.message : String(err);
5801
- if (/^CLI update required\b/i.test(msg)) {
5802
- console.error(msg);
5803
- process.exit(1);
5804
- } else {
5805
- logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5806
- }
5833
+ logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5807
5834
  }
5808
5835
  logger.debug("[DAEMON RUN] Auth and machine setup complete");
5809
5836
  const shouldStartUnrealMcp = String(process.env.FLOCKBAY_UNREAL_MCP_ENABLED || "").trim() === "1";
@@ -6579,10 +6606,18 @@ Log: ${logPath || `not found (check ${configuration.logsDir})`}` + formatLogExce
6579
6606
  cliPolicyCheckInFlight = true;
6580
6607
  lastCliPolicyCheckAtMs = Date.now();
6581
6608
  try {
6582
- await enforceCliVersionPolicy({
6609
+ const { evaluation } = await enforceCliVersionPolicy({
6583
6610
  serverUrl: configuration.serverUrl,
6584
6611
  currentVersion: packageJson.version,
6585
6612
  timeoutMs: Number.parseInt(process.env.FLOCKBAY_CLI_VERSION_CHECK_TIMEOUT_MS || "3000", 10) || 3e3,
6613
+ onUpdateRequired: ({ minimumSupported, updateCommand, message }) => {
6614
+ const note = message ? `
6615
+ ${message}` : "";
6616
+ logger.debug(
6617
+ `[DAEMON RUN] CLI update required (installed: ${packageJson.version}, required: ${minimumSupported}).${note}
6618
+ Update: ${updateCommand}`
6619
+ );
6620
+ },
6586
6621
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
6587
6622
  const note = message ? `
6588
6623
  ${message}` : "";
@@ -6592,13 +6627,10 @@ Update: ${updateCommand}`
6592
6627
  );
6593
6628
  }
6594
6629
  });
6630
+ if (evaluation.status === "update_required") {
6631
+ }
6595
6632
  } catch (err) {
6596
6633
  const msg = err instanceof Error ? err.message : String(err);
6597
- if (/^CLI update required\b/i.test(msg)) {
6598
- logger.debug("[DAEMON RUN] CLI update required; shutting down daemon:", msg);
6599
- requestShutdown("exception", msg);
6600
- return;
6601
- }
6602
6634
  logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
6603
6635
  } finally {
6604
6636
  cliPolicyCheckInFlight = false;
@@ -14882,7 +14914,8 @@ async function startDaemonDetachedOrExit(opts) {
14882
14914
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14883
14915
  console.log("");
14884
14916
  if (opts?.openWebapp) openUrlBestEffort(configuration.webappUrl);
14885
- process.exit(0);
14917
+ process.exitCode = 0;
14918
+ return;
14886
14919
  }
14887
14920
  const authMismatch = lastUpsertStatus === 401 || /unauthorized/i.test(lastConnectError);
14888
14921
  if (authMismatch && !opts?.reauthAttempted) {
@@ -14953,7 +14986,8 @@ async function startDaemonDetachedOrExit(opts) {
14953
14986
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14954
14987
  console.log("");
14955
14988
  if (opts?.openWebapp) openUrlBestEffort(configuration.webappUrl);
14956
- process.exit(0);
14989
+ process.exitCode = 0;
14990
+ return;
14957
14991
  } else {
14958
14992
  const latest = await getLatestDaemonLog();
14959
14993
  if (latest?.path) console.error(`Latest daemon log: ${latest.path}`);
@@ -15083,7 +15117,7 @@ async function authAndSetupMachineIfNeeded() {
15083
15117
  process.exit(1);
15084
15118
  }
15085
15119
  try {
15086
- const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-BenVKITz.mjs');
15120
+ const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-DAAX2TDX.mjs');
15087
15121
  const result = migrateUnrealMcpToFlockbayMcp({
15088
15122
  engineRoot,
15089
15123
  projectUprojectPath: project || void 0,
@@ -15222,7 +15256,7 @@ ${engineRoot}`, {
15222
15256
  } else if (subcommand === "codex") {
15223
15257
  try {
15224
15258
  await chdirToNearestUprojectRootIfPresent();
15225
- const { runCodex } = await import('./runCodex-aBjsormW.mjs');
15259
+ const { runCodex } = await import('./runCodex-C_dwGw9p.mjs');
15226
15260
  let startedBy = void 0;
15227
15261
  let sessionId = void 0;
15228
15262
  for (let i = 1; i < args.length; i++) {
@@ -15324,7 +15358,7 @@ ${engineRoot}`, {
15324
15358
  }
15325
15359
  try {
15326
15360
  await chdirToNearestUprojectRootIfPresent();
15327
- const { runGemini } = await import('./runGemini-D9bi1Ih3.mjs');
15361
+ const { runGemini } = await import('./runGemini-CWiIoJag.mjs');
15328
15362
  let startedBy = void 0;
15329
15363
  let sessionId = void 0;
15330
15364
  for (let i = 1; i < args.length; i++) {
@@ -3,7 +3,7 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var types = require('./types-DTy-RPNv.cjs');
6
+ var types = require('./types-tRJ8NBIX.cjs');
7
7
  var node_child_process = require('node:child_process');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -1316,7 +1316,7 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
1316
1316
  env[pathKey] = [...prepend, ...existingParts].join(pathSep);
1317
1317
  return env;
1318
1318
  }
1319
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Bih-iANW.cjs', document.baseURI).href)));
1319
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-CVBvClyV.cjs', document.baseURI).href)));
1320
1320
  const __dirname$1 = path.join(__filename$1, "..");
1321
1321
  function getGlobalClaudeVersion(claudeExecutable) {
1322
1322
  try {
@@ -5283,13 +5283,35 @@ function resolveTsxImportArgs(projectRoot) {
5283
5283
  path.join(projectRoot, "node_modules", "tsx", "dist", "index.js")
5284
5284
  ];
5285
5285
  const resolved = candidates.find(fs.existsSync);
5286
- return resolved ? ["--import", resolved] : ["--import", "tsx"];
5286
+ return resolved ? ["--import", toNodeSpecifier(resolved)] : ["--import", "tsx"];
5287
+ }
5288
+ function toNodeSpecifier(p) {
5289
+ if (process$1.platform !== "win32") return p;
5290
+ if (!/^[a-zA-Z]:[\\/]/.test(p)) return p;
5291
+ return node_url.pathToFileURL(p).href;
5287
5292
  }
5288
5293
  function spawnFlockbayCLI(args, options = {}) {
5289
5294
  const projectRoot = types.projectPath();
5290
5295
  const distEntrypoint = path.join(projectRoot, "dist", "index.mjs");
5291
5296
  const devEntrypoint = path.join(projectRoot, "src", "index.ts");
5292
- const entrypoint = fs.existsSync(distEntrypoint) ? distEntrypoint : devEntrypoint;
5297
+ const entrypoint = (() => {
5298
+ const forceSrc = process$1.env.FLOCKBAY_USE_SRC === "1";
5299
+ const forceDist = process$1.env.FLOCKBAY_USE_DIST === "1";
5300
+ const hasDist = fs.existsSync(distEntrypoint);
5301
+ const hasDev = fs.existsSync(devEntrypoint);
5302
+ if (forceSrc && hasDev) return devEntrypoint;
5303
+ if (forceDist && hasDist) return distEntrypoint;
5304
+ if (hasDist && hasDev) {
5305
+ try {
5306
+ const devTime = fs.statSync(devEntrypoint).mtimeMs;
5307
+ const distTime = fs.statSync(distEntrypoint).mtimeMs;
5308
+ if (devTime > distTime) return devEntrypoint;
5309
+ } catch {
5310
+ }
5311
+ return distEntrypoint;
5312
+ }
5313
+ return hasDist ? distEntrypoint : devEntrypoint;
5314
+ })();
5293
5315
  const useTsx = entrypoint.endsWith(".ts");
5294
5316
  const desiredCwd = "cwd" in options && typeof options.cwd === "string" ? options.cwd : process$1.cwd();
5295
5317
  const windowsHide = typeof options?.windowsHide === "boolean" ? Boolean(options.windowsHide) : process$1.platform === "win32";
@@ -5705,12 +5727,14 @@ async function enforceCliVersionPolicy(opts) {
5705
5727
  const policy = await fetchCliVersionPolicy({ serverUrl: opts.serverUrl, timeoutMs: opts.timeoutMs });
5706
5728
  const evaluation = evaluateCliVersion({ currentVersion, policy });
5707
5729
  if (evaluation.status === "update_required") {
5708
- const header = `CLI update required (installed: ${currentVersion}, required: ${evaluation.minimumSupported})`;
5709
- const msg = evaluation.message ? `
5710
- ${evaluation.message}` : "";
5711
- const help = `
5712
- Update: ${evaluation.updateCommand}`;
5713
- throw new Error(`${header}${msg}${help}`);
5730
+ try {
5731
+ opts.onUpdateRequired?.({
5732
+ minimumSupported: evaluation.minimumSupported,
5733
+ updateCommand: evaluation.updateCommand,
5734
+ message: evaluation.message
5735
+ });
5736
+ } catch {
5737
+ }
5714
5738
  }
5715
5739
  if (evaluation.status === "update_available") {
5716
5740
  try {
@@ -5811,6 +5835,14 @@ async function startDaemon() {
5811
5835
  serverUrl: types.configuration.serverUrl,
5812
5836
  currentVersion: types.packageJson.version,
5813
5837
  timeoutMs: Number.parseInt(process.env.FLOCKBAY_CLI_VERSION_CHECK_TIMEOUT_MS || "3000", 10) || 3e3,
5838
+ onUpdateRequired: ({ minimumSupported, updateCommand, message }) => {
5839
+ const note = message ? `
5840
+ ${message}` : "";
5841
+ console.error(
5842
+ `CLI update required (installed: ${types.packageJson.version}, required: ${minimumSupported})${note}
5843
+ Update: ${updateCommand}`
5844
+ );
5845
+ },
5814
5846
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
5815
5847
  const note = message ? `
5816
5848
  ${message}` : "";
@@ -5820,12 +5852,7 @@ Update: ${updateCommand}`);
5820
5852
  });
5821
5853
  } catch (err) {
5822
5854
  const msg = err instanceof Error ? err.message : String(err);
5823
- if (/^CLI update required\b/i.test(msg)) {
5824
- console.error(msg);
5825
- process.exit(1);
5826
- } else {
5827
- types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5828
- }
5855
+ types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5829
5856
  }
5830
5857
  types.logger.debug("[DAEMON RUN] Auth and machine setup complete");
5831
5858
  const shouldStartUnrealMcp = String(process.env.FLOCKBAY_UNREAL_MCP_ENABLED || "").trim() === "1";
@@ -6601,10 +6628,18 @@ Log: ${logPath || `not found (check ${types.configuration.logsDir})`}` + formatL
6601
6628
  cliPolicyCheckInFlight = true;
6602
6629
  lastCliPolicyCheckAtMs = Date.now();
6603
6630
  try {
6604
- await enforceCliVersionPolicy({
6631
+ const { evaluation } = await enforceCliVersionPolicy({
6605
6632
  serverUrl: types.configuration.serverUrl,
6606
6633
  currentVersion: types.packageJson.version,
6607
6634
  timeoutMs: Number.parseInt(process.env.FLOCKBAY_CLI_VERSION_CHECK_TIMEOUT_MS || "3000", 10) || 3e3,
6635
+ onUpdateRequired: ({ minimumSupported, updateCommand, message }) => {
6636
+ const note = message ? `
6637
+ ${message}` : "";
6638
+ types.logger.debug(
6639
+ `[DAEMON RUN] CLI update required (installed: ${types.packageJson.version}, required: ${minimumSupported}).${note}
6640
+ Update: ${updateCommand}`
6641
+ );
6642
+ },
6608
6643
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
6609
6644
  const note = message ? `
6610
6645
  ${message}` : "";
@@ -6614,13 +6649,10 @@ Update: ${updateCommand}`
6614
6649
  );
6615
6650
  }
6616
6651
  });
6652
+ if (evaluation.status === "update_required") {
6653
+ }
6617
6654
  } catch (err) {
6618
6655
  const msg = err instanceof Error ? err.message : String(err);
6619
- if (/^CLI update required\b/i.test(msg)) {
6620
- types.logger.debug("[DAEMON RUN] CLI update required; shutting down daemon:", msg);
6621
- requestShutdown("exception", msg);
6622
- return;
6623
- }
6624
6656
  types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
6625
6657
  } finally {
6626
6658
  cliPolicyCheckInFlight = false;
@@ -14904,7 +14936,8 @@ async function startDaemonDetachedOrExit(opts) {
14904
14936
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14905
14937
  console.log("");
14906
14938
  if (opts?.openWebapp) openUrlBestEffort(types.configuration.webappUrl);
14907
- process.exit(0);
14939
+ process.exitCode = 0;
14940
+ return;
14908
14941
  }
14909
14942
  const authMismatch = lastUpsertStatus === 401 || /unauthorized/i.test(lastConnectError);
14910
14943
  if (authMismatch && !opts?.reauthAttempted) {
@@ -14975,7 +15008,8 @@ async function startDaemonDetachedOrExit(opts) {
14975
15008
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14976
15009
  console.log("");
14977
15010
  if (opts?.openWebapp) openUrlBestEffort(types.configuration.webappUrl);
14978
- process.exit(0);
15011
+ process.exitCode = 0;
15012
+ return;
14979
15013
  } else {
14980
15014
  const latest = await types.getLatestDaemonLog();
14981
15015
  if (latest?.path) console.error(`Latest daemon log: ${latest.path}`);
@@ -15105,7 +15139,7 @@ async function authAndSetupMachineIfNeeded() {
15105
15139
  process.exit(1);
15106
15140
  }
15107
15141
  try {
15108
- const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-CrSh19dY.cjs'); });
15142
+ const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-BL02mitg.cjs'); });
15109
15143
  const result = migrateUnrealMcpToFlockbayMcp({
15110
15144
  engineRoot,
15111
15145
  projectUprojectPath: project || void 0,
@@ -15244,7 +15278,7 @@ ${engineRoot}`, {
15244
15278
  } else if (subcommand === "codex") {
15245
15279
  try {
15246
15280
  await chdirToNearestUprojectRootIfPresent();
15247
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-CJa61r9H.cjs'); });
15281
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-DcQmhprg.cjs'); });
15248
15282
  let startedBy = void 0;
15249
15283
  let sessionId = void 0;
15250
15284
  for (let i = 1; i < args.length; i++) {
@@ -15346,7 +15380,7 @@ ${engineRoot}`, {
15346
15380
  }
15347
15381
  try {
15348
15382
  await chdirToNearestUprojectRootIfPresent();
15349
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-gcPF3ASy.cjs'); });
15383
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CJF0id5I.cjs'); });
15350
15384
  let startedBy = void 0;
15351
15385
  let sessionId = void 0;
15352
15386
  for (let i = 1; i < args.length; i++) {
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-Bih-iANW.cjs');
5
- require('./types-DTy-RPNv.cjs');
4
+ require('./index-CVBvClyV.cjs');
5
+ require('./types-tRJ8NBIX.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:fs');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-ZFx58JSw.mjs';
3
- import './types-1s9-Oj5w.mjs';
2
+ import './index-BfBX93aY.mjs';
3
+ import './types-D8EqTVgB.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:fs';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-DTy-RPNv.cjs');
3
+ var types = require('./types-tRJ8NBIX.cjs');
4
4
  require('axios');
5
5
  require('node:fs');
6
6
  require('node:os');
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-1s9-Oj5w.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-D8EqTVgB.mjs';
2
2
  import 'axios';
3
3
  import 'node:fs';
4
4
  import 'node:os';
@@ -2,7 +2,7 @@
2
2
 
3
3
  var fs = require('node:fs');
4
4
  var path = require('node:path');
5
- var types = require('./types-DTy-RPNv.cjs');
5
+ var types = require('./types-tRJ8NBIX.cjs');
6
6
  require('axios');
7
7
  require('node:os');
8
8
  require('node:events');
@@ -1,6 +1,6 @@
1
1
  import fs__default from 'node:fs';
2
2
  import path__default from 'node:path';
3
- import { i as installUnrealMcpPluginToEngine } from './types-1s9-Oj5w.mjs';
3
+ import { i as installUnrealMcpPluginToEngine } from './types-D8EqTVgB.mjs';
4
4
  import 'axios';
5
5
  import 'node:os';
6
6
  import 'node:events';
@@ -1,6 +1,6 @@
1
1
  import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
- import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-1s9-Oj5w.mjs';
3
+ import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-D8EqTVgB.mjs';
4
4
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5
5
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
6
6
  import { z } from 'zod';
@@ -10,7 +10,7 @@ import fs__default from 'node:fs';
10
10
  import os__default from 'node:os';
11
11
  import path__default, { resolve, join } from 'node:path';
12
12
  import { spawnSync } from 'node:child_process';
13
- import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-ZFx58JSw.mjs';
13
+ import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-BfBX93aY.mjs';
14
14
  import 'axios';
15
15
  import 'node:events';
16
16
  import 'socket.io-client';
@@ -2,7 +2,7 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-DTy-RPNv.cjs');
5
+ var types = require('./types-tRJ8NBIX.cjs');
6
6
  var index_js = require('@modelcontextprotocol/sdk/client/index.js');
7
7
  var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
8
8
  var z = require('zod');
@@ -12,7 +12,7 @@ var fs = require('node:fs');
12
12
  var os = require('node:os');
13
13
  var path = require('node:path');
14
14
  var node_child_process = require('node:child_process');
15
- var index = require('./index-Bih-iANW.cjs');
15
+ var index = require('./index-CVBvClyV.cjs');
16
16
  require('axios');
17
17
  require('node:events');
18
18
  require('socket.io-client');
@@ -6,8 +6,8 @@ var node_crypto = require('node:crypto');
6
6
  var os = require('node:os');
7
7
  var path = require('node:path');
8
8
  var fs$2 = require('node:fs/promises');
9
- var types = require('./types-DTy-RPNv.cjs');
10
- var index = require('./index-Bih-iANW.cjs');
9
+ var types = require('./types-tRJ8NBIX.cjs');
10
+ var index = require('./index-CVBvClyV.cjs');
11
11
  var node_child_process = require('node:child_process');
12
12
  var sdk = require('@agentclientprotocol/sdk');
13
13
  var fs = require('fs');
@@ -4,8 +4,8 @@ import { randomUUID, createHash } from 'node:crypto';
4
4
  import os__default from 'node:os';
5
5
  import path__default, { resolve, join as join$1, basename } from 'node:path';
6
6
  import { mkdir, writeFile, readFile } from 'node:fs/promises';
7
- import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-1s9-Oj5w.mjs';
8
- import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, o as extractUserImagesMarker, p as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, j as autoFinalizeCoordinationWorkItem, E as ElicitationHub, k as detectScreenshotsForGate, m as stopCaffeinate } from './index-ZFx58JSw.mjs';
7
+ import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-D8EqTVgB.mjs';
8
+ import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, o as extractUserImagesMarker, p as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, j as autoFinalizeCoordinationWorkItem, E as ElicitationHub, k as detectScreenshotsForGate, m as stopCaffeinate } from './index-BfBX93aY.mjs';
9
9
  import { spawn, spawnSync } from 'node:child_process';
10
10
  import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
11
11
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
@@ -23,7 +23,7 @@ import { createServer } from 'http';
23
23
  import open$2 from 'open';
24
24
 
25
25
  var name = "flockbay";
26
- var version = "0.10.43";
26
+ var version = "0.10.44";
27
27
  var description = "Flockbay CLI (local agent + daemon)";
28
28
  var author = "Eduardo Orellana";
29
29
  var license = "UNLICENSED";
@@ -3397,11 +3397,11 @@ function createBackoff(opts) {
3397
3397
  }
3398
3398
  let backoff = createBackoff();
3399
3399
 
3400
- function looksLikeEngineRoot(engineRoot) {
3400
+ function looksLikeEngineRoot$1(engineRoot) {
3401
3401
  if (!engineRoot) return false;
3402
3402
  return fs__default.existsSync(path__default.join(engineRoot, "Engine")) && fs__default.existsSync(path__default.join(engineRoot, "Engine", "Plugins"));
3403
3403
  }
3404
- function findFilesNamedUnderDir(options) {
3404
+ function findFilesNamedUnderDir$1(options) {
3405
3405
  const rootDir = options.rootDir;
3406
3406
  const filename = options.filename;
3407
3407
  const maxDepth = Math.max(0, Math.floor(options.maxDepth));
@@ -3429,7 +3429,7 @@ function findFilesNamedUnderDir(options) {
3429
3429
  }
3430
3430
  function installUnrealMcpPluginToEngine(engineRootRaw) {
3431
3431
  const engineRoot = (engineRootRaw || "").trim();
3432
- if (!looksLikeEngineRoot(engineRoot)) {
3432
+ if (!looksLikeEngineRoot$1(engineRoot)) {
3433
3433
  return {
3434
3434
  ok: false,
3435
3435
  errorMessage: `Invalid engine root (expected an Unreal Engine install folder containing Engine/\u2026): ${engineRoot || "(empty)"}`
@@ -3443,7 +3443,7 @@ function installUnrealMcpPluginToEngine(engineRootRaw) {
3443
3443
  const destUpluginPath = path__default.join(destDir, "FlockbayMCP.uplugin");
3444
3444
  try {
3445
3445
  const enginePluginsDir = path__default.join(engineRoot, "Engine", "Plugins");
3446
- const candidates = findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 });
3446
+ const candidates = findFilesNamedUnderDir$1({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 });
3447
3447
  const otherCopies = candidates.map((p) => path__default.resolve(p)).filter((p) => !p.startsWith(path__default.resolve(destDir) + path__default.sep));
3448
3448
  if (otherCopies.length > 0) {
3449
3449
  return {
@@ -3463,7 +3463,7 @@ Fix:
3463
3463
  - Re-run the Flockbay MCP plugin install, then restart Unreal Editor so it rebuilds the plugin`
3464
3464
  };
3465
3465
  }
3466
- const legacyCandidates = findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 });
3466
+ const legacyCandidates = findFilesNamedUnderDir$1({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 });
3467
3467
  if (legacyCandidates.length > 0) {
3468
3468
  return {
3469
3469
  ok: false,
@@ -3542,7 +3542,7 @@ Error: ${message}`
3542
3542
  }
3543
3543
  }
3544
3544
 
3545
- function readJsonIfPossible(filePath) {
3545
+ function readJsonIfPossible$1(filePath) {
3546
3546
  try {
3547
3547
  return JSON.parse(fs__default.readFileSync(filePath, "utf8"));
3548
3548
  } catch {
@@ -3553,7 +3553,7 @@ function writeJsonPretty(filePath, value) {
3553
3553
  fs__default.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
3554
3554
  }
3555
3555
  function ensureProjectPluginEnabled(uprojectPath, pluginName) {
3556
- const parsed = readJsonIfPossible(uprojectPath);
3556
+ const parsed = readJsonIfPossible$1(uprojectPath);
3557
3557
  if (!parsed || typeof parsed !== "object") {
3558
3558
  return { ok: false, error: `Invalid .uproject (expected JSON): ${uprojectPath}` };
3559
3559
  }
@@ -3638,7 +3638,7 @@ Fix:
3638
3638
  Expected: ${destUpluginPath}`
3639
3639
  };
3640
3640
  }
3641
- const uplugin = readJsonIfPossible(destUpluginPath);
3641
+ const uplugin = readJsonIfPossible$1(destUpluginPath);
3642
3642
  const friendlyName = typeof uplugin?.FriendlyName === "string" ? uplugin.FriendlyName : null;
3643
3643
  const createdBy = typeof uplugin?.CreatedBy === "string" ? uplugin.CreatedBy : null;
3644
3644
  if (friendlyName !== "Flockbay MCP" || createdBy !== "Respaced Inc.") {
@@ -3800,6 +3800,182 @@ Log: ${buildLogPath}`
3800
3800
  return { ok: true, buildLogPath };
3801
3801
  }
3802
3802
 
3803
+ function canWriteDir$1(dir) {
3804
+ const root = String(dir || "").trim();
3805
+ if (!root) return false;
3806
+ try {
3807
+ const tmp = path__default.join(root, `.__flockbay_write_test_${Date.now()}_${Math.random().toString(16).slice(2)}.tmp`);
3808
+ fs__default.writeFileSync(tmp, "ok", "utf8");
3809
+ fs__default.unlinkSync(tmp);
3810
+ return true;
3811
+ } catch {
3812
+ return false;
3813
+ }
3814
+ }
3815
+ function looksLikeEngineRoot(engineRoot) {
3816
+ if (!engineRoot) return false;
3817
+ return fs__default.existsSync(path__default.join(engineRoot, "Engine", "Plugins"));
3818
+ }
3819
+ function readJsonIfPossible(filePath) {
3820
+ try {
3821
+ return JSON.parse(fs__default.readFileSync(filePath, "utf8"));
3822
+ } catch {
3823
+ return null;
3824
+ }
3825
+ }
3826
+ function isPluginDescriptorOk(parsed) {
3827
+ const friendlyName = typeof parsed?.FriendlyName === "string" ? parsed.FriendlyName : null;
3828
+ const createdBy = typeof parsed?.CreatedBy === "string" ? parsed.CreatedBy : null;
3829
+ return friendlyName === "Flockbay MCP" && createdBy === "Respaced Inc.";
3830
+ }
3831
+ function isPathUnderDir(childPath, parentDir) {
3832
+ const child = path__default.resolve(childPath);
3833
+ const parent = path__default.resolve(parentDir);
3834
+ return child === parent || child.startsWith(parent + path__default.sep);
3835
+ }
3836
+ function findFilesNamedUnderDir(options) {
3837
+ const rootDir = options.rootDir;
3838
+ const filename = options.filename;
3839
+ const maxDepth = Math.max(0, Math.floor(options.maxDepth));
3840
+ const results = [];
3841
+ const visit = (dir, depth) => {
3842
+ if (depth > maxDepth) return;
3843
+ let entries = [];
3844
+ try {
3845
+ entries = fs__default.readdirSync(dir, { withFileTypes: true });
3846
+ } catch {
3847
+ return;
3848
+ }
3849
+ for (const entry of entries) {
3850
+ if (entry.name === ".DS_Store") continue;
3851
+ const full = path__default.join(dir, entry.name);
3852
+ if (entry.isDirectory()) {
3853
+ visit(full, depth + 1);
3854
+ continue;
3855
+ }
3856
+ if (entry.isFile() && entry.name === filename) results.push(full);
3857
+ }
3858
+ };
3859
+ visit(rootDir, 0);
3860
+ return results;
3861
+ }
3862
+ function readUprojectPluginEnabled(uprojectPath, pluginName) {
3863
+ const parsed = readJsonIfPossible(uprojectPath);
3864
+ if (!parsed || typeof parsed !== "object") {
3865
+ return { ok: false, error: `Invalid .uproject (expected JSON): ${uprojectPath}` };
3866
+ }
3867
+ const plugins = Array.isArray(parsed.Plugins) ? parsed.Plugins : [];
3868
+ for (const p of plugins) {
3869
+ if (!p || typeof p !== "object") continue;
3870
+ if (p.Name === pluginName) return { ok: true, enabled: p.Enabled === true };
3871
+ }
3872
+ return { ok: true, enabled: false };
3873
+ }
3874
+ function getUnrealMcpPluginDiskStatus(params) {
3875
+ const checkedAtMs = Date.now();
3876
+ const engineRoot = String(params?.engineRoot || "").trim();
3877
+ const installScope = String(params?.installScope || "auto");
3878
+ const projectUprojectPathRaw = typeof params?.projectUprojectPath === "string" ? params.projectUprojectPath.trim() : "";
3879
+ if (!engineRoot) return { success: false, error: "Missing engineRoot." };
3880
+ if (!looksLikeEngineRoot(engineRoot)) {
3881
+ return { success: false, error: `Invalid engine root (expected an Unreal Engine install folder containing Engine/Plugins): ${engineRoot}` };
3882
+ }
3883
+ const enginePluginsDir = path__default.join(engineRoot, "Engine", "Plugins");
3884
+ const enginePluginDir = path__default.join(enginePluginsDir, "FlockbayMCP");
3885
+ const engineUpluginPath = path__default.join(enginePluginDir, "FlockbayMCP.uplugin");
3886
+ const engineDescriptor = fs__default.existsSync(engineUpluginPath) ? readJsonIfPossible(engineUpluginPath) : null;
3887
+ const engineInfo = {
3888
+ pluginDir: enginePluginDir,
3889
+ upluginPath: engineUpluginPath,
3890
+ exists: fs__default.existsSync(engineUpluginPath),
3891
+ descriptorOk: engineDescriptor ? isPluginDescriptorOk(engineDescriptor) : false,
3892
+ hasBinaries: fs__default.existsSync(path__default.join(enginePluginDir, "Binaries")),
3893
+ enginePluginsWritable: canWriteDir$1(enginePluginsDir),
3894
+ conflicts: [],
3895
+ legacy: []
3896
+ };
3897
+ const conflictSet = /* @__PURE__ */ new Set();
3898
+ const legacySet = /* @__PURE__ */ new Set();
3899
+ const fastCandidates = [
3900
+ path__default.join(enginePluginsDir, "Marketplace", "FlockbayMCP", "FlockbayMCP.uplugin"),
3901
+ path__default.join(enginePluginsDir, "Marketplace", "UnrealMCP", "UnrealMCP.uplugin"),
3902
+ path__default.join(enginePluginsDir, "UnrealMCP", "UnrealMCP.uplugin")
3903
+ ];
3904
+ for (const p of fastCandidates) {
3905
+ if (fs__default.existsSync(p)) {
3906
+ if (p.toLowerCase().endsWith("unrealmcp.uplugin")) legacySet.add(path__default.resolve(p));
3907
+ if (p.toLowerCase().endsWith("flockbaymcp.uplugin")) conflictSet.add(path__default.resolve(p));
3908
+ }
3909
+ }
3910
+ for (const p of findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 })) {
3911
+ const resolved = path__default.resolve(p);
3912
+ if (isPathUnderDir(resolved, enginePluginDir)) continue;
3913
+ conflictSet.add(resolved);
3914
+ }
3915
+ for (const p of findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 })) {
3916
+ legacySet.add(path__default.resolve(p));
3917
+ }
3918
+ engineInfo.conflicts = Array.from(conflictSet).sort();
3919
+ engineInfo.legacy = Array.from(legacySet).sort();
3920
+ const project = (() => {
3921
+ if (!projectUprojectPathRaw) return null;
3922
+ const uprojectPath = path__default.resolve(projectUprojectPathRaw);
3923
+ if (!uprojectPath.toLowerCase().endsWith(".uproject")) {
3924
+ return { error: `Invalid .uproject path (expected *.uproject): ${uprojectPath}` };
3925
+ }
3926
+ if (!fs__default.existsSync(uprojectPath)) {
3927
+ return { error: `Missing .uproject: ${uprojectPath}` };
3928
+ }
3929
+ const projectRoot = path__default.dirname(uprojectPath);
3930
+ const pluginDir = path__default.join(projectRoot, "Plugins", "FlockbayMCP");
3931
+ const upluginPath = path__default.join(pluginDir, "FlockbayMCP.uplugin");
3932
+ const descriptor = fs__default.existsSync(upluginPath) ? readJsonIfPossible(upluginPath) : null;
3933
+ const enabled = readUprojectPluginEnabled(uprojectPath, "FlockbayMCP");
3934
+ if (!enabled.ok) return { error: enabled.error };
3935
+ return {
3936
+ uprojectPath,
3937
+ pluginDir,
3938
+ upluginPath,
3939
+ exists: fs__default.existsSync(upluginPath),
3940
+ descriptorOk: descriptor ? isPluginDescriptorOk(descriptor) : false,
3941
+ enabledInUproject: enabled.enabled
3942
+ };
3943
+ })();
3944
+ if (project && "error" in project) return { success: false, error: project.error };
3945
+ if (installScope === "project" && !project) {
3946
+ return { success: false, error: "Missing projectUprojectPath (required for installScope=project)." };
3947
+ }
3948
+ const engineInstalled = engineInfo.exists && engineInfo.descriptorOk && engineInfo.hasBinaries;
3949
+ const projectInstalled = Boolean(project && project.exists && project.descriptorOk && project.enabledInUproject);
3950
+ const effectiveScope = installScope === "engine" ? "engine" : installScope === "project" ? "project" : engineInstalled ? "engine" : project && !engineInfo.enginePluginsWritable ? "project" : "engine";
3951
+ const conflict = engineInfo.conflicts.length > 0;
3952
+ const legacyConflict = engineInfo.legacy.length > 0;
3953
+ const baseInstalled = effectiveScope === "engine" ? engineInstalled : projectInstalled;
3954
+ const installed = baseInstalled && !conflict && !legacyConflict;
3955
+ const status = conflict ? "conflict" : legacyConflict ? "legacy_conflict" : installed ? "ok" : "not_installed";
3956
+ const fix = status === "conflict" ? [
3957
+ "Close Unreal Editor.",
3958
+ "Delete/rename the conflicting FlockbayMCP plugin folder(s) listed under engine.conflicts.",
3959
+ "Ensure there is only ONE FlockbayMCP.uplugin under Engine/Plugins (common conflict: Engine/Plugins/Marketplace/FlockbayMCP).",
3960
+ "Reinstall the plugin and restart Unreal Editor so it rebuilds the plugin binaries."
3961
+ ] : status === "legacy_conflict" ? [
3962
+ "Close Unreal Editor.",
3963
+ "Delete/rename the legacy UnrealMCP plugin folder(s) listed under engine.legacy.",
3964
+ "Reinstall the Flockbay MCP plugin and restart Unreal Editor."
3965
+ ] : void 0;
3966
+ return {
3967
+ success: true,
3968
+ checkedAtMs,
3969
+ engineRoot,
3970
+ effectiveScope,
3971
+ installed,
3972
+ status,
3973
+ engine: engineInfo,
3974
+ project: project || void 0,
3975
+ fix
3976
+ };
3977
+ }
3978
+
3803
3979
  async function openBrowser(url) {
3804
3980
  try {
3805
3981
  const forceOpen = process.env.FLOCKBAY_FORCE_BROWSER === "1" || process.env.FLOCKBAY_FORCE_BROWSER === "true";
@@ -4525,6 +4701,10 @@ class ApiMachineClient {
4525
4701
  return { success: true, engineRoot: result.engineRoot, destDir: result.destDir };
4526
4702
  }
4527
4703
  );
4704
+ this.rpcHandlerManager.registerHandler(
4705
+ "unreal-mcp-plugin-disk-status",
4706
+ async (params) => getUnrealMcpPluginDiskStatus(params)
4707
+ );
4528
4708
  }
4529
4709
  socket;
4530
4710
  keepAliveInterval = null;
@@ -44,7 +44,7 @@ function _interopNamespaceDefault(e) {
44
44
  var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
45
45
 
46
46
  var name = "flockbay";
47
- var version = "0.10.43";
47
+ var version = "0.10.44";
48
48
  var description = "Flockbay CLI (local agent + daemon)";
49
49
  var author = "Eduardo Orellana";
50
50
  var license = "UNLICENSED";
@@ -774,7 +774,7 @@ class RpcHandlerManager {
774
774
  }
775
775
  }
776
776
 
777
- const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-DTy-RPNv.cjs', document.baseURI).href))));
777
+ const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-tRJ8NBIX.cjs', document.baseURI).href))));
778
778
  function projectPath() {
779
779
  const path = path$1.resolve(__dirname$1, "..");
780
780
  return path;
@@ -3418,11 +3418,11 @@ function createBackoff(opts) {
3418
3418
  }
3419
3419
  let backoff = createBackoff();
3420
3420
 
3421
- function looksLikeEngineRoot(engineRoot) {
3421
+ function looksLikeEngineRoot$1(engineRoot) {
3422
3422
  if (!engineRoot) return false;
3423
3423
  return fs.existsSync(path.join(engineRoot, "Engine")) && fs.existsSync(path.join(engineRoot, "Engine", "Plugins"));
3424
3424
  }
3425
- function findFilesNamedUnderDir(options) {
3425
+ function findFilesNamedUnderDir$1(options) {
3426
3426
  const rootDir = options.rootDir;
3427
3427
  const filename = options.filename;
3428
3428
  const maxDepth = Math.max(0, Math.floor(options.maxDepth));
@@ -3450,7 +3450,7 @@ function findFilesNamedUnderDir(options) {
3450
3450
  }
3451
3451
  function installUnrealMcpPluginToEngine(engineRootRaw) {
3452
3452
  const engineRoot = (engineRootRaw || "").trim();
3453
- if (!looksLikeEngineRoot(engineRoot)) {
3453
+ if (!looksLikeEngineRoot$1(engineRoot)) {
3454
3454
  return {
3455
3455
  ok: false,
3456
3456
  errorMessage: `Invalid engine root (expected an Unreal Engine install folder containing Engine/\u2026): ${engineRoot || "(empty)"}`
@@ -3464,7 +3464,7 @@ function installUnrealMcpPluginToEngine(engineRootRaw) {
3464
3464
  const destUpluginPath = path.join(destDir, "FlockbayMCP.uplugin");
3465
3465
  try {
3466
3466
  const enginePluginsDir = path.join(engineRoot, "Engine", "Plugins");
3467
- const candidates = findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 });
3467
+ const candidates = findFilesNamedUnderDir$1({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 });
3468
3468
  const otherCopies = candidates.map((p) => path.resolve(p)).filter((p) => !p.startsWith(path.resolve(destDir) + path.sep));
3469
3469
  if (otherCopies.length > 0) {
3470
3470
  return {
@@ -3484,7 +3484,7 @@ Fix:
3484
3484
  - Re-run the Flockbay MCP plugin install, then restart Unreal Editor so it rebuilds the plugin`
3485
3485
  };
3486
3486
  }
3487
- const legacyCandidates = findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 });
3487
+ const legacyCandidates = findFilesNamedUnderDir$1({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 });
3488
3488
  if (legacyCandidates.length > 0) {
3489
3489
  return {
3490
3490
  ok: false,
@@ -3563,7 +3563,7 @@ Error: ${message}`
3563
3563
  }
3564
3564
  }
3565
3565
 
3566
- function readJsonIfPossible(filePath) {
3566
+ function readJsonIfPossible$1(filePath) {
3567
3567
  try {
3568
3568
  return JSON.parse(fs.readFileSync(filePath, "utf8"));
3569
3569
  } catch {
@@ -3574,7 +3574,7 @@ function writeJsonPretty(filePath, value) {
3574
3574
  fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
3575
3575
  }
3576
3576
  function ensureProjectPluginEnabled(uprojectPath, pluginName) {
3577
- const parsed = readJsonIfPossible(uprojectPath);
3577
+ const parsed = readJsonIfPossible$1(uprojectPath);
3578
3578
  if (!parsed || typeof parsed !== "object") {
3579
3579
  return { ok: false, error: `Invalid .uproject (expected JSON): ${uprojectPath}` };
3580
3580
  }
@@ -3659,7 +3659,7 @@ Fix:
3659
3659
  Expected: ${destUpluginPath}`
3660
3660
  };
3661
3661
  }
3662
- const uplugin = readJsonIfPossible(destUpluginPath);
3662
+ const uplugin = readJsonIfPossible$1(destUpluginPath);
3663
3663
  const friendlyName = typeof uplugin?.FriendlyName === "string" ? uplugin.FriendlyName : null;
3664
3664
  const createdBy = typeof uplugin?.CreatedBy === "string" ? uplugin.CreatedBy : null;
3665
3665
  if (friendlyName !== "Flockbay MCP" || createdBy !== "Respaced Inc.") {
@@ -3821,6 +3821,182 @@ Log: ${buildLogPath}`
3821
3821
  return { ok: true, buildLogPath };
3822
3822
  }
3823
3823
 
3824
+ function canWriteDir$1(dir) {
3825
+ const root = String(dir || "").trim();
3826
+ if (!root) return false;
3827
+ try {
3828
+ const tmp = path.join(root, `.__flockbay_write_test_${Date.now()}_${Math.random().toString(16).slice(2)}.tmp`);
3829
+ fs.writeFileSync(tmp, "ok", "utf8");
3830
+ fs.unlinkSync(tmp);
3831
+ return true;
3832
+ } catch {
3833
+ return false;
3834
+ }
3835
+ }
3836
+ function looksLikeEngineRoot(engineRoot) {
3837
+ if (!engineRoot) return false;
3838
+ return fs.existsSync(path.join(engineRoot, "Engine", "Plugins"));
3839
+ }
3840
+ function readJsonIfPossible(filePath) {
3841
+ try {
3842
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
3843
+ } catch {
3844
+ return null;
3845
+ }
3846
+ }
3847
+ function isPluginDescriptorOk(parsed) {
3848
+ const friendlyName = typeof parsed?.FriendlyName === "string" ? parsed.FriendlyName : null;
3849
+ const createdBy = typeof parsed?.CreatedBy === "string" ? parsed.CreatedBy : null;
3850
+ return friendlyName === "Flockbay MCP" && createdBy === "Respaced Inc.";
3851
+ }
3852
+ function isPathUnderDir(childPath, parentDir) {
3853
+ const child = path.resolve(childPath);
3854
+ const parent = path.resolve(parentDir);
3855
+ return child === parent || child.startsWith(parent + path.sep);
3856
+ }
3857
+ function findFilesNamedUnderDir(options) {
3858
+ const rootDir = options.rootDir;
3859
+ const filename = options.filename;
3860
+ const maxDepth = Math.max(0, Math.floor(options.maxDepth));
3861
+ const results = [];
3862
+ const visit = (dir, depth) => {
3863
+ if (depth > maxDepth) return;
3864
+ let entries = [];
3865
+ try {
3866
+ entries = fs.readdirSync(dir, { withFileTypes: true });
3867
+ } catch {
3868
+ return;
3869
+ }
3870
+ for (const entry of entries) {
3871
+ if (entry.name === ".DS_Store") continue;
3872
+ const full = path.join(dir, entry.name);
3873
+ if (entry.isDirectory()) {
3874
+ visit(full, depth + 1);
3875
+ continue;
3876
+ }
3877
+ if (entry.isFile() && entry.name === filename) results.push(full);
3878
+ }
3879
+ };
3880
+ visit(rootDir, 0);
3881
+ return results;
3882
+ }
3883
+ function readUprojectPluginEnabled(uprojectPath, pluginName) {
3884
+ const parsed = readJsonIfPossible(uprojectPath);
3885
+ if (!parsed || typeof parsed !== "object") {
3886
+ return { ok: false, error: `Invalid .uproject (expected JSON): ${uprojectPath}` };
3887
+ }
3888
+ const plugins = Array.isArray(parsed.Plugins) ? parsed.Plugins : [];
3889
+ for (const p of plugins) {
3890
+ if (!p || typeof p !== "object") continue;
3891
+ if (p.Name === pluginName) return { ok: true, enabled: p.Enabled === true };
3892
+ }
3893
+ return { ok: true, enabled: false };
3894
+ }
3895
+ function getUnrealMcpPluginDiskStatus(params) {
3896
+ const checkedAtMs = Date.now();
3897
+ const engineRoot = String(params?.engineRoot || "").trim();
3898
+ const installScope = String(params?.installScope || "auto");
3899
+ const projectUprojectPathRaw = typeof params?.projectUprojectPath === "string" ? params.projectUprojectPath.trim() : "";
3900
+ if (!engineRoot) return { success: false, error: "Missing engineRoot." };
3901
+ if (!looksLikeEngineRoot(engineRoot)) {
3902
+ return { success: false, error: `Invalid engine root (expected an Unreal Engine install folder containing Engine/Plugins): ${engineRoot}` };
3903
+ }
3904
+ const enginePluginsDir = path.join(engineRoot, "Engine", "Plugins");
3905
+ const enginePluginDir = path.join(enginePluginsDir, "FlockbayMCP");
3906
+ const engineUpluginPath = path.join(enginePluginDir, "FlockbayMCP.uplugin");
3907
+ const engineDescriptor = fs.existsSync(engineUpluginPath) ? readJsonIfPossible(engineUpluginPath) : null;
3908
+ const engineInfo = {
3909
+ pluginDir: enginePluginDir,
3910
+ upluginPath: engineUpluginPath,
3911
+ exists: fs.existsSync(engineUpluginPath),
3912
+ descriptorOk: engineDescriptor ? isPluginDescriptorOk(engineDescriptor) : false,
3913
+ hasBinaries: fs.existsSync(path.join(enginePluginDir, "Binaries")),
3914
+ enginePluginsWritable: canWriteDir$1(enginePluginsDir),
3915
+ conflicts: [],
3916
+ legacy: []
3917
+ };
3918
+ const conflictSet = /* @__PURE__ */ new Set();
3919
+ const legacySet = /* @__PURE__ */ new Set();
3920
+ const fastCandidates = [
3921
+ path.join(enginePluginsDir, "Marketplace", "FlockbayMCP", "FlockbayMCP.uplugin"),
3922
+ path.join(enginePluginsDir, "Marketplace", "UnrealMCP", "UnrealMCP.uplugin"),
3923
+ path.join(enginePluginsDir, "UnrealMCP", "UnrealMCP.uplugin")
3924
+ ];
3925
+ for (const p of fastCandidates) {
3926
+ if (fs.existsSync(p)) {
3927
+ if (p.toLowerCase().endsWith("unrealmcp.uplugin")) legacySet.add(path.resolve(p));
3928
+ if (p.toLowerCase().endsWith("flockbaymcp.uplugin")) conflictSet.add(path.resolve(p));
3929
+ }
3930
+ }
3931
+ for (const p of findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "FlockbayMCP.uplugin", maxDepth: 6 })) {
3932
+ const resolved = path.resolve(p);
3933
+ if (isPathUnderDir(resolved, enginePluginDir)) continue;
3934
+ conflictSet.add(resolved);
3935
+ }
3936
+ for (const p of findFilesNamedUnderDir({ rootDir: enginePluginsDir, filename: "UnrealMCP.uplugin", maxDepth: 6 })) {
3937
+ legacySet.add(path.resolve(p));
3938
+ }
3939
+ engineInfo.conflicts = Array.from(conflictSet).sort();
3940
+ engineInfo.legacy = Array.from(legacySet).sort();
3941
+ const project = (() => {
3942
+ if (!projectUprojectPathRaw) return null;
3943
+ const uprojectPath = path.resolve(projectUprojectPathRaw);
3944
+ if (!uprojectPath.toLowerCase().endsWith(".uproject")) {
3945
+ return { error: `Invalid .uproject path (expected *.uproject): ${uprojectPath}` };
3946
+ }
3947
+ if (!fs.existsSync(uprojectPath)) {
3948
+ return { error: `Missing .uproject: ${uprojectPath}` };
3949
+ }
3950
+ const projectRoot = path.dirname(uprojectPath);
3951
+ const pluginDir = path.join(projectRoot, "Plugins", "FlockbayMCP");
3952
+ const upluginPath = path.join(pluginDir, "FlockbayMCP.uplugin");
3953
+ const descriptor = fs.existsSync(upluginPath) ? readJsonIfPossible(upluginPath) : null;
3954
+ const enabled = readUprojectPluginEnabled(uprojectPath, "FlockbayMCP");
3955
+ if (!enabled.ok) return { error: enabled.error };
3956
+ return {
3957
+ uprojectPath,
3958
+ pluginDir,
3959
+ upluginPath,
3960
+ exists: fs.existsSync(upluginPath),
3961
+ descriptorOk: descriptor ? isPluginDescriptorOk(descriptor) : false,
3962
+ enabledInUproject: enabled.enabled
3963
+ };
3964
+ })();
3965
+ if (project && "error" in project) return { success: false, error: project.error };
3966
+ if (installScope === "project" && !project) {
3967
+ return { success: false, error: "Missing projectUprojectPath (required for installScope=project)." };
3968
+ }
3969
+ const engineInstalled = engineInfo.exists && engineInfo.descriptorOk && engineInfo.hasBinaries;
3970
+ const projectInstalled = Boolean(project && project.exists && project.descriptorOk && project.enabledInUproject);
3971
+ const effectiveScope = installScope === "engine" ? "engine" : installScope === "project" ? "project" : engineInstalled ? "engine" : project && !engineInfo.enginePluginsWritable ? "project" : "engine";
3972
+ const conflict = engineInfo.conflicts.length > 0;
3973
+ const legacyConflict = engineInfo.legacy.length > 0;
3974
+ const baseInstalled = effectiveScope === "engine" ? engineInstalled : projectInstalled;
3975
+ const installed = baseInstalled && !conflict && !legacyConflict;
3976
+ const status = conflict ? "conflict" : legacyConflict ? "legacy_conflict" : installed ? "ok" : "not_installed";
3977
+ const fix = status === "conflict" ? [
3978
+ "Close Unreal Editor.",
3979
+ "Delete/rename the conflicting FlockbayMCP plugin folder(s) listed under engine.conflicts.",
3980
+ "Ensure there is only ONE FlockbayMCP.uplugin under Engine/Plugins (common conflict: Engine/Plugins/Marketplace/FlockbayMCP).",
3981
+ "Reinstall the plugin and restart Unreal Editor so it rebuilds the plugin binaries."
3982
+ ] : status === "legacy_conflict" ? [
3983
+ "Close Unreal Editor.",
3984
+ "Delete/rename the legacy UnrealMCP plugin folder(s) listed under engine.legacy.",
3985
+ "Reinstall the Flockbay MCP plugin and restart Unreal Editor."
3986
+ ] : void 0;
3987
+ return {
3988
+ success: true,
3989
+ checkedAtMs,
3990
+ engineRoot,
3991
+ effectiveScope,
3992
+ installed,
3993
+ status,
3994
+ engine: engineInfo,
3995
+ project: project || void 0,
3996
+ fix
3997
+ };
3998
+ }
3999
+
3824
4000
  async function openBrowser(url) {
3825
4001
  try {
3826
4002
  const forceOpen = process.env.FLOCKBAY_FORCE_BROWSER === "1" || process.env.FLOCKBAY_FORCE_BROWSER === "true";
@@ -4546,6 +4722,10 @@ class ApiMachineClient {
4546
4722
  return { success: true, engineRoot: result.engineRoot, destDir: result.destDir };
4547
4723
  }
4548
4724
  );
4725
+ this.rpcHandlerManager.registerHandler(
4726
+ "unreal-mcp-plugin-disk-status",
4727
+ async (params) => getUnrealMcpPluginDiskStatus(params)
4728
+ );
4549
4729
  }
4550
4730
  socket;
4551
4731
  keepAliveInterval = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flockbay",
3
- "version": "0.10.43",
3
+ "version": "0.10.44",
4
4
  "description": "Flockbay CLI (local agent + daemon)",
5
5
  "author": "Eduardo Orellana",
6
6
  "license": "UNLICENSED",