flockbay 0.10.40 → 0.10.42

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.
@@ -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, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, o as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, q as run, t as run$1, x as buildShellInvocation, y as clearCredentials, z as clearMachineId, i as installUnrealMcpPluginToEngine, B as buildAndInstallUnrealMcpPlugin, C as getLatestDaemonLog, D as normalizeServerUrlForNode } from './types-4acLcOdW.mjs';
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-D1UKSrkg.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';
@@ -10,33 +10,32 @@ import { createInterface } from 'node:readline';
10
10
  import * as fs from 'node:fs';
11
11
  import fs__default, { existsSync, readFileSync, mkdirSync, readdirSync, accessSync, constants, statSync, createReadStream, writeFileSync, unlinkSync } from 'node:fs';
12
12
  import process$1 from 'node:process';
13
- import fs$1, { readFile, access as access$1, mkdir, readdir, stat, writeFile, copyFile, rename, open as open$1 } from 'node:fs/promises';
13
+ import fs$1, { readFile, access as access$1, mkdir, readdir, stat, writeFile, copyFile, rename, open } from 'node:fs/promises';
14
14
  import fs$2, { watch, access, mkdir as mkdir$1, writeFile as writeFile$1, rm } from 'fs/promises';
15
15
  import { useStdout, useInput, Box, Text, render } from 'ink';
16
16
  import React, { useState, useRef, useEffect, useCallback } from 'react';
17
17
  import { fileURLToPath } from 'node:url';
18
18
  import axios from 'axios';
19
- import { EventEmitter } from 'node:events';
20
19
  import 'socket.io-client';
21
- import { spawn as spawn$1, execFileSync as execFileSync$1, exec } from 'child_process';
22
- import { createHash, randomBytes as randomBytes$1 } from 'crypto';
20
+ import { spawn as spawn$1, execFileSync as execFileSync$1 } from 'child_process';
21
+ import { createHash } from 'crypto';
23
22
  import { join as join$1, basename, dirname as dirname$1 } from 'path';
24
23
  import os$1 from 'os';
25
24
  import 'node:net';
25
+ import 'http';
26
+ import 'open';
26
27
  import { readFileSync as readFileSync$1, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, existsSync as existsSync$1, unlinkSync as unlinkSync$1 } from 'fs';
27
28
  import psList from 'ps-list';
28
29
  import spawn$2 from 'cross-spawn';
29
30
  import * as tmp from 'tmp';
30
- import open from 'open';
31
31
  import fastify from 'fastify';
32
32
  import { z } from 'zod';
33
33
  import { validatorCompiler, serializerCompiler } from 'fastify-type-provider-zod';
34
34
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
35
35
  import { createServer } from 'node:http';
36
36
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
37
+ import { EventEmitter } from 'node:events';
37
38
  import 'tweetnacl';
38
- import { createServer as createServer$1 } from 'http';
39
- import { promisify } from 'util';
40
39
  import { deflateSync } from 'node:zlib';
41
40
 
42
41
  class Session {
@@ -5180,23 +5179,6 @@ ${typeLabels[type] || type}:`));
5180
5179
  console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
5181
5180
  }
5182
5181
 
5183
- async function openBrowser(url) {
5184
- try {
5185
- const forceOpen = process.env.FLOCKBAY_FORCE_BROWSER === "1" || process.env.FLOCKBAY_FORCE_BROWSER === "true";
5186
- if (!forceOpen && (!process.stdout.isTTY || process.env.CI || process.env.HEADLESS)) {
5187
- logger.debug("[browser] Headless/non-interactive environment detected, skipping browser open");
5188
- return false;
5189
- }
5190
- logger.debug(`[browser] Attempting to open URL: ${url}`);
5191
- await open(url, { wait: false });
5192
- logger.debug("[browser] Browser opened successfully");
5193
- return true;
5194
- } catch (error) {
5195
- logger.debug("[browser] Failed to open browser:", error);
5196
- return false;
5197
- }
5198
- }
5199
-
5200
5182
  async function loginWithClerkAndPairMachine() {
5201
5183
  logger.debug("[AUTH] Starting Clerk-based CLI login + machine pairing");
5202
5184
  const settings = await updateSettings(async (s) => {
@@ -7877,7 +7859,7 @@ function detectImageMimeTypeFromBuffer$1(buf) {
7877
7859
  return null;
7878
7860
  }
7879
7861
  async function readFileHeader(filePath, bytes) {
7880
- const fh = await open$1(filePath, "r");
7862
+ const fh = await open(filePath, "r");
7881
7863
  try {
7882
7864
  const maxBytes = Math.max(1, Math.floor(bytes));
7883
7865
  const buf = Buffer.allocUnsafe(maxBytes);
@@ -13164,7 +13146,7 @@ Update: ${updateCommand}`);
13164
13146
  summary: currentMetadata?.summary
13165
13147
  }));
13166
13148
  }
13167
- await session.connectAndWait(15e3);
13149
+ await session.connectAndWait();
13168
13150
  session.keepAlive(false, options.startingMode === "remote" ? "remote" : "local");
