flockbay 0.10.21 → 0.10.23
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-Bhkn02hu.cjs → index-BtB1Sqpy.cjs} +353 -17
- package/dist/{index-By332wvJ.mjs → index-CRGcIpET.mjs} +354 -17
- 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-d2KQX2mn.mjs → runCodex-BC3IImzm.mjs} +11 -28
- package/dist/{runCodex-CH4lz1QX.cjs → runCodex-ozeIEfAo.cjs} +11 -28
- package/dist/{runGemini-DNSymY04.cjs → runGemini-B-sAKY5u.cjs} +135 -20
- package/dist/{runGemini-Cn0C7MS1.mjs → runGemini-C43IKGUU.mjs} +135 -20
- package/dist/{types-mXJc7o0P.mjs → types-CNn15BaT.mjs} +47 -6
- package/dist/{types-DeH24uWs.cjs → types-DvlwEGpS.cjs} +47 -5
- package/package.json +1 -1
|
@@ -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
|
|
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-CNn15BaT.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, readdir, stat } from 'node:fs/promises';
|
|
11
|
+
import fs$1, { readFile, access as access$1, mkdir, readdir, stat, rename, open as open$1 } 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';
|
|
@@ -386,7 +386,7 @@ const PLATFORM_SYSTEM_PROMPT = trimIdent(`
|
|
|
386
386
|
|
|
387
387
|
# Policy blocks (not user rejections)
|
|
388
388
|
|
|
389
|
-
If a tool call is **blocked by
|
|
389
|
+
If a tool call is **blocked by Policy** (e.g. a \`FlockbayPolicy\` card, or a denial reason like \u201CBlocked by Policy \u2026\u201D), this is automatic enforcement by the platform \u2014 it is **not** the user rejecting your tool call. Follow the provided next-step instructions (read docs/ledger, claim files, etc) and then retry.
|
|
390
390
|
|
|
391
391
|
# Documentation Library (server-stored docs)
|
|
392
392
|
|
|
@@ -2523,7 +2523,7 @@ class PermissionHandler {
|
|
|
2523
2523
|
const decision = args.decision;
|
|
2524
2524
|
const reason = args.reason;
|
|
2525
2525
|
const kind = decision === "approved" || decision === "approved_for_session" ? "policy_allow" : decision === "abort" && reason === "permission_prompt_required" ? "policy_prompt" : "policy_block";
|
|
2526
|
-
const summary = kind === "policy_allow" ? "Allowed." : kind === "policy_prompt" ? "Waiting for permission to run this tool." : reason ? `Blocked: ${reason}` : "Blocked by
|
|
2526
|
+
const summary = kind === "policy_allow" ? "Allowed." : kind === "policy_prompt" ? "Waiting for permission to run this tool." : reason ? `Blocked: ${reason}` : "Blocked by Policy.";
|
|
2527
2527
|
const callId = `policy:${args.toolCallId}:${randomUUID().slice(0, 8)}`;
|
|
2528
2528
|
const payload = {
|
|
2529
2529
|
kind,
|
|
@@ -2588,13 +2588,13 @@ class PermissionHandler {
|
|
|
2588
2588
|
if (args.reason === "docs_index_read_required") {
|
|
2589
2589
|
return {
|
|
2590
2590
|
uiReason: "read the game Documentation index before making edits.",
|
|
2591
|
-
modelMessage: "Blocked by
|
|
2591
|
+
modelMessage: "Blocked by Policy: read the game Documentation index before making edits.\nNext: call `mcp__flockbay__docs_index_read`, then retry the edit."
|
|
2592
2592
|
};
|
|
2593
2593
|
}
|
|
2594
2594
|
if (args.reason === "ledger_read_required") {
|
|
2595
2595
|
return {
|
|
2596
2596
|
uiReason: "read the ledger before making file edits.",
|
|
2597
|
-
modelMessage: "Blocked by
|
|
2597
|
+
modelMessage: "Blocked by Policy: read the ledger before making file edits.\nNext: call `mcp__flockbay__ledger_read` (or `mcp__flockbay__coordination_ledger_snapshot`), then retry the edit."
|
|
2598
2598
|
};
|
|
2599
2599
|
}
|
|
2600
2600
|
if (args.reason === "file_claim_required") {
|
|
@@ -2602,13 +2602,13 @@ class PermissionHandler {
|
|
|
2602
2602
|
const next = file ? `Next: claim it via \`mcp__flockbay__ledger_claim\` (files: ["${file}"]) or \`mcp__flockbay__coordination_claim_files\`, then retry the edit.` : "Next: claim the file via `mcp__flockbay__ledger_claim` (or `mcp__flockbay__coordination_claim_files`), then retry the edit.";
|
|
2603
2603
|
return {
|
|
2604
2604
|
uiReason: display,
|
|
2605
|
-
modelMessage: `Blocked by
|
|
2605
|
+
modelMessage: `Blocked by Policy: ${display}
|
|
2606
2606
|
${next}`
|
|
2607
2607
|
};
|
|
2608
2608
|
}
|
|
2609
2609
|
return {
|
|
2610
2610
|
uiReason: "this session is in read-only mode.",
|
|
2611
|
-
modelMessage: "Blocked by
|
|
2611
|
+
modelMessage: "Blocked by Policy: this session is in read-only mode.\nNext: switch permission mode to allow edits, then retry."
|
|
2612
2612
|
};
|
|
2613
2613
|
}
|
|
2614
2614
|
enforceCoordinationGate(toolName, input) {
|
|
@@ -7173,7 +7173,7 @@ async function uploadScreenshotViewsForSession(args) {
|
|
|
7173
7173
|
const buf = await readFile(v.path);
|
|
7174
7174
|
const filename = path.basename(v.path);
|
|
7175
7175
|
const contentType = (() => {
|
|
7176
|
-
const mime = detectImageMimeTypeFromBuffer(buf);
|
|
7176
|
+
const mime = detectImageMimeTypeFromBuffer$1(buf);
|
|
7177
7177
|
if (mime) return mime;
|
|
7178
7178
|
throw new Error(`Unsupported screenshot format (expected PNG/JPEG): ${v.path}`);
|
|
7179
7179
|
})();
|
|
@@ -7217,7 +7217,7 @@ async function uploadScreenshotViewsForSession(args) {
|
|
|
7217
7217
|
}
|
|
7218
7218
|
return out;
|
|
7219
7219
|
}
|
|
7220
|
-
function detectImageMimeTypeFromBuffer(buf) {
|
|
7220
|
+
function detectImageMimeTypeFromBuffer$1(buf) {
|
|
7221
7221
|
if (!buf || buf.length < 12) return null;
|
|
7222
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
7223
|
return "image/png";
|
|
@@ -7233,6 +7233,48 @@ function detectImageMimeTypeFromBuffer(buf) {
|
|
|
7233
7233
|
}
|
|
7234
7234
|
return null;
|
|
7235
7235
|
}
|
|
7236
|
+
async function readFileHeader(filePath, bytes) {
|
|
7237
|
+
const fh = await open$1(filePath, "r");
|
|
7238
|
+
try {
|
|
7239
|
+
const maxBytes = Math.max(1, Math.floor(bytes));
|
|
7240
|
+
const buf = Buffer.allocUnsafe(maxBytes);
|
|
7241
|
+
const { bytesRead } = await fh.read(buf, 0, maxBytes, 0);
|
|
7242
|
+
return buf.subarray(0, bytesRead);
|
|
7243
|
+
} finally {
|
|
7244
|
+
try {
|
|
7245
|
+
await fh.close();
|
|
7246
|
+
} catch {
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
async function normalizeScreenshotPathExtensionToMatchBytes(filePath) {
|
|
7251
|
+
const abs = String(filePath || "").trim();
|
|
7252
|
+
if (!abs) return { path: abs, changed: false };
|
|
7253
|
+
if (!existsSync(abs)) return { path: abs, changed: false };
|
|
7254
|
+
const lower = abs.toLowerCase();
|
|
7255
|
+
const header = await readFileHeader(abs, 16);
|
|
7256
|
+
const mime = detectImageMimeTypeFromBuffer$1(header);
|
|
7257
|
+
if (!mime) {
|
|
7258
|
+
return { path: abs, changed: false, detail: "unknown_image_format" };
|
|
7259
|
+
}
|
|
7260
|
+
if (mime === "image/jpeg" && lower.endsWith(".png")) {
|
|
7261
|
+
const next = abs.replace(/\.png$/i, ".jpg");
|
|
7262
|
+
if (existsSync(next)) {
|
|
7263
|
+
throw new Error(`Screenshot already exists at normalized path: ${next}`);
|
|
7264
|
+
}
|
|
7265
|
+
await rename(abs, next);
|
|
7266
|
+
return { path: next, changed: true, detail: "renamed_png_to_jpg" };
|
|
7267
|
+
}
|
|
7268
|
+
if (mime === "image/png" && (lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) {
|
|
7269
|
+
const next = abs.replace(/\.(jpg|jpeg)$/i, ".png");
|
|
7270
|
+
if (existsSync(next)) {
|
|
7271
|
+
throw new Error(`Screenshot already exists at normalized path: ${next}`);
|
|
7272
|
+
}
|
|
7273
|
+
await rename(abs, next);
|
|
7274
|
+
return { path: next, changed: true, detail: "renamed_jpg_to_png" };
|
|
7275
|
+
}
|
|
7276
|
+
return { path: abs, changed: false };
|
|
7277
|
+
}
|
|
7236
7278
|
async function startFlockbayServer(client, options) {
|
|
7237
7279
|
const handler = async (title) => {
|
|
7238
7280
|
logger.debug("[flockbayMCP] Changing title to:", title);
|
|
@@ -8829,7 +8871,7 @@ ${String(st.stdout || "").trim()}`
|
|
|
8829
8871
|
throw new Error(`Image too large (${st.size} bytes) to embed: ${abs}`);
|
|
8830
8872
|
}
|
|
8831
8873
|
const buf = await readFile(abs);
|
|
8832
|
-
const mime = detectImageMimeTypeFromBuffer(buf);
|
|
8874
|
+
const mime = detectImageMimeTypeFromBuffer$1(buf);
|
|
8833
8875
|
if (!mime) {
|
|
8834
8876
|
throw new Error(`Unsupported image format (expected PNG/JPEG): ${abs}`);
|
|
8835
8877
|
}
|
|
@@ -8879,7 +8921,7 @@ ${String(st.stdout || "").trim()}`
|
|
|
8879
8921
|
);
|
|
8880
8922
|
mcp.registerTool("unreal_latest_screenshots", {
|
|
8881
8923
|
title: "Latest Unreal Screenshots (Validation)",
|
|
8882
|
-
description: "Fetch the latest PNG
|
|
8924
|
+
description: "Fetch the latest screenshots (PNG/JPG) from `Saved/Screenshots/Flockbay/` (for validation) and return a `{ views: [...] }` payload so the app can display them.",
|
|
8883
8925
|
inputSchema: {
|
|
8884
8926
|
uprojectPath: z.string().describe("Absolute path to the .uproject file."),
|
|
8885
8927
|
limit: z.number().int().positive().optional().describe("Max number of screenshots to return (default 12)."),
|
|
@@ -8916,7 +8958,7 @@ ${String(st.stdout || "").trim()}`
|
|
|
8916
8958
|
};
|
|
8917
8959
|
}
|
|
8918
8960
|
const files = await readdir(outDir);
|
|
8919
|
-
const candidates = files.filter((f) =>
|
|
8961
|
+
const candidates = files.filter((f) => /\.(png|jpg|jpeg)$/i.test(f));
|
|
8920
8962
|
if (candidates.length === 0) {
|
|
8921
8963
|
return {
|
|
8922
8964
|
content: [
|
|
@@ -9171,10 +9213,26 @@ ${String(st.stdout || "").trim()}`
|
|
|
9171
9213
|
const pluginInfoWasCached = Boolean(unrealMcpPluginInfoCache);
|
|
9172
9214
|
const pluginInfo = type !== "get_plugin_info" ? await getUnrealMcpPluginInfoBestEffort(timeoutMs) : null;
|
|
9173
9215
|
const response = await sendUnrealMcpTcpCommand({ type, params, timeoutMs });
|
|
9216
|
+
let screenshotNormalizationNote = null;
|
|
9217
|
+
if (type === "take_screenshot") {
|
|
9218
|
+
const responseObj = response && typeof response === "object" ? response : null;
|
|
9219
|
+
const candidate = responseObj && typeof responseObj.filepath === "string" ? responseObj : responseObj && responseObj.result && typeof responseObj.result === "object" && typeof responseObj.result.filepath === "string" ? responseObj.result : null;
|
|
9220
|
+
if (candidate && typeof candidate.filepath === "string") {
|
|
9221
|
+
const before = String(candidate.filepath || "").trim();
|
|
9222
|
+
if (before) {
|
|
9223
|
+
const normalized = await normalizeScreenshotPathExtensionToMatchBytes(before);
|
|
9224
|
+
if (normalized.changed) {
|
|
9225
|
+
candidate.filepath = normalized.path;
|
|
9226
|
+
screenshotNormalizationNote = `Normalized screenshot path (${normalized.detail || "extension_fixed"}): ${before} \u2192 ${normalized.path}`;
|
|
9227
|
+
}
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
}
|
|
9174
9231
|
unrealEditorSupervisor.noteUnrealReachable();
|
|
9175
9232
|
return {
|
|
9176
9233
|
content: [
|
|
9177
9234
|
{ type: "text", text: `UnrealMCP command ok: ${type}` },
|
|
9235
|
+
...screenshotNormalizationNote ? [{ type: "text", text: screenshotNormalizationNote }] : [],
|
|
9178
9236
|
{ type: "text", text: JSON.stringify(response, null, 2) },
|
|
9179
9237
|
...pluginInfo && !pluginInfoWasCached ? [{ type: "text", text: formatUnrealMcpCapabilities(pluginInfo) }] : []
|
|
9180
9238
|
],
|
|
@@ -11834,6 +11892,269 @@ async function handleConnectVendor(vendor, displayName, flags) {
|
|
|
11834
11892
|
}
|
|
11835
11893
|
}
|
|
11836
11894
|
|
|
11895
|
+
function readArgValue$1(args, key) {
|
|
11896
|
+
const idx = args.indexOf(key);
|
|
11897
|
+
if (idx === -1) return null;
|
|
11898
|
+
const value = args[idx + 1];
|
|
11899
|
+
if (!value || value.startsWith("-")) return null;
|
|
11900
|
+
return value;
|
|
11901
|
+
}
|
|
11902
|
+
function splitList(value) {
|
|
11903
|
+
if (!value) return [];
|
|
11904
|
+
return value.split(/[;,]/g).map((v) => v.trim()).filter(Boolean);
|
|
11905
|
+
}
|
|
11906
|
+
function ensureDir(dir) {
|
|
11907
|
+
fs__default.mkdirSync(dir, { recursive: true });
|
|
11908
|
+
}
|
|
11909
|
+
function detectImageMimeTypeFromBuffer(buf) {
|
|
11910
|
+
if (!buf || buf.length < 12) return null;
|
|
11911
|
+
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) {
|
|
11912
|
+
return "image/png";
|
|
11913
|
+
}
|
|
11914
|
+
if (buf[0] === 255 && buf[1] === 216 && buf[2] === 255) return "image/jpeg";
|
|
11915
|
+
if (buf[0] === 71 && buf[1] === 73 && buf[2] === 70 && buf[3] === 56) return "image/gif";
|
|
11916
|
+
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) {
|
|
11917
|
+
return "image/webp";
|
|
11918
|
+
}
|
|
11919
|
+
return null;
|
|
11920
|
+
}
|
|
11921
|
+
async function waitForUnreal(options) {
|
|
11922
|
+
const startedAt = Date.now();
|
|
11923
|
+
let lastErr = null;
|
|
11924
|
+
while (Date.now() - startedAt < options.timeoutMs) {
|
|
11925
|
+
try {
|
|
11926
|
+
const res = await sendUnrealMcpTcpCommand({ type: "ping", host: options.host, port: options.port, timeoutMs: 2e3 });
|
|
11927
|
+
const msg = typeof res?.message === "string" ? res.message : null;
|
|
11928
|
+
if (msg === "pong") return { ok: true };
|
|
11929
|
+
} catch (err) {
|
|
11930
|
+
lastErr = err instanceof Error ? err.message : String(err);
|
|
11931
|
+
}
|
|
11932
|
+
await new Promise((r) => setTimeout(r, 750));
|
|
11933
|
+
}
|
|
11934
|
+
return {
|
|
11935
|
+
ok: false,
|
|
11936
|
+
error: `Timed out waiting for UnrealMCP ping after ${options.timeoutMs}ms.${lastErr ? ` Last error: ${lastErr}` : ""}`
|
|
11937
|
+
};
|
|
11938
|
+
}
|
|
11939
|
+
function resolveUnrealEditorExe(engineRoot) {
|
|
11940
|
+
const exe = process.platform === "win32" ? path.join(engineRoot, "Engine", "Binaries", "Win64", "UnrealEditor.exe") : path.join(engineRoot, "Engine", "Binaries", process.platform === "darwin" ? "Mac" : "Linux", "UnrealEditor");
|
|
11941
|
+
return exe;
|
|
11942
|
+
}
|
|
11943
|
+
async function runRuntimeSmoke(options) {
|
|
11944
|
+
const editorExe = resolveUnrealEditorExe(options.engineRoot);
|
|
11945
|
+
if (!fs__default.existsSync(editorExe)) {
|
|
11946
|
+
return { ok: false, error: `Missing UnrealEditor executable: ${editorExe}` };
|
|
11947
|
+
}
|
|
11948
|
+
if (!fs__default.existsSync(options.projectPath)) {
|
|
11949
|
+
return { ok: false, error: `Missing .uproject: ${options.projectPath}` };
|
|
11950
|
+
}
|
|
11951
|
+
let child = null;
|
|
11952
|
+
const ping = await waitForUnreal({ host: options.host, port: options.port, timeoutMs: 2e3 }).catch((e) => ({ ok: false, error: String(e) }));
|
|
11953
|
+
if (!ping.ok && options.launchIfNeeded) {
|
|
11954
|
+
const args = [
|
|
11955
|
+
options.projectPath,
|
|
11956
|
+
"-NoSplash",
|
|
11957
|
+
"-NoSound",
|
|
11958
|
+
"-nop4"
|
|
11959
|
+
];
|
|
11960
|
+
child = spawn(editorExe, args, {
|
|
11961
|
+
stdio: "ignore",
|
|
11962
|
+
detached: false
|
|
11963
|
+
});
|
|
11964
|
+
}
|
|
11965
|
+
const ready = await waitForUnreal({ host: options.host, port: options.port, timeoutMs: options.connectTimeoutMs });
|
|
11966
|
+
if (!ready.ok) {
|
|
11967
|
+
try {
|
|
11968
|
+
child?.kill();
|
|
11969
|
+
} catch {
|
|
11970
|
+
}
|
|
11971
|
+
return ready;
|
|
11972
|
+
}
|
|
11973
|
+
try {
|
|
11974
|
+
const pluginInfo = await sendUnrealMcpTcpCommand({ type: "get_plugin_info", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
|
|
11975
|
+
const createdBy = String(pluginInfo?.createdBy || "").trim();
|
|
11976
|
+
const friendlyName = String(pluginInfo?.friendlyName || "").trim();
|
|
11977
|
+
const baseDir = String(pluginInfo?.baseDir || "").trim();
|
|
11978
|
+
const schemaVersion = Number(pluginInfo?.schemaVersion);
|
|
11979
|
+
const commands = Array.isArray(pluginInfo?.commands) ? pluginInfo.commands.filter((c) => typeof c === "string") : [];
|
|
11980
|
+
if (friendlyName !== "Flockbay MCP" || createdBy !== "Respaced Inc.") {
|
|
11981
|
+
return {
|
|
11982
|
+
ok: false,
|
|
11983
|
+
error: `Unexpected plugin identity loaded by Unreal.
|
|
11984
|
+
friendlyName=${friendlyName || "(missing)"} createdBy=${createdBy || "(missing)"}
|
|
11985
|
+
baseDir=${baseDir || "(missing)"}
|
|
11986
|
+
Expected FriendlyName="Flockbay MCP" CreatedBy="Respaced Inc."`
|
|
11987
|
+
};
|
|
11988
|
+
}
|
|
11989
|
+
if (!Number.isFinite(schemaVersion) || schemaVersion <= 0) {
|
|
11990
|
+
return { ok: false, error: `Invalid schemaVersion from get_plugin_info: ${String(pluginInfo?.schemaVersion)}` };
|
|
11991
|
+
}
|
|
11992
|
+
const requireCommands = [
|
|
11993
|
+
"ping",
|
|
11994
|
+
"get_plugin_info",
|
|
11995
|
+
"list_capabilities",
|
|
11996
|
+
"get_command_schema",
|
|
11997
|
+
"get_play_in_editor_status",
|
|
11998
|
+
"play_in_editor_windowed",
|
|
11999
|
+
"stop_play_in_editor",
|
|
12000
|
+
"take_screenshot",
|
|
12001
|
+
"create_blueprint",
|
|
12002
|
+
"compile_blueprint",
|
|
12003
|
+
"map_check"
|
|
12004
|
+
];
|
|
12005
|
+
const missing = requireCommands.filter((c) => !commands.includes(c));
|
|
12006
|
+
if (missing.length > 0) {
|
|
12007
|
+
return { ok: false, error: `Missing required commands in this UnrealMCP build: ${missing.join(", ")}` };
|
|
12008
|
+
}
|
|
12009
|
+
const playStatus0 = await sendUnrealMcpTcpCommand({ type: "get_play_in_editor_status", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
|
|
12010
|
+
const isPlaying = Boolean(playStatus0?.isPlaySessionInProgress);
|
|
12011
|
+
if (isPlaying) {
|
|
12012
|
+
await sendUnrealMcpTcpCommand({ type: "stop_play_in_editor", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
|
|
12013
|
+
}
|
|
12014
|
+
await sendUnrealMcpTcpCommand({ type: "play_in_editor_windowed", host: options.host, port: options.port, timeoutMs: Math.max(options.timeoutMs, 2e4) });
|
|
12015
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
12016
|
+
await sendUnrealMcpTcpCommand({ type: "stop_play_in_editor", host: options.host, port: options.port, timeoutMs: Math.max(options.timeoutMs, 2e4) });
|
|
12017
|
+
const projectDir = path.dirname(options.projectPath);
|
|
12018
|
+
const shotsDir = path.join(projectDir, "Saved", "Screenshots", "Flockbay");
|
|
12019
|
+
ensureDir(shotsDir);
|
|
12020
|
+
const shotPath = path.join(shotsDir, `smoke_${Date.now()}.png`);
|
|
12021
|
+
await sendUnrealMcpTcpCommand({
|
|
12022
|
+
type: "take_screenshot",
|
|
12023
|
+
params: { filepath: shotPath },
|
|
12024
|
+
host: options.host,
|
|
12025
|
+
port: options.port,
|
|
12026
|
+
timeoutMs: options.timeoutMs
|
|
12027
|
+
});
|
|
12028
|
+
if (!fs__default.existsSync(shotPath)) return { ok: false, error: `Screenshot did not exist on disk after take_screenshot: ${shotPath}` };
|
|
12029
|
+
const bytes = fs__default.readFileSync(shotPath);
|
|
12030
|
+
const mime = detectImageMimeTypeFromBuffer(bytes);
|
|
12031
|
+
if (mime !== "image/png") {
|
|
12032
|
+
return { ok: false, error: `Screenshot bytes do not match .png extension (detected ${mime || "unknown"}): ${shotPath}` };
|
|
12033
|
+
}
|
|
12034
|
+
const bpName = `BP_Smoke_${Date.now()}`;
|
|
12035
|
+
await sendUnrealMcpTcpCommand({
|
|
12036
|
+
type: "create_blueprint",
|
|
12037
|
+
params: { name: bpName, path: "/Game/FlockbaySmoke/", parent_class: "Actor" },
|
|
12038
|
+
host: options.host,
|
|
12039
|
+
port: options.port,
|
|
12040
|
+
timeoutMs: Math.max(options.timeoutMs, 2e4)
|
|
12041
|
+
});
|
|
12042
|
+
await sendUnrealMcpTcpCommand({
|
|
12043
|
+
type: "compile_blueprint",
|
|
12044
|
+
params: { blueprint_name: bpName },
|
|
12045
|
+
host: options.host,
|
|
12046
|
+
port: options.port,
|
|
12047
|
+
timeoutMs: Math.max(options.timeoutMs, 6e4)
|
|
12048
|
+
});
|
|
12049
|
+
await sendUnrealMcpTcpCommand({
|
|
12050
|
+
type: "map_check",
|
|
12051
|
+
host: options.host,
|
|
12052
|
+
port: options.port,
|
|
12053
|
+
timeoutMs: Math.max(options.timeoutMs, 3e4)
|
|
12054
|
+
});
|
|
12055
|
+
return { ok: true };
|
|
12056
|
+
} finally {
|
|
12057
|
+
if (options.killAfter && child) {
|
|
12058
|
+
try {
|
|
12059
|
+
if (process.platform === "win32") {
|
|
12060
|
+
spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
12061
|
+
} else {
|
|
12062
|
+
child.kill();
|
|
12063
|
+
}
|
|
12064
|
+
} catch {
|
|
12065
|
+
}
|
|
12066
|
+
}
|
|
12067
|
+
}
|
|
12068
|
+
}
|
|
12069
|
+
async function runUnrealMcpMatrixSmoke(args) {
|
|
12070
|
+
const engineRoots = splitList(readArgValue$1(args, "--engine-roots")) || [];
|
|
12071
|
+
const engineRootSingle = readArgValue$1(args, "--engine-root");
|
|
12072
|
+
if (engineRootSingle) engineRoots.push(engineRootSingle.trim());
|
|
12073
|
+
const project = readArgValue$1(args, "--project");
|
|
12074
|
+
const host = (readArgValue$1(args, "--host") || "127.0.0.1").trim() || "127.0.0.1";
|
|
12075
|
+
const port = Number(readArgValue$1(args, "--port") || "55557");
|
|
12076
|
+
const connectTimeoutMs = Number(readArgValue$1(args, "--connect-timeout-ms") || "180000");
|
|
12077
|
+
const timeoutMs = Number(readArgValue$1(args, "--timeout-ms") || "30000");
|
|
12078
|
+
const doBuild = !args.includes("--runtime-only");
|
|
12079
|
+
const doRuntime = !args.includes("--build-only");
|
|
12080
|
+
const launch = args.includes("--launch-editor");
|
|
12081
|
+
const killAfter = args.includes("--kill-editor");
|
|
12082
|
+
if (engineRoots.length === 0) {
|
|
12083
|
+
console.error(chalk.red("Missing --engine-root or --engine-roots."));
|
|
12084
|
+
console.error(chalk.gray('Example: flockbay doctor unreal-mcp-smoke --engine-roots "C:\\\\Epic\\\\UE_5.5;C:\\\\Epic\\\\UE_5.6" --project "C:\\\\Projects\\\\MyProj\\\\MyProj.uproject" --launch-editor --kill-editor'));
|
|
12085
|
+
process.exit(1);
|
|
12086
|
+
}
|
|
12087
|
+
if (doRuntime && !project) {
|
|
12088
|
+
console.error(chalk.red("Missing --project (required for runtime smoke)."));
|
|
12089
|
+
process.exit(1);
|
|
12090
|
+
}
|
|
12091
|
+
console.log(chalk.bold("\nUnrealMCP Matrix Smoke\n"));
|
|
12092
|
+
console.log(chalk.gray(`Platform: ${process.platform}`));
|
|
12093
|
+
console.log(chalk.gray(`Host: ${host}:${port}`));
|
|
12094
|
+
console.log(chalk.gray(`Engines: ${engineRoots.join(", ")}`));
|
|
12095
|
+
if (project) console.log(chalk.gray(`Project: ${project}`));
|
|
12096
|
+
console.log(chalk.gray(`Build: ${doBuild ? "yes" : "no"} Runtime: ${doRuntime ? "yes" : "no"} Launch: ${launch ? "yes" : "no"} Kill: ${killAfter ? "yes" : "no"}`));
|
|
12097
|
+
console.log("");
|
|
12098
|
+
const failures = [];
|
|
12099
|
+
for (const engineRootRaw of engineRoots) {
|
|
12100
|
+
const engineRoot = engineRootRaw.trim();
|
|
12101
|
+
if (!engineRoot) continue;
|
|
12102
|
+
console.log(chalk.bold(`== Engine: ${engineRoot} ==`));
|
|
12103
|
+
if (doBuild) {
|
|
12104
|
+
console.log(chalk.cyan("Build: installing UnrealMCP plugin sources..."));
|
|
12105
|
+
const installed = installUnrealMcpPluginToEngine(engineRoot);
|
|
12106
|
+
if (!installed.ok) {
|
|
12107
|
+
failures.push({ engineRoot, phase: "build", error: installed.errorMessage });
|
|
12108
|
+
console.log(chalk.red(`Build: failed (install)
|
|
12109
|
+
${installed.errorMessage}
|
|
12110
|
+
`));
|
|
12111
|
+
if (!doRuntime) continue;
|
|
12112
|
+
} else {
|
|
12113
|
+
console.log(chalk.green(`Build: sources installed to ${installed.destDir}`));
|
|
12114
|
+
console.log(chalk.cyan("Build: compiling plugin via RunUAT BuildPlugin..."));
|
|
12115
|
+
const built = await buildAndInstallUnrealMcpPlugin({ engineRoot, flockbayHomeDir: configuration.flockbayHomeDir });
|
|
12116
|
+
if (!built.ok) {
|
|
12117
|
+
failures.push({ engineRoot, phase: "build", error: built.errorMessage });
|
|
12118
|
+
console.log(chalk.red(`Build: failed
|
|
12119
|
+
${built.errorMessage}
|
|
12120
|
+
`));
|
|
12121
|
+
} else {
|
|
12122
|
+
console.log(chalk.green(`Build: ok (log: ${built.buildLogPath})`));
|
|
12123
|
+
}
|
|
12124
|
+
}
|
|
12125
|
+
}
|
|
12126
|
+
if (doRuntime) {
|
|
12127
|
+
console.log(chalk.cyan("Runtime: running command smoke..."));
|
|
12128
|
+
const res = await runRuntimeSmoke({
|
|
12129
|
+
engineRoot,
|
|
12130
|
+
projectPath: project,
|
|
12131
|
+
host,
|
|
12132
|
+
port,
|
|
12133
|
+
connectTimeoutMs,
|
|
12134
|
+
timeoutMs,
|
|
12135
|
+
launchIfNeeded: launch,
|
|
12136
|
+
killAfter
|
|
12137
|
+
});
|
|
12138
|
+
if (!res.ok) {
|
|
12139
|
+
failures.push({ engineRoot, phase: "runtime", error: res.error });
|
|
12140
|
+
console.log(chalk.red(`Runtime: failed
|
|
12141
|
+
${res.error}
|
|
12142
|
+
`));
|
|
12143
|
+
} else {
|
|
12144
|
+
console.log(chalk.green("Runtime: ok\n"));
|
|
12145
|
+
}
|
|
12146
|
+
}
|
|
12147
|
+
}
|
|
12148
|
+
if (failures.length > 0) {
|
|
12149
|
+
console.error(chalk.red("\nMatrix smoke failed.\n"));
|
|
12150
|
+
for (const f of failures) {
|
|
12151
|
+
console.error(chalk.red(`- ${f.engineRoot} (${f.phase}): ${f.error}`));
|
|
12152
|
+
}
|
|
12153
|
+
process.exit(1);
|
|
12154
|
+
}
|
|
12155
|
+
console.log(chalk.green("\nMatrix smoke passed.\n"));
|
|
12156
|
+
}
|
|
12157
|
+
|
|
11837
12158
|
function readTailUtf8(filePath, maxBytes) {
|
|
11838
12159
|
try {
|
|
11839
12160
|
const stat = fs.statSync(filePath);
|
|
@@ -12194,6 +12515,16 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
12194
12515
|
}
|
|
12195
12516
|
if (!args.includes("--version")) ;
|
|
12196
12517
|
if (subcommand === "doctor") {
|
|
12518
|
+
if (args[1] === "unreal-mcp-smoke") {
|
|
12519
|
+
try {
|
|
12520
|
+
await runUnrealMcpMatrixSmoke(args.slice(2));
|
|
12521
|
+
} catch (error) {
|
|
12522
|
+
console.error(chalk.red("UnrealMCP smoke failed:"), error instanceof Error ? error.message : String(error));
|
|
12523
|
+
if (process.env.DEBUG) console.error(error);
|
|
12524
|
+
process.exit(1);
|
|
12525
|
+
}
|
|
12526
|
+
return;
|
|
12527
|
+
}
|
|
12197
12528
|
if (args[1] === "clean") {
|
|
12198
12529
|
const result = await killRunawayFlockbayProcesses();
|
|
12199
12530
|
console.log(`Cleaned up ${result.killed} runaway processes`);
|
|
@@ -12305,7 +12636,7 @@ ${engineRoot}`, {
|
|
|
12305
12636
|
} else if (subcommand === "codex") {
|
|
12306
12637
|
try {
|
|
12307
12638
|
await chdirToNearestUprojectRootIfPresent();
|
|
12308
|
-
const { runCodex } = await import('./runCodex-
|
|
12639
|
+
const { runCodex } = await import('./runCodex-BC3IImzm.mjs');
|
|
12309
12640
|
let startedBy = void 0;
|
|
12310
12641
|
let sessionId = void 0;
|
|
12311
12642
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -12331,7 +12662,13 @@ ${engineRoot}`, {
|
|
|
12331
12662
|
const geminiSubcommand = args[1];
|
|
12332
12663
|
if (geminiSubcommand === "model" && args[2] === "set" && args[3]) {
|
|
12333
12664
|
const modelName = args[3];
|
|
12334
|
-
const validModels = [
|
|
12665
|
+
const validModels = [
|
|
12666
|
+
"gemini-2.5-pro",
|
|
12667
|
+
"gemini-2.5-flash",
|
|
12668
|
+
"gemini-2.5-flash-lite",
|
|
12669
|
+
"gemini-3-pro-preview",
|
|
12670
|
+
"gemini-3-flash-preview"
|
|
12671
|
+
];
|
|
12335
12672
|
if (!validModels.includes(modelName)) {
|
|
12336
12673
|
console.error(`Invalid model: ${modelName}`);
|
|
12337
12674
|
console.error(`Available models: ${validModels.join(", ")}`);
|
|
@@ -12400,7 +12737,7 @@ ${engineRoot}`, {
|
|
|
12400
12737
|
}
|
|
12401
12738
|
try {
|
|
12402
12739
|
await chdirToNearestUprojectRootIfPresent();
|
|
12403
|
-
const { runGemini } = await import('./runGemini-
|
|
12740
|
+
const { runGemini } = await import('./runGemini-C43IKGUU.mjs');
|
|
12404
12741
|
let startedBy = void 0;
|
|
12405
12742
|
let sessionId = void 0;
|
|
12406
12743
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -12731,4 +13068,4 @@ ${chalk.bold("Examples:")}
|
|
|
12731
13068
|
}
|
|
12732
13069
|
}
|
|
12733
13070
|
|
|
12734
|
-
export { ElicitationHub as E, MessageQueue2 as M, PLATFORM_SYSTEM_PROMPT as P, setLatestUserImages as a, MessageBuffer as b, consumeToolQuota as c, startFlockbayServer as d,
|
|
13071
|
+
export { ElicitationHub as E, MessageQueue2 as M, PLATFORM_SYSTEM_PROMPT as P, setLatestUserImages as a, MessageBuffer as b, consumeToolQuota as c, startFlockbayServer as d, buildProjectCapsule as e, formatQuotaDeniedReason as f, autoFinalizeCoordinationWorkItem as g, hashObject as h, initialMachineMetadata as i, detectScreenshotsForGate as j, applyCoordinationSideEffectsFromMcpToolResult as k, stopCaffeinate as l, extractUserImagesMarker as m, notifyDaemonSessionStarted as n, getLatestUserImages as o, registerKillSessionHandler as r, shouldCountToolCall as s, trimIdent as t, withUserImagesMarker as w };
|
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-CNn15BaT.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:os';
|
|
@@ -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-CNn15BaT.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
|
|
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 buildProjectCapsule, t as trimIdent, g as autoFinalizeCoordinationWorkItem, j as detectScreenshotsForGate, k as applyCoordinationSideEffectsFromMcpToolResult, l as stopCaffeinate } from './index-CRGcIpET.mjs';
|
|
14
14
|
import 'axios';
|
|
15
15
|
import 'node:events';
|
|
16
16
|
import 'socket.io-client';
|
|
@@ -250,18 +250,18 @@ function buildMcpElicitationResult(decision, requestedSchemaRaw, options) {
|
|
|
250
250
|
if (!raw) return "";
|
|
251
251
|
if (/^Blocked\b/.test(raw)) return raw;
|
|
252
252
|
if (raw === "ledger_read_required") {
|
|
253
|
-
return "Blocked by
|
|
253
|
+
return "Blocked by Policy (automatic; not the user): read the ledger before making file edits. Next: call mcp__flockbay__ledger_read, then retry the edit.";
|
|
254
254
|
}
|
|
255
255
|
if (raw === "docs_index_read_required") {
|
|
256
|
-
return "Blocked by
|
|
256
|
+
return "Blocked by Policy (automatic; not the user): read the game Documentation index before making edits. Next: call mcp__flockbay__docs_index_read, then retry the edit.";
|
|
257
257
|
}
|
|
258
258
|
if (raw.startsWith("file_claim_required:")) {
|
|
259
259
|
const withoutPrefix = raw.slice("file_claim_required:".length);
|
|
260
260
|
const file = withoutPrefix.split("(")[0]?.trim() || "the file";
|
|
261
|
-
return `Blocked by
|
|
261
|
+
return `Blocked by Policy (automatic; not the user): claim ${file} before editing it. Next: claim the file via mcp__flockbay__ledger_claim (or mcp__flockbay__coordination_claim_files), then retry the edit.`;
|
|
262
262
|
}
|
|
263
263
|
if (raw === "read_only_mode") {
|
|
264
|
-
return "Blocked by
|
|
264
|
+
return "Blocked by Policy (automatic; not the user): this session is in read-only mode. Next: switch permission mode to allow edits, then retry.";
|
|
265
265
|
}
|
|
266
266
|
return `Blocked: ${raw}`;
|
|
267
267
|
};
|
|
@@ -1740,7 +1740,7 @@ function buildPolicyHint(reason, decision, gate) {
|
|
|
1740
1740
|
};
|
|
1741
1741
|
}
|
|
1742
1742
|
return {
|
|
1743
|
-
summary: "Blocked by
|
|
1743
|
+
summary: "Blocked by Policy.",
|
|
1744
1744
|
nextSteps: []
|
|
1745
1745
|
};
|
|
1746
1746
|
}
|
|
@@ -1752,7 +1752,7 @@ function buildPolicyHint(reason, decision, gate) {
|
|
|
1752
1752
|
}
|
|
1753
1753
|
if (raw === "ledger_read_required") {
|
|
1754
1754
|
return {
|
|
1755
|
-
summary: "Blocked by
|
|
1755
|
+
summary: "Blocked by Policy (automatic; not the user): read the ledger before making file edits.",
|
|
1756
1756
|
nextSteps: [
|
|
1757
1757
|
"Call `mcp__flockbay__ledger_read` (or `mcp__flockbay__coordination_ledger_snapshot`).",
|
|
1758
1758
|
"Then retry the file edit."
|
|
@@ -1761,7 +1761,7 @@ function buildPolicyHint(reason, decision, gate) {
|
|
|
1761
1761
|
}
|
|
1762
1762
|
if (raw === "docs_index_read_required") {
|
|
1763
1763
|
return {
|
|
1764
|
-
summary: "Blocked by
|
|
1764
|
+
summary: "Blocked by Policy (automatic; not the user): read the game Documentation index before making edits.",
|
|
1765
1765
|
nextSteps: [
|
|
1766
1766
|
"Call `mcp__flockbay__docs_index_read`.",
|
|
1767
1767
|
"Then retry the edit."
|
|
@@ -1772,7 +1772,7 @@ function buildPolicyHint(reason, decision, gate) {
|
|
|
1772
1772
|
const withoutPrefix = raw.slice("file_claim_required:".length);
|
|
1773
1773
|
const file = withoutPrefix.split("(")[0]?.trim() || "the file";
|
|
1774
1774
|
return {
|
|
1775
|
-
summary: `Blocked by
|
|
1775
|
+
summary: `Blocked by Policy (automatic; not the user): claim \`${file}\` before editing it.`,
|
|
1776
1776
|
nextSteps: [
|
|
1777
1777
|
`Claim the file via \`mcp__flockbay__ledger_claim\` or \`mcp__flockbay__coordination_claim_files\` (files: ["${file}"]).`,
|
|
1778
1778
|
"Then retry the file edit."
|
|
@@ -1781,7 +1781,7 @@ function buildPolicyHint(reason, decision, gate) {
|
|
|
1781
1781
|
}
|
|
1782
1782
|
if (raw === "read_only_mode") {
|
|
1783
1783
|
return {
|
|
1784
|
-
summary: "Blocked by
|
|
1784
|
+
summary: "Blocked by Policy (automatic; not the user): this session is in read-only mode.",
|
|
1785
1785
|
nextSteps: [
|
|
1786
1786
|
"Switch permission mode to allow edits (disable read-only).",
|
|
1787
1787
|
"Then retry the action."
|
|
@@ -2381,7 +2381,6 @@ async function runCodex(opts) {
|
|
|
2381
2381
|
appendSystemPrompt: PLATFORM_SYSTEM_PROMPT
|
|
2382
2382
|
});
|
|
2383
2383
|
}
|
|
2384
|
-
const bypassUeGates = String(process.env.FLOCKBAY_DEV_BYPASS_UE_GATES || "") === "1";
|
|
2385
2384
|
let currentPermissionMode = void 0;
|
|
2386
2385
|
let currentModel = void 0;
|
|
2387
2386
|
const defaultAppendSystemPrompt = PLATFORM_SYSTEM_PROMPT;
|
|
@@ -3449,22 +3448,6 @@ Error: ${message}`,
|
|
|
3449
3448
|
try {
|
|
3450
3449
|
resetScreenshotGateForTurn();
|
|
3451
3450
|
const overrides = { approvalPolicy: "untrusted", sandbox: "workspace-write" };
|
|
3452
|
-
if (!bypassUeGates) {
|
|
3453
|
-
const detection = await detectUnrealProject(process.cwd());
|
|
3454
|
-
if (!detection.ok) {
|
|
3455
|
-
session.sendCodexMessage({
|
|
3456
|
-
type: "message",
|
|
3457
|
-
message: "Select an Unreal project folder (the folder containing a *.uproject) to continue.",
|
|
3458
|
-
id: randomUUID()
|
|
3459
|
-
});
|
|
3460
|
-
if (wasCreated) {
|
|
3461
|
-
client.clearSession();
|
|
3462
|
-
wasCreated = false;
|
|
3463
|
-
currentModeHash = null;
|
|
3464
|
-
}
|
|
3465
|
-
continue;
|
|
3466
|
-
}
|
|
3467
|
-
}
|
|
3468
3451
|
if (!wasCreated) {
|
|
3469
3452
|
const projectCapsule = await buildProjectCapsule({ startDir: process.cwd() });
|
|
3470
3453
|
const modelOverride = resolveCodexModelOverride(message.mode.model);
|