flockbay 0.10.44 → 0.10.46
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/README.md +4 -0
- package/dist/{index-CVBvClyV.cjs → index-BsespsLC.cjs} +5 -5
- package/dist/{index-BfBX93aY.mjs → index-CNHBXWGe.mjs} +4 -4
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{migratePlugin-BL02mitg.cjs → migratePlugin-B2SM0IhP.cjs} +1 -1
- package/dist/{migratePlugin-DAAX2TDX.mjs → migratePlugin-CcRAl4zO.mjs} +1 -1
- package/dist/{runCodex-DcQmhprg.cjs → runCodex-Rx9uhhBt.cjs} +113 -6
- package/dist/{runCodex-C_dwGw9p.mjs → runCodex-b9J0CZko.mjs} +113 -6
- package/dist/{runGemini-CJF0id5I.cjs → runGemini-BEFeFruX.cjs} +2 -2
- package/dist/{runGemini-CWiIoJag.mjs → runGemini-C3cdyIH7.mjs} +2 -2
- package/dist/{types-tRJ8NBIX.cjs → types-CziwW90U.cjs} +67 -9
- package/dist/{types-D8EqTVgB.mjs → types-H7oBEqpR.mjs} +67 -9
- package/package.json +1 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +19 -4
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +24 -9
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPEditorCommands.cpp +17 -2
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/MCPServerRunnable.cpp +3 -3
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@ Run `flockbay --help` for the complete list of options.
|
|
|
51
51
|
to mobile app
|
|
52
52
|
- Claude CLI installed & logged in (`claude` command available in PATH)
|
|
53
53
|
|
|
54
|
+
## Windows UX note
|
|
55
|
+
|
|
56
|
+
- Codex MCP child processes are started with hidden console windows to prevent blank `cmd.exe` popups during session startup.
|
|
57
|
+
|
|
54
58
|
## License
|
|
55
59
|
|
|
56
60
|
Proprietary. Copyright (c) 2024-2026 Flockbay. All rights reserved.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
4
|
var os = require('node:os');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
|
-
var types = require('./types-
|
|
6
|
+
var types = require('./types-CziwW90U.cjs');
|
|
7
7
|
var node_child_process = require('node:child_process');
|
|
8
8
|
var path = require('node:path');
|
|
9
9
|
var node_readline = require('node:readline');
|
|
@@ -1316,7 +1316,7 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
|
|
|
1316
1316
|
env[pathKey] = [...prepend, ...existingParts].join(pathSep);
|
|
1317
1317
|
return env;
|
|
1318
1318
|
}
|
|
1319
|
-
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
1319
|
+
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-BsespsLC.cjs', document.baseURI).href)));
|
|
1320
1320
|
const __dirname$1 = path.join(__filename$1, "..");
|
|
1321
1321
|
function getGlobalClaudeVersion(claudeExecutable) {
|
|
1322
1322
|
try {
|
|
@@ -15139,7 +15139,7 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15139
15139
|
process.exit(1);
|
|
15140
15140
|
}
|
|
15141
15141
|
try {
|
|
15142
|
-
const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-
|
|
15142
|
+
const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-B2SM0IhP.cjs'); });
|
|
15143
15143
|
const result = migrateUnrealMcpToFlockbayMcp({
|
|
15144
15144
|
engineRoot,
|
|
15145
15145
|
projectUprojectPath: project || void 0,
|
|
@@ -15278,7 +15278,7 @@ ${engineRoot}`, {
|
|
|
15278
15278
|
} else if (subcommand === "codex") {
|
|
15279
15279
|
try {
|
|
15280
15280
|
await chdirToNearestUprojectRootIfPresent();
|
|
15281
|
-
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-
|
|
15281
|
+
const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Rx9uhhBt.cjs'); });
|
|
15282
15282
|
let startedBy = void 0;
|
|
15283
15283
|
let sessionId = void 0;
|
|
15284
15284
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -15380,7 +15380,7 @@ ${engineRoot}`, {
|
|
|
15380
15380
|
}
|
|
15381
15381
|
try {
|
|
15382
15382
|
await chdirToNearestUprojectRootIfPresent();
|
|
15383
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
15383
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BEFeFruX.cjs'); });
|
|
15384
15384
|
let startedBy = void 0;
|
|
15385
15385
|
let sessionId = void 0;
|
|
15386
15386
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
|
|
|
2
2
|
import * as os from 'node:os';
|
|
3
3
|
import os__default, { homedir } from 'node:os';
|
|
4
4
|
import { randomUUID, createCipheriv, randomBytes, createHash as createHash$1 } from 'node:crypto';
|
|
5
|
-
import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-
|
|
5
|
+
import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-H7oBEqpR.mjs';
|
|
6
6
|
import { spawn, execFileSync, execSync } from 'node:child_process';
|
|
7
7
|
import * as path from 'node:path';
|
|
8
8
|
import path__default, { resolve, join, dirname } from 'node:path';
|
|
@@ -15117,7 +15117,7 @@ async function authAndSetupMachineIfNeeded() {
|
|
|
15117
15117
|
process.exit(1);
|
|
15118
15118
|
}
|
|
15119
15119
|
try {
|
|
15120
|
-
const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-
|
|
15120
|
+
const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-CcRAl4zO.mjs');
|
|
15121
15121
|
const result = migrateUnrealMcpToFlockbayMcp({
|
|
15122
15122
|
engineRoot,
|
|
15123
15123
|
projectUprojectPath: project || void 0,
|
|
@@ -15256,7 +15256,7 @@ ${engineRoot}`, {
|
|
|
15256
15256
|
} else if (subcommand === "codex") {
|
|
15257
15257
|
try {
|
|
15258
15258
|
await chdirToNearestUprojectRootIfPresent();
|
|
15259
|
-
const { runCodex } = await import('./runCodex-
|
|
15259
|
+
const { runCodex } = await import('./runCodex-b9J0CZko.mjs');
|
|
15260
15260
|
let startedBy = void 0;
|
|
15261
15261
|
let sessionId = void 0;
|
|
15262
15262
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -15358,7 +15358,7 @@ ${engineRoot}`, {
|
|
|
15358
15358
|
}
|
|
15359
15359
|
try {
|
|
15360
15360
|
await chdirToNearestUprojectRootIfPresent();
|
|
15361
|
-
const { runGemini } = await import('./runGemini-
|
|
15361
|
+
const { runGemini } = await import('./runGemini-C3cdyIH7.mjs');
|
|
15362
15362
|
let startedBy = void 0;
|
|
15363
15363
|
let sessionId = void 0;
|
|
15364
15364
|
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-H7oBEqpR.mjs';
|
|
2
2
|
import 'axios';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:os';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs__default from 'node:fs';
|
|
2
2
|
import path__default from 'node:path';
|
|
3
|
-
import { i as installUnrealMcpPluginToEngine } from './types-
|
|
3
|
+
import { i as installUnrealMcpPluginToEngine } from './types-H7oBEqpR.mjs';
|
|
4
4
|
import 'axios';
|
|
5
5
|
import 'node:os';
|
|
6
6
|
import 'node:events';
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var ink = require('ink');
|
|
4
4
|
var React = require('react');
|
|
5
|
-
var types = require('./types-
|
|
5
|
+
var types = require('./types-CziwW90U.cjs');
|
|
6
6
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
7
|
-
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
8
7
|
var z = require('zod');
|
|
9
8
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
10
9
|
var node_crypto = require('node:crypto');
|
|
@@ -12,7 +11,12 @@ var fs = require('node:fs');
|
|
|
12
11
|
var os = require('node:os');
|
|
13
12
|
var path = require('node:path');
|
|
14
13
|
var node_child_process = require('node:child_process');
|
|
15
|
-
var
|
|
14
|
+
var spawn = require('cross-spawn');
|
|
15
|
+
var process$1 = require('node:process');
|
|
16
|
+
var node_stream = require('node:stream');
|
|
17
|
+
var stdio_js$1 = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
18
|
+
var stdio_js = require('@modelcontextprotocol/sdk/shared/stdio.js');
|
|
19
|
+
var index = require('./index-BsespsLC.cjs');
|
|
16
20
|
require('axios');
|
|
17
21
|
require('node:events');
|
|
18
22
|
require('socket.io-client');
|
|
@@ -24,7 +28,6 @@ require('fs/promises');
|
|
|
24
28
|
require('crypto');
|
|
25
29
|
require('path');
|
|
26
30
|
require('url');
|
|
27
|
-
require('node:process');
|
|
28
31
|
require('os');
|
|
29
32
|
require('node:net');
|
|
30
33
|
require('http');
|
|
@@ -32,7 +35,6 @@ require('open');
|
|
|
32
35
|
require('node:readline');
|
|
33
36
|
require('node:url');
|
|
34
37
|
require('ps-list');
|
|
35
|
-
require('cross-spawn');
|
|
36
38
|
require('tmp');
|
|
37
39
|
require('fastify');
|
|
38
40
|
require('fastify-type-provider-zod');
|
|
@@ -336,6 +338,111 @@ function buildMcpElicitationResult(decision, requestedSchemaRaw, options) {
|
|
|
336
338
|
return { action, content, decision: codexDecision };
|
|
337
339
|
}
|
|
338
340
|
|
|
341
|
+
class WindowsHiddenStdioClientTransport {
|
|
342
|
+
processRef;
|
|
343
|
+
abortController = new AbortController();
|
|
344
|
+
readBuffer = new stdio_js.ReadBuffer();
|
|
345
|
+
serverParams;
|
|
346
|
+
stderrStream = null;
|
|
347
|
+
platform;
|
|
348
|
+
onclose;
|
|
349
|
+
onerror;
|
|
350
|
+
onmessage;
|
|
351
|
+
constructor(server, options = {}) {
|
|
352
|
+
this.serverParams = server;
|
|
353
|
+
this.platform = options.platform ?? process$1.platform;
|
|
354
|
+
if (server.stderr === "pipe" || server.stderr === "overlapped") {
|
|
355
|
+
this.stderrStream = new node_stream.PassThrough();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
async start() {
|
|
359
|
+
if (this.processRef) {
|
|
360
|
+
throw new Error("WindowsHiddenStdioClientTransport already started");
|
|
361
|
+
}
|
|
362
|
+
await new Promise((resolve, reject) => {
|
|
363
|
+
this.processRef = spawn(this.serverParams.command, this.serverParams.args ?? [], {
|
|
364
|
+
env: {
|
|
365
|
+
...stdio_js$1.getDefaultEnvironment(),
|
|
366
|
+
...this.serverParams.env
|
|
367
|
+
},
|
|
368
|
+
stdio: ["pipe", "pipe", this.serverParams.stderr ?? "inherit"],
|
|
369
|
+
shell: false,
|
|
370
|
+
signal: this.abortController.signal,
|
|
371
|
+
windowsHide: this.platform === "win32",
|
|
372
|
+
cwd: this.serverParams.cwd
|
|
373
|
+
});
|
|
374
|
+
this.processRef.on("error", (error) => {
|
|
375
|
+
if (error.name === "AbortError") {
|
|
376
|
+
this.onclose?.();
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
reject(error);
|
|
380
|
+
this.onerror?.(error);
|
|
381
|
+
});
|
|
382
|
+
this.processRef.on("spawn", () => {
|
|
383
|
+
resolve();
|
|
384
|
+
});
|
|
385
|
+
this.processRef.on("close", () => {
|
|
386
|
+
this.processRef = void 0;
|
|
387
|
+
this.onclose?.();
|
|
388
|
+
});
|
|
389
|
+
this.processRef.stdin?.on("error", (error) => {
|
|
390
|
+
this.onerror?.(error);
|
|
391
|
+
});
|
|
392
|
+
this.processRef.stdout?.on("data", (chunk) => {
|
|
393
|
+
this.readBuffer.append(chunk);
|
|
394
|
+
this.processReadBuffer();
|
|
395
|
+
});
|
|
396
|
+
this.processRef.stdout?.on("error", (error) => {
|
|
397
|
+
this.onerror?.(error);
|
|
398
|
+
});
|
|
399
|
+
if (this.stderrStream && this.processRef.stderr) {
|
|
400
|
+
this.processRef.stderr.pipe(this.stderrStream);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
get stderr() {
|
|
405
|
+
if (this.stderrStream) {
|
|
406
|
+
return this.stderrStream;
|
|
407
|
+
}
|
|
408
|
+
return this.processRef?.stderr ?? null;
|
|
409
|
+
}
|
|
410
|
+
get pid() {
|
|
411
|
+
return this.processRef?.pid ?? null;
|
|
412
|
+
}
|
|
413
|
+
async close() {
|
|
414
|
+
this.abortController.abort();
|
|
415
|
+
this.processRef = void 0;
|
|
416
|
+
this.readBuffer.clear();
|
|
417
|
+
}
|
|
418
|
+
send(message) {
|
|
419
|
+
return new Promise((resolve) => {
|
|
420
|
+
if (!this.processRef?.stdin) {
|
|
421
|
+
throw new Error("Not connected");
|
|
422
|
+
}
|
|
423
|
+
const payload = stdio_js.serializeMessage(message);
|
|
424
|
+
if (this.processRef.stdin.write(payload)) {
|
|
425
|
+
resolve();
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
this.processRef.stdin.once("drain", resolve);
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
processReadBuffer() {
|
|
432
|
+
while (true) {
|
|
433
|
+
try {
|
|
434
|
+
const message = this.readBuffer.readMessage();
|
|
435
|
+
if (message === null) {
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
this.onmessage?.(message);
|
|
439
|
+
} catch (error) {
|
|
440
|
+
this.onerror?.(error);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
339
446
|
const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
|
|
340
447
|
function getCodexMcpCommand() {
|
|
341
448
|
try {
|
|
@@ -790,7 +897,7 @@ class CodexMcpClient {
|
|
|
790
897
|
const codexBin = resolveCodexBin();
|
|
791
898
|
types.logger.debug(`[CodexMCP] Connecting to Codex MCP server using command: ${codexBin} ${mcpCommand}`);
|
|
792
899
|
const env = buildCodexSpawnEnv(codexBin);
|
|
793
|
-
this.transport = new
|
|
900
|
+
this.transport = new WindowsHiddenStdioClientTransport({
|
|
794
901
|
command: codexBin,
|
|
795
902
|
args: [mcpCommand],
|
|
796
903
|
env
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
2
2
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
-
import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-
|
|
3
|
+
import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-H7oBEqpR.mjs';
|
|
4
4
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
6
5
|
import { z } from 'zod';
|
|
7
6
|
import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
7
|
import { randomUUID } from 'node:crypto';
|
|
@@ -10,7 +9,12 @@ import fs__default from 'node:fs';
|
|
|
10
9
|
import os__default from 'node:os';
|
|
11
10
|
import path__default, { resolve, join } from 'node:path';
|
|
12
11
|
import { spawnSync } from 'node:child_process';
|
|
13
|
-
import
|
|
12
|
+
import spawn from 'cross-spawn';
|
|
13
|
+
import process$1 from 'node:process';
|
|
14
|
+
import { PassThrough } from 'node:stream';
|
|
15
|
+
import { getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
16
|
+
import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk/shared/stdio.js';
|
|
17
|
+
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-CNHBXWGe.mjs';
|
|
14
18
|
import 'axios';
|
|
15
19
|
import 'node:events';
|
|
16
20
|
import 'socket.io-client';
|
|
@@ -22,7 +26,6 @@ import 'fs/promises';
|
|
|
22
26
|
import 'crypto';
|
|
23
27
|
import 'path';
|
|
24
28
|
import 'url';
|
|
25
|
-
import 'node:process';
|
|
26
29
|
import 'os';
|
|
27
30
|
import 'node:net';
|
|
28
31
|
import 'http';
|
|
@@ -30,7 +33,6 @@ import 'open';
|
|
|
30
33
|
import 'node:readline';
|
|
31
34
|
import 'node:url';
|
|
32
35
|
import 'ps-list';
|
|
33
|
-
import 'cross-spawn';
|
|
34
36
|
import 'tmp';
|
|
35
37
|
import 'fastify';
|
|
36
38
|
import 'fastify-type-provider-zod';
|
|
@@ -334,6 +336,111 @@ function buildMcpElicitationResult(decision, requestedSchemaRaw, options) {
|
|
|
334
336
|
return { action, content, decision: codexDecision };
|
|
335
337
|
}
|
|
336
338
|
|
|
339
|
+
class WindowsHiddenStdioClientTransport {
|
|
340
|
+
processRef;
|
|
341
|
+
abortController = new AbortController();
|
|
342
|
+
readBuffer = new ReadBuffer();
|
|
343
|
+
serverParams;
|
|
344
|
+
stderrStream = null;
|
|
345
|
+
platform;
|
|
346
|
+
onclose;
|
|
347
|
+
onerror;
|
|
348
|
+
onmessage;
|
|
349
|
+
constructor(server, options = {}) {
|
|
350
|
+
this.serverParams = server;
|
|
351
|
+
this.platform = options.platform ?? process$1.platform;
|
|
352
|
+
if (server.stderr === "pipe" || server.stderr === "overlapped") {
|
|
353
|
+
this.stderrStream = new PassThrough();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async start() {
|
|
357
|
+
if (this.processRef) {
|
|
358
|
+
throw new Error("WindowsHiddenStdioClientTransport already started");
|
|
359
|
+
}
|
|
360
|
+
await new Promise((resolve, reject) => {
|
|
361
|
+
this.processRef = spawn(this.serverParams.command, this.serverParams.args ?? [], {
|
|
362
|
+
env: {
|
|
363
|
+
...getDefaultEnvironment(),
|
|
364
|
+
...this.serverParams.env
|
|
365
|
+
},
|
|
366
|
+
stdio: ["pipe", "pipe", this.serverParams.stderr ?? "inherit"],
|
|
367
|
+
shell: false,
|
|
368
|
+
signal: this.abortController.signal,
|
|
369
|
+
windowsHide: this.platform === "win32",
|
|
370
|
+
cwd: this.serverParams.cwd
|
|
371
|
+
});
|
|
372
|
+
this.processRef.on("error", (error) => {
|
|
373
|
+
if (error.name === "AbortError") {
|
|
374
|
+
this.onclose?.();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
reject(error);
|
|
378
|
+
this.onerror?.(error);
|
|
379
|
+
});
|
|
380
|
+
this.processRef.on("spawn", () => {
|
|
381
|
+
resolve();
|
|
382
|
+
});
|
|
383
|
+
this.processRef.on("close", () => {
|
|
384
|
+
this.processRef = void 0;
|
|
385
|
+
this.onclose?.();
|
|
386
|
+
});
|
|
387
|
+
this.processRef.stdin?.on("error", (error) => {
|
|
388
|
+
this.onerror?.(error);
|
|
389
|
+
});
|
|
390
|
+
this.processRef.stdout?.on("data", (chunk) => {
|
|
391
|
+
this.readBuffer.append(chunk);
|
|
392
|
+
this.processReadBuffer();
|
|
393
|
+
});
|
|
394
|
+
this.processRef.stdout?.on("error", (error) => {
|
|
395
|
+
this.onerror?.(error);
|
|
396
|
+
});
|
|
397
|
+
if (this.stderrStream && this.processRef.stderr) {
|
|
398
|
+
this.processRef.stderr.pipe(this.stderrStream);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
get stderr() {
|
|
403
|
+
if (this.stderrStream) {
|
|
404
|
+
return this.stderrStream;
|
|
405
|
+
}
|
|
406
|
+
return this.processRef?.stderr ?? null;
|
|
407
|
+
}
|
|
408
|
+
get pid() {
|
|
409
|
+
return this.processRef?.pid ?? null;
|
|
410
|
+
}
|
|
411
|
+
async close() {
|
|
412
|
+
this.abortController.abort();
|
|
413
|
+
this.processRef = void 0;
|
|
414
|
+
this.readBuffer.clear();
|
|
415
|
+
}
|
|
416
|
+
send(message) {
|
|
417
|
+
return new Promise((resolve) => {
|
|
418
|
+
if (!this.processRef?.stdin) {
|
|
419
|
+
throw new Error("Not connected");
|
|
420
|
+
}
|
|
421
|
+
const payload = serializeMessage(message);
|
|
422
|
+
if (this.processRef.stdin.write(payload)) {
|
|
423
|
+
resolve();
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this.processRef.stdin.once("drain", resolve);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
processReadBuffer() {
|
|
430
|
+
while (true) {
|
|
431
|
+
try {
|
|
432
|
+
const message = this.readBuffer.readMessage();
|
|
433
|
+
if (message === null) {
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
this.onmessage?.(message);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
this.onerror?.(error);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
337
444
|
const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
|
|
338
445
|
function getCodexMcpCommand() {
|
|
339
446
|
try {
|
|
@@ -788,7 +895,7 @@ class CodexMcpClient {
|
|
|
788
895
|
const codexBin = resolveCodexBin();
|
|
789
896
|
logger.debug(`[CodexMCP] Connecting to Codex MCP server using command: ${codexBin} ${mcpCommand}`);
|
|
790
897
|
const env = buildCodexSpawnEnv(codexBin);
|
|
791
|
-
this.transport = new
|
|
898
|
+
this.transport = new WindowsHiddenStdioClientTransport({
|
|
792
899
|
command: codexBin,
|
|
793
900
|
args: [mcpCommand],
|
|
794
901
|
env
|
|
@@ -6,8 +6,8 @@ var node_crypto = require('node:crypto');
|
|
|
6
6
|
var os = require('node:os');
|
|
7
7
|
var path = require('node:path');
|
|
8
8
|
var fs$2 = require('node:fs/promises');
|
|
9
|
-
var types = require('./types-
|
|
10
|
-
var index = require('./index-
|
|
9
|
+
var types = require('./types-CziwW90U.cjs');
|
|
10
|
+
var index = require('./index-BsespsLC.cjs');
|
|
11
11
|
var node_child_process = require('node:child_process');
|
|
12
12
|
var sdk = require('@agentclientprotocol/sdk');
|
|
13
13
|
var fs = require('fs');
|
|
@@ -4,8 +4,8 @@ import { randomUUID, createHash } from 'node:crypto';
|
|
|
4
4
|
import os__default from 'node:os';
|
|
5
5
|
import path__default, { resolve, join as join$1, basename } from 'node:path';
|
|
6
6
|
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
|
7
|
-
import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-
|
|
8
|
-
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, o as extractUserImagesMarker, p as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, j as autoFinalizeCoordinationWorkItem, E as ElicitationHub, k as detectScreenshotsForGate, m as stopCaffeinate } from './index-
|
|
7
|
+
import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-H7oBEqpR.mjs';
|
|
8
|
+
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, o as extractUserImagesMarker, p as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, j as autoFinalizeCoordinationWorkItem, E as ElicitationHub, k as detectScreenshotsForGate, m as stopCaffeinate } from './index-CNHBXWGe.mjs';
|
|
9
9
|
import { spawn, spawnSync } from 'node:child_process';
|
|
10
10
|
import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
|
|
11
11
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
@@ -44,7 +44,7 @@ function _interopNamespaceDefault(e) {
|
|
|
44
44
|
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
45
45
|
|
|
46
46
|
var name = "flockbay";
|
|
47
|
-
var version = "0.10.
|
|
47
|
+
var version = "0.10.46";
|
|
48
48
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
49
49
|
var author = "Eduardo Orellana";
|
|
50
50
|
var license = "UNLICENSED";
|
|
@@ -292,6 +292,54 @@ const configuration = new Configuration();
|
|
|
292
292
|
const defaultSettings = {
|
|
293
293
|
onboardingCompleted: false
|
|
294
294
|
};
|
|
295
|
+
const daemonStateSchema = z__namespace.object({
|
|
296
|
+
pid: z__namespace.number(),
|
|
297
|
+
httpPort: z__namespace.number(),
|
|
298
|
+
startTime: z__namespace.string(),
|
|
299
|
+
startedWithCliVersion: z__namespace.string(),
|
|
300
|
+
lastHeartbeat: z__namespace.string().optional(),
|
|
301
|
+
daemonLogPath: z__namespace.string().optional()
|
|
302
|
+
}).passthrough();
|
|
303
|
+
function sleepSync(ms) {
|
|
304
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
305
|
+
}
|
|
306
|
+
function writeFileSyncAtomic(destinationPath, content) {
|
|
307
|
+
const tmpPath = `${destinationPath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
|
|
308
|
+
fs.writeFileSync(tmpPath, content, "utf-8");
|
|
309
|
+
const maxAttempts = 5;
|
|
310
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
311
|
+
try {
|
|
312
|
+
if (fs.existsSync(destinationPath)) {
|
|
313
|
+
fs.unlinkSync(destinationPath);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
const code = error?.code;
|
|
317
|
+
if (attempt === maxAttempts || code && !["EPERM", "EACCES", "EBUSY", "ENOENT"].includes(code)) {
|
|
318
|
+
try {
|
|
319
|
+
fs.unlinkSync(tmpPath);
|
|
320
|
+
} catch {
|
|
321
|
+
}
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
sleepSync(10 * attempt);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
fs.renameSync(tmpPath, destinationPath);
|
|
329
|
+
return;
|
|
330
|
+
} catch (error) {
|
|
331
|
+
const code = error?.code;
|
|
332
|
+
if (attempt === maxAttempts || code && !["EPERM", "EACCES", "EBUSY", "EEXIST"].includes(code)) {
|
|
333
|
+
try {
|
|
334
|
+
fs.unlinkSync(tmpPath);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
sleepSync(10 * attempt);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
295
343
|
async function readSettings() {
|
|
296
344
|
if (!fs.existsSync(configuration.settingsFile)) {
|
|
297
345
|
return { ...defaultSettings };
|
|
@@ -391,19 +439,29 @@ async function clearMachineId() {
|
|
|
391
439
|
}));
|
|
392
440
|
}
|
|
393
441
|
async function readDaemonState() {
|
|
442
|
+
if (!fs.existsSync(configuration.daemonStateFile)) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
394
445
|
try {
|
|
395
|
-
if (!fs.existsSync(configuration.daemonStateFile)) {
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
446
|
const content = await fs$1.readFile(configuration.daemonStateFile, "utf-8");
|
|
399
|
-
|
|
447
|
+
if (!content.trim()) {
|
|
448
|
+
throw new Error("Empty daemon state file");
|
|
449
|
+
}
|
|
450
|
+
const parsedJson = JSON.parse(content);
|
|
451
|
+
return daemonStateSchema.parse(parsedJson);
|
|
400
452
|
} catch (error) {
|
|
401
|
-
|
|
453
|
+
await clearDaemonState().catch(() => null);
|
|
454
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
455
|
+
if (process.env.DEBUG || process.env.FLOCKBAY_DEBUG_PERSISTENCE) {
|
|
456
|
+
console.error(`[PERSISTENCE] Daemon state file corrupted: ${configuration.daemonStateFile}`, error);
|
|
457
|
+
} else {
|
|
458
|
+
console.warn(`[PERSISTENCE] Daemon state file corrupted; cleared ${configuration.daemonStateFile} (${message})`);
|
|
459
|
+
}
|
|
402
460
|
return null;
|
|
403
461
|
}
|
|
404
462
|
}
|
|
405
463
|
function writeDaemonState(state) {
|
|
406
|
-
|
|
464
|
+
writeFileSyncAtomic(configuration.daemonStateFile, JSON.stringify(state, null, 2));
|
|
407
465
|
}
|
|
408
466
|
async function clearDaemonState() {
|
|
409
467
|
if (fs.existsSync(configuration.daemonStateFile)) {
|
|
@@ -774,7 +832,7 @@ class RpcHandlerManager {
|
|
|
774
832
|
}
|
|
775
833
|
}
|
|
776
834
|
|
|
777
|
-
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-
|
|
835
|
+
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-CziwW90U.cjs', document.baseURI).href))));
|
|
778
836
|
function projectPath() {
|
|
779
837
|
const path = path$1.resolve(__dirname$1, "..");
|
|
780
838
|
return path;
|
|
@@ -3778,7 +3836,7 @@ exitCode: ${exitCode}
|
|
|
3778
3836
|
buildLogPath,
|
|
3779
3837
|
errorMessage: `Failed to build the Flockbay MCP plugin.
|
|
3780
3838
|
Log: ${buildLogPath}
|
|
3781
|
-
|
|
3839
|
+
Open the log to see the exact failure (missing compiler toolchain vs plugin compile errors).`
|
|
3782
3840
|
};
|
|
3783
3841
|
}
|
|
3784
3842
|
const resolved = resolvePackagedPluginDir(packageDir);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import fs__default, { existsSync, readFileSync, mkdirSync, constants, unlinkSync, writeFileSync, readdirSync, statSync, createWriteStream } from 'node:fs';
|
|
2
|
+
import fs__default, { existsSync, readFileSync, mkdirSync, constants, unlinkSync, writeFileSync, renameSync, readdirSync, statSync, createWriteStream } from 'node:fs';
|
|
3
3
|
import os__default, { homedir } from 'node:os';
|
|
4
4
|
import path__default, { join, basename } from 'node:path';
|
|
5
5
|
import { EventEmitter } from 'node:events';
|
|
@@ -23,7 +23,7 @@ import { createServer } from 'http';
|
|
|
23
23
|
import open$2 from 'open';
|
|
24
24
|
|
|
25
25
|
var name = "flockbay";
|
|
26
|
-
var version = "0.10.
|
|
26
|
+
var version = "0.10.46";
|
|
27
27
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
28
28
|
var author = "Eduardo Orellana";
|
|
29
29
|
var license = "UNLICENSED";
|
|
@@ -271,6 +271,54 @@ const configuration = new Configuration();
|
|
|
271
271
|
const defaultSettings = {
|
|
272
272
|
onboardingCompleted: false
|
|
273
273
|
};
|
|
274
|
+
const daemonStateSchema = z.object({
|
|
275
|
+
pid: z.number(),
|
|
276
|
+
httpPort: z.number(),
|
|
277
|
+
startTime: z.string(),
|
|
278
|
+
startedWithCliVersion: z.string(),
|
|
279
|
+
lastHeartbeat: z.string().optional(),
|
|
280
|
+
daemonLogPath: z.string().optional()
|
|
281
|
+
}).passthrough();
|
|
282
|
+
function sleepSync(ms) {
|
|
283
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
284
|
+
}
|
|
285
|
+
function writeFileSyncAtomic(destinationPath, content) {
|
|
286
|
+
const tmpPath = `${destinationPath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
|
|
287
|
+
writeFileSync(tmpPath, content, "utf-8");
|
|
288
|
+
const maxAttempts = 5;
|
|
289
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
290
|
+
try {
|
|
291
|
+
if (existsSync(destinationPath)) {
|
|
292
|
+
unlinkSync(destinationPath);
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const code = error?.code;
|
|
296
|
+
if (attempt === maxAttempts || code && !["EPERM", "EACCES", "EBUSY", "ENOENT"].includes(code)) {
|
|
297
|
+
try {
|
|
298
|
+
unlinkSync(tmpPath);
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
sleepSync(10 * attempt);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
renameSync(tmpPath, destinationPath);
|
|
308
|
+
return;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const code = error?.code;
|
|
311
|
+
if (attempt === maxAttempts || code && !["EPERM", "EACCES", "EBUSY", "EEXIST"].includes(code)) {
|
|
312
|
+
try {
|
|
313
|
+
unlinkSync(tmpPath);
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
318
|
+
sleepSync(10 * attempt);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
274
322
|
async function readSettings() {
|
|
275
323
|
if (!existsSync(configuration.settingsFile)) {
|
|
276
324
|
return { ...defaultSettings };
|
|
@@ -370,19 +418,29 @@ async function clearMachineId() {
|
|
|
370
418
|
}));
|
|
371
419
|
}
|
|
372
420
|
async function readDaemonState() {
|
|
421
|
+
if (!existsSync(configuration.daemonStateFile)) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
373
424
|
try {
|
|
374
|
-
if (!existsSync(configuration.daemonStateFile)) {
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
425
|
const content = await readFile(configuration.daemonStateFile, "utf-8");
|
|
378
|
-
|
|
426
|
+
if (!content.trim()) {
|
|
427
|
+
throw new Error("Empty daemon state file");
|
|
428
|
+
}
|
|
429
|
+
const parsedJson = JSON.parse(content);
|
|
430
|
+
return daemonStateSchema.parse(parsedJson);
|
|
379
431
|
} catch (error) {
|
|
380
|
-
|
|
432
|
+
await clearDaemonState().catch(() => null);
|
|
433
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
434
|
+
if (process.env.DEBUG || process.env.FLOCKBAY_DEBUG_PERSISTENCE) {
|
|
435
|
+
console.error(`[PERSISTENCE] Daemon state file corrupted: ${configuration.daemonStateFile}`, error);
|
|
436
|
+
} else {
|
|
437
|
+
console.warn(`[PERSISTENCE] Daemon state file corrupted; cleared ${configuration.daemonStateFile} (${message})`);
|
|
438
|
+
}
|
|
381
439
|
return null;
|
|
382
440
|
}
|
|
383
441
|
}
|
|
384
442
|
function writeDaemonState(state) {
|
|
385
|
-
|
|
443
|
+
writeFileSyncAtomic(configuration.daemonStateFile, JSON.stringify(state, null, 2));
|
|
386
444
|
}
|
|
387
445
|
async function clearDaemonState() {
|
|
388
446
|
if (existsSync(configuration.daemonStateFile)) {
|
|
@@ -3757,7 +3815,7 @@ exitCode: ${exitCode}
|
|
|
3757
3815
|
buildLogPath,
|
|
3758
3816
|
errorMessage: `Failed to build the Flockbay MCP plugin.
|
|
3759
3817
|
Log: ${buildLogPath}
|
|
3760
|
-
|
|
3818
|
+
Open the log to see the exact failure (missing compiler toolchain vs plugin compile errors).`
|
|
3761
3819
|
};
|
|
3762
3820
|
}
|
|
3763
3821
|
const resolved = resolvePackagedPluginDir(packageDir);
|
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
#include "Engine/SCS_Node.h"
|
|
17
17
|
#include "UObject/Field.h"
|
|
18
18
|
#include "UObject/FieldPath.h"
|
|
19
|
+
#include "UObject/UObjectGlobals.h"
|
|
19
20
|
#include "EditorAssetLibrary.h"
|
|
20
21
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
21
22
|
#include "MessageLogModule.h"
|
|
@@ -23,6 +24,20 @@
|
|
|
23
24
|
#include "GameFramework/Actor.h"
|
|
24
25
|
#include "GameFramework/Pawn.h"
|
|
25
26
|
|
|
27
|
+
static UClass* FindMcpClassByName(const TCHAR* ClassName)
|
|
28
|
+
{
|
|
29
|
+
#if defined(ANY_PACKAGE)
|
|
30
|
+
return FindObject<UClass>(ANY_PACKAGE, ClassName);
|
|
31
|
+
#else
|
|
32
|
+
return FindFirstObject<UClass>(ClassName);
|
|
33
|
+
#endif
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static UClass* FindMcpClassByName(const FString& ClassName)
|
|
37
|
+
{
|
|
38
|
+
return FindMcpClassByName(*ClassName);
|
|
39
|
+
}
|
|
40
|
+
|
|
26
41
|
FUnrealMCPBlueprintCommands::FUnrealMCPBlueprintCommands()
|
|
27
42
|
{
|
|
28
43
|
}
|
|
@@ -249,26 +264,26 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleAddComponentToBluepri
|
|
|
249
264
|
UClass* ComponentClass = nullptr;
|
|
250
265
|
|
|
251
266
|
// Try to find the class with exact name first
|
|
252
|
-
ComponentClass =
|
|
267
|
+
ComponentClass = FindMcpClassByName(ComponentType);
|
|
253
268
|
|
|
254
269
|
// If not found, try with "Component" suffix
|
|
255
270
|
if (!ComponentClass && !ComponentType.EndsWith(TEXT("Component")))
|
|
256
271
|
{
|
|
257
272
|
FString ComponentTypeWithSuffix = ComponentType + TEXT("Component");
|
|
258
|
-
ComponentClass =
|
|
273
|
+
ComponentClass = FindMcpClassByName(ComponentTypeWithSuffix);
|
|
259
274
|
}
|
|
260
275
|
|
|
261
276
|
// If still not found, try with "U" prefix
|
|
262
277
|
if (!ComponentClass && !ComponentType.StartsWith(TEXT("U")))
|
|
263
278
|
{
|
|
264
279
|
FString ComponentTypeWithPrefix = TEXT("U") + ComponentType;
|
|
265
|
-
ComponentClass =
|
|
280
|
+
ComponentClass = FindMcpClassByName(ComponentTypeWithPrefix);
|
|
266
281
|
|
|
267
282
|
// Try with both prefix and suffix
|
|
268
283
|
if (!ComponentClass && !ComponentType.EndsWith(TEXT("Component")))
|
|
269
284
|
{
|
|
270
285
|
FString ComponentTypeWithBoth = TEXT("U") + ComponentType + TEXT("Component");
|
|
271
|
-
ComponentClass =
|
|
286
|
+
ComponentClass = FindMcpClassByName(ComponentTypeWithBoth);
|
|
272
287
|
}
|
|
273
288
|
}
|
|
274
289
|
|
|
@@ -17,11 +17,26 @@
|
|
|
17
17
|
#include "Kismet/GameplayStatics.h"
|
|
18
18
|
#include "EdGraphSchema_K2.h"
|
|
19
19
|
#include "UObject/UObjectIterator.h"
|
|
20
|
+
#include "UObject/UObjectGlobals.h"
|
|
20
21
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
|
21
22
|
|
|
22
23
|
// Declare the log category
|
|
23
24
|
DEFINE_LOG_CATEGORY_STATIC(LogUnrealMCP, Log, All);
|
|
24
25
|
|
|
26
|
+
static UClass* FindMcpClassByName(const TCHAR* ClassName)
|
|
27
|
+
{
|
|
28
|
+
#if defined(ANY_PACKAGE)
|
|
29
|
+
return FindObject<UClass>(ANY_PACKAGE, ClassName);
|
|
30
|
+
#else
|
|
31
|
+
return FindFirstObject<UClass>(ClassName);
|
|
32
|
+
#endif
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static UClass* FindMcpClassByName(const FString& ClassName)
|
|
36
|
+
{
|
|
37
|
+
return FindMcpClassByName(*ClassName);
|
|
38
|
+
}
|
|
39
|
+
|
|
25
40
|
FUnrealMCPBlueprintNodeCommands::FUnrealMCPBlueprintNodeCommands()
|
|
26
41
|
{
|
|
27
42
|
}
|
|
@@ -413,7 +428,7 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
413
428
|
UClass* TargetClass = nullptr;
|
|
414
429
|
|
|
415
430
|
// First try without a prefix
|
|
416
|
-
TargetClass =
|
|
431
|
+
TargetClass = FindMcpClassByName(Target);
|
|
417
432
|
UE_LOG(LogTemp, Display, TEXT("Tried to find class '%s': %s"),
|
|
418
433
|
*Target, TargetClass ? TEXT("Found") : TEXT("Not found"));
|
|
419
434
|
|
|
@@ -421,7 +436,7 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
421
436
|
if (!TargetClass && !Target.StartsWith(TEXT("U")))
|
|
422
437
|
{
|
|
423
438
|
FString TargetWithPrefix = FString(TEXT("U")) + Target;
|
|
424
|
-
TargetClass =
|
|
439
|
+
TargetClass = FindMcpClassByName(TargetWithPrefix);
|
|
425
440
|
UE_LOG(LogTemp, Display, TEXT("Tried to find class '%s': %s"),
|
|
426
441
|
*TargetWithPrefix, TargetClass ? TEXT("Found") : TEXT("Not found"));
|
|
427
442
|
}
|
|
@@ -436,7 +451,7 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
436
451
|
|
|
437
452
|
for (const FString& ClassName : PossibleClassNames)
|
|
438
453
|
{
|
|
439
|
-
TargetClass =
|
|
454
|
+
TargetClass = FindMcpClassByName(ClassName);
|
|
440
455
|
if (TargetClass)
|
|
441
456
|
{
|
|
442
457
|
UE_LOG(LogTemp, Display, TEXT("Found class using alternative name '%s'"), *ClassName);
|
|
@@ -449,7 +464,7 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
449
464
|
if (!TargetClass && Target == TEXT("UGameplayStatics"))
|
|
450
465
|
{
|
|
451
466
|
// For UGameplayStatics, use a direct reference to known class
|
|
452
|
-
TargetClass =
|
|
467
|
+
TargetClass = FindMcpClassByName(TEXT("UGameplayStatics"));
|
|
453
468
|
if (!TargetClass)
|
|
454
469
|
{
|
|
455
470
|
// Try loading it from its known package
|
|
@@ -594,7 +609,7 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
594
609
|
const FString& ClassName = StringVal;
|
|
595
610
|
|
|
596
611
|
// TODO: This likely won't work in UE5.5+, so don't rely on it.
|
|
597
|
-
UClass* Class =
|
|
612
|
+
UClass* Class = FindMcpClassByName(ClassName);
|
|
598
613
|
|
|
599
614
|
if (!Class)
|
|
600
615
|
{
|
|
@@ -796,18 +811,18 @@ static UClass* ResolveClassBestEffort(const FString& Target)
|
|
|
796
811
|
return LoadObject<UClass>(nullptr, *T);
|
|
797
812
|
}
|
|
798
813
|
|
|
799
|
-
UClass* Found =
|
|
814
|
+
UClass* Found = FindMcpClassByName(T);
|
|
800
815
|
if (!Found && !T.StartsWith(TEXT("U")))
|
|
801
816
|
{
|
|
802
|
-
Found =
|
|
817
|
+
Found = FindMcpClassByName(FString(TEXT("U")) + T);
|
|
803
818
|
}
|
|
804
819
|
if (!Found && !T.EndsWith(TEXT("Library")))
|
|
805
820
|
{
|
|
806
|
-
Found =
|
|
821
|
+
Found = FindMcpClassByName(FString(TEXT("U")) + T + TEXT("Library"));
|
|
807
822
|
}
|
|
808
823
|
if (!Found && !T.EndsWith(TEXT("Component")))
|
|
809
824
|
{
|
|
810
|
-
Found =
|
|
825
|
+
Found = FindMcpClassByName(FString(TEXT("U")) + T + TEXT("Component"));
|
|
811
826
|
}
|
|
812
827
|
return Found;
|
|
813
828
|
}
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
45
45
|
#include "UObject/SoftObjectPath.h"
|
|
46
46
|
#include "UObject/Package.h"
|
|
47
|
+
#include "UObject/UObjectGlobals.h"
|
|
47
48
|
#include "FileHelpers.h"
|
|
48
49
|
#include "MessageLogModule.h"
|
|
49
50
|
#include "IMessageLogListing.h"
|
|
@@ -56,6 +57,20 @@
|
|
|
56
57
|
#include "Components/SceneCaptureComponent2D.h"
|
|
57
58
|
#include "Engine/TextureRenderTarget2D.h"
|
|
58
59
|
|
|
60
|
+
static UClass* FindMcpClassByName(const TCHAR* ClassName)
|
|
61
|
+
{
|
|
62
|
+
#if defined(ANY_PACKAGE)
|
|
63
|
+
return FindObject<UClass>(ANY_PACKAGE, ClassName);
|
|
64
|
+
#else
|
|
65
|
+
return FindFirstObject<UClass>(ClassName);
|
|
66
|
+
#endif
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static UClass* FindMcpClassByName(const FString& ClassName)
|
|
70
|
+
{
|
|
71
|
+
return FindMcpClassByName(*ClassName);
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
static bool SavePngToFile(const FString& FilePath, int32 Width, int32 Height, TArray<FColor>& Bitmap)
|
|
60
75
|
{
|
|
61
76
|
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
|
|
@@ -560,10 +575,10 @@ static bool TryResolveAssetClassFilter(const TSharedPtr<FJsonObject>& Params, FA
|
|
|
560
575
|
}
|
|
561
576
|
else
|
|
562
577
|
{
|
|
563
|
-
Class =
|
|
578
|
+
Class = FindMcpClassByName(ClassName);
|
|
564
579
|
if (!Class && !ClassName.StartsWith(TEXT("U")))
|
|
565
580
|
{
|
|
566
|
-
Class =
|
|
581
|
+
Class = FindMcpClassByName(TEXT("U") + ClassName);
|
|
567
582
|
}
|
|
568
583
|
}
|
|
569
584
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
#include "HAL/PlatformTime.h"
|
|
13
13
|
|
|
14
14
|
// Buffer size for receiving data
|
|
15
|
-
const int32
|
|
15
|
+
const int32 RecvBufferSizeBytes = 8192;
|
|
16
16
|
|
|
17
17
|
static bool SendAll(FSocket* Socket, const uint8* Data, int32 TotalBytes, int32& OutTotalBytesSent)
|
|
18
18
|
{
|
|
@@ -102,7 +102,7 @@ uint32 FMCPServerRunnable::Run()
|
|
|
102
102
|
ClientSocket->SetSendBufferSize(SocketBufferSize, SocketBufferSize);
|
|
103
103
|
ClientSocket->SetReceiveBufferSize(SocketBufferSize, SocketBufferSize);
|
|
104
104
|
|
|
105
|
-
uint8 Buffer[
|
|
105
|
+
uint8 Buffer[RecvBufferSizeBytes + 1];
|
|
106
106
|
while (bRunning)
|
|
107
107
|
{
|
|
108
108
|
int32 BytesRead = 0;
|
|
@@ -116,7 +116,7 @@ uint32 FMCPServerRunnable::Run()
|
|
|
116
116
|
|
|
117
117
|
// Convert received data to string
|
|
118
118
|
// Null-terminate safely (Recv can fill the entire buffer).
|
|
119
|
-
const int32 SafeIndex = FMath::Clamp(BytesRead, 0,
|
|
119
|
+
const int32 SafeIndex = FMath::Clamp(BytesRead, 0, RecvBufferSizeBytes);
|
|
120
120
|
Buffer[SafeIndex] = '\0';
|
|
121
121
|
FString ReceivedText = UTF8_TO_TCHAR(Buffer);
|
|
122
122
|
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Received: %s"), *ReceivedText);
|