13169
13151
  try {
13170
13152
  logger.debug(`[START] Reporting session ${response.id} to daemon`);
@@ -13806,511 +13788,6 @@ ${chalk.bold("Usage:")}
13806
13788
  `);
13807
13789
  }
13808
13790
 
13809
- const CLIENT_ID$2 = "app_EMoamEEZ73f0CkXaXp7hrann";
13810
- const AUTH_BASE_URL = "https://auth.openai.com";
13811
- const DEFAULT_PORT$2 = 1455;
13812
- function generatePKCE$2() {
13813
- const verifier = randomBytes$1(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
13814
- const challenge = createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
13815
- return { verifier, challenge };
13816
- }
13817
- function generateState$2() {
13818
- return randomBytes$1(16).toString("hex");
13819
- }
13820
- function parseJWT(token) {
13821
- const parts = token.split(".");
13822
- if (parts.length !== 3) {
13823
- throw new Error("Invalid JWT format");
13824
- }
13825
- const payload = Buffer.from(parts[1], "base64url").toString();
13826
- return JSON.parse(payload);
13827
- }
13828
- async function findAvailablePort$2() {
13829
- return new Promise((resolve) => {
13830
- const server = createServer$1();
13831
- server.listen(0, "127.0.0.1", () => {
13832
- const port = server.address().port;
13833
- server.close(() => resolve(port));
13834
- });
13835
- });
13836
- }
13837
- async function isPortAvailable$2(port) {
13838
- return new Promise((resolve) => {
13839
- const testServer = createServer$1();
13840
- testServer.once("error", () => {
13841
- testServer.close();
13842
- resolve(false);
13843
- });
13844
- testServer.listen(port, "127.0.0.1", () => {
13845
- testServer.close(() => resolve(true));
13846
- });
13847
- });
13848
- }
13849
- async function exchangeCodeForTokens$2(code, verifier, port) {
13850
- const response = await fetch(`${AUTH_BASE_URL}/oauth/token`, {
13851
- method: "POST",
13852
- headers: {
13853
- "Content-Type": "application/x-www-form-urlencoded"
13854
- },
13855
- body: new URLSearchParams({
13856
- grant_type: "authorization_code",
13857
- client_id: CLIENT_ID$2,
13858
- code,
13859
- code_verifier: verifier,
13860
- redirect_uri: `http://localhost:${port}/auth/callback`
13861
- })
13862
- });
13863
- if (!response.ok) {
13864
- const error = await response.text();
13865
- throw new Error(`Token exchange failed: ${error}`);
13866
- }
13867
- const data = await response.json();
13868
- const idTokenPayload = parseJWT(data.id_token);
13869
- let accountId = idTokenPayload.chatgpt_account_id;
13870
- if (!accountId) {
13871
- const authClaim = idTokenPayload["https://api.openai.com/auth"];
13872
- if (authClaim && typeof authClaim === "object") {
13873
- accountId = authClaim.chatgpt_account_id || authClaim.account_id;
13874
- }
13875
- }
13876
- return {
13877
- id_token: data.id_token,
13878
- access_token: data.access_token || data.id_token,
13879
- refresh_token: data.refresh_token,
13880
- account_id: accountId
13881
- };
13882
- }
13883
- async function startCallbackServer$2(state, verifier, port) {
13884
- return new Promise((resolve, reject) => {
13885
- const server = createServer$1(async (req, res) => {
13886
- const url = new URL(req.url, `http://localhost:${port}`);
13887
- if (url.pathname === "/auth/callback") {
13888
- const code = url.searchParams.get("code");
13889
- const receivedState = url.searchParams.get("state");
13890
- if (receivedState !== state) {
13891
- res.writeHead(400);
13892
- res.end("Invalid state parameter");
13893
- server.close();
13894
- reject(new Error("Invalid state parameter"));
13895
- return;
13896
- }
13897
- if (!code) {
13898
- res.writeHead(400);
13899
- res.end("No authorization code received");
13900
- server.close();
13901
- reject(new Error("No authorization code received"));
13902
- return;
13903
- }
13904
- try {
13905
- const tokens = await exchangeCodeForTokens$2(code, verifier, port);
13906
- res.writeHead(200, { "Content-Type": "text/html" });
13907
- res.end(`
13908
- <html>
13909
- <body style="font-family: sans-serif; padding: 20px;">
13910
- <h2>\u2705 Authentication Successful!</h2>
13911
- <p>You can close this window and return to your terminal.</p>
13912
- <script>setTimeout(() => window.close(), 3000);<\/script>
13913
- </body>
13914
- </html>
13915
- `);
13916
- server.close();
13917
- resolve(tokens);
13918
- } catch (error) {
13919
- res.writeHead(500);
13920
- res.end("Token exchange failed");
13921
- server.close();
13922
- reject(error);
13923
- }
13924
- }
13925
- });
13926
- server.listen(port, "127.0.0.1", () => {
13927
- });
13928
- setTimeout(() => {
13929
- server.close();
13930
- reject(new Error("Authentication timeout"));
13931
- }, 5 * 60 * 1e3);
13932
- });
13933
- }
13934
- async function authenticateCodex() {
13935
- const { verifier, challenge } = generatePKCE$2();
13936
- const state = generateState$2();
13937
- let port = DEFAULT_PORT$2;
13938
- const portAvailable = await isPortAvailable$2(port);
13939
- if (!portAvailable) {
13940
- port = await findAvailablePort$2();
13941
- }
13942
- const serverPromise = startCallbackServer$2(state, verifier, port);
13943
- await new Promise((resolve) => setTimeout(resolve, 100));
13944
- const redirect_uri = `http://localhost:${port}/auth/callback`;
13945
- const params = [
13946
- ["response_type", "code"],
13947
- ["client_id", CLIENT_ID$2],
13948
- ["redirect_uri", redirect_uri],
13949
- ["scope", "openid profile email offline_access"],
13950
- ["code_challenge", challenge],
13951
- ["code_challenge_method", "S256"],
13952
- ["id_token_add_organizations", "true"],
13953
- ["codex_cli_simplified_flow", "true"],
13954
- ["state", state]
13955
- ];
13956
- const queryString = params.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
13957
- const authUrl = `${AUTH_BASE_URL}/oauth/authorize?${queryString}`;
13958
- console.log("\u{1F4CB} Opening browser for authentication...");
13959
- console.log(`If browser doesn't open, visit:
13960
- ${authUrl}
13961
- `);
13962
- await openBrowser(authUrl);
13963
- const tokens = await serverPromise;
13964
- console.log("\u{1F389} Authentication successful!");
13965
- return tokens;
13966
- }
13967
-
13968
- const CLIENT_ID$1 = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
13969
- const CLAUDE_AI_AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
13970
- const TOKEN_URL$1 = "https://console.anthropic.com/v1/oauth/token";
13971
- const DEFAULT_PORT$1 = 54545;
13972
- const SCOPE = "user:inference";
13973
- function generatePKCE$1() {
13974
- const verifier = randomBytes$1(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
13975
- const challenge = createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
13976
- return { verifier, challenge };
13977
- }
13978
- function generateState$1() {
13979
- return randomBytes$1(32).toString("base64url");
13980
- }
13981
- async function findAvailablePort$1() {
13982
- return new Promise((resolve) => {
13983
- const server = createServer$1();
13984
- server.listen(0, "127.0.0.1", () => {
13985
- const port = server.address().port;
13986
- server.close(() => resolve(port));
13987
- });
13988
- });
13989
- }
13990
- async function isPortAvailable$1(port) {
13991
- return new Promise((resolve) => {
13992
- const testServer = createServer$1();
13993
- testServer.once("error", () => {
13994
- testServer.close();
13995
- resolve(false);
13996
- });
13997
- testServer.listen(port, "127.0.0.1", () => {
13998
- testServer.close(() => resolve(true));
13999
- });
14000
- });
14001
- }
14002
- async function exchangeCodeForTokens$1(code, verifier, port, state) {
14003
- const tokenResponse = await fetch(TOKEN_URL$1, {
14004
- method: "POST",
14005
- headers: {
14006
- "Content-Type": "application/json"
14007
- },
14008
- body: JSON.stringify({
14009
- grant_type: "authorization_code",
14010
- code,
14011
- redirect_uri: `http://localhost:${port}/callback`,
14012
- client_id: CLIENT_ID$1,
14013
- code_verifier: verifier,
14014
- state
14015
- })
14016
- });
14017
- if (!tokenResponse.ok) {
14018
- throw new Error(`Token exchange failed: ${tokenResponse.statusText}`);
14019
- }
14020
- const tokenData = await tokenResponse.json();
14021
- return {
14022
- raw: tokenData,
14023
- token: tokenData.access_token,
14024
- expires: Date.now() + tokenData.expires_in * 1e3
14025
- };
14026
- }
14027
- async function startCallbackServer$1(state, verifier, port) {
14028
- return new Promise((resolve, reject) => {
14029
- const server = createServer$1(async (req, res) => {
14030
- const url = new URL(req.url, `http://localhost:${port}`);
14031
- if (url.pathname === "/callback") {
14032
- const code = url.searchParams.get("code");
14033
- const receivedState = url.searchParams.get("state");
14034
- if (receivedState !== state) {
14035
- res.writeHead(400);
14036
- res.end("Invalid state parameter");
14037
- server.close();
14038
- reject(new Error("Invalid state parameter"));
14039
- return;
14040
- }
14041
- if (!code) {
14042
- res.writeHead(400);
14043
- res.end("No authorization code received");
14044
- server.close();
14045
- reject(new Error("No authorization code received"));
14046
- return;
14047
- }
14048
- try {
14049
- const tokens = await exchangeCodeForTokens$1(code, verifier, port, state);
14050
- res.writeHead(302, {
14051
- "Location": "https://console.anthropic.com/oauth/code/success?app=claude-code"
14052
- });
14053
- res.end();
14054
- server.close();
14055
- resolve(tokens);
14056
- } catch (error) {
14057
- res.writeHead(500);
14058
- res.end("Token exchange failed");
14059
- server.close();
14060
- reject(error);
14061
- }
14062
- }
14063
- });
14064
- server.listen(port, "127.0.0.1", () => {
14065
- });
14066
- setTimeout(() => {
14067
- server.close();
14068
- reject(new Error("Authentication timeout"));
14069
- }, 5 * 60 * 1e3);
14070
- });
14071
- }
14072
- async function authenticateClaude() {
14073
- console.log("\u{1F680} Starting Anthropic Claude authentication...");
14074
- const { verifier, challenge } = generatePKCE$1();
14075
- const state = generateState$1();
14076
- let port = DEFAULT_PORT$1;
14077
- const portAvailable = await isPortAvailable$1(port);
14078
- if (!portAvailable) {
14079
- console.log(`Port ${port} is in use, finding an available port...`);
14080
- port = await findAvailablePort$1();
14081
- }
14082
- console.log(`\u{1F4E1} Using callback port: ${port}`);
14083
- const serverPromise = startCallbackServer$1(state, verifier, port);
14084
- await new Promise((resolve) => setTimeout(resolve, 100));
14085
- const redirect_uri = `http://localhost:${port}/callback`;
14086
- const params = new URLSearchParams({
14087
- code: "true",
14088
- // This tells Claude.ai to show the code AND redirect
14089
- client_id: CLIENT_ID$1,
14090
- response_type: "code",
14091
- redirect_uri,
14092
- scope: SCOPE,
14093
- code_challenge: challenge,
14094
- code_challenge_method: "S256",
14095
- state
14096
- });
14097
- const authUrl = `${CLAUDE_AI_AUTHORIZE_URL}?${params}`;
14098
- console.log("\u{1F4CB} Opening browser for authentication...");
14099
- console.log("If browser doesn't open, visit this URL:");
14100
- console.log();
14101
- console.log(`${authUrl}`);
14102
- console.log();
14103
- await openBrowser(authUrl);
14104
- try {
14105
- const tokens = await serverPromise;
14106
- console.log("\u{1F389} Authentication successful!");
14107
- console.log("\u2705 OAuth tokens received");
14108
- return tokens;
14109
- } catch (error) {
14110
- console.error("\n\u274C Failed to authenticate with Anthropic");
14111
- throw error;
14112
- }
14113
- }
14114
-
14115
- const execAsync = promisify(exec);
14116
- const CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
14117
- const CLIENT_SECRET = "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";
14118
- const AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
14119
- const TOKEN_URL = "https://oauth2.googleapis.com/token";
14120
- const DEFAULT_PORT = 54545;
14121
- const SCOPES = [
14122
- "https://www.googleapis.com/auth/cloud-platform",
14123
- "https://www.googleapis.com/auth/userinfo.email",
14124
- "https://www.googleapis.com/auth/userinfo.profile"
14125
- ].join(" ");
14126
- function generatePKCE() {
14127
- const verifier = randomBytes$1(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
14128
- const challenge = createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
14129
- return { verifier, challenge };
14130
- }
14131
- function generateState() {
14132
- return randomBytes$1(32).toString("hex");
14133
- }
14134
- async function findAvailablePort() {
14135
- return new Promise((resolve) => {
14136
- const server = createServer$1();
14137
- server.listen(0, "127.0.0.1", () => {
14138
- const port = server.address().port;
14139
- server.close(() => resolve(port));
14140
- });
14141
- });
14142
- }
14143
- async function isPortAvailable(port) {
14144
- return new Promise((resolve) => {
14145
- const testServer = createServer$1();
14146
- testServer.once("error", () => {
14147
- testServer.close();
14148
- resolve(false);
14149
- });
14150
- testServer.listen(port, "127.0.0.1", () => {
14151
- testServer.close(() => resolve(true));
14152
- });
14153
- });
14154
- }
14155
- async function exchangeCodeForTokens(code, verifier, port) {
14156
- const response = await fetch(TOKEN_URL, {
14157
- method: "POST",
14158
- headers: {
14159
- "Content-Type": "application/x-www-form-urlencoded"
14160
- },
14161
- body: new URLSearchParams({
14162
- grant_type: "authorization_code",
14163
- client_id: CLIENT_ID,
14164
- client_secret: CLIENT_SECRET,
14165
- code,
14166
- code_verifier: verifier,
14167
- redirect_uri: `http://localhost:${port}/oauth2callback`
14168
- })
14169
- });
14170
- if (!response.ok) {
14171
- const error = await response.text();
14172
- throw new Error(`Token exchange failed: ${error}`);
14173
- }
14174
- const data = await response.json();
14175
- return data;
14176
- }
14177
- async function startCallbackServer(state, verifier, port) {
14178
- return new Promise((resolve, reject) => {
14179
- const server = createServer$1(async (req, res) => {
14180
- const url = new URL(req.url, `http://localhost:${port}`);
14181
- if (url.pathname === "/oauth2callback") {
14182
- const code = url.searchParams.get("code");
14183
- const receivedState = url.searchParams.get("state");
14184
- const error = url.searchParams.get("error");
14185
- if (error) {
14186
- res.writeHead(302, {
14187
- "Location": "https://developers.google.com/gemini-code-assist/auth_failure_gemini"
14188
- });
14189
- res.end();
14190
- server.close();
14191
- reject(new Error(`Authentication error: ${error}`));
14192
- return;
14193
- }
14194
- if (receivedState !== state) {
14195
- res.writeHead(400);
14196
- res.end("State mismatch. Possible CSRF attack");
14197
- server.close();
14198
- reject(new Error("Invalid state parameter"));
14199
- return;
14200
- }
14201
- if (!code) {
14202
- res.writeHead(400);
14203
- res.end("No authorization code received");
14204
- server.close();
14205
- reject(new Error("No authorization code received"));
14206
- return;
14207
- }
14208
- try {
14209
- const tokens = await exchangeCodeForTokens(code, verifier, port);
14210
- res.writeHead(302, {
14211
- "Location": "https://developers.google.com/gemini-code-assist/auth_success_gemini"
14212
- });
14213
- res.end();
14214
- server.close();
14215
- resolve(tokens);
14216
- } catch (error2) {
14217
- res.writeHead(500);
14218
- res.end("Token exchange failed");
14219
- server.close();
14220
- reject(error2);
14221
- }
14222
- }
14223
- });
14224
- server.listen(port, "127.0.0.1", () => {
14225
- });
14226
- setTimeout(() => {
14227
- server.close();
14228
- reject(new Error("Authentication timeout"));
14229
- }, 5 * 60 * 1e3);
14230
- });
14231
- }
14232
- async function authenticateGemini() {
14233
- console.log("\u{1F680} Starting Google Gemini authentication...");
14234
- const { verifier, challenge } = generatePKCE();
14235
- const state = generateState();
14236
- let port = DEFAULT_PORT;
14237
- const portAvailable = await isPortAvailable(port);
14238
- if (!portAvailable) {
14239
- console.log(`Port ${port} is in use, finding an available port...`);
14240
- port = await findAvailablePort();
14241
- }
14242
- console.log(`\u{1F4E1} Using callback port: ${port}`);
14243
- const serverPromise = startCallbackServer(state, verifier, port);
14244
- await new Promise((resolve) => setTimeout(resolve, 100));
14245
- const redirect_uri = `http://localhost:${port}/oauth2callback`;
14246
- const params = new URLSearchParams({
14247
- client_id: CLIENT_ID,
14248
- response_type: "code",
14249
- redirect_uri,
14250
- scope: SCOPES,
14251
- access_type: "offline",
14252
- // To get refresh token
14253
- code_challenge: challenge,
14254
- code_challenge_method: "S256",
14255
- state,
14256
- prompt: "consent"
14257
- // Force consent to get refresh token
14258
- });
14259
- const authUrl = `${AUTHORIZE_URL}?${params}`;
14260
- console.log("\n\u{1F4CB} Opening browser for authentication...");
14261
- console.log("If browser doesn't open, visit this URL:");
14262
- console.log(`
14263
- ${authUrl}
14264
- `);
14265
- const platform = process.platform;
14266
- const openCommand = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
14267
- try {
14268
- await execAsync(`${openCommand} "${authUrl}"`);
14269
- } catch {
14270
- console.log("\u26A0\uFE0F Could not open browser automatically");
14271
- }
14272
- try {
14273
- const tokens = await serverPromise;
14274
- console.log("\n\u{1F389} Authentication successful!");
14275
- console.log("\u2705 OAuth tokens received");
14276
- return tokens;
14277
- } catch (error) {
14278
- console.error("\n\u274C Failed to authenticate with Google");
14279
- throw error;
14280
- }
14281
- }
14282
-
14283
- async function syncCodexCliAuth(tokens) {
14284
- const authFilePath = path__default.join(os__default.homedir(), ".codex", "auth.json");
14285
- const authDir = path__default.dirname(authFilePath);
14286
- let previousAccountId;
14287
- let previousApiKey = null;
14288
- try {
14289
- const existingRaw = await fs$1.readFile(authFilePath, "utf8");
14290
- const existing = JSON.parse(existingRaw);
14291
- previousAccountId = existing?.tokens?.account_id;
14292
- previousApiKey = typeof existing?.OPENAI_API_KEY === "string" ? existing.OPENAI_API_KEY : null;
14293
- } catch {
14294
- }
14295
- await fs$1.mkdir(authDir, { recursive: true });
14296
- const next = {
14297
- OPENAI_API_KEY: previousApiKey,
14298
- tokens: {
14299
- id_token: tokens.id_token,
14300
- access_token: tokens.access_token,
14301
- refresh_token: tokens.refresh_token,
14302
- account_id: tokens.account_id
14303
- },
14304
- last_refresh: (/* @__PURE__ */ new Date()).toISOString()
14305
- };
14306
- await fs$1.writeFile(authFilePath, JSON.stringify(next, null, 2) + "\n", "utf8");
14307
- return {
14308
- authFilePath,
14309
- previousAccountId,
14310
- newAccountId: tokens.account_id
14311
- };
14312
- }
14313
-
14314
13791
  async function handleConnectCommand(args) {
14315
13792
  const subcommand = args[0];
14316
13793
  const flags = args.slice(1);
@@ -14650,7 +14127,8 @@ async function runSmokeForAgent(agent, args) {
14650
14127
  const skipUnreal = !readFlag(args, "--with-unreal");
14651
14128
  const baseDir = readArgValue$2(args, "--directory") || readArgValue$2(args, "--dir");
14652
14129
  const timeoutMsRaw = readArgValue$2(args, "--timeout-ms");
14653
- const timeoutMs = timeoutMsRaw && Number.isFinite(Number(timeoutMsRaw)) ? Number(timeoutMsRaw) : 9e4;
14130
+ const defaultTimeoutMs = process.platform === "win32" ? 24e4 : 9e4;
14131
+ const timeoutMs = timeoutMsRaw && Number.isFinite(Number(timeoutMsRaw)) ? Number(timeoutMsRaw) : defaultTimeoutMs;
14654
14132
  let sessionId;
14655
14133
  let directory;
14656
14134
  let sessionClient = null;
@@ -14698,7 +14176,7 @@ Update: ${updateCommand}`);
14698
14176
  throw new Error(msg);
14699
14177
  }
14700
14178
  sessionClient = api.sessionSyncClient(session);
14701
- await sessionClient.connectAndWait(15e3);
14179
+ await sessionClient.connectAndWait();
14702
14180
  await ensureSessionActive(api, sessionId, 25e3);
14703
14181
  const permissionMode = permissionModeForAgent(agent);
14704
14182
  scenarios.push(await runScenario("basic-message", async () => {
@@ -14803,7 +14281,7 @@ Options:
14803
14281
  --agent, -a Run a single agent
14804
14282
  --agents Comma-separated list of agents
14805
14283
  --directory, --dir Directory to run the session in (defaults to a temp folder)
14806
- --timeout-ms Per-scenario timeout (default 90000)
14284
+ --timeout-ms Per-scenario timeout (default 90000; Windows default 240000)
14807
14285
  --keep Do not stop session or delete temp dir
14808
14286
  --json Write results JSON to a file
14809
14287
  --with-unreal Allow Unreal MCP prompts (off by default)
@@ -14867,6 +14345,18 @@ function splitList(value) {
14867
14345
  function ensureDir(dir) {
14868
14346
  fs__default.mkdirSync(dir, { recursive: true });
14869
14347
  }
14348
+ function canWriteDir(dir) {
14349
+ const root = (dir || "").trim();
14350
+ if (!root) return false;
14351
+ try {
14352
+ const tmp = path__default.join(root, `.__flockbay_write_test_${Date.now()}_${Math.random().toString(16).slice(2)}.tmp`);
14353
+ fs__default.writeFileSync(tmp, "ok", "utf8");
14354
+ fs__default.unlinkSync(tmp);
14355
+ return true;
14356
+ } catch {
14357
+ return false;
14358
+ }
14359
+ }
14870
14360
  function detectImageMimeTypeFromBuffer(buf) {
14871
14361
  if (!buf || buf.length < 12) return null;
14872
14362
  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) {
@@ -14885,7 +14375,7 @@ async function waitForUnreal(options) {
14885
14375
  while (Date.now() - startedAt < options.timeoutMs) {
14886
14376
  try {
14887
14377
  const res = await sendUnrealMcpTcpCommand({ type: "ping", host: options.host, port: options.port, timeoutMs: 2e3 });
14888
- const msg = typeof res?.message === "string" ? res.message : null;
14378
+ const msg = typeof res?.message === "string" ? res.message : typeof res?.result?.message === "string" ? res.result.message : null;
14889
14379
  if (msg === "pong") return { ok: true };
14890
14380
  } catch (err) {
14891
14381
  lastErr = err instanceof Error ? err.message : String(err);
@@ -14933,22 +14423,23 @@ async function runRuntimeSmoke(options) {
14933
14423
  }
14934
14424
  try {
14935
14425
  const pluginInfo = await sendUnrealMcpTcpCommand({ type: "get_plugin_info", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
14936
- const createdBy = String(pluginInfo?.createdBy || "").trim();
14937
- const friendlyName = String(pluginInfo?.friendlyName || "").trim();
14938
- const baseDir = String(pluginInfo?.baseDir || "").trim();
14939
- const schemaVersion = Number(pluginInfo?.schemaVersion);
14940
- const commands = Array.isArray(pluginInfo?.commands) ? pluginInfo.commands.filter((c) => typeof c === "string") : [];
14941
- if (friendlyName !== "Unreal MCP Plugin" || createdBy !== "Respaced Inc.") {
14426
+ const pluginInfoResult = pluginInfo?.result && typeof pluginInfo.result === "object" ? pluginInfo.result : pluginInfo;
14427
+ const createdBy = String(pluginInfoResult?.createdBy || "").trim();
14428
+ const friendlyName = String(pluginInfoResult?.friendlyName || "").trim();
14429
+ const baseDir = String(pluginInfoResult?.baseDir || "").trim();
14430
+ const schemaVersion = Number(pluginInfoResult?.schemaVersion);
14431
+ const commands = Array.isArray(pluginInfoResult?.commands) ? pluginInfoResult.commands.filter((c) => typeof c === "string") : [];
14432
+ if (friendlyName !== "Flockbay MCP" || createdBy !== "Respaced Inc.") {
14942
14433
  return {
14943
14434
  ok: false,
14944
14435
  error: `Unexpected plugin identity loaded by Unreal.
14945
14436
  friendlyName=${friendlyName || "(missing)"} createdBy=${createdBy || "(missing)"}
14946
14437
  baseDir=${baseDir || "(missing)"}
14947
- Expected FriendlyName="Unreal MCP Plugin" CreatedBy="Respaced Inc."`
14438
+ Expected FriendlyName="Flockbay MCP" CreatedBy="Respaced Inc."`
14948
14439
  };
14949
14440
  }
14950
14441
  if (!Number.isFinite(schemaVersion) || schemaVersion <= 0) {
14951
- return { ok: false, error: `Invalid schemaVersion from get_plugin_info: ${String(pluginInfo?.schemaVersion)}` };
14442
+ return { ok: false, error: `Invalid schemaVersion from get_plugin_info: ${String(pluginInfoResult?.schemaVersion)}` };
14952
14443
  }
14953
14444
  const requireCommands = [
14954
14445
  "ping",
@@ -14968,7 +14459,8 @@ Expected FriendlyName="Unreal MCP Plugin" CreatedBy="Respaced Inc."`
14968
14459
  return { ok: false, error: `Missing required commands in this Unreal MCP build: ${missing.join(", ")}` };
14969
14460
  }
14970
14461
  const playStatus0 = await sendUnrealMcpTcpCommand({ type: "get_play_in_editor_status", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
14971
- const isPlaying = Boolean(playStatus0?.isPlaySessionInProgress);
14462
+ const playStatusResult = playStatus0?.result && typeof playStatus0.result === "object" ? playStatus0.result : playStatus0;
14463
+ const isPlaying = Boolean(playStatusResult?.isPlaySessionInProgress);
14972
14464
  if (isPlaying) {
14973
14465
  await sendUnrealMcpTcpCommand({ type: "stop_play_in_editor", host: options.host, port: options.port, timeoutMs: options.timeoutMs });
14974
14466
  }
@@ -14995,7 +14487,9 @@ Expected FriendlyName="Unreal MCP Plugin" CreatedBy="Respaced Inc."`
14995
14487
  const bpName = `BP_Smoke_${Date.now()}`;
14996
14488
  await sendUnrealMcpTcpCommand({
14997
14489
  type: "create_blueprint",
14998
- params: { name: bpName, path: "/Game/FlockbaySmoke/", parent_class: "Actor" },
14490
+ // Important: pass only the name so the plugin's default (/Game/Blueprints/) is used.
14491
+ // The plugin's "compile_blueprint" name-only lookup searches /Game/Blueprints by design.
14492
+ params: { name: bpName, parent_class: "Actor" },
14999
14493
  host: options.host,
15000
14494
  port: options.port,
15001
14495
  timeoutMs: Math.max(options.timeoutMs, 2e4)
@@ -15062,26 +14556,73 @@ async function runUnrealMcpMatrixSmoke(args) {
15062
14556
  if (!engineRoot) continue;
15063
14557
  console.log(chalk.bold(`== Engine: ${engineRoot} ==`));
15064
14558
  if (doBuild) {
15065
- console.log(chalk.cyan("Build: installing Flockbay MCP plugin sources (folder: FlockbayMCP)..."));
15066
- const installed = installUnrealMcpPluginToEngine(engineRoot);
15067
- if (!installed.ok) {
15068
- failures.push({ engineRoot, phase: "build", error: installed.errorMessage });
15069
- console.log(chalk.red(`Build: failed (install)
14559
+ const enginePluginsDir = path__default.join(engineRoot, "Engine", "Plugins");
14560
+ const enginePluginDir = path__default.join(enginePluginsDir, "FlockbayMCP");
14561
+ const enginePluginUplugin = path__default.join(enginePluginDir, "FlockbayMCP.uplugin");
14562
+ const enginePluginHasBinaries = fs__default.existsSync(path__default.join(enginePluginDir, "Binaries"));
14563
+ const projectUprojectPath = project ? path__default.resolve(project) : null;
14564
+ if (fs__default.existsSync(enginePluginUplugin) && enginePluginHasBinaries) {
14565
+ console.log(chalk.green(`Build: engine plugin already installed + built (${enginePluginDir})`));
14566
+ } else if (canWriteDir(enginePluginsDir)) {
14567
+ console.log(chalk.cyan("Build: installing Flockbay MCP plugin sources into the engine (folder: FlockbayMCP)..."));
14568
+ const installed = installUnrealMcpPluginToEngine(engineRoot);
14569
+ if (!installed.ok) {
14570
+ failures.push({ engineRoot, phase: "build", error: installed.errorMessage });
14571
+ console.log(chalk.red(`Build: failed (install)
15070
14572
  ${installed.errorMessage}
15071
14573
  `));
15072
- if (!doRuntime) continue;
15073
- } else {
15074
- console.log(chalk.green(`Build: sources installed to ${installed.destDir}`));
15075
- console.log(chalk.cyan("Build: compiling plugin via RunUAT BuildPlugin..."));
15076
- const built = await buildAndInstallUnrealMcpPlugin({ engineRoot, flockbayHomeDir: configuration.flockbayHomeDir });
15077
- if (!built.ok) {
15078
- failures.push({ engineRoot, phase: "build", error: built.errorMessage });
15079
- console.log(chalk.red(`Build: failed
14574
+ if (!doRuntime) continue;
14575
+ } else {
14576
+ console.log(chalk.green(`Build: sources installed to ${installed.destDir}`));
14577
+ console.log(chalk.cyan("Build: compiling plugin via RunUAT BuildPlugin..."));
14578
+ const built = await buildAndInstallUnrealMcpPlugin({ engineRoot, flockbayHomeDir: configuration.flockbayHomeDir });
14579
+ if (!built.ok) {
14580
+ failures.push({ engineRoot, phase: "build", error: built.errorMessage });
14581
+ console.log(chalk.red(`Build: failed
15080
14582
  ${built.errorMessage}
15081
14583
  `));
14584
+ } else {
14585
+ console.log(chalk.green(`Build: ok (log: ${built.buildLogPath})`));
14586
+ }
14587
+ }
14588
+ } else if (projectUprojectPath) {
14589
+ console.log(chalk.cyan("Build: engine install not writable; installing plugin into the project instead..."));
14590
+ const installedProject = installUnrealMcpPluginToProject(projectUprojectPath);
14591
+ if (!installedProject.ok) {
14592
+ failures.push({ engineRoot, phase: "build", error: installedProject.errorMessage });
14593
+ console.log(chalk.red(`Build: failed (project install)
14594
+ ${installedProject.errorMessage}
14595
+ `));
14596
+ if (!doRuntime) continue;
15082
14597
  } else {
15083
- console.log(chalk.green(`Build: ok (log: ${built.buildLogPath})`));
14598
+ console.log(chalk.green(`Build: sources installed to ${installedProject.destDir}`));
14599
+ console.log(chalk.cyan("Build: compiling plugin via RunUAT BuildPlugin..."));
14600
+ const built = await buildAndInstallUnrealMcpPlugin({
14601
+ engineRoot,
14602
+ flockbayHomeDir: configuration.flockbayHomeDir,
14603
+ pluginDir: installedProject.destDir
14604
+ });
14605
+ if (!built.ok) {
14606
+ failures.push({ engineRoot, phase: "build", error: built.errorMessage });
14607
+ console.log(chalk.red(`Build: failed
14608
+ ${built.errorMessage}
14609
+ `));
14610
+ } else {
14611
+ console.log(chalk.green(`Build: ok (log: ${built.buildLogPath})`));
14612
+ }
15084
14613
  }
14614
+ } else {
14615
+ const error = `Engine plugins folder is not writable:
14616
+ ${enginePluginsDir}
14617
+
14618
+ Fix:
14619
+ - Re-run with --project "<path-to-your-project>.uproject" so we can install the plugin into the project (no admin), OR
14620
+ - Run the installer with Windows admin permissions.`;
14621
+ failures.push({ engineRoot, phase: "build", error });
14622
+ console.log(chalk.red(`Build: failed
14623
+ ${error}
14624
+ `));
14625
+ if (!doRuntime) continue;
15085
14626
  }
15086
14627
  }
15087
14628
  if (doRuntime) {
@@ -15540,7 +15081,7 @@ async function authAndSetupMachineIfNeeded() {
15540
15081
  process.exit(1);
15541
15082
  }
15542
15083
  try {
15543
- const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-Beo3Vgvz.mjs');
15084
+ const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-CCepAUqm.mjs');
15544
15085
  const result = migrateUnrealMcpToFlockbayMcp({
15545
15086
  engineRoot,
15546
15087
  projectUprojectPath: project || void 0,
@@ -15679,7 +15220,7 @@ ${engineRoot}`, {
15679
15220
  } else if (subcommand === "codex") {
15680
15221
  try {
15681
15222
  await chdirToNearestUprojectRootIfPresent();
15682
- const { runCodex } = await import('./runCodex-BAbRZt7Y.mjs');
15223
+ const { runCodex } = await import('./runCodex-7GeFJuM_.mjs');
15683
15224
  let startedBy = void 0;
15684
15225
  let sessionId = void 0;
15685
15226
  for (let i = 1; i < args.length; i++) {
@@ -15781,7 +15322,7 @@ ${engineRoot}`, {
15781
15322
  }
15782
15323
  try {
15783
15324
  await chdirToNearestUprojectRootIfPresent();
15784
- const { runGemini } = await import('./runGemini-D9WGwILY.mjs');
15325
+ const { runGemini } = await import('./runGemini-9LGJaWVk.mjs');
15785
15326
  let startedBy = void 0;
15786
15327
  let sessionId = void 0;
15787
15328
  for (let i = 1; i < args.length; i++) {