flockbay 0.10.19 → 0.10.21
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/codex/flockbayMcpStdioBridge.cjs +8 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +8 -0
- package/dist/{index-BiUf5vLX.cjs → index-Bhkn02hu.cjs} +279 -38
- package/dist/{index-5jfGXWTy.mjs → index-By332wvJ.mjs} +279 -38
- 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/{runCodex-Bh3-ebwT.cjs → runCodex-CH4lz1QX.cjs} +9 -5
- package/dist/{runCodex-DwsaTF4s.mjs → runCodex-d2KQX2mn.mjs} +9 -5
- package/dist/{runGemini-qA5dD13X.mjs → runGemini-Cn0C7MS1.mjs} +101 -31
- package/dist/{runGemini-hXryGqFd.cjs → runGemini-DNSymY04.cjs} +101 -31
- package/dist/{types-CL_3YyS9.cjs → types-DeH24uWs.cjs} +2 -2
- package/dist/{types-BQvaA3sv.mjs → types-mXJc7o0P.mjs} +1 -1
- package/package.json +1 -1
- package/scripts/claude_version_utils.cjs +66 -12
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommandSchema.cpp +10 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +205 -13
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +1 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
|
|
2
2
|
import os, { homedir } from 'node:os';
|
|
3
3
|
import { randomUUID, createCipheriv, randomBytes } from 'node:crypto';
|
|
4
|
-
import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as getLatestDaemonLog, x as normalizeServerUrlForNode } from './types-
|
|
4
|
+
import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as getLatestDaemonLog, x as normalizeServerUrlForNode } from './types-mXJc7o0P.mjs';
|
|
5
5
|
import { spawn, execFileSync, execSync } from 'node:child_process';
|
|
6
6
|
import path, { resolve, join, dirname } from 'node:path';
|
|
7
7
|
import { createInterface } from 'node:readline';
|
|
8
8
|
import * as fs from 'node:fs';
|
|
9
9
|
import fs__default, { existsSync, readFileSync, mkdirSync, readdirSync, accessSync, constants, statSync, createReadStream, writeFileSync, unlinkSync } from 'node:fs';
|
|
10
10
|
import process$1 from 'node:process';
|
|
11
|
-
import fs$1, { readFile, access as access$1, mkdir,
|
|
11
|
+
import fs$1, { readFile, access as access$1, mkdir, readdir, stat } from 'node:fs/promises';
|
|
12
12
|
import fs$2, { watch, access } from 'fs/promises';
|
|
13
13
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
14
14
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
@@ -1236,7 +1236,8 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
|
|
|
1236
1236
|
if (!p) return;
|
|
1237
1237
|
if (!prepend.includes(p) && !existingParts.includes(p)) prepend.push(p);
|
|
1238
1238
|
};
|
|
1239
|
-
|
|
1239
|
+
const isPathLike = typeof binPath === "string" && binPath.length > 0 && (binPath.includes("/") || binPath.includes("\\")) && !binPath.startsWith("\\\\");
|
|
1240
|
+
if (isPathLike) {
|
|
1240
1241
|
add(dirname(binPath));
|
|
1241
1242
|
}
|
|
1242
1243
|
add(dirname(process$1.execPath));
|
|
@@ -1255,7 +1256,7 @@ const __dirname$1 = join(__filename$1, "..");
|
|
|
1255
1256
|
function getGlobalClaudeVersion(claudeExecutable) {
|
|
1256
1257
|
try {
|
|
1257
1258
|
const cleanEnv = buildDaemonSafeEnv(getCleanEnv(), claudeExecutable);
|
|
1258
|
-
const output = claudeExecutable.includes("/") && !claudeExecutable.startsWith("\\\\") ? execFileSync(claudeExecutable, ["--version"], {
|
|
1259
|
+
const output = (claudeExecutable.includes("/") || claudeExecutable.includes("\\")) && !claudeExecutable.startsWith("\\\\") ? execFileSync(claudeExecutable, ["--version"], {
|
|
1259
1260
|
encoding: "utf8",
|
|
1260
1261
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1261
1262
|
cwd: homedir(),
|
|
@@ -1273,6 +1274,35 @@ function getGlobalClaudeVersion(claudeExecutable) {
|
|
|
1273
1274
|
return null;
|
|
1274
1275
|
}
|
|
1275
1276
|
}
|
|
1277
|
+
function tryReadBundledClaudeVersion(nodeModulesCliPath) {
|
|
1278
|
+
try {
|
|
1279
|
+
const pkgPath = join(dirname(dirname(nodeModulesCliPath)), "package.json");
|
|
1280
|
+
if (!existsSync(pkgPath)) return null;
|
|
1281
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
1282
|
+
const parsed = JSON.parse(raw);
|
|
1283
|
+
const v = typeof parsed?.version === "string" ? parsed.version.trim() : "";
|
|
1284
|
+
return v || null;
|
|
1285
|
+
} catch {
|
|
1286
|
+
return null;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
function parseSemver3(v) {
|
|
1290
|
+
const m = String(v || "").trim().match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
1291
|
+
if (!m) return null;
|
|
1292
|
+
const a = Number(m[1]);
|
|
1293
|
+
const b = Number(m[2]);
|
|
1294
|
+
const c = Number(m[3]);
|
|
1295
|
+
if (!Number.isFinite(a) || !Number.isFinite(b) || !Number.isFinite(c)) return null;
|
|
1296
|
+
return [a, b, c];
|
|
1297
|
+
}
|
|
1298
|
+
function compareSemver(a, b) {
|
|
1299
|
+
const pa = parseSemver3(a);
|
|
1300
|
+
const pb = parseSemver3(b);
|
|
1301
|
+
if (!pa || !pb) return null;
|
|
1302
|
+
if (pa[0] !== pb[0]) return pa[0] - pb[0];
|
|
1303
|
+
if (pa[1] !== pb[1]) return pa[1] - pb[1];
|
|
1304
|
+
return pa[2] - pb[2];
|
|
1305
|
+
}
|
|
1276
1306
|
function getCleanEnv() {
|
|
1277
1307
|
const env = { ...process$1.env };
|
|
1278
1308
|
const cwd = process$1.cwd();
|
|
@@ -1392,11 +1422,22 @@ function getDefaultClaudeCodePath() {
|
|
|
1392
1422
|
return nodeModulesPath;
|
|
1393
1423
|
}
|
|
1394
1424
|
const globalVersion = getGlobalClaudeVersion(globalPath);
|
|
1425
|
+
const bundledVersion = tryReadBundledClaudeVersion(nodeModulesPath);
|
|
1395
1426
|
logger.debug(`[Claude SDK] Global version: ${globalVersion || "unknown"}`);
|
|
1396
|
-
|
|
1427
|
+
logger.debug(`[Claude SDK] Bundled version: ${bundledVersion || "unknown"}`);
|
|
1428
|
+
if (!globalVersion || !bundledVersion) {
|
|
1397
1429
|
logger.debug(`[Claude SDK] Cannot compare versions, using global: ${globalPath}`);
|
|
1398
1430
|
return globalPath;
|
|
1399
1431
|
}
|
|
1432
|
+
const cmp = compareSemver(bundledVersion, globalVersion);
|
|
1433
|
+
if (cmp === null) {
|
|
1434
|
+
logger.debug(`[Claude SDK] Cannot parse versions, using global: ${globalPath}`);
|
|
1435
|
+
return globalPath;
|
|
1436
|
+
}
|
|
1437
|
+
if (cmp > 0) {
|
|
1438
|
+
logger.debug(`[Claude SDK] Bundled Claude is newer (${bundledVersion} > ${globalVersion}), using bundled: ${nodeModulesPath}`);
|
|
1439
|
+
return nodeModulesPath;
|
|
1440
|
+
}
|
|
1400
1441
|
return globalPath;
|
|
1401
1442
|
}
|
|
1402
1443
|
function logDebug(message) {
|
|
@@ -1671,8 +1712,9 @@ function query(config) {
|
|
|
1671
1712
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1672
1713
|
signal: config.options?.abort,
|
|
1673
1714
|
env: spawnEnv,
|
|
1674
|
-
//
|
|
1675
|
-
|
|
1715
|
+
// Only use a shell on Windows when spawning a bare command (e.g. "claude").
|
|
1716
|
+
// Passing large `--allowedTools` lists through cmd.exe can hit the ~8k command line limit.
|
|
1717
|
+
shell: isCommandOnly && process$1.platform === "win32"
|
|
1676
1718
|
});
|
|
1677
1719
|
let childStdin = null;
|
|
1678
1720
|
if (typeof prompt === "string") {
|
|
@@ -2448,6 +2490,21 @@ async function consumeToolQuota(args) {
|
|
|
2448
2490
|
return { ok: true, allowed: true, unlimited: true };
|
|
2449
2491
|
}
|
|
2450
2492
|
|
|
2493
|
+
function canonicalizeToolNameForMatching(name) {
|
|
2494
|
+
if (name === "ExitPlanMode") return "exit_plan_mode";
|
|
2495
|
+
return name;
|
|
2496
|
+
}
|
|
2497
|
+
function stripUndefinedDeep(value) {
|
|
2498
|
+
if (value === null || value === void 0) return value;
|
|
2499
|
+
if (Array.isArray(value)) return value.map(stripUndefinedDeep);
|
|
2500
|
+
if (typeof value !== "object") return value;
|
|
2501
|
+
const out = {};
|
|
2502
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2503
|
+
if (child === void 0) continue;
|
|
2504
|
+
out[key] = stripUndefinedDeep(child);
|
|
2505
|
+
}
|
|
2506
|
+
return out;
|
|
2507
|
+
}
|
|
2451
2508
|
class PermissionHandler {
|
|
2452
2509
|
toolCalls = [];
|
|
2453
2510
|
responses = /* @__PURE__ */ new Map();
|
|
@@ -2731,8 +2788,13 @@ ${next}`
|
|
|
2731
2788
|
}
|
|
2732
2789
|
let toolCallId = this.resolveToolCallId(toolName, input);
|
|
2733
2790
|
if (!toolCallId) {
|
|
2734
|
-
|
|
2735
|
-
|
|
2791
|
+
const isPlanMode = toolName === "exit_plan_mode" || toolName === "ExitPlanMode";
|
|
2792
|
+
const timeoutMs = isPlanMode ? 3e3 : 1e3;
|
|
2793
|
+
const deadline = Date.now() + timeoutMs;
|
|
2794
|
+
while (!toolCallId && Date.now() < deadline) {
|
|
2795
|
+
await delay(100);
|
|
2796
|
+
toolCallId = this.resolveToolCallId(toolName, input);
|
|
2797
|
+
}
|
|
2736
2798
|
if (!toolCallId) {
|
|
2737
2799
|
throw new Error(`Could not resolve tool call ID for ${toolName}`);
|
|
2738
2800
|
}
|
|
@@ -2813,9 +2875,12 @@ ${next}`
|
|
|
2813
2875
|
* Resolves tool call ID based on tool name and input
|
|
2814
2876
|
*/
|
|
2815
2877
|
resolveToolCallId(name, args) {
|
|
2878
|
+
const normalizedName = canonicalizeToolNameForMatching(name);
|
|
2879
|
+
const normalizedArgs = stripUndefinedDeep(args);
|
|
2816
2880
|
for (let i = this.toolCalls.length - 1; i >= 0; i--) {
|
|
2817
2881
|
const call = this.toolCalls[i];
|
|
2818
|
-
|
|
2882
|
+
const callName = canonicalizeToolNameForMatching(call.name);
|
|
2883
|
+
if (callName === normalizedName && deepEqual(stripUndefinedDeep(call.input), normalizedArgs)) {
|
|
2819
2884
|
if (call.used) {
|
|
2820
2885
|
return null;
|
|
2821
2886
|
}
|
|
@@ -2823,6 +2888,18 @@ ${next}`
|
|
|
2823
2888
|
return call.id;
|
|
2824
2889
|
}
|
|
2825
2890
|
}
|
|
2891
|
+
const candidates = [];
|
|
2892
|
+
for (let i = this.toolCalls.length - 1; i >= 0; i--) {
|
|
2893
|
+
const call = this.toolCalls[i];
|
|
2894
|
+
if (call.used) continue;
|
|
2895
|
+
const callName = canonicalizeToolNameForMatching(call.name);
|
|
2896
|
+
if (callName === normalizedName) candidates.push(call);
|
|
2897
|
+
if (candidates.length > 1) break;
|
|
2898
|
+
}
|
|
2899
|
+
if (candidates.length === 1) {
|
|
2900
|
+
candidates[0].used = true;
|
|
2901
|
+
return candidates[0].id;
|
|
2902
|
+
}
|
|
2826
2903
|
return null;
|
|
2827
2904
|
}
|
|
2828
2905
|
/**
|
|
@@ -7095,7 +7172,11 @@ async function uploadScreenshotViewsForSession(args) {
|
|
|
7095
7172
|
for (const v of args.views) {
|
|
7096
7173
|
const buf = await readFile(v.path);
|
|
7097
7174
|
const filename = path.basename(v.path);
|
|
7098
|
-
const contentType =
|
|
7175
|
+
const contentType = (() => {
|
|
7176
|
+
const mime = detectImageMimeTypeFromBuffer(buf);
|
|
7177
|
+
if (mime) return mime;
|
|
7178
|
+
throw new Error(`Unsupported screenshot format (expected PNG/JPEG): ${v.path}`);
|
|
7179
|
+
})();
|
|
7099
7180
|
const blob = new Blob([buf], { type: contentType });
|
|
7100
7181
|
form.append(`file:${v.id}`, blob, filename);
|
|
7101
7182
|
}
|
|
@@ -7136,6 +7217,22 @@ async function uploadScreenshotViewsForSession(args) {
|
|
|
7136
7217
|
}
|
|
7137
7218
|
return out;
|
|
7138
7219
|
}
|
|
7220
|
+
function detectImageMimeTypeFromBuffer(buf) {
|
|
7221
|
+
if (!buf || buf.length < 12) return null;
|
|
7222
|
+
if (buf[0] === 137 && buf[1] === 80 && buf[2] === 78 && buf[3] === 71 && buf[4] === 13 && buf[5] === 10 && buf[6] === 26 && buf[7] === 10) {
|
|
7223
|
+
return "image/png";
|
|
7224
|
+
}
|
|
7225
|
+
if (buf[0] === 255 && buf[1] === 216 && buf[2] === 255) {
|
|
7226
|
+
return "image/jpeg";
|
|
7227
|
+
}
|
|
7228
|
+
if (buf[0] === 71 && buf[1] === 73 && buf[2] === 70 && buf[3] === 56 && (buf[4] === 55 || buf[4] === 57) && buf[5] === 97) {
|
|
7229
|
+
return "image/gif";
|
|
7230
|
+
}
|
|
7231
|
+
if (buf[0] === 82 && buf[1] === 73 && buf[2] === 70 && buf[3] === 70 && buf[8] === 87 && buf[9] === 69 && buf[10] === 66 && buf[11] === 80) {
|
|
7232
|
+
return "image/webp";
|
|
7233
|
+
}
|
|
7234
|
+
return null;
|
|
7235
|
+
}
|
|
7139
7236
|
async function startFlockbayServer(client, options) {
|
|
7140
7237
|
const handler = async (title) => {
|
|
7141
7238
|
logger.debug("[flockbayMCP] Changing title to:", title);
|
|
@@ -7208,7 +7305,8 @@ async function startFlockbayServer(client, options) {
|
|
|
7208
7305
|
lastReachableAtMs: 0,
|
|
7209
7306
|
lastIssueAtMs: 0,
|
|
7210
7307
|
lastIssueKey: "",
|
|
7211
|
-
launched: null
|
|
7308
|
+
launched: null,
|
|
7309
|
+
lastLaunch: null
|
|
7212
7310
|
};
|
|
7213
7311
|
const emitIssue = (event) => {
|
|
7214
7312
|
const key = `${event.kind}:${event.severity}:${event.message}`;
|
|
@@ -7233,6 +7331,93 @@ async function startFlockbayServer(client, options) {
|
|
|
7233
7331
|
}
|
|
7234
7332
|
}
|
|
7235
7333
|
};
|
|
7334
|
+
const tailText = (text, maxChars) => {
|
|
7335
|
+
const t = String(text || "").trim();
|
|
7336
|
+
if (!t) return "";
|
|
7337
|
+
if (t.length <= maxChars) return t;
|
|
7338
|
+
return t.slice(t.length - maxChars);
|
|
7339
|
+
};
|
|
7340
|
+
const findLatestFile = async (dir, filter) => {
|
|
7341
|
+
try {
|
|
7342
|
+
const entries = await readdir(dir);
|
|
7343
|
+
let best = null;
|
|
7344
|
+
for (const name of entries) {
|
|
7345
|
+
if (!filter(name)) continue;
|
|
7346
|
+
const full = path.join(dir, name);
|
|
7347
|
+
let st;
|
|
7348
|
+
try {
|
|
7349
|
+
st = await stat(full);
|
|
7350
|
+
} catch {
|
|
7351
|
+
continue;
|
|
7352
|
+
}
|
|
7353
|
+
if (!st?.isFile?.()) continue;
|
|
7354
|
+
const mtimeMs = Number(st.mtimeMs || 0);
|
|
7355
|
+
if (!best || mtimeMs > best.mtimeMs) best = { path: full, mtimeMs };
|
|
7356
|
+
}
|
|
7357
|
+
return best?.path ?? null;
|
|
7358
|
+
} catch {
|
|
7359
|
+
return null;
|
|
7360
|
+
}
|
|
7361
|
+
};
|
|
7362
|
+
const findLatestCrashDir = async (projectRoot) => {
|
|
7363
|
+
const crashesDir = path.join(projectRoot, "Saved", "Crashes");
|
|
7364
|
+
try {
|
|
7365
|
+
const entries = await readdir(crashesDir);
|
|
7366
|
+
let best = null;
|
|
7367
|
+
for (const name of entries) {
|
|
7368
|
+
const full = path.join(crashesDir, name);
|
|
7369
|
+
let st;
|
|
7370
|
+
try {
|
|
7371
|
+
st = await stat(full);
|
|
7372
|
+
} catch {
|
|
7373
|
+
continue;
|
|
7374
|
+
}
|
|
7375
|
+
if (!st?.isDirectory?.()) continue;
|
|
7376
|
+
const mtimeMs = Number(st.mtimeMs || 0);
|
|
7377
|
+
if (!best || mtimeMs > best.mtimeMs) best = { path: full, mtimeMs };
|
|
7378
|
+
}
|
|
7379
|
+
return best?.path ?? null;
|
|
7380
|
+
} catch {
|
|
7381
|
+
return null;
|
|
7382
|
+
}
|
|
7383
|
+
};
|
|
7384
|
+
const readFileTail = async (filePath, maxBytes) => {
|
|
7385
|
+
try {
|
|
7386
|
+
const buf = await readFile(filePath);
|
|
7387
|
+
const slice = buf.length > maxBytes ? buf.subarray(buf.length - maxBytes) : buf;
|
|
7388
|
+
return slice.toString("utf8");
|
|
7389
|
+
} catch {
|
|
7390
|
+
return null;
|
|
7391
|
+
}
|
|
7392
|
+
};
|
|
7393
|
+
const gatherCrashDiagnosticsBestEffort = async (uprojectPath) => {
|
|
7394
|
+
const projectRoot = path.dirname(uprojectPath);
|
|
7395
|
+
const summary = [];
|
|
7396
|
+
const detail = { uprojectPath, projectRoot };
|
|
7397
|
+
const latestLog = await findLatestFile(path.join(projectRoot, "Saved", "Logs"), (n) => n.toLowerCase().endsWith(".log"));
|
|
7398
|
+
if (latestLog) {
|
|
7399
|
+
detail.projectLogPath = latestLog;
|
|
7400
|
+
const tail = await readFileTail(latestLog, 24e3);
|
|
7401
|
+
if (tail) {
|
|
7402
|
+
detail.projectLogTail = tailText(tail, 12e3);
|
|
7403
|
+
summary.push(`Latest log: ${latestLog}`);
|
|
7404
|
+
}
|
|
7405
|
+
}
|
|
7406
|
+
const latestCrashDir = await findLatestCrashDir(projectRoot);
|
|
7407
|
+
if (latestCrashDir) {
|
|
7408
|
+
detail.latestCrashDir = latestCrashDir;
|
|
7409
|
+
const crashContext = await findLatestFile(latestCrashDir, (n) => n.toLowerCase().includes("crashcontext") && n.toLowerCase().endsWith(".xml"));
|
|
7410
|
+
if (crashContext) {
|
|
7411
|
+
detail.crashContextPath = crashContext;
|
|
7412
|
+
const tail = await readFileTail(crashContext, 24e3);
|
|
7413
|
+
if (tail) {
|
|
7414
|
+
detail.crashContextTail = tailText(tail, 12e3);
|
|
7415
|
+
summary.push(`CrashContext: ${crashContext}`);
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
}
|
|
7419
|
+
return { detail, summary };
|
|
7420
|
+
};
|
|
7236
7421
|
const getUnrealEditorExe = (engineRoot) => {
|
|
7237
7422
|
const root = engineRoot.trim().replace(/[\\/]+$/, "");
|
|
7238
7423
|
if (process.platform === "darwin") {
|
|
@@ -7288,7 +7473,7 @@ ${res.stderr}`;
|
|
|
7288
7473
|
kind: "unreachable",
|
|
7289
7474
|
severity: "warning",
|
|
7290
7475
|
detectedAtMs: now,
|
|
7291
|
-
message: "Unreal Editor is no longer reachable (it was reachable earlier). It may have crashed or been closed.",
|
|
7476
|
+
message: "Unreal Editor is no longer reachable (it was reachable earlier). It may have crashed or been closed.\nNext: fix the issue, then relaunch via unreal_editor_relaunch_last (if you launched from this session) or unreal_editor_launch.",
|
|
7292
7477
|
detail: {
|
|
7293
7478
|
lastReachableAtMs: state.lastReachableAtMs
|
|
7294
7479
|
}
|
|
@@ -7320,20 +7505,35 @@ ${res.stderr}`;
|
|
|
7320
7505
|
engineRoot,
|
|
7321
7506
|
startedAtMs: Date.now()
|
|
7322
7507
|
};
|
|
7508
|
+
state.lastLaunch = {
|
|
7509
|
+
uprojectPath,
|
|
7510
|
+
engineRoot,
|
|
7511
|
+
extraArgs,
|
|
7512
|
+
startedAtMs: Date.now()
|
|
7513
|
+
};
|
|
7323
7514
|
child.on("exit", (code, signal) => {
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7515
|
+
void (async () => {
|
|
7516
|
+
const now = Date.now();
|
|
7517
|
+
const exitCode = typeof code === "number" ? code : null;
|
|
7518
|
+
const sig = typeof signal === "string" ? signal : null;
|
|
7519
|
+
const isCrash = sig !== null || exitCode !== null && exitCode !== 0;
|
|
7520
|
+
state.launched = null;
|
|
7521
|
+
if (!isCrash) return;
|
|
7522
|
+
const diag = await gatherCrashDiagnosticsBestEffort(uprojectPath).catch(() => ({ detail: {}, summary: [] }));
|
|
7523
|
+
const msgParts = [
|
|
7524
|
+
`Unreal Editor process exited unexpectedly (code=${exitCode ?? "null"} signal=${sig ?? "null"}).`,
|
|
7525
|
+
`Project: ${uprojectPath}`,
|
|
7526
|
+
...diag.summary,
|
|
7527
|
+
`Next: fix the issue, then relaunch via unreal_editor_relaunch_last (or unreal_editor_launch).`
|
|
7528
|
+
];
|
|
7529
|
+
emitIssue({
|
|
7530
|
+
kind: "process_exit",
|
|
7531
|
+
severity: "crash",
|
|
7532
|
+
detectedAtMs: now,
|
|
7533
|
+
message: msgParts.filter(Boolean).join("\n"),
|
|
7534
|
+
detail: { exitCode, signal: sig, pid, uprojectPath, ...diag.detail }
|
|
7535
|
+
});
|
|
7536
|
+
})();
|
|
7337
7537
|
});
|
|
7338
7538
|
child.on("error", (err) => {
|
|
7339
7539
|
const now = Date.now();
|
|
@@ -7342,7 +7542,9 @@ ${res.stderr}`;
|
|
|
7342
7542
|
kind: "process_exit",
|
|
7343
7543
|
severity: "crash",
|
|
7344
7544
|
detectedAtMs: now,
|
|
7345
|
-
message: `Failed to launch Unreal Editor: ${err instanceof Error ? err.message : String(err)}
|
|
7545
|
+
message: `Failed to launch Unreal Editor: ${err instanceof Error ? err.message : String(err)}
|
|
7546
|
+
Project: ${uprojectPath}
|
|
7547
|
+
Next: fix the issue, then relaunch via unreal_editor_relaunch_last (or unreal_editor_launch).`,
|
|
7346
7548
|
detail: { pid, uprojectPath }
|
|
7347
7549
|
});
|
|
7348
7550
|
});
|
|
@@ -7352,6 +7554,12 @@ ${res.stderr}`;
|
|
|
7352
7554
|
noteUnrealActivity,
|
|
7353
7555
|
noteUnrealReachable,
|
|
7354
7556
|
launchEditor,
|
|
7557
|
+
relaunchLast: async (extraArgs) => {
|
|
7558
|
+
const last = state.lastLaunch;
|
|
7559
|
+
if (!last) throw new Error("No known prior Unreal launch in this session. Use unreal_editor_launch with an explicit uprojectPath.");
|
|
7560
|
+
const mergedArgs = Array.isArray(extraArgs) && extraArgs.length > 0 ? extraArgs.filter((a) => typeof a === "string" && a.trim()) : last.extraArgs;
|
|
7561
|
+
return launchEditor({ uprojectPath: last.uprojectPath, engineRoot: last.engineRoot, extraArgs: mergedArgs });
|
|
7562
|
+
},
|
|
7355
7563
|
stop: () => {
|
|
7356
7564
|
try {
|
|
7357
7565
|
interval.unref();
|
|
@@ -8554,13 +8762,13 @@ ${String(st.stdout || "").trim()}`
|
|
|
8554
8762
|
"read_images",
|
|
8555
8763
|
{
|
|
8556
8764
|
title: "Read Images",
|
|
8557
|
-
description: "Read one or more local
|
|
8765
|
+
description: "Read one or more local images by path (PNG/JPEG) and return a `{ views: [...] }` payload so the app can render them as a gallery.",
|
|
8558
8766
|
inputSchema: {
|
|
8559
|
-
paths: z.array(z.string()).describe("Image paths (absolute or relative to the session directory). PNG only."),
|
|
8767
|
+
paths: z.array(z.string()).describe("Image paths (absolute or relative to the session directory). PNG/JPG only."),
|
|
8560
8768
|
limit: z.number().int().positive().optional().describe("Max number of images to include (default 10)."),
|
|
8561
8769
|
upload: z.boolean().optional().describe("Upload images to the session screenshots store and return HTTPS URLs (default true)."),
|
|
8562
8770
|
includeBase64: z.boolean().optional().describe("Include base64 data in the payload (default false)."),
|
|
8563
|
-
includeToolImages: z.boolean().optional().describe("Include MCP image blocks so vision models can see the
|
|
8771
|
+
includeToolImages: z.boolean().optional().describe("Include MCP image blocks so vision models can see the images (default false)."),
|
|
8564
8772
|
maxBytesPerImage: z.number().int().positive().optional().describe("Max bytes per image when includeBase64=true (default 2500000).")
|
|
8565
8773
|
}
|
|
8566
8774
|
},
|
|
@@ -8592,14 +8800,16 @@ ${String(st.stdout || "").trim()}`
|
|
|
8592
8800
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
8593
8801
|
if (home) return path.join(home, p.slice(2));
|
|
8594
8802
|
}
|
|
8595
|
-
|
|
8803
|
+
const baseDir = readSessionWorkingDirectory();
|
|
8804
|
+
return path.isAbsolute(p) ? p : path.resolve(baseDir, p);
|
|
8596
8805
|
};
|
|
8597
8806
|
const idsSeen = /* @__PURE__ */ new Set();
|
|
8598
8807
|
const viewsLocal = [];
|
|
8599
8808
|
for (const inputPath of paths) {
|
|
8600
8809
|
const abs = resolvePath(inputPath);
|
|
8601
|
-
|
|
8602
|
-
|
|
8810
|
+
const lower = abs.toLowerCase();
|
|
8811
|
+
if (!lower.endsWith(".png") && !lower.endsWith(".jpg") && !lower.endsWith(".jpeg")) {
|
|
8812
|
+
throw new Error(`Only PNG/JPG images are supported: ${abs}`);
|
|
8603
8813
|
}
|
|
8604
8814
|
if (!existsSync(abs)) {
|
|
8605
8815
|
throw new Error(`Image not found: ${abs}`);
|
|
@@ -8619,7 +8829,11 @@ ${String(st.stdout || "").trim()}`
|
|
|
8619
8829
|
throw new Error(`Image too large (${st.size} bytes) to embed: ${abs}`);
|
|
8620
8830
|
}
|
|
8621
8831
|
const buf = await readFile(abs);
|
|
8622
|
-
|
|
8832
|
+
const mime = detectImageMimeTypeFromBuffer(buf);
|
|
8833
|
+
if (!mime) {
|
|
8834
|
+
throw new Error(`Unsupported image format (expected PNG/JPEG): ${abs}`);
|
|
8835
|
+
}
|
|
8836
|
+
viewsLocal.push({ id: unique, path: abs, base64: buf.toString("base64"), mimeType: mime });
|
|
8623
8837
|
} else {
|
|
8624
8838
|
viewsLocal.push({ id: unique, path: abs });
|
|
8625
8839
|
}
|
|
@@ -8644,7 +8858,7 @@ ${String(st.stdout || "").trim()}`
|
|
|
8644
8858
|
viewsLocal.forEach((v, idx) => {
|
|
8645
8859
|
if (!v.base64) return;
|
|
8646
8860
|
content.push({ type: "text", text: `Image ${idx + 1}: ${v.id}` });
|
|
8647
|
-
content.push({ type: "image", data: v.base64, mimeType: "image/png" });
|
|
8861
|
+
content.push({ type: "image", data: v.base64, mimeType: v.mimeType || "image/png" });
|
|
8648
8862
|
});
|
|
8649
8863
|
}
|
|
8650
8864
|
return {
|
|
@@ -8656,7 +8870,7 @@ ${String(st.stdout || "").trim()}`
|
|
|
8656
8870
|
return {
|
|
8657
8871
|
content: [
|
|
8658
8872
|
{ type: "text", text: `Failed to read images: ${error instanceof Error ? error.message : String(error)}` },
|
|
8659
|
-
{ type: "text", text: `Tip: pass absolute PNG paths, or relative paths from the session folder.` }
|
|
8873
|
+
{ type: "text", text: `Tip: pass absolute PNG/JPG paths, or relative paths from the session folder.` }
|
|
8660
8874
|
],
|
|
8661
8875
|
isError: true
|
|
8662
8876
|
};
|
|
@@ -8858,6 +9072,32 @@ ${String(st.stdout || "").trim()}`
|
|
|
8858
9072
|
isError: false
|
|
8859
9073
|
};
|
|
8860
9074
|
}));
|
|
9075
|
+
mcp.registerTool("unreal_editor_relaunch_last", {
|
|
9076
|
+
title: "Unreal Editor: Relaunch Last Project",
|
|
9077
|
+
description: "Relaunch the last Unreal project previously launched via unreal_editor_launch in this session (no auto-restart). Use this after a crash once you\u2019ve fixed files. If it crashes again, Flockbay will abort and report again.",
|
|
9078
|
+
inputSchema: {
|
|
9079
|
+
extraArgs: z.array(z.string()).optional().describe("Optional replacement UnrealEditor command-line args (advanced).")
|
|
9080
|
+
}
|
|
9081
|
+
}, async (args) => runWithMcpToolCard("unreal_editor_relaunch_last", args, async () => {
|
|
9082
|
+
const extraArgs = Array.isArray(args?.extraArgs) ? args.extraArgs : void 0;
|
|
9083
|
+
unrealEditorSupervisor.noteUnrealActivity();
|
|
9084
|
+
try {
|
|
9085
|
+
const launched = await unrealEditorSupervisor.relaunchLast(extraArgs);
|
|
9086
|
+
return {
|
|
9087
|
+
content: [
|
|
9088
|
+
{ type: "text", text: `Relaunched Unreal Editor (last project).` },
|
|
9089
|
+
{ type: "text", text: JSON.stringify({ pid: launched.pid, exePath: launched.exePath }, null, 2) },
|
|
9090
|
+
{ type: "text", text: "Next: wait for the editor to finish loading, then re-run UnrealMCP tools." }
|
|
9091
|
+
],
|
|
9092
|
+
isError: false
|
|
9093
|
+
};
|
|
9094
|
+
} catch (err) {
|
|
9095
|
+
return {
|
|
9096
|
+
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
9097
|
+
isError: true
|
|
9098
|
+
};
|
|
9099
|
+
}
|
|
9100
|
+
}));
|
|
8861
9101
|
mcp.registerTool("unreal_build_project", {
|
|
8862
9102
|
title: "Unreal Build Project (UBT)",
|
|
8863
9103
|
description: "Build the project via Unreal Build Tool (via Engine/Build/BatchFiles/Build.*). Returns structured errors (file/line) and a log path for deep debugging.",
|
|
@@ -10283,6 +10523,7 @@ Fix: ${res.hint}` : "";
|
|
|
10283
10523
|
"unreal_headless_screenshot",
|
|
10284
10524
|
"unreal_latest_screenshots",
|
|
10285
10525
|
"unreal_editor_launch",
|
|
10526
|
+
"unreal_editor_relaunch_last",
|
|
10286
10527
|
"unreal_build_project",
|
|
10287
10528
|
"unreal_mcp_command",
|
|
10288
10529
|
"unreal_mcp_list_capabilities",
|
|
@@ -12064,7 +12305,7 @@ ${engineRoot}`, {
|
|
|
12064
12305
|
} else if (subcommand === "codex") {
|
|
12065
12306
|
try {
|
|
12066
12307
|
await chdirToNearestUprojectRootIfPresent();
|
|
12067
|
-
const { runCodex } = await import('./runCodex-
|
|
12308
|
+
const { runCodex } = await import('./runCodex-d2KQX2mn.mjs');
|
|
12068
12309
|
let startedBy = void 0;
|
|
12069
12310
|
let sessionId = void 0;
|
|
12070
12311
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -12159,7 +12400,7 @@ ${engineRoot}`, {
|
|
|
12159
12400
|
}
|
|
12160
12401
|
try {
|
|
12161
12402
|
await chdirToNearestUprojectRootIfPresent();
|
|
12162
|
-
const { runGemini } = await import('./runGemini-
|
|
12403
|
+
const { runGemini } = await import('./runGemini-Cn0C7MS1.mjs');
|
|
12163
12404
|
let startedBy = void 0;
|
|
12164
12405
|
let sessionId = void 0;
|
|
12165
12406
|
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-mXJc7o0P.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:os';
|
|
@@ -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-DeH24uWs.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-
|
|
15
|
+
var index = require('./index-Bhkn02hu.cjs');
|
|
16
16
|
require('axios');
|
|
17
17
|
require('node:events');
|
|
18
18
|
require('socket.io-client');
|
|
@@ -2589,7 +2589,8 @@ async function runCodex(opts) {
|
|
|
2589
2589
|
const push = (role, text) => {
|
|
2590
2590
|
const t = String(text || "").trim();
|
|
2591
2591
|
if (!t) return;
|
|
2592
|
-
|
|
2592
|
+
const label = role === "user" ? "User" : role === "assistant" ? "Assistant" : "System";
|
|
2593
|
+
lines.push(`${label}: ${t}`);
|
|
2593
2594
|
};
|
|
2594
2595
|
for (const row of rows.slice(-80)) {
|
|
2595
2596
|
const content = row?.content;
|
|
@@ -2613,6 +2614,11 @@ async function runCodex(opts) {
|
|
|
2613
2614
|
if (txt) push("assistant", txt);
|
|
2614
2615
|
}
|
|
2615
2616
|
}
|
|
2617
|
+
} else if (payload.type === "event") {
|
|
2618
|
+
const data = payload.data;
|
|
2619
|
+
if (data && typeof data === "object" && data.type === "message" && typeof data.message === "string") {
|
|
2620
|
+
push("system", data.message);
|
|
2621
|
+
}
|
|
2616
2622
|
} else if (payload.type === "codex") {
|
|
2617
2623
|
const data = payload.data;
|
|
2618
2624
|
if (data && typeof data === "object" && data.type === "message" && typeof data.message === "string") {
|
|
@@ -3173,11 +3179,9 @@ async function runCodex(opts) {
|
|
|
3173
3179
|
} else if (msg.type === "task_complete") {
|
|
3174
3180
|
messageBuffer.addMessage("Task completed", "status");
|
|
3175
3181
|
flushInflightExecCalls({ isError: false, reason: "task_complete" });
|
|
3176
|
-
sendReady();
|
|
3177
3182
|
} else if (msg.type === "turn_aborted") {
|
|
3178
3183
|
messageBuffer.addMessage("Turn aborted", "status");
|
|
3179
3184
|
flushInflightExecCalls({ isError: true, reason: "turn_aborted" });
|
|
3180
|
-
sendReady();
|
|
3181
3185
|
}
|
|
3182
3186
|
if (msg.type === "task_started") {
|
|
3183
3187
|
if (!thinking) {
|
|
@@ -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, r as readSettings, p as projectPath, c as configuration, b as packageJson } from './types-
|
|
3
|
+
import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, b as packageJson } from './types-mXJc7o0P.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 from 'node:os';
|
|
11
11
|
import path, { 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, 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, e as detectUnrealProject, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-
|
|
13
|
+
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, 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, e as detectUnrealProject, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-By332wvJ.mjs';
|
|
14
14
|
import 'axios';
|
|
15
15
|
import 'node:events';
|
|
16
16
|
import 'socket.io-client';
|
|
@@ -2587,7 +2587,8 @@ async function runCodex(opts) {
|
|
|
2587
2587
|
const push = (role, text) => {
|
|
2588
2588
|
const t = String(text || "").trim();
|
|
2589
2589
|
if (!t) return;
|
|
2590
|
-
|
|
2590
|
+
const label = role === "user" ? "User" : role === "assistant" ? "Assistant" : "System";
|
|
2591
|
+
lines.push(`${label}: ${t}`);
|
|
2591
2592
|
};
|
|
2592
2593
|
for (const row of rows.slice(-80)) {
|
|
2593
2594
|
const content = row?.content;
|
|
@@ -2611,6 +2612,11 @@ async function runCodex(opts) {
|
|
|
2611
2612
|
if (txt) push("assistant", txt);
|
|
2612
2613
|
}
|
|
2613
2614
|
}
|
|
2615
|
+
} else if (payload.type === "event") {
|
|
2616
|
+
const data = payload.data;
|
|
2617
|
+
if (data && typeof data === "object" && data.type === "message" && typeof data.message === "string") {
|
|
2618
|
+
push("system", data.message);
|
|
2619
|
+
}
|
|
2614
2620
|
} else if (payload.type === "codex") {
|
|
2615
2621
|
const data = payload.data;
|
|
2616
2622
|
if (data && typeof data === "object" && data.type === "message" && typeof data.message === "string") {
|
|
@@ -3171,11 +3177,9 @@ async function runCodex(opts) {
|
|
|
3171
3177
|
} else if (msg.type === "task_complete") {
|
|
3172
3178
|
messageBuffer.addMessage("Task completed", "status");
|
|
3173
3179
|
flushInflightExecCalls({ isError: false, reason: "task_complete" });
|
|
3174
|
-
sendReady();
|
|
3175
3180
|
} else if (msg.type === "turn_aborted") {
|
|
3176
3181
|
messageBuffer.addMessage("Turn aborted", "status");
|
|
3177
3182
|
flushInflightExecCalls({ isError: true, reason: "turn_aborted" });
|
|
3178
|
-
sendReady();
|
|
3179
3183
|
}
|
|
3180
3184
|
if (msg.type === "task_started") {
|
|
3181
3185
|
if (!thinking) {
|