flockbay 0.10.42 → 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-D1UKSrkg.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,17 +5261,41 @@ 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();
5295
+ const windowsHide = typeof options?.windowsHide === "boolean" ? Boolean(options.windowsHide) : process$1.platform === "win32";
5273
5296
  const spawnOptions = {
5274
5297
  ...options,
5298
+ windowsHide,
5275
5299
  ...useTsx ? { cwd: projectRoot } : {},
5276
5300
  env: {
5277
5301
  ...process$1.env,
@@ -5681,12 +5705,14 @@ async function enforceCliVersionPolicy(opts) {
5681
5705
  const policy = await fetchCliVersionPolicy({ serverUrl: opts.serverUrl, timeoutMs: opts.timeoutMs });
5682
5706
  const evaluation = evaluateCliVersion({ currentVersion, policy });
5683
5707
  if (evaluation.status === "update_required") {
5684
- const header = `CLI update required (installed: ${currentVersion}, required: ${evaluation.minimumSupported})`;
5685
- const msg = evaluation.message ? `
5686
- ${evaluation.message}` : "";
5687
- const help = `
5688
- Update: ${evaluation.updateCommand}`;
5689
- 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
+ }
5690
5716
  }
5691
5717
  if (evaluation.status === "update_available") {
5692
5718
  try {
@@ -5787,6 +5813,14 @@ async function startDaemon() {
5787
5813
  serverUrl: configuration.serverUrl,
5788
5814
  currentVersion: packageJson.version,
5789
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
+ },
5790
5824
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
5791
5825
  const note = message ? `
5792
5826
  ${message}` : "";
@@ -5796,12 +5830,7 @@ Update: ${updateCommand}`);
5796
5830
  });
5797
5831
  } catch (err) {
5798
5832
  const msg = err instanceof Error ? err.message : String(err);
5799
- if (/^CLI update required\b/i.test(msg)) {
5800
- console.error(msg);
5801
- process.exit(1);
5802
- } else {
5803
- logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5804
- }
5833
+ logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5805
5834
  }
5806
5835
  logger.debug("[DAEMON RUN] Auth and machine setup complete");
5807
5836
  const shouldStartUnrealMcp = String(process.env.FLOCKBAY_UNREAL_MCP_ENABLED || "").trim() === "1";
@@ -6577,10 +6606,18 @@ Log: ${logPath || `not found (check ${configuration.logsDir})`}` + formatLogExce
6577
6606
  cliPolicyCheckInFlight = true;
6578
6607
  lastCliPolicyCheckAtMs = Date.now();
6579
6608
  try {
6580
- await enforceCliVersionPolicy({
6609
+ const { evaluation } = await enforceCliVersionPolicy({
6581
6610
  serverUrl: configuration.serverUrl,
6582
6611
  currentVersion: packageJson.version,
6583
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
+ },
6584
6621
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
6585
6622
  const note = message ? `
6586
6623
  ${message}` : "";
@@ -6590,13 +6627,10 @@ Update: ${updateCommand}`
6590
6627
  );
6591
6628
  }
6592
6629
  });
6630
+ if (evaluation.status === "update_required") {
6631
+ }
6593
6632
  } catch (err) {
6594
6633
  const msg = err instanceof Error ? err.message : String(err);
6595
- if (/^CLI update required\b/i.test(msg)) {
6596
- logger.debug("[DAEMON RUN] CLI update required; shutting down daemon:", msg);
6597
- requestShutdown("exception", msg);
6598
- return;
6599
- }
6600
6634
  logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
6601
6635
  } finally {
6602
6636
  cliPolicyCheckInFlight = false;
@@ -7013,7 +7047,7 @@ ${scriptCandidates.map((p) => `- ${p}`).join("\n")}
7013
7047
  logStream.write(`args: ${JSON.stringify(buildArgs)}
7014
7048
 
7015
7049
  `);
7016
- const child = osPlatform === "win32" ? spawn("cmd.exe", ["/c", script, ...buildArgs], { stdio: ["ignore", "pipe", "pipe"] }) : spawn(script, buildArgs, { stdio: ["ignore", "pipe", "pipe"] });
7050
+ const child = osPlatform === "win32" ? spawn("cmd.exe", ["/c", script, ...buildArgs], { stdio: ["ignore", "pipe", "pipe"], windowsHide: true }) : spawn(script, buildArgs, { stdio: ["ignore", "pipe", "pipe"] });
7017
7051
  let combinedTail = "";
7018
7052
  const appendTail = (chunk) => {
7019
7053
  combinedTail += chunk.toString("utf8");
@@ -14880,7 +14914,8 @@ async function startDaemonDetachedOrExit(opts) {
14880
14914
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14881
14915
  console.log("");
14882
14916
  if (opts?.openWebapp) openUrlBestEffort(configuration.webappUrl);
14883
- process.exit(0);
14917
+ process.exitCode = 0;
14918
+ return;
14884
14919
  }
14885
14920
  const authMismatch = lastUpsertStatus === 401 || /unauthorized/i.test(lastConnectError);
14886
14921
  if (authMismatch && !opts?.reauthAttempted) {
@@ -14951,7 +14986,8 @@ async function startDaemonDetachedOrExit(opts) {
14951
14986
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14952
14987
  console.log("");
14953
14988
  if (opts?.openWebapp) openUrlBestEffort(configuration.webappUrl);
14954
- process.exit(0);
14989
+ process.exitCode = 0;
14990
+ return;
14955
14991
  } else {
14956
14992
  const latest = await getLatestDaemonLog();
14957
14993
  if (latest?.path) console.error(`Latest daemon log: ${latest.path}`);
@@ -15081,7 +15117,7 @@ async function authAndSetupMachineIfNeeded() {
15081
15117
  process.exit(1);
15082
15118
  }
15083
15119
  try {
15084
- const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-CCepAUqm.mjs');
15120
+ const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-DAAX2TDX.mjs');
15085
15121
  const result = migrateUnrealMcpToFlockbayMcp({
15086
15122
  engineRoot,
15087
15123
  projectUprojectPath: project || void 0,
@@ -15220,7 +15256,7 @@ ${engineRoot}`, {
15220
15256
  } else if (subcommand === "codex") {
15221
15257
  try {
15222
15258
  await chdirToNearestUprojectRootIfPresent();
15223
- const { runCodex } = await import('./runCodex-7GeFJuM_.mjs');
15259
+ const { runCodex } = await import('./runCodex-C_dwGw9p.mjs');
15224
15260
  let startedBy = void 0;
15225
15261
  let sessionId = void 0;
15226
15262
  for (let i = 1; i < args.length; i++) {
@@ -15322,7 +15358,7 @@ ${engineRoot}`, {
15322
15358
  }
15323
15359
  try {
15324
15360
  await chdirToNearestUprojectRootIfPresent();
15325
- const { runGemini } = await import('./runGemini-9LGJaWVk.mjs');
15361
+ const { runGemini } = await import('./runGemini-CWiIoJag.mjs');
15326
15362
  let startedBy = void 0;
15327
15363
  let sessionId = void 0;
15328
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-wdJcHT5x.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-F8r81l86.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,17 +5283,41 @@ 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();
5317
+ const windowsHide = typeof options?.windowsHide === "boolean" ? Boolean(options.windowsHide) : process$1.platform === "win32";
5295
5318
  const spawnOptions = {
5296
5319
  ...options,
5320
+ windowsHide,
5297
5321
  ...useTsx ? { cwd: projectRoot } : {},
5298
5322
  env: {
5299
5323
  ...process$1.env,
@@ -5703,12 +5727,14 @@ async function enforceCliVersionPolicy(opts) {
5703
5727
  const policy = await fetchCliVersionPolicy({ serverUrl: opts.serverUrl, timeoutMs: opts.timeoutMs });
5704
5728
  const evaluation = evaluateCliVersion({ currentVersion, policy });
5705
5729
  if (evaluation.status === "update_required") {
5706
- const header = `CLI update required (installed: ${currentVersion}, required: ${evaluation.minimumSupported})`;
5707
- const msg = evaluation.message ? `
5708
- ${evaluation.message}` : "";
5709
- const help = `
5710
- Update: ${evaluation.updateCommand}`;
5711
- 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
+ }
5712
5738
  }
5713
5739
  if (evaluation.status === "update_available") {
5714
5740
  try {
@@ -5809,6 +5835,14 @@ async function startDaemon() {
5809
5835
  serverUrl: types.configuration.serverUrl,
5810
5836
  currentVersion: types.packageJson.version,
5811
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
+ },
5812
5846
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
5813
5847
  const note = message ? `
5814
5848
  ${message}` : "";
@@ -5818,12 +5852,7 @@ Update: ${updateCommand}`);
5818
5852
  });
5819
5853
  } catch (err) {
5820
5854
  const msg = err instanceof Error ? err.message : String(err);
5821
- if (/^CLI update required\b/i.test(msg)) {
5822
- console.error(msg);
5823
- process.exit(1);
5824
- } else {
5825
- types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5826
- }
5855
+ types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
5827
5856
  }
5828
5857
  types.logger.debug("[DAEMON RUN] Auth and machine setup complete");
5829
5858
  const shouldStartUnrealMcp = String(process.env.FLOCKBAY_UNREAL_MCP_ENABLED || "").trim() === "1";
@@ -6599,10 +6628,18 @@ Log: ${logPath || `not found (check ${types.configuration.logsDir})`}` + formatL
6599
6628
  cliPolicyCheckInFlight = true;
6600
6629
  lastCliPolicyCheckAtMs = Date.now();
6601
6630
  try {
6602
- await enforceCliVersionPolicy({
6631
+ const { evaluation } = await enforceCliVersionPolicy({
6603
6632
  serverUrl: types.configuration.serverUrl,
6604
6633
  currentVersion: types.packageJson.version,
6605
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
+ },
6606
6643
  onUpdateAvailable: ({ latest, updateCommand, message }) => {
6607
6644
  const note = message ? `
6608
6645
  ${message}` : "";
@@ -6612,13 +6649,10 @@ Update: ${updateCommand}`
6612
6649
  );
6613
6650
  }
6614
6651
  });
6652
+ if (evaluation.status === "update_required") {
6653
+ }
6615
6654
  } catch (err) {
6616
6655
  const msg = err instanceof Error ? err.message : String(err);
6617
- if (/^CLI update required\b/i.test(msg)) {
6618
- types.logger.debug("[DAEMON RUN] CLI update required; shutting down daemon:", msg);
6619
- requestShutdown("exception", msg);
6620
- return;
6621
- }
6622
6656
  types.logger.debug("[DAEMON RUN] CLI version policy check failed (non-fatal):", msg);
6623
6657
  } finally {
6624
6658
  cliPolicyCheckInFlight = false;
@@ -7035,7 +7069,7 @@ ${scriptCandidates.map((p) => `- ${p}`).join("\n")}
7035
7069
  logStream.write(`args: ${JSON.stringify(buildArgs)}
7036
7070
 
7037
7071
  `);
7038
- const child = osPlatform === "win32" ? node_child_process.spawn("cmd.exe", ["/c", script, ...buildArgs], { stdio: ["ignore", "pipe", "pipe"] }) : node_child_process.spawn(script, buildArgs, { stdio: ["ignore", "pipe", "pipe"] });
7072
+ const child = osPlatform === "win32" ? node_child_process.spawn("cmd.exe", ["/c", script, ...buildArgs], { stdio: ["ignore", "pipe", "pipe"], windowsHide: true }) : node_child_process.spawn(script, buildArgs, { stdio: ["ignore", "pipe", "pipe"] });
7039
7073
  let combinedTail = "";
7040
7074
  const appendTail = (chunk) => {
7041
7075
  combinedTail += chunk.toString("utf8");
@@ -14902,7 +14936,8 @@ async function startDaemonDetachedOrExit(opts) {
14902
14936
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14903
14937
  console.log("");
14904
14938
  if (opts?.openWebapp) openUrlBestEffort(types.configuration.webappUrl);
14905
- process.exit(0);
14939
+ process.exitCode = 0;
14940
+ return;
14906
14941
  }
14907
14942
  const authMismatch = lastUpsertStatus === 401 || /unauthorized/i.test(lastConnectError);
14908
14943
  if (authMismatch && !opts?.reauthAttempted) {
@@ -14973,7 +15008,8 @@ async function startDaemonDetachedOrExit(opts) {
14973
15008
  console.log(chalk.gray(`Daemon: ${daemon?.pid ? `pid=${daemon.pid} port=${daemon.httpPort}` : "not running"}`));
14974
15009
  console.log("");
14975
15010
  if (opts?.openWebapp) openUrlBestEffort(types.configuration.webappUrl);
14976
- process.exit(0);
15011
+ process.exitCode = 0;
15012
+ return;
14977
15013
  } else {
14978
15014
  const latest = await types.getLatestDaemonLog();
14979
15015
  if (latest?.path) console.error(`Latest daemon log: ${latest.path}`);
@@ -15103,7 +15139,7 @@ async function authAndSetupMachineIfNeeded() {
15103
15139
  process.exit(1);
15104
15140
  }
15105
15141
  try {
15106
- const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-T0MOGk0T.cjs'); });
15142
+ const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-BL02mitg.cjs'); });
15107
15143
  const result = migrateUnrealMcpToFlockbayMcp({
15108
15144
  engineRoot,
15109
15145
  projectUprojectPath: project || void 0,
@@ -15242,7 +15278,7 @@ ${engineRoot}`, {
15242
15278
  } else if (subcommand === "codex") {
15243
15279
  try {
15244
15280
  await chdirToNearestUprojectRootIfPresent();
15245
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Bx4E0ukk.cjs'); });
15281
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-DcQmhprg.cjs'); });
15246
15282
  let startedBy = void 0;
15247
15283
  let sessionId = void 0;
15248
15284
  for (let i = 1; i < args.length; i++) {
@@ -15344,7 +15380,7 @@ ${engineRoot}`, {
15344
15380
  }
15345
15381
  try {
15346
15382
  await chdirToNearestUprojectRootIfPresent();
15347
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-xvROo10g.cjs'); });
15383
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-CJF0id5I.cjs'); });
15348
15384
  let startedBy = void 0;
15349
15385
  let sessionId = void 0;
15350
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-F8r81l86.cjs');
5
- require('./types-wdJcHT5x.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-B6WkRhlp.mjs';
3
- import './types-D1UKSrkg.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-wdJcHT5x.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-D1UKSrkg.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-wdJcHT5x.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-D1UKSrkg.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-D1UKSrkg.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-B6WkRhlp.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-wdJcHT5x.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-F8r81l86.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-wdJcHT5x.cjs');
10
- var index = require('./index-F8r81l86.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-D1UKSrkg.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-B6WkRhlp.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.42";
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.") {
@@ -3741,7 +3741,8 @@ async function buildAndInstallUnrealMcpPlugin(options) {
3741
3741
  const cmdLine = `""${uat}" ${args.map(quoteCmdArg).join(" ")}`;
3742
3742
  return spawn$1("cmd.exe", ["/s", "/c", cmdLine], {
3743
3743
  stdio: ["ignore", "pipe", "pipe"],
3744
- windowsVerbatimArguments: true
3744
+ windowsVerbatimArguments: true,
3745
+ windowsHide: true
3745
3746
  });
3746
3747
  })() : spawn$1(uat, args, { stdio: ["ignore", "pipe", "pipe"] });
3747
3748
  child.stdout?.on("data", (chunk) => logStream.write(chunk));
@@ -3799,6 +3800,182 @@ Log: ${buildLogPath}`
3799
3800
  return { ok: true, buildLogPath };
3800
3801
  }
3801
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
+
3802
3979
  async function openBrowser(url) {
3803
3980
  try {
3804
3981
  const forceOpen = process.env.FLOCKBAY_FORCE_BROWSER === "1" || process.env.FLOCKBAY_FORCE_BROWSER === "true";
@@ -4524,6 +4701,10 @@ class ApiMachineClient {
4524
4701
  return { success: true, engineRoot: result.engineRoot, destDir: result.destDir };
4525
4702
  }
4526
4703
  );
4704
+ this.rpcHandlerManager.registerHandler(
4705
+ "unreal-mcp-plugin-disk-status",
4706
+ async (params) => getUnrealMcpPluginDiskStatus(params)
4707
+ );
4527
4708
  }
4528
4709
  socket;
4529
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.42";
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-wdJcHT5x.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.") {
@@ -3762,7 +3762,8 @@ async function buildAndInstallUnrealMcpPlugin(options) {
3762
3762
  const cmdLine = `""${uat}" ${args.map(quoteCmdArg).join(" ")}`;
3763
3763
  return node_child_process.spawn("cmd.exe", ["/s", "/c", cmdLine], {
3764
3764
  stdio: ["ignore", "pipe", "pipe"],
3765
- windowsVerbatimArguments: true
3765
+ windowsVerbatimArguments: true,
3766
+ windowsHide: true
3766
3767
  });
3767
3768
  })() : node_child_process.spawn(uat, args, { stdio: ["ignore", "pipe", "pipe"] });
3768
3769
  child.stdout?.on("data", (chunk) => logStream.write(chunk));
@@ -3820,6 +3821,182 @@ Log: ${buildLogPath}`
3820
3821
  return { ok: true, buildLogPath };
3821
3822
  }
3822
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
+
3823
4000
  async function openBrowser(url) {
3824
4001
  try {
3825
4002
  const forceOpen = process.env.FLOCKBAY_FORCE_BROWSER === "1" || process.env.FLOCKBAY_FORCE_BROWSER === "true";
@@ -4545,6 +4722,10 @@ class ApiMachineClient {
4545
4722
  return { success: true, engineRoot: result.engineRoot, destDir: result.destDir };
4546
4723
  }
4547
4724
  );
4725
+ this.rpcHandlerManager.registerHandler(
4726
+ "unreal-mcp-plugin-disk-status",
4727
+ async (params) => getUnrealMcpPluginDiskStatus(params)
4728
+ );
4548
4729
  }
4549
4730
  socket;
4550
4731
  keepAliveInterval = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flockbay",
3
- "version": "0.10.42",
3
+ "version": "0.10.44",
4
4
  "description": "Flockbay CLI (local agent + daemon)",
5
5
  "author": "Eduardo Orellana",
6
6
  "license": "UNLICENSED",