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