flockbay 0.10.47 → 0.10.49
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.
- package/dist/{index-BWNZJMIV.mjs → index-D8AeVbvv.mjs} +115 -39
- package/dist/{index-0Arkr3mL.cjs → index-r3VTdgFI.cjs} +116 -40
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{migratePlugin-9YalMg61.mjs → migratePlugin-CEvGPul8.mjs} +18 -1
- package/dist/{migratePlugin-Bd4y5ID_.cjs → migratePlugin-wFK-k3Wk.cjs} +18 -1
- package/dist/{runCodex-EHn5VQcY.cjs → runCodex-DuyuYqoB.cjs} +71 -34
- package/dist/{runCodex-Ck-v-SW_.mjs → runCodex-ZfUyhHF6.mjs} +71 -34
- package/dist/{runGemini-DLUQln_I.cjs → runGemini-D7j5Y5TF.cjs} +2 -2
- package/dist/{runGemini-CTyWoAvM.mjs → runGemini-DBU1mMdp.mjs} +2 -2
- package/dist/{types-e5yrDcQZ.mjs → types-BRJuZQj_.mjs} +57 -5
- package/dist/{types-DUoq_qFJ.cjs → types-DNr0xwSy.cjs} +58 -5
- package/package.json +1 -1
|
@@ -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,
|
|
5
|
+
import { l as logger, e as projectPath, f as backoff, g as delay, R as RawJSONLinesSchema, c as configuration, h as readDaemonState, j as clearDaemonState, p as packageJson, r as readSettings, k as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, m as unrealMcpPythonDir, n as acquireDaemonLock, q as writeDaemonState, s as ApiMachineClient, t as releaseDaemonLock, v as sendUnrealMcpTcpCommand, A as ApiClient, x as validatePath, y as run, z as run$1, B as buildShellInvocation, C as clearCredentials, D as clearMachineId, E as authenticateCodex, F as syncCodexCliAuth, G as authenticateClaude, H as authenticateGemini, d as installUnrealMcpPluginToEngine, I as buildAndInstallUnrealMcpPlugin, i as installUnrealMcpPluginToProject, b as isInstalledEngineRoot, J as getLatestDaemonLog, K as normalizeServerUrlForNode } from './types-BRJuZQj_.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';
|
|
@@ -793,6 +793,9 @@ async function createSessionScanner(opts) {
|
|
|
793
793
|
await sync.invalidateAndAwait();
|
|
794
794
|
sync.stop();
|
|
795
795
|
},
|
|
796
|
+
flush: async () => {
|
|
797
|
+
await sync.invalidateAndAwait();
|
|
798
|
+
},
|
|
796
799
|
onNewSession: (sessionId) => {
|
|
797
800
|
if (currentSessionId === sessionId) {
|
|
798
801
|
logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
|
|
@@ -13953,6 +13956,16 @@ function permissionModeForAgent(agent) {
|
|
|
13953
13956
|
if (agent === "claude") return "bypassPermissions";
|
|
13954
13957
|
return "yolo";
|
|
13955
13958
|
}
|
|
13959
|
+
function modelOverrideForAgent(agent, args) {
|
|
13960
|
+
const explicitCodexModel = readArgValue$2(args, "--codex-model");
|
|
13961
|
+
const explicitModel = readArgValue$2(args, "--model");
|
|
13962
|
+
const explicitGeminiModel = readArgValue$2(args, "--gemini-model");
|
|
13963
|
+
const explicitClaudeModel = readArgValue$2(args, "--claude-model");
|
|
13964
|
+
if (agent === "codex") return (explicitCodexModel || explicitModel || "gpt-5-codex-medium").trim();
|
|
13965
|
+
if (agent === "gemini") return explicitGeminiModel ? explicitGeminiModel.trim() : null;
|
|
13966
|
+
if (agent === "claude") return explicitClaudeModel ? explicitClaudeModel.trim() : null;
|
|
13967
|
+
return null;
|
|
13968
|
+
}
|
|
13956
13969
|
function nowIsoCompact() {
|
|
13957
13970
|
const d = /* @__PURE__ */ new Date();
|
|
13958
13971
|
const pad = (n) => String(n).padStart(2, "0");
|
|
@@ -13990,14 +14003,26 @@ async function ensureDaemonRunning({ skipUnreal }) {
|
|
|
13990
14003
|
async function createSmokeWorkspaceDir(baseDir) {
|
|
13991
14004
|
const root = baseDir?.trim() ? path__default.resolve(baseDir) : path__default.join(os__default.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + randomUUID().slice(0, 8));
|
|
13992
14005
|
await fs$1.mkdir(root, { recursive: true });
|
|
13993
|
-
const
|
|
14006
|
+
const marker = `SMOKE_MARKER_${randomUUID().slice(0, 8)}`;
|
|
13994
14007
|
await fs$1.writeFile(path__default.join(root, "smoke.txt"), `flockbay smoke test
|
|
13995
|
-
|
|
14008
|
+
SMOKE_MARKER=${marker}
|
|
13996
14009
|
`, "utf8");
|
|
13997
|
-
return { dir: root, secret };
|
|
14010
|
+
return { dir: root, secret: marker };
|
|
13998
14011
|
}
|
|
13999
|
-
function
|
|
14000
|
-
return record && typeof record === "object" && record.role === "
|
|
14012
|
+
function isUserRecord(record) {
|
|
14013
|
+
return record && typeof record === "object" && record.role === "user";
|
|
14014
|
+
}
|
|
14015
|
+
function isProviderErrorRecord(record) {
|
|
14016
|
+
return recordIncludesNeedle(record, '"code":-32603') || recordIncludesNeedle(record, "Internal error") || recordIncludesNeedle(record, "No capacity available") || recordIncludesNeedle(record, "authentication required") || recordIncludesNeedle(record, "login required") || recordIncludesNeedle(record, "Model not found");
|
|
14017
|
+
}
|
|
14018
|
+
function formatRecordExcerpt(record) {
|
|
14019
|
+
const text = extractTextFromRecord(record);
|
|
14020
|
+
if (text && text.trim()) return text.trim().slice(0, 400);
|
|
14021
|
+
try {
|
|
14022
|
+
return JSON.stringify(record).slice(0, 400);
|
|
14023
|
+
} catch {
|
|
14024
|
+
return String(record ?? "").slice(0, 400);
|
|
14025
|
+
}
|
|
14001
14026
|
}
|
|
14002
14027
|
function extractTextFromRecord(record) {
|
|
14003
14028
|
try {
|
|
@@ -14224,43 +14249,70 @@ Update: ${updateCommand}`);
|
|
|
14224
14249
|
await sessionClient.connectAndWait();
|
|
14225
14250
|
await ensureSessionActive(api, sessionId, 25e3);
|
|
14226
14251
|
const permissionMode = permissionModeForAgent(agent);
|
|
14252
|
+
const modelOverride = modelOverrideForAgent(agent, args);
|
|
14253
|
+
const baseMeta = modelOverride ? { permissionMode, model: modelOverride } : { permissionMode };
|
|
14227
14254
|
scenarios.push(await runScenario("basic-message", async () => {
|
|
14228
14255
|
const token = `SMOKE_OK_${agent}_${randomUUID().slice(0, 6)}`;
|
|
14229
|
-
sessionClient.sendUserText(`Reply with exactly: ${token}`,
|
|
14230
|
-
await waitForMessage({
|
|
14256
|
+
sessionClient.sendUserText(`Reply with exactly: ${token}`, baseMeta);
|
|
14257
|
+
const msg = await waitForMessage({
|
|
14231
14258
|
sessionClient,
|
|
14232
|
-
predicate: (r) =>
|
|
14259
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
|
|
14233
14260
|
timeoutMs,
|
|
14234
14261
|
progressLabel: `${agent}:basic-message`
|
|
14235
14262
|
});
|
|
14263
|
+
const record = msg?.content;
|
|
14264
|
+
if (isProviderErrorRecord(record)) {
|
|
14265
|
+
throw new Error(`provider_error_basic_message: ${formatRecordExcerpt(record)}`);
|
|
14266
|
+
}
|
|
14236
14267
|
}));
|
|
14237
14268
|
scenarios.push(await runScenario("tool-search", async () => {
|
|
14238
14269
|
const token = `TOOL_SEARCH_OK_${randomUUID().slice(0, 6)}`;
|
|
14270
|
+
const promptLines = agent === "codex" ? [
|
|
14271
|
+
"Use your Terminal tool to read `smoke.txt` in the project directory (do NOT ask for confirmation).",
|
|
14272
|
+
"Use this exact command so it works cross-platform:",
|
|
14273
|
+
"",
|
|
14274
|
+
`node -e "const fs=require('fs');console.log(fs.readFileSync('smoke.txt','utf8'))"`,
|
|
14275
|
+
"",
|
|
14276
|
+
"Find the value after `SMOKE_MARKER=`.",
|
|
14277
|
+
"",
|
|
14278
|
+
`Reply with two lines exactly:`,
|
|
14279
|
+
`1) SMOKE_MARKER=<value>`,
|
|
14280
|
+
`2) ${token}`
|
|
14281
|
+
] : [
|
|
14282
|
+
"Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
|
|
14283
|
+
"Find the value after `SMOKE_MARKER=`.",
|
|
14284
|
+
"",
|
|
14285
|
+
`Reply with two lines exactly:`,
|
|
14286
|
+
`1) SMOKE_MARKER=<value>`,
|
|
14287
|
+
`2) ${token}`
|
|
14288
|
+
];
|
|
14239
14289
|
sessionClient.sendUserText(
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
"Find the value after `SMOKE_SECRET=`.",
|
|
14243
|
-
"",
|
|
14244
|
-
`Reply with two lines exactly:`,
|
|
14245
|
-
`1) SMOKE_SECRET=<value>`,
|
|
14246
|
-
`2) ${token}`
|
|
14247
|
-
].join("\n"),
|
|
14248
|
-
{ permissionMode }
|
|
14290
|
+
promptLines.join("\n"),
|
|
14291
|
+
baseMeta
|
|
14249
14292
|
);
|
|
14250
|
-
await waitForMessage({
|
|
14293
|
+
const msg = await waitForMessage({
|
|
14251
14294
|
sessionClient,
|
|
14252
|
-
predicate: (r) =>
|
|
14295
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, `SMOKE_MARKER=${secret}`) && recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
|
|
14253
14296
|
timeoutMs,
|
|
14254
14297
|
progressLabel: `${agent}:tool-search`
|
|
14255
14298
|
});
|
|
14299
|
+
const record = msg?.content;
|
|
14300
|
+
if (isProviderErrorRecord(record)) {
|
|
14301
|
+
throw new Error(`provider_error_tool_search: ${formatRecordExcerpt(record)}`);
|
|
14302
|
+
}
|
|
14256
14303
|
}));
|
|
14257
14304
|
scenarios.push(await runScenario("image-attachment", async () => {
|
|
14258
14305
|
const token = `IMAGE_OK_${randomUUID().slice(0, 6)}`;
|
|
14259
14306
|
const base64 = tinyPngBase64();
|
|
14307
|
+
const prompt = agent === "codex" ? `Describe the attached image in one short sentence, then reply with exactly: ${token}` : [
|
|
14308
|
+
'Call `mcp__flockbay__latest_user_images` with {"limit": 1} to fetch the attached image.',
|
|
14309
|
+
"Then describe the attached image in one short sentence.",
|
|
14310
|
+
`Finally, reply with exactly: ${token}`
|
|
14311
|
+
].join("\n");
|
|
14260
14312
|
sessionClient.sendUserText(
|
|
14261
|
-
|
|
14313
|
+
prompt,
|
|
14262
14314
|
{
|
|
14263
|
-
|
|
14315
|
+
...baseMeta,
|
|
14264
14316
|
attachments: {
|
|
14265
14317
|
images: [{ mimeType: "image/png", base64, name: "smoke.png" }]
|
|
14266
14318
|
}
|
|
@@ -14268,7 +14320,7 @@ Update: ${updateCommand}`);
|
|
|
14268
14320
|
);
|
|
14269
14321
|
const msg = await waitForMessage({
|
|
14270
14322
|
sessionClient,
|
|
14271
|
-
predicate: (r) =>
|
|
14323
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error") || isProviderErrorRecord(r)),
|
|
14272
14324
|
timeoutMs,
|
|
14273
14325
|
progressLabel: `${agent}:image-attachment`
|
|
14274
14326
|
});
|
|
@@ -14276,6 +14328,9 @@ Update: ${updateCommand}`);
|
|
|
14276
14328
|
if (agent === "codex" && recordIncludesNeedle(record, "image-attachment-missing")) {
|
|
14277
14329
|
throw new Error("image-attachment-missing (Codex did not receive images; check latest_user_images tool + vision support)");
|
|
14278
14330
|
}
|
|
14331
|
+
if (isProviderErrorRecord(record)) {
|
|
14332
|
+
throw new Error(`provider_error_image_attachment: ${formatRecordExcerpt(record)}`);
|
|
14333
|
+
}
|
|
14279
14334
|
if (recordIncludesNeedle(record, "Could not process image") || recordIncludesNeedle(record, "invalid_request_error")) {
|
|
14280
14335
|
throw new Error("provider_image_invalid (image rejected by provider; check base64/mimeType pipeline)");
|
|
14281
14336
|
}
|
|
@@ -14328,6 +14383,10 @@ Options:
|
|
|
14328
14383
|
--all Run all agents (default)
|
|
14329
14384
|
--agent, -a Run a single agent
|
|
14330
14385
|
--agents Comma-separated list of agents
|
|
14386
|
+
--codex-model Codex model mode override (e.g. gpt-5.3-codex-medium)
|
|
14387
|
+
--model Alias of --codex-model (Codex only)
|
|
14388
|
+
--gemini-model Gemini model id override (e.g. gemini-2.5-pro)
|
|
14389
|
+
--claude-model Claude model id override (e.g. claude-sonnet-4-6)
|
|
14331
14390
|
--directory, --dir Directory to run the session in (defaults to a temp folder)
|
|
14332
14391
|
--timeout-ms Per-scenario timeout (default 90000; Windows default 240000)
|
|
14333
14392
|
--keep Do not stop session or delete temp dir
|
|
@@ -15131,7 +15190,7 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15131
15190
|
process.exit(1);
|
|
15132
15191
|
}
|
|
15133
15192
|
try {
|
|
15134
|
-
const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-
|
|
15193
|
+
const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-CEvGPul8.mjs');
|
|
15135
15194
|
const result = migrateUnrealMcpToFlockbayMcp({
|
|
15136
15195
|
engineRoot,
|
|
15137
15196
|
projectUprojectPath: project || void 0,
|
|
@@ -15241,19 +15300,36 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15241
15300
|
if (!parsed.skipUnreal) {
|
|
15242
15301
|
const engineRoot = readArgValue(startArgs, "--engine-root") || (process.env.UE_ENGINE_ROOT || "").trim() || (process.env.ENGINE_ROOT || "").trim() || null;
|
|
15243
15302
|
if (engineRoot) {
|
|
15244
|
-
const
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15251
|
-
|
|
15252
|
-
|
|
15253
|
-
|
|
15254
|
-
|
|
15255
|
-
|
|
15256
|
-
|
|
15303
|
+
const installedEngine = isInstalledEngineRoot(engineRoot);
|
|
15304
|
+
const detection = await detectUnrealProject(process.cwd());
|
|
15305
|
+
const uproject = detection.ok ? detection.uprojectFile : null;
|
|
15306
|
+
const promptTarget = installedEngine ? uproject ? `Install Flockbay MCP plugin into this Unreal project?
|
|
15307
|
+
${uproject}` : null : `Install Flockbay MCP plugin into this Unreal Engine folder?
|
|
15308
|
+
${engineRoot}`;
|
|
15309
|
+
if (installedEngine && !uproject) {
|
|
15310
|
+
console.error(chalk.yellow("Unreal MCP plugin install skipped:"));
|
|
15311
|
+
console.error(
|
|
15312
|
+
chalk.gray(
|
|
15313
|
+
[
|
|
15314
|
+
"This engine appears to be an Installed Build (Epic Launcher).",
|
|
15315
|
+
"Engine-scope install can break builds. Run `flockbay start` from a project folder, or pass --project <path> to install as a project plugin."
|
|
15316
|
+
].join("\n")
|
|
15317
|
+
)
|
|
15318
|
+
);
|
|
15319
|
+
} else {
|
|
15320
|
+
const shouldInstall = await promptYesNo(promptTarget, {
|
|
15321
|
+
defaultYes: true
|
|
15322
|
+
});
|
|
15323
|
+
if (shouldInstall) {
|
|
15324
|
+
const result = installedEngine && uproject ? installUnrealMcpPluginToProject(uproject) : installUnrealMcpPluginToEngine(engineRoot);
|
|
15325
|
+
if (result.ok) {
|
|
15326
|
+
console.log(`Flockbay MCP plugin installed: ${result.destDir}`);
|
|
15327
|
+
process.env.FLOCKBAY_UNREAL_MCP_ENABLED = "1";
|
|
15328
|
+
process.env.ENGINE_ROOT = engineRoot;
|
|
15329
|
+
} else {
|
|
15330
|
+
console.error(chalk.yellow("Flockbay MCP plugin install skipped:"));
|
|
15331
|
+
console.error(chalk.gray(result.errorMessage));
|
|
15332
|
+
}
|
|
15257
15333
|
}
|
|
15258
15334
|
}
|
|
15259
15335
|
}
|
|
@@ -15270,7 +15346,7 @@ ${engineRoot}`, {
|
|
|
15270
15346
|
} else if (subcommand === "codex") {
|
|
15271
15347
|
try {
|
|
15272
15348
|
await chdirToNearestUprojectRootIfPresent();
|
|
15273
|
-
const { runCodex } = await import('./runCodex-
|
|
15349
|
+
const { runCodex } = await import('./runCodex-ZfUyhHF6.mjs');
|
|
15274
15350
|
let startedBy = void 0;
|
|
15275
15351
|
let sessionId = void 0;
|
|
15276
15352
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -15372,7 +15448,7 @@ ${engineRoot}`, {
|
|
|
15372
15448
|
}
|
|
15373
15449
|
try {
|
|
15374
15450
|
await chdirToNearestUprojectRootIfPresent();
|
|
15375
|
-
const { runGemini } = await import('./runGemini-
|
|
15451
|
+
const { runGemini } = await import('./runGemini-DBU1mMdp.mjs');
|
|
15376
15452
|
let startedBy = void 0;
|
|
15377
15453
|
let sessionId = void 0;
|
|
15378
15454
|
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-
|
|
6
|
+
var types = require('./types-DNr0xwSy.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');
|
|
@@ -815,6 +815,9 @@ async function createSessionScanner(opts) {
|
|
|
815
815
|
await sync.invalidateAndAwait();
|
|
816
816
|
sync.stop();
|
|
817
817
|
},
|
|
818
|
+
flush: async () => {
|
|
819
|
+
await sync.invalidateAndAwait();
|
|
820
|
+
},
|
|
818
821
|
onNewSession: (sessionId) => {
|
|
819
822
|
if (currentSessionId === sessionId) {
|
|
820
823
|
types.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
|
|
@@ -1316,7 +1319,7 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
|
|
|
1316
1319
|
env[pathKey] = [...prepend, ...existingParts].join(pathSep);
|
|
1317
1320
|
return env;
|
|
1318
1321
|
}
|
|
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-
|
|
1322
|
+
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-r3VTdgFI.cjs', document.baseURI).href)));
|
|
1320
1323
|
const __dirname$1 = path.join(__filename$1, "..");
|
|
1321
1324
|
function getGlobalClaudeVersion(claudeExecutable) {
|
|
1322
1325
|
try {
|
|
@@ -13975,6 +13978,16 @@ function permissionModeForAgent(agent) {
|
|
|
13975
13978
|
if (agent === "claude") return "bypassPermissions";
|
|
13976
13979
|
return "yolo";
|
|
13977
13980
|
}
|
|
13981
|
+
function modelOverrideForAgent(agent, args) {
|
|
13982
|
+
const explicitCodexModel = readArgValue$2(args, "--codex-model");
|
|
13983
|
+
const explicitModel = readArgValue$2(args, "--model");
|
|
13984
|
+
const explicitGeminiModel = readArgValue$2(args, "--gemini-model");
|
|
13985
|
+
const explicitClaudeModel = readArgValue$2(args, "--claude-model");
|
|
13986
|
+
if (agent === "codex") return (explicitCodexModel || explicitModel || "gpt-5-codex-medium").trim();
|
|
13987
|
+
if (agent === "gemini") return explicitGeminiModel ? explicitGeminiModel.trim() : null;
|
|
13988
|
+
if (agent === "claude") return explicitClaudeModel ? explicitClaudeModel.trim() : null;
|
|
13989
|
+
return null;
|
|
13990
|
+
}
|
|
13978
13991
|
function nowIsoCompact() {
|
|
13979
13992
|
const d = /* @__PURE__ */ new Date();
|
|
13980
13993
|
const pad = (n) => String(n).padStart(2, "0");
|
|
@@ -14012,14 +14025,26 @@ async function ensureDaemonRunning({ skipUnreal }) {
|
|
|
14012
14025
|
async function createSmokeWorkspaceDir(baseDir) {
|
|
14013
14026
|
const root = baseDir?.trim() ? path.resolve(baseDir) : path.join(os.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + node_crypto.randomUUID().slice(0, 8));
|
|
14014
14027
|
await fs$2.mkdir(root, { recursive: true });
|
|
14015
|
-
const
|
|
14028
|
+
const marker = `SMOKE_MARKER_${node_crypto.randomUUID().slice(0, 8)}`;
|
|
14016
14029
|
await fs$2.writeFile(path.join(root, "smoke.txt"), `flockbay smoke test
|
|
14017
|
-
|
|
14030
|
+
SMOKE_MARKER=${marker}
|
|
14018
14031
|
`, "utf8");
|
|
14019
|
-
return { dir: root, secret };
|
|
14032
|
+
return { dir: root, secret: marker };
|
|
14020
14033
|
}
|
|
14021
|
-
function
|
|
14022
|
-
return record && typeof record === "object" && record.role === "
|
|
14034
|
+
function isUserRecord(record) {
|
|
14035
|
+
return record && typeof record === "object" && record.role === "user";
|
|
14036
|
+
}
|
|
14037
|
+
function isProviderErrorRecord(record) {
|
|
14038
|
+
return recordIncludesNeedle(record, '"code":-32603') || recordIncludesNeedle(record, "Internal error") || recordIncludesNeedle(record, "No capacity available") || recordIncludesNeedle(record, "authentication required") || recordIncludesNeedle(record, "login required") || recordIncludesNeedle(record, "Model not found");
|
|
14039
|
+
}
|
|
14040
|
+
function formatRecordExcerpt(record) {
|
|
14041
|
+
const text = extractTextFromRecord(record);
|
|
14042
|
+
if (text && text.trim()) return text.trim().slice(0, 400);
|
|
14043
|
+
try {
|
|
14044
|
+
return JSON.stringify(record).slice(0, 400);
|
|
14045
|
+
} catch {
|
|
14046
|
+
return String(record ?? "").slice(0, 400);
|
|
14047
|
+
}
|
|
14023
14048
|
}
|
|
14024
14049
|
function extractTextFromRecord(record) {
|
|
14025
14050
|
try {
|
|
@@ -14246,43 +14271,70 @@ Update: ${updateCommand}`);
|
|
|
14246
14271
|
await sessionClient.connectAndWait();
|
|
14247
14272
|
await ensureSessionActive(api, sessionId, 25e3);
|
|
14248
14273
|
const permissionMode = permissionModeForAgent(agent);
|
|
14274
|
+
const modelOverride = modelOverrideForAgent(agent, args);
|
|
14275
|
+
const baseMeta = modelOverride ? { permissionMode, model: modelOverride } : { permissionMode };
|
|
14249
14276
|
scenarios.push(await runScenario("basic-message", async () => {
|
|
14250
14277
|
const token = `SMOKE_OK_${agent}_${node_crypto.randomUUID().slice(0, 6)}`;
|
|
14251
|
-
sessionClient.sendUserText(`Reply with exactly: ${token}`,
|
|
14252
|
-
await waitForMessage({
|
|
14278
|
+
sessionClient.sendUserText(`Reply with exactly: ${token}`, baseMeta);
|
|
14279
|
+
const msg = await waitForMessage({
|
|
14253
14280
|
sessionClient,
|
|
14254
|
-
predicate: (r) =>
|
|
14281
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
|
|
14255
14282
|
timeoutMs,
|
|
14256
14283
|
progressLabel: `${agent}:basic-message`
|
|
14257
14284
|
});
|
|
14285
|
+
const record = msg?.content;
|
|
14286
|
+
if (isProviderErrorRecord(record)) {
|
|
14287
|
+
throw new Error(`provider_error_basic_message: ${formatRecordExcerpt(record)}`);
|
|
14288
|
+
}
|
|
14258
14289
|
}));
|
|
14259
14290
|
scenarios.push(await runScenario("tool-search", async () => {
|
|
14260
14291
|
const token = `TOOL_SEARCH_OK_${node_crypto.randomUUID().slice(0, 6)}`;
|
|
14292
|
+
const promptLines = agent === "codex" ? [
|
|
14293
|
+
"Use your Terminal tool to read `smoke.txt` in the project directory (do NOT ask for confirmation).",
|
|
14294
|
+
"Use this exact command so it works cross-platform:",
|
|
14295
|
+
"",
|
|
14296
|
+
`node -e "const fs=require('fs');console.log(fs.readFileSync('smoke.txt','utf8'))"`,
|
|
14297
|
+
"",
|
|
14298
|
+
"Find the value after `SMOKE_MARKER=`.",
|
|
14299
|
+
"",
|
|
14300
|
+
`Reply with two lines exactly:`,
|
|
14301
|
+
`1) SMOKE_MARKER=<value>`,
|
|
14302
|
+
`2) ${token}`
|
|
14303
|
+
] : [
|
|
14304
|
+
"Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
|
|
14305
|
+
"Find the value after `SMOKE_MARKER=`.",
|
|
14306
|
+
"",
|
|
14307
|
+
`Reply with two lines exactly:`,
|
|
14308
|
+
`1) SMOKE_MARKER=<value>`,
|
|
14309
|
+
`2) ${token}`
|
|
14310
|
+
];
|
|
14261
14311
|
sessionClient.sendUserText(
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
"Find the value after `SMOKE_SECRET=`.",
|
|
14265
|
-
"",
|
|
14266
|
-
`Reply with two lines exactly:`,
|
|
14267
|
-
`1) SMOKE_SECRET=<value>`,
|
|
14268
|
-
`2) ${token}`
|
|
14269
|
-
].join("\n"),
|
|
14270
|
-
{ permissionMode }
|
|
14312
|
+
promptLines.join("\n"),
|
|
14313
|
+
baseMeta
|
|
14271
14314
|
);
|
|
14272
|
-
await waitForMessage({
|
|
14315
|
+
const msg = await waitForMessage({
|
|
14273
14316
|
sessionClient,
|
|
14274
|
-
predicate: (r) =>
|
|
14317
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, `SMOKE_MARKER=${secret}`) && recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
|
|
14275
14318
|
timeoutMs,
|
|
14276
14319
|
progressLabel: `${agent}:tool-search`
|
|
14277
14320
|
});
|
|
14321
|
+
const record = msg?.content;
|
|
14322
|
+
if (isProviderErrorRecord(record)) {
|
|
14323
|
+
throw new Error(`provider_error_tool_search: ${formatRecordExcerpt(record)}`);
|
|
14324
|
+
}
|
|
14278
14325
|
}));
|
|
14279
14326
|
scenarios.push(await runScenario("image-attachment", async () => {
|
|
14280
14327
|
const token = `IMAGE_OK_${node_crypto.randomUUID().slice(0, 6)}`;
|
|
14281
14328
|
const base64 = tinyPngBase64();
|
|
14329
|
+
const prompt = agent === "codex" ? `Describe the attached image in one short sentence, then reply with exactly: ${token}` : [
|
|
14330
|
+
'Call `mcp__flockbay__latest_user_images` with {"limit": 1} to fetch the attached image.',
|
|
14331
|
+
"Then describe the attached image in one short sentence.",
|
|
14332
|
+
`Finally, reply with exactly: ${token}`
|
|
14333
|
+
].join("\n");
|
|
14282
14334
|
sessionClient.sendUserText(
|
|
14283
|
-
|
|
14335
|
+
prompt,
|
|
14284
14336
|
{
|
|
14285
|
-
|
|
14337
|
+
...baseMeta,
|
|
14286
14338
|
attachments: {
|
|
14287
14339
|
images: [{ mimeType: "image/png", base64, name: "smoke.png" }]
|
|
14288
14340
|
}
|
|
@@ -14290,7 +14342,7 @@ Update: ${updateCommand}`);
|
|
|
14290
14342
|
);
|
|
14291
14343
|
const msg = await waitForMessage({
|
|
14292
14344
|
sessionClient,
|
|
14293
|
-
predicate: (r) =>
|
|
14345
|
+
predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error") || isProviderErrorRecord(r)),
|
|
14294
14346
|
timeoutMs,
|
|
14295
14347
|
progressLabel: `${agent}:image-attachment`
|
|
14296
14348
|
});
|
|
@@ -14298,6 +14350,9 @@ Update: ${updateCommand}`);
|
|
|
14298
14350
|
if (agent === "codex" && recordIncludesNeedle(record, "image-attachment-missing")) {
|
|
14299
14351
|
throw new Error("image-attachment-missing (Codex did not receive images; check latest_user_images tool + vision support)");
|
|
14300
14352
|
}
|
|
14353
|
+
if (isProviderErrorRecord(record)) {
|
|
14354
|
+
throw new Error(`provider_error_image_attachment: ${formatRecordExcerpt(record)}`);
|
|
14355
|
+
}
|
|
14301
14356
|
if (recordIncludesNeedle(record, "Could not process image") || recordIncludesNeedle(record, "invalid_request_error")) {
|
|
14302
14357
|
throw new Error("provider_image_invalid (image rejected by provider; check base64/mimeType pipeline)");
|
|
14303
14358
|
}
|
|
@@ -14350,6 +14405,10 @@ Options:
|
|
|
14350
14405
|
--all Run all agents (default)
|
|
14351
14406
|
--agent, -a Run a single agent
|
|
14352
14407
|
--agents Comma-separated list of agents
|
|
14408
|
+
--codex-model Codex model mode override (e.g. gpt-5.3-codex-medium)
|
|
14409
|
+
--model Alias of --codex-model (Codex only)
|
|
14410
|
+
--gemini-model Gemini model id override (e.g. gemini-2.5-pro)
|
|
14411
|
+
--claude-model Claude model id override (e.g. claude-sonnet-4-6)
|
|
14353
14412
|
--directory, --dir Directory to run the session in (defaults to a temp folder)
|
|
14354
14413
|
--timeout-ms Per-scenario timeout (default 90000; Windows default 240000)
|
|
14355
14414
|
--keep Do not stop session or delete temp dir
|
|
@@ -15153,7 +15212,7 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15153
15212
|
process.exit(1);
|
|
15154
15213
|
}
|
|
15155
15214
|
try {
|
|
15156
|
-
const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-
|
|
15215
|
+
const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-wFK-k3Wk.cjs'); });
|
|
15157
15216
|
const result = migrateUnrealMcpToFlockbayMcp({
|
|
15158
15217
|
engineRoot,
|
|
15159
15218
|
projectUprojectPath: project || void 0,
|
|
@@ -15263,19 +15322,36 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15263
15322
|
if (!parsed.skipUnreal) {
|
|
15264
15323
|
const engineRoot = readArgValue(startArgs, "--engine-root") || (process.env.UE_ENGINE_ROOT || "").trim() || (process.env.ENGINE_ROOT || "").trim() || null;
|
|
15265
15324
|
if (engineRoot) {
|
|
15266
|
-
const
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
|
|
15273
|
-
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
|
|
15277
|
-
|
|
15278
|
-
|
|
15325
|
+
const installedEngine = types.isInstalledEngineRoot(engineRoot);
|
|
15326
|
+
const detection = await detectUnrealProject(process.cwd());
|
|
15327
|
+
const uproject = detection.ok ? detection.uprojectFile : null;
|
|
15328
|
+
const promptTarget = installedEngine ? uproject ? `Install Flockbay MCP plugin into this Unreal project?
|
|
15329
|
+
${uproject}` : null : `Install Flockbay MCP plugin into this Unreal Engine folder?
|
|
15330
|
+
${engineRoot}`;
|
|
15331
|
+
if (installedEngine && !uproject) {
|
|
15332
|
+
console.error(chalk.yellow("Unreal MCP plugin install skipped:"));
|
|
15333
|
+
console.error(
|
|
15334
|
+
chalk.gray(
|
|
15335
|
+
[
|
|
15336
|
+
"This engine appears to be an Installed Build (Epic Launcher).",
|
|
15337
|
+
"Engine-scope install can break builds. Run `flockbay start` from a project folder, or pass --project <path> to install as a project plugin."
|
|
15338
|
+
].join("\n")
|
|
15339
|
+
)
|
|
15340
|
+
);
|
|
15341
|
+
} else {
|
|
15342
|
+
const shouldInstall = await promptYesNo(promptTarget, {
|
|
15343
|
+
defaultYes: true
|
|
15344
|
+
});
|
|
15345
|
+
if (shouldInstall) {
|
|
15346
|
+
const result = installedEngine && uproject ? types.installUnrealMcpPluginToProject(uproject) : types.installUnrealMcpPluginToEngine(engineRoot);
|
|
15347
|
+
if (result.ok) {
|
|
15348
|
+
console.log(`Flockbay MCP plugin installed: ${result.destDir}`);
|
|
15349
|
+
process.env.FLOCKBAY_UNREAL_MCP_ENABLED = "1";
|
|
15350
|
+
process.env.ENGINE_ROOT = engineRoot;
|
|
15351
|
+
} else {
|
|
15352
|
+
console.error(chalk.yellow("Flockbay MCP plugin install skipped:"));
|
|
15353
|
+
console.error(chalk.gray(result.errorMessage));
|
|
15354
|
+
}
|
|
15279
15355
|
}
|
|
15280
15356
|
}
|
|
15281
15357
|
}
|
|
@@ -15292,7 +15368,7 @@ ${engineRoot}`, {
|
|
|
15292
15368
|
} else if (subcommand === "codex") {
|
|
15293
15369
|
try {
|
|
15294
15370
|
await chdirToNearestUprojectRootIfPresent();
|
|
15295
|
-
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-
|
|
15371
|
+
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-DuyuYqoB.cjs'); });
|
|
15296
15372
|
let startedBy = void 0;
|
|
15297
15373
|
let sessionId = void 0;
|
|
15298
15374
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -15394,7 +15470,7 @@ ${engineRoot}`, {
|
|
|
15394
15470
|
}
|
|
15395
15471
|
try {
|
|
15396
15472
|
await chdirToNearestUprojectRootIfPresent();
|
|
15397
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
15473
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-D7j5Y5TF.cjs'); });
|
|
15398
15474
|
let startedBy = void 0;
|
|
15399
15475
|
let sessionId = void 0;
|
|
15400
15476
|
for (let i = 1; i < args.length; i++) {
|
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
package/dist/lib.cjs
CHANGED
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-
|
|
1
|
+
export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BRJuZQj_.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:os';
|
|
@@ -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-
|
|
3
|
+
import { i as installUnrealMcpPluginToProject, b as isInstalledEngineRoot, d as installUnrealMcpPluginToEngine } from './types-BRJuZQj_.mjs';
|
|
4
4
|
import 'axios';
|
|
5
5
|
import 'node:os';
|
|
6
6
|
import 'node:events';
|
|
@@ -138,6 +138,23 @@ Error: ${message}` };
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
+
if (projectUprojectPath) {
|
|
142
|
+
const installedProject = installUnrealMcpPluginToProject(projectUprojectPath);
|
|
143
|
+
if (!installedProject.ok) return { ok: false, errorMessage: installedProject.errorMessage };
|
|
144
|
+
return { ok: true, installedDestDir: installedProject.destDir, changedProjectPath, removedLegacyPluginDirs };
|
|
145
|
+
}
|
|
146
|
+
if (isInstalledEngineRoot(engineRoot)) {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
errorMessage: [
|
|
150
|
+
"This Unreal Engine install appears to be an Installed Build (Epic Launcher / precompiled engine).",
|
|
151
|
+
"Engine-scope install of a source-only plugin can break builds.",
|
|
152
|
+
"",
|
|
153
|
+
"Fix: re-run migration with a project path to install as a project plugin:",
|
|
154
|
+
" flockbay unreal-mcp migrate --engine-root <ENGINE_ROOT> --project <PATH_TO_.UPROJECT> --remove-legacy"
|
|
155
|
+
].join("\n")
|
|
156
|
+
};
|
|
157
|
+
}
|
|
141
158
|
const installed = installUnrealMcpPluginToEngine(engineRoot);
|
|
142
159
|
if (!installed.ok) return installed;
|
|
143
160
|
return { ok: true, installedDestDir: installed.destDir, changedProjectPath, removedLegacyPluginDirs };
|
|
@@ -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-
|
|
5
|
+
var types = require('./types-DNr0xwSy.cjs');
|
|
6
6
|
require('axios');
|
|
7
7
|
require('node:os');
|
|
8
8
|
require('node:events');
|
|
@@ -140,6 +140,23 @@ Error: ${message}` };
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
+
if (projectUprojectPath) {
|
|
144
|
+
const installedProject = types.installUnrealMcpPluginToProject(projectUprojectPath);
|
|
145
|
+
if (!installedProject.ok) return { ok: false, errorMessage: installedProject.errorMessage };
|
|
146
|
+
return { ok: true, installedDestDir: installedProject.destDir, changedProjectPath, removedLegacyPluginDirs };
|
|
147
|
+
}
|
|
148
|
+
if (types.isInstalledEngineRoot(engineRoot)) {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
errorMessage: [
|
|
152
|
+
"This Unreal Engine install appears to be an Installed Build (Epic Launcher / precompiled engine).",
|
|
153
|
+
"Engine-scope install of a source-only plugin can break builds.",
|
|
154
|
+
"",
|
|
155
|
+
"Fix: re-run migration with a project path to install as a project plugin:",
|
|
156
|
+
" flockbay unreal-mcp migrate --engine-root <ENGINE_ROOT> --project <PATH_TO_.UPROJECT> --remove-legacy"
|
|
157
|
+
].join("\n")
|
|
158
|
+
};
|
|
159
|
+
}
|
|
143
160
|
const installed = types.installUnrealMcpPluginToEngine(engineRoot);
|
|
144
161
|
if (!installed.ok) return installed;
|
|
145
162
|
return { ok: true, installedDestDir: installed.destDir, changedProjectPath, removedLegacyPluginDirs };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var ink = require('ink');
|
|
4
4
|
var React = require('react');
|
|
5
|
-
var types = require('./types-
|
|
5
|
+
var types = require('./types-DNr0xwSy.cjs');
|
|
6
6
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
7
7
|
var z = require('zod');
|
|
8
8
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
@@ -16,7 +16,7 @@ var process$1 = require('node:process');
|
|
|
16
16
|
var node_stream = require('node:stream');
|
|
17
17
|
var stdio_js$1 = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
18
18
|
var stdio_js = require('@modelcontextprotocol/sdk/shared/stdio.js');
|
|
19
|
-
var index = require('./index-
|
|
19
|
+
var index = require('./index-r3VTdgFI.cjs');
|
|
20
20
|
require('axios');
|
|
21
21
|
require('node:events');
|
|
22
22
|
require('socket.io-client');
|
|
@@ -443,36 +443,17 @@ class WindowsHiddenStdioClientTransport {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return "mcp-server";
|
|
458
|
-
}
|
|
459
|
-
const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
|
|
460
|
-
if (!match) return "mcp-server";
|
|
461
|
-
const versionStr = match[1];
|
|
462
|
-
const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
|
|
463
|
-
if (major > 0 || minor > 43) return "mcp-server";
|
|
464
|
-
if (minor === 43 && patch === 0) {
|
|
465
|
-
if (versionStr.includes("-alpha.")) {
|
|
466
|
-
const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
|
|
467
|
-
return alphaNum >= 5 ? "mcp-server" : "mcp";
|
|
468
|
-
}
|
|
469
|
-
return "mcp-server";
|
|
470
|
-
}
|
|
471
|
-
return "mcp";
|
|
472
|
-
} catch (error) {
|
|
473
|
-
types.logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
|
|
474
|
-
return "mcp-server";
|
|
475
|
-
}
|
|
446
|
+
function parseCodexCliVersion(output) {
|
|
447
|
+
const raw = String(output || "").trim();
|
|
448
|
+
if (!raw) return null;
|
|
449
|
+
const m = raw.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/);
|
|
450
|
+
if (!m) return null;
|
|
451
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), raw: m[0] };
|
|
452
|
+
}
|
|
453
|
+
function isCodexCliAtLeast(v, minimum) {
|
|
454
|
+
if (v.major !== minimum.major) return v.major > minimum.major;
|
|
455
|
+
if (v.minor !== minimum.minor) return v.minor > minimum.minor;
|
|
456
|
+
return v.patch >= minimum.patch;
|
|
476
457
|
}
|
|
477
458
|
function buildCodexSpawnEnv(codexBin) {
|
|
478
459
|
const env = Object.keys(process.env).reduce((acc, key) => {
|
|
@@ -563,6 +544,53 @@ function resolveCodexBin() {
|
|
|
563
544
|
if (fromBash) return fromBash;
|
|
564
545
|
return "codex";
|
|
565
546
|
}
|
|
547
|
+
function getInstalledCodexCliVersion(codexBin) {
|
|
548
|
+
const bin = resolveCodexBin();
|
|
549
|
+
try {
|
|
550
|
+
const res = node_child_process.spawnSync(bin, ["--version"], {
|
|
551
|
+
encoding: "utf8",
|
|
552
|
+
env: buildCodexSpawnEnv(bin),
|
|
553
|
+
timeout: 4e3
|
|
554
|
+
});
|
|
555
|
+
const versionOut = String(res.stdout || "").trim();
|
|
556
|
+
if (res.status !== 0 || !versionOut) return null;
|
|
557
|
+
return parseCodexCliVersion(versionOut);
|
|
558
|
+
} catch {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
|
|
564
|
+
function getCodexMcpCommand() {
|
|
565
|
+
try {
|
|
566
|
+
const codexBin = resolveCodexBin();
|
|
567
|
+
const versionRes = node_child_process.spawnSync(codexBin, ["--version"], {
|
|
568
|
+
encoding: "utf8",
|
|
569
|
+
env: buildCodexSpawnEnv(codexBin),
|
|
570
|
+
timeout: 4e3
|
|
571
|
+
});
|
|
572
|
+
const version = String(versionRes.stdout || "").trim();
|
|
573
|
+
if (versionRes.status !== 0 || !version) {
|
|
574
|
+
return "mcp-server";
|
|
575
|
+
}
|
|
576
|
+
const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
|
|
577
|
+
if (!match) return "mcp-server";
|
|
578
|
+
const versionStr = match[1];
|
|
579
|
+
const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
|
|
580
|
+
if (major > 0 || minor > 43) return "mcp-server";
|
|
581
|
+
if (minor === 43 && patch === 0) {
|
|
582
|
+
if (versionStr.includes("-alpha.")) {
|
|
583
|
+
const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
|
|
584
|
+
return alphaNum >= 5 ? "mcp-server" : "mcp";
|
|
585
|
+
}
|
|
586
|
+
return "mcp-server";
|
|
587
|
+
}
|
|
588
|
+
return "mcp";
|
|
589
|
+
} catch (error) {
|
|
590
|
+
types.logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
|
|
591
|
+
return "mcp-server";
|
|
592
|
+
}
|
|
593
|
+
}
|
|
566
594
|
function normalizeRelativePath(input) {
|
|
567
595
|
const raw = typeof input === "string" ? input.trim() : String(input ?? "").trim();
|
|
568
596
|
if (!raw) return null;
|
|
@@ -2321,6 +2349,7 @@ function hashCodexSessionModeFromEnhancedMode(mode) {
|
|
|
2321
2349
|
return hashCodexSessionMode({ model: mode.model, appendSystemPrompt: mode.appendSystemPrompt });
|
|
2322
2350
|
}
|
|
2323
2351
|
|
|
2352
|
+
const MIN_CODEX_CLI_FOR_GPT_53_CODEX = { major: 0, minor: 104, patch: 0 };
|
|
2324
2353
|
function readCodexAuthIsChatGptAccount() {
|
|
2325
2354
|
try {
|
|
2326
2355
|
const authPath = path.join(os.homedir(), ".codex", "auth.json");
|
|
@@ -2344,8 +2373,9 @@ function parseEffortSuffix(model) {
|
|
|
2344
2373
|
function parseCodexModelTarget(model) {
|
|
2345
2374
|
const trimmed = String(model || "").trim();
|
|
2346
2375
|
if (!trimmed) return null;
|
|
2347
|
-
if (trimmed.startsWith("gpt-5
|
|
2348
|
-
|
|
2376
|
+
if (trimmed === "gpt-5-minimal" || trimmed === "gpt-5-low" || trimmed === "gpt-5-medium" || trimmed === "gpt-5-high" || trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-") || trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) {
|
|
2377
|
+
if (trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-")) return "gpt-5.2-codex";
|
|
2378
|
+
if (trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) return "gpt-5.3-codex";
|
|
2349
2379
|
return "gpt-5.2";
|
|
2350
2380
|
}
|
|
2351
2381
|
return null;
|
|
@@ -2356,6 +2386,13 @@ function resolveCodexModelOverride(rawModel) {
|
|
|
2356
2386
|
const effort = parseEffortSuffix(model);
|
|
2357
2387
|
const codexModelTarget = parseCodexModelTarget(model);
|
|
2358
2388
|
if (codexModelTarget) {
|
|
2389
|
+
if (codexModelTarget === "gpt-5.3-codex") {
|
|
2390
|
+
const installed = getInstalledCodexCliVersion();
|
|
2391
|
+
if (!installed || !isCodexCliAtLeast(installed, MIN_CODEX_CLI_FOR_GPT_53_CODEX)) {
|
|
2392
|
+
const installedText = installed ? `${installed.major}.${installed.minor}.${installed.patch}` : "unknown";
|
|
2393
|
+
throw new Error(`Codex CLI >= 0.104.0 is required for gpt-5.3-codex (installed: ${installedText}).`);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2359
2396
|
const nextEffort = effort ?? "medium";
|
|
2360
2397
|
return {
|
|
2361
2398
|
config: {
|
|
@@ -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,
|
|
3
|
+
import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, e as projectPath } from './types-BRJuZQj_.mjs';
|
|
4
4
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
@@ -14,7 +14,7 @@ import process$1 from 'node:process';
|
|
|
14
14
|
import { PassThrough } from 'node:stream';
|
|
15
15
|
import { getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
16
16
|
import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk/shared/stdio.js';
|
|
17
|
-
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-
|
|
17
|
+
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-D8AeVbvv.mjs';
|
|
18
18
|
import 'axios';
|
|
19
19
|
import 'node:events';
|
|
20
20
|
import 'socket.io-client';
|
|
@@ -441,36 +441,17 @@ class WindowsHiddenStdioClientTransport {
|
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
return "mcp-server";
|
|
456
|
-
}
|
|
457
|
-
const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
|
|
458
|
-
if (!match) return "mcp-server";
|
|
459
|
-
const versionStr = match[1];
|
|
460
|
-
const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
|
|
461
|
-
if (major > 0 || minor > 43) return "mcp-server";
|
|
462
|
-
if (minor === 43 && patch === 0) {
|
|
463
|
-
if (versionStr.includes("-alpha.")) {
|
|
464
|
-
const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
|
|
465
|
-
return alphaNum >= 5 ? "mcp-server" : "mcp";
|
|
466
|
-
}
|
|
467
|
-
return "mcp-server";
|
|
468
|
-
}
|
|
469
|
-
return "mcp";
|
|
470
|
-
} catch (error) {
|
|
471
|
-
logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
|
|
472
|
-
return "mcp-server";
|
|
473
|
-
}
|
|
444
|
+
function parseCodexCliVersion(output) {
|
|
445
|
+
const raw = String(output || "").trim();
|
|
446
|
+
if (!raw) return null;
|
|
447
|
+
const m = raw.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/);
|
|
448
|
+
if (!m) return null;
|
|
449
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), raw: m[0] };
|
|
450
|
+
}
|
|
451
|
+
function isCodexCliAtLeast(v, minimum) {
|
|
452
|
+
if (v.major !== minimum.major) return v.major > minimum.major;
|
|
453
|
+
if (v.minor !== minimum.minor) return v.minor > minimum.minor;
|
|
454
|
+
return v.patch >= minimum.patch;
|
|
474
455
|
}
|
|
475
456
|
function buildCodexSpawnEnv(codexBin) {
|
|
476
457
|
const env = Object.keys(process.env).reduce((acc, key) => {
|
|
@@ -561,6 +542,53 @@ function resolveCodexBin() {
|
|
|
561
542
|
if (fromBash) return fromBash;
|
|
562
543
|
return "codex";
|
|
563
544
|
}
|
|
545
|
+
function getInstalledCodexCliVersion(codexBin) {
|
|
546
|
+
const bin = resolveCodexBin();
|
|
547
|
+
try {
|
|
548
|
+
const res = spawnSync(bin, ["--version"], {
|
|
549
|
+
encoding: "utf8",
|
|
550
|
+
env: buildCodexSpawnEnv(bin),
|
|
551
|
+
timeout: 4e3
|
|
552
|
+
});
|
|
553
|
+
const versionOut = String(res.stdout || "").trim();
|
|
554
|
+
if (res.status !== 0 || !versionOut) return null;
|
|
555
|
+
return parseCodexCliVersion(versionOut);
|
|
556
|
+
} catch {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
|
|
562
|
+
function getCodexMcpCommand() {
|
|
563
|
+
try {
|
|
564
|
+
const codexBin = resolveCodexBin();
|
|
565
|
+
const versionRes = spawnSync(codexBin, ["--version"], {
|
|
566
|
+
encoding: "utf8",
|
|
567
|
+
env: buildCodexSpawnEnv(codexBin),
|
|
568
|
+
timeout: 4e3
|
|
569
|
+
});
|
|
570
|
+
const version = String(versionRes.stdout || "").trim();
|
|
571
|
+
if (versionRes.status !== 0 || !version) {
|
|
572
|
+
return "mcp-server";
|
|
573
|
+
}
|
|
574
|
+
const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
|
|
575
|
+
if (!match) return "mcp-server";
|
|
576
|
+
const versionStr = match[1];
|
|
577
|
+
const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
|
|
578
|
+
if (major > 0 || minor > 43) return "mcp-server";
|
|
579
|
+
if (minor === 43 && patch === 0) {
|
|
580
|
+
if (versionStr.includes("-alpha.")) {
|
|
581
|
+
const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
|
|
582
|
+
return alphaNum >= 5 ? "mcp-server" : "mcp";
|
|
583
|
+
}
|
|
584
|
+
return "mcp-server";
|
|
585
|
+
}
|
|
586
|
+
return "mcp";
|
|
587
|
+
} catch (error) {
|
|
588
|
+
logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
|
|
589
|
+
return "mcp-server";
|
|
590
|
+
}
|
|
591
|
+
}
|
|
564
592
|
function normalizeRelativePath(input) {
|
|
565
593
|
const raw = typeof input === "string" ? input.trim() : String(input ?? "").trim();
|
|
566
594
|
if (!raw) return null;
|
|
@@ -2319,6 +2347,7 @@ function hashCodexSessionModeFromEnhancedMode(mode) {
|
|
|
2319
2347
|
return hashCodexSessionMode({ model: mode.model, appendSystemPrompt: mode.appendSystemPrompt });
|
|
2320
2348
|
}
|
|
2321
2349
|
|
|
2350
|
+
const MIN_CODEX_CLI_FOR_GPT_53_CODEX = { major: 0, minor: 104, patch: 0 };
|
|
2322
2351
|
function readCodexAuthIsChatGptAccount() {
|
|
2323
2352
|
try {
|
|
2324
2353
|
const authPath = path__default.join(os__default.homedir(), ".codex", "auth.json");
|
|
@@ -2342,8 +2371,9 @@ function parseEffortSuffix(model) {
|
|
|
2342
2371
|
function parseCodexModelTarget(model) {
|
|
2343
2372
|
const trimmed = String(model || "").trim();
|
|
2344
2373
|
if (!trimmed) return null;
|
|
2345
|
-
if (trimmed.startsWith("gpt-5
|
|
2346
|
-
|
|
2374
|
+
if (trimmed === "gpt-5-minimal" || trimmed === "gpt-5-low" || trimmed === "gpt-5-medium" || trimmed === "gpt-5-high" || trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-") || trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) {
|
|
2375
|
+
if (trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-")) return "gpt-5.2-codex";
|
|
2376
|
+
if (trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) return "gpt-5.3-codex";
|
|
2347
2377
|
return "gpt-5.2";
|
|
2348
2378
|
}
|
|
2349
2379
|
return null;
|
|
@@ -2354,6 +2384,13 @@ function resolveCodexModelOverride(rawModel) {
|
|
|
2354
2384
|
const effort = parseEffortSuffix(model);
|
|
2355
2385
|
const codexModelTarget = parseCodexModelTarget(model);
|
|
2356
2386
|
if (codexModelTarget) {
|
|
2387
|
+
if (codexModelTarget === "gpt-5.3-codex") {
|
|
2388
|
+
const installed = getInstalledCodexCliVersion();
|
|
2389
|
+
if (!installed || !isCodexCliAtLeast(installed, MIN_CODEX_CLI_FOR_GPT_53_CODEX)) {
|
|
2390
|
+
const installedText = installed ? `${installed.major}.${installed.minor}.${installed.patch}` : "unknown";
|
|
2391
|
+
throw new Error(`Codex CLI >= 0.104.0 is required for gpt-5.3-codex (installed: ${installedText}).`);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2357
2394
|
const nextEffort = effort ?? "medium";
|
|
2358
2395
|
return {
|
|
2359
2396
|
config: {
|
|
@@ -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-
|
|
10
|
-
var index = require('./index-
|
|
9
|
+
var types = require('./types-DNr0xwSy.cjs');
|
|
10
|
+
var index = require('./index-r3VTdgFI.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,
|
|
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-
|
|
7
|
+
import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, e as projectPath } from './types-BRJuZQj_.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-D8AeVbvv.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.
|
|
26
|
+
var version = "0.10.49";
|
|
27
27
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
28
28
|
var author = "Eduardo Orellana";
|
|
29
29
|
var license = "UNLICENSED";
|
|
@@ -3455,6 +3455,14 @@ function createBackoff(opts) {
|
|
|
3455
3455
|
}
|
|
3456
3456
|
let backoff = createBackoff();
|
|
3457
3457
|
|
|
3458
|
+
function isInstalledEngineRoot(engineRootRaw) {
|
|
3459
|
+
const engineRoot = String(engineRootRaw || "").trim();
|
|
3460
|
+
if (!engineRoot) return false;
|
|
3461
|
+
if (fs__default.existsSync(path__default.join(engineRoot, "Engine", "Build", "InstalledBuild.txt"))) return true;
|
|
3462
|
+
if (fs__default.existsSync(path__default.join(engineRoot, "Engine", "Build", "InstalledBuild.xml"))) return true;
|
|
3463
|
+
return false;
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3458
3466
|
function looksLikeEngineRoot$1(engineRoot) {
|
|
3459
3467
|
if (!engineRoot) return false;
|
|
3460
3468
|
return fs__default.existsSync(path__default.join(engineRoot, "Engine")) && fs__default.existsSync(path__default.join(engineRoot, "Engine", "Plugins"));
|
|
@@ -3493,6 +3501,24 @@ function installUnrealMcpPluginToEngine(engineRootRaw) {
|
|
|
3493
3501
|
errorMessage: `Invalid engine root (expected an Unreal Engine install folder containing Engine/\u2026): ${engineRoot || "(empty)"}`
|
|
3494
3502
|
};
|
|
3495
3503
|
}
|
|
3504
|
+
if (isInstalledEngineRoot(engineRoot)) {
|
|
3505
|
+
return {
|
|
3506
|
+
ok: false,
|
|
3507
|
+
errorMessage: [
|
|
3508
|
+
"This Unreal Engine install appears to be an Installed Build (Epic Launcher / precompiled engine).",
|
|
3509
|
+
"",
|
|
3510
|
+
"Installing a source-only plugin into Engine/Plugins can break builds with errors like:",
|
|
3511
|
+
` Expecting to find a type to be declared in a module rules named 'FlockbayMCP' in 'UE5Rules'`,
|
|
3512
|
+
"",
|
|
3513
|
+
"Fix: install the Flockbay MCP plugin into your project instead:",
|
|
3514
|
+
" <YourProject>/Plugins/FlockbayMCP",
|
|
3515
|
+
"",
|
|
3516
|
+
"If you are using the Flockbay UI/CLI, choose a project-scope install or pass a project path.",
|
|
3517
|
+
"Example:",
|
|
3518
|
+
" flockbay unreal-mcp migrate --engine-root <ENGINE_ROOT> --project <PATH_TO_.UPROJECT> --remove-legacy"
|
|
3519
|
+
].join("\n")
|
|
3520
|
+
};
|
|
3521
|
+
}
|
|
3496
3522
|
const srcDir = unrealMcpPluginSourceDir();
|
|
3497
3523
|
if (!fs__default.existsSync(srcDir)) {
|
|
3498
3524
|
return { ok: false, errorMessage: `Missing Flockbay MCP plugin source folder: ${srcDir}` };
|
|
@@ -4725,9 +4751,35 @@ class ApiMachineClient {
|
|
|
4725
4751
|
const enginePluginDir = path__default.join(enginePluginsDir, "FlockbayMCP");
|
|
4726
4752
|
const enginePluginUplugin = path__default.join(enginePluginDir, "FlockbayMCP.uplugin");
|
|
4727
4753
|
const enginePluginHasBinaries = fs__default.existsSync(path__default.join(enginePluginDir, "Binaries"));
|
|
4728
|
-
const
|
|
4729
|
-
|
|
4730
|
-
|
|
4754
|
+
const installedEngine = isInstalledEngineRoot(engineRoot);
|
|
4755
|
+
if (scope === "engine" && installedEngine) {
|
|
4756
|
+
return {
|
|
4757
|
+
success: false,
|
|
4758
|
+
error: [
|
|
4759
|
+
"Refusing engine-scope install: this engine is an Installed Build (Epic Launcher / precompiled rules).",
|
|
4760
|
+
"Install the Flockbay MCP plugin into your project instead (recommended).",
|
|
4761
|
+
"Provide projectUprojectPath and use installScope=project, or installScope=auto."
|
|
4762
|
+
].join("\n")
|
|
4763
|
+
};
|
|
4764
|
+
}
|
|
4765
|
+
if (scope === "auto" && installedEngine && !projectUprojectPath) {
|
|
4766
|
+
return {
|
|
4767
|
+
success: false,
|
|
4768
|
+
error: [
|
|
4769
|
+
"This engine is an Installed Build (Epic Launcher / precompiled rules).",
|
|
4770
|
+
"To avoid breaking Unreal builds, Flockbay must install the plugin into a project.",
|
|
4771
|
+
"Missing required param: projectUprojectPath"
|
|
4772
|
+
].join("\n")
|
|
4773
|
+
};
|
|
4774
|
+
}
|
|
4775
|
+
const shouldUseProject = scope === "project" || scope === "auto" && (installedEngine ? (
|
|
4776
|
+
// Installed engines: always use project plugin install (even if an engine copy already exists).
|
|
4777
|
+
Boolean(projectUprojectPath)
|
|
4778
|
+
) : (
|
|
4779
|
+
// Non-installed engines: if the engine plugin is already installed+built, keep using it (no project mutation).
|
|
4780
|
+
!(fs__default.existsSync(enginePluginUplugin) && enginePluginHasBinaries) && // Otherwise, use a project-scope install when the engine folder isn't writable.
|
|
4781
|
+
!canWriteDir(enginePluginsDir) && Boolean(projectUprojectPath)
|
|
4782
|
+
));
|
|
4731
4783
|
if (shouldUseProject) {
|
|
4732
4784
|
if (!projectUprojectPath) return { success: false, error: "Missing projectUprojectPath (required for project-scope install)." };
|
|
4733
4785
|
const installedProject = installUnrealMcpPluginToProject(projectUprojectPath);
|
|
@@ -5293,4 +5345,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
|
5293
5345
|
}).passthrough()
|
|
5294
5346
|
]);
|
|
5295
5347
|
|
|
5296
|
-
export { ApiClient as A,
|
|
5348
|
+
export { ApiClient as A, buildShellInvocation as B, clearCredentials as C, clearMachineId as D, authenticateCodex as E, syncCodexCliAuth as F, authenticateClaude as G, authenticateGemini as H, buildAndInstallUnrealMcpPlugin as I, getLatestDaemonLog as J, normalizeServerUrlForNode as K, RawJSONLinesSchema as R, ApiSessionClient as a, isInstalledEngineRoot as b, configuration as c, installUnrealMcpPluginToEngine as d, projectPath as e, backoff as f, delay as g, readDaemonState as h, installUnrealMcpPluginToProject as i, clearDaemonState as j, readCredentials as k, logger as l, unrealMcpPythonDir as m, acquireDaemonLock as n, openBrowser as o, packageJson as p, writeDaemonState as q, readSettings as r, ApiMachineClient as s, releaseDaemonLock as t, updateSettings as u, sendUnrealMcpTcpCommand as v, writeCredentials as w, validatePath as x, run$1 as y, run as z };
|
|
@@ -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.
|
|
47
|
+
var version = "0.10.49";
|
|
48
48
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
49
49
|
var author = "Eduardo Orellana";
|
|
50
50
|
var license = "UNLICENSED";
|
|
@@ -832,7 +832,7 @@ class RpcHandlerManager {
|
|
|
832
832
|
}
|
|
833
833
|
}
|
|
834
834
|
|
|
835
|
-
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-
|
|
835
|
+
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-DNr0xwSy.cjs', document.baseURI).href))));
|
|
836
836
|
function projectPath() {
|
|
837
837
|
const path = path$1.resolve(__dirname$1, "..");
|
|
838
838
|
return path;
|
|
@@ -3476,6 +3476,14 @@ function createBackoff(opts) {
|
|
|
3476
3476
|
}
|
|
3477
3477
|
let backoff = createBackoff();
|
|
3478
3478
|
|
|
3479
|
+
function isInstalledEngineRoot(engineRootRaw) {
|
|
3480
|
+
const engineRoot = String(engineRootRaw || "").trim();
|
|
3481
|
+
if (!engineRoot) return false;
|
|
3482
|
+
if (fs.existsSync(path.join(engineRoot, "Engine", "Build", "InstalledBuild.txt"))) return true;
|
|
3483
|
+
if (fs.existsSync(path.join(engineRoot, "Engine", "Build", "InstalledBuild.xml"))) return true;
|
|
3484
|
+
return false;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3479
3487
|
function looksLikeEngineRoot$1(engineRoot) {
|
|
3480
3488
|
if (!engineRoot) return false;
|
|
3481
3489
|
return fs.existsSync(path.join(engineRoot, "Engine")) && fs.existsSync(path.join(engineRoot, "Engine", "Plugins"));
|
|
@@ -3514,6 +3522,24 @@ function installUnrealMcpPluginToEngine(engineRootRaw) {
|
|
|
3514
3522
|
errorMessage: `Invalid engine root (expected an Unreal Engine install folder containing Engine/\u2026): ${engineRoot || "(empty)"}`
|
|
3515
3523
|
};
|
|
3516
3524
|
}
|
|
3525
|
+
if (isInstalledEngineRoot(engineRoot)) {
|
|
3526
|
+
return {
|
|
3527
|
+
ok: false,
|
|
3528
|
+
errorMessage: [
|
|
3529
|
+
"This Unreal Engine install appears to be an Installed Build (Epic Launcher / precompiled engine).",
|
|
3530
|
+
"",
|
|
3531
|
+
"Installing a source-only plugin into Engine/Plugins can break builds with errors like:",
|
|
3532
|
+
` Expecting to find a type to be declared in a module rules named 'FlockbayMCP' in 'UE5Rules'`,
|
|
3533
|
+
"",
|
|
3534
|
+
"Fix: install the Flockbay MCP plugin into your project instead:",
|
|
3535
|
+
" <YourProject>/Plugins/FlockbayMCP",
|
|
3536
|
+
"",
|
|
3537
|
+
"If you are using the Flockbay UI/CLI, choose a project-scope install or pass a project path.",
|
|
3538
|
+
"Example:",
|
|
3539
|
+
" flockbay unreal-mcp migrate --engine-root <ENGINE_ROOT> --project <PATH_TO_.UPROJECT> --remove-legacy"
|
|
3540
|
+
].join("\n")
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3517
3543
|
const srcDir = unrealMcpPluginSourceDir();
|
|
3518
3544
|
if (!fs.existsSync(srcDir)) {
|
|
3519
3545
|
return { ok: false, errorMessage: `Missing Flockbay MCP plugin source folder: ${srcDir}` };
|
|
@@ -4746,9 +4772,35 @@ class ApiMachineClient {
|
|
|
4746
4772
|
const enginePluginDir = path.join(enginePluginsDir, "FlockbayMCP");
|
|
4747
4773
|
const enginePluginUplugin = path.join(enginePluginDir, "FlockbayMCP.uplugin");
|
|
4748
4774
|
const enginePluginHasBinaries = fs.existsSync(path.join(enginePluginDir, "Binaries"));
|
|
4749
|
-
const
|
|
4750
|
-
|
|
4751
|
-
|
|
4775
|
+
const installedEngine = isInstalledEngineRoot(engineRoot);
|
|
4776
|
+
if (scope === "engine" && installedEngine) {
|
|
4777
|
+
return {
|
|
4778
|
+
success: false,
|
|
4779
|
+
error: [
|
|
4780
|
+
"Refusing engine-scope install: this engine is an Installed Build (Epic Launcher / precompiled rules).",
|
|
4781
|
+
"Install the Flockbay MCP plugin into your project instead (recommended).",
|
|
4782
|
+
"Provide projectUprojectPath and use installScope=project, or installScope=auto."
|
|
4783
|
+
].join("\n")
|
|
4784
|
+
};
|
|
4785
|
+
}
|
|
4786
|
+
if (scope === "auto" && installedEngine && !projectUprojectPath) {
|
|
4787
|
+
return {
|
|
4788
|
+
success: false,
|
|
4789
|
+
error: [
|
|
4790
|
+
"This engine is an Installed Build (Epic Launcher / precompiled rules).",
|
|
4791
|
+
"To avoid breaking Unreal builds, Flockbay must install the plugin into a project.",
|
|
4792
|
+
"Missing required param: projectUprojectPath"
|
|
4793
|
+
].join("\n")
|
|
4794
|
+
};
|
|
4795
|
+
}
|
|
4796
|
+
const shouldUseProject = scope === "project" || scope === "auto" && (installedEngine ? (
|
|
4797
|
+
// Installed engines: always use project plugin install (even if an engine copy already exists).
|
|
4798
|
+
Boolean(projectUprojectPath)
|
|
4799
|
+
) : (
|
|
4800
|
+
// Non-installed engines: if the engine plugin is already installed+built, keep using it (no project mutation).
|
|
4801
|
+
!(fs.existsSync(enginePluginUplugin) && enginePluginHasBinaries) && // Otherwise, use a project-scope install when the engine folder isn't writable.
|
|
4802
|
+
!canWriteDir(enginePluginsDir) && Boolean(projectUprojectPath)
|
|
4803
|
+
));
|
|
4752
4804
|
if (shouldUseProject) {
|
|
4753
4805
|
if (!projectUprojectPath) return { success: false, error: "Missing projectUprojectPath (required for project-scope install)." };
|
|
4754
4806
|
const installedProject = installUnrealMcpPluginToProject(projectUprojectPath);
|
|
@@ -5333,6 +5385,7 @@ exports.delay = delay;
|
|
|
5333
5385
|
exports.getLatestDaemonLog = getLatestDaemonLog;
|
|
5334
5386
|
exports.installUnrealMcpPluginToEngine = installUnrealMcpPluginToEngine;
|
|
5335
5387
|
exports.installUnrealMcpPluginToProject = installUnrealMcpPluginToProject;
|
|
5388
|
+
exports.isInstalledEngineRoot = isInstalledEngineRoot;
|
|
5336
5389
|
exports.logger = logger;
|
|
5337
5390
|
exports.normalizeServerUrlForNode = normalizeServerUrlForNode;
|
|
5338
5391
|
exports.openBrowser = openBrowser;
|