flockbay 0.10.15 → 0.10.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codex/flockbayMcpStdioBridge.cjs +339 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +339 -0
- package/dist/{index--o4BPz5o.cjs → index-BxBuBx7C.cjs} +2706 -609
- package/dist/{index-CUp3juDS.mjs → index-CHm9r89K.mjs} +2707 -611
- package/dist/index.cjs +3 -5
- package/dist/index.mjs +3 -5
- package/dist/lib.cjs +7 -9
- package/dist/lib.d.cts +219 -531
- package/dist/lib.d.mts +219 -531
- package/dist/lib.mjs +7 -9
- package/dist/{runCodex-D3eT-TvB.cjs → runCodex-DuCGwO2K.cjs} +264 -43
- package/dist/{runCodex-o6PCbHQ7.mjs → runCodex-DudVDqNh.mjs} +263 -42
- package/dist/{runGemini-CBxZp6I7.cjs → runGemini-B25LZ4Cw.cjs} +64 -29
- package/dist/{runGemini-Bt0oEj_g.mjs → runGemini-Ddu8UCOS.mjs} +63 -28
- package/dist/{types-C-jnUdn_.cjs → types-CGQhv7Z-.cjs} +470 -1146
- package/dist/{types-DGd6ea2Z.mjs → types-DuhcLxar.mjs} +469 -1142
- package/package.json +1 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +195 -6
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +376 -5
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommandSchema.cpp +731 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +476 -8
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +1518 -94
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +7 -4
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +150 -112
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +2 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +4 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommandSchema.h +42 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +4 -1
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +0 -136
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +0 -138
|
@@ -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-DuhcLxar.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,15 +10,13 @@ import fs__default from 'node:fs';
|
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import path, { resolve, join } from 'node:path';
|
|
12
12
|
import { spawnSync } from 'node:child_process';
|
|
13
|
-
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, e as detectUnrealProject, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as
|
|
14
|
-
import { d as detectScreenshotsForGate } from './flockbayScreenshotGate-DJX3Is5d.mjs';
|
|
13
|
+
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, e as detectUnrealProject, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-CHm9r89K.mjs';
|
|
15
14
|
import 'axios';
|
|
15
|
+
import 'node:events';
|
|
16
|
+
import 'socket.io-client';
|
|
16
17
|
import 'chalk';
|
|
17
18
|
import 'fs';
|
|
18
19
|
import 'node:fs/promises';
|
|
19
|
-
import 'tweetnacl';
|
|
20
|
-
import 'node:events';
|
|
21
|
-
import 'socket.io-client';
|
|
22
20
|
import 'child_process';
|
|
23
21
|
import 'fs/promises';
|
|
24
22
|
import 'crypto';
|
|
@@ -27,19 +25,18 @@ import 'url';
|
|
|
27
25
|
import 'node:process';
|
|
28
26
|
import 'os';
|
|
29
27
|
import 'node:net';
|
|
30
|
-
import 'expo-server-sdk';
|
|
31
28
|
import 'node:readline';
|
|
32
29
|
import 'node:url';
|
|
33
30
|
import 'ps-list';
|
|
34
31
|
import 'cross-spawn';
|
|
35
32
|
import 'tmp';
|
|
36
|
-
import 'qrcode-terminal';
|
|
37
33
|
import 'open';
|
|
38
34
|
import 'fastify';
|
|
39
35
|
import 'fastify-type-provider-zod';
|
|
40
36
|
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
41
37
|
import 'node:http';
|
|
42
38
|
import '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
39
|
+
import 'tweetnacl';
|
|
43
40
|
import 'http';
|
|
44
41
|
import 'util';
|
|
45
42
|
|
|
@@ -1286,6 +1283,27 @@ class CodexMcpClient {
|
|
|
1286
1283
|
logger.debug("[CodexMCP] Storing conversation for potential resume:", this.conversationId);
|
|
1287
1284
|
return this.conversationId;
|
|
1288
1285
|
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Best-effort interrupt for an in-flight Codex request.
|
|
1288
|
+
* Codex MCP does not currently support protocol-level cancellation, so we interrupt the
|
|
1289
|
+
* underlying `codex` process. This should stop streaming and allow the UI abort button
|
|
1290
|
+
* to actually halt the current turn.
|
|
1291
|
+
*/
|
|
1292
|
+
interrupt() {
|
|
1293
|
+
const pid = this.transport?.pid ?? null;
|
|
1294
|
+
if (!pid) return false;
|
|
1295
|
+
try {
|
|
1296
|
+
logger.debug("[CodexMCP] Interrupt requested; sending SIGINT to child", { pid });
|
|
1297
|
+
process.kill(pid, "SIGINT");
|
|
1298
|
+
return true;
|
|
1299
|
+
} catch (error) {
|
|
1300
|
+
const e = error;
|
|
1301
|
+
if (e?.code !== "ESRCH") {
|
|
1302
|
+
logger.debug("[CodexMCP] Failed to SIGINT child process", { pid, error });
|
|
1303
|
+
}
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1289
1307
|
async disconnect() {
|
|
1290
1308
|
if (!this.connected) return;
|
|
1291
1309
|
const pid = this.transport?.pid ?? null;
|
|
@@ -1331,6 +1349,8 @@ class CodexMcpClient {
|
|
|
1331
1349
|
this.sessionId = null;
|
|
1332
1350
|
this.conversationId = null;
|
|
1333
1351
|
this.authSnapshot = null;
|
|
1352
|
+
this.reconnectPromise = null;
|
|
1353
|
+
this.client = this.createClient();
|
|
1334
1354
|
logger.debug("[CodexMCP] Disconnected");
|
|
1335
1355
|
}
|
|
1336
1356
|
}
|
|
@@ -1548,11 +1568,14 @@ class CodexPermissionHandler {
|
|
|
1548
1568
|
this.pendingRequests.clear();
|
|
1549
1569
|
this.aliasToPrimary.clear();
|
|
1550
1570
|
this.session.updateAgentState((currentState) => {
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1571
|
+
const pendingRaw = currentState?.requests;
|
|
1572
|
+
const pendingRequests = pendingRaw && typeof pendingRaw === "object" ? pendingRaw : {};
|
|
1573
|
+
const completedRaw = currentState?.completedRequests;
|
|
1574
|
+
const completedRequests = completedRaw && typeof completedRaw === "object" ? { ...completedRaw } : {};
|
|
1553
1575
|
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
1576
|
+
const reqObj = request && typeof request === "object" ? request : { value: request };
|
|
1554
1577
|
completedRequests[id] = {
|
|
1555
|
-
...
|
|
1578
|
+
...reqObj,
|
|
1556
1579
|
completedAt: Date.now(),
|
|
1557
1580
|
status: "canceled",
|
|
1558
1581
|
reason: "Session reset"
|
|
@@ -2321,10 +2344,21 @@ async function runCodex(opts) {
|
|
|
2321
2344
|
lifecycleStateSince: Date.now(),
|
|
2322
2345
|
flavor: "codex"
|
|
2323
2346
|
};
|
|
2324
|
-
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
2347
|
+
const response = opts.sessionId ? await api.getSessionById(opts.sessionId) : await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
2325
2348
|
const session = api.sessionSyncClient(response);
|
|
2349
|
+
if (opts.sessionId) {
|
|
2350
|
+
session.updateMetadata((currentMetadata) => ({
|
|
2351
|
+
...currentMetadata,
|
|
2352
|
+
...metadata,
|
|
2353
|
+
// Preserve user-facing fields set by other clients.
|
|
2354
|
+
name: currentMetadata?.name,
|
|
2355
|
+
summary: currentMetadata?.summary
|
|
2356
|
+
}));
|
|
2357
|
+
}
|
|
2326
2358
|
const elicitationHub = new ElicitationHub();
|
|
2327
2359
|
const permissionHandler = new CodexPermissionHandler(session, { elicitationHub });
|
|
2360
|
+
await session.connectAndWait(15e3);
|
|
2361
|
+
session.keepAlive(false, "remote");
|
|
2328
2362
|
try {
|
|
2329
2363
|
logger.debug(`[START] Reporting session ${response.id} to daemon`);
|
|
2330
2364
|
const result = await notifyDaemonSessionStarted(response.id, metadata);
|
|
@@ -2339,8 +2373,10 @@ async function runCodex(opts) {
|
|
|
2339
2373
|
const messageQueue = new MessageQueue2((mode) => hashCodexSessionModeFromEnhancedMode(mode));
|
|
2340
2374
|
const autoPrompt = String(process.env.FLOCKBAY_AUTO_PROMPT || "").trim();
|
|
2341
2375
|
if (autoPrompt) {
|
|
2376
|
+
const autoPromptPermissionModeRaw = String(process.env.FLOCKBAY_AUTO_PROMPT_PERMISSION_MODE || "").trim();
|
|
2377
|
+
const autoPromptPermissionMode = autoPromptPermissionModeRaw === "safe-yolo" || autoPromptPermissionModeRaw === "yolo" || autoPromptPermissionModeRaw === "bypassPermissions" ? autoPromptPermissionModeRaw : "default";
|
|
2342
2378
|
messageQueue.push(autoPrompt, {
|
|
2343
|
-
permissionMode:
|
|
2379
|
+
permissionMode: autoPromptPermissionMode,
|
|
2344
2380
|
model: void 0,
|
|
2345
2381
|
appendSystemPrompt: PLATFORM_SYSTEM_PROMPT
|
|
2346
2382
|
});
|
|
@@ -2435,13 +2471,46 @@ async function runCodex(opts) {
|
|
|
2435
2471
|
logger.debug("[codex][handles] Failed to serialize active handles:", error);
|
|
2436
2472
|
}
|
|
2437
2473
|
}
|
|
2474
|
+
let wasCreated = false;
|
|
2475
|
+
let currentModeHash = null;
|
|
2438
2476
|
let abortController = new AbortController();
|
|
2439
2477
|
let shouldExit = false;
|
|
2440
2478
|
let storedConversationIdForRecovery = null;
|
|
2441
|
-
|
|
2479
|
+
let abortNote = null;
|
|
2480
|
+
let abortNoteSentToSession = false;
|
|
2481
|
+
let abortRequested = false;
|
|
2482
|
+
function normalizeCancelNote(input) {
|
|
2483
|
+
if (typeof input === "string") return input.trim() ? input.trim() : null;
|
|
2484
|
+
if (!input || typeof input !== "object") return null;
|
|
2485
|
+
const note = typeof input.note === "string" ? String(input.note).trim() : "";
|
|
2486
|
+
if (note) return note;
|
|
2487
|
+
const reason = typeof input.reason === "string" ? String(input.reason).trim() : "";
|
|
2488
|
+
if (reason) return reason;
|
|
2489
|
+
return null;
|
|
2490
|
+
}
|
|
2491
|
+
async function handleAbort(note, options) {
|
|
2442
2492
|
logger.debug("[Codex] Abort requested - stopping current task");
|
|
2443
2493
|
try {
|
|
2494
|
+
abortRequested = true;
|
|
2495
|
+
const normalizedNote = normalizeCancelNote(note);
|
|
2496
|
+
if (normalizedNote) {
|
|
2497
|
+
abortNote = normalizedNote;
|
|
2498
|
+
abortNoteSentToSession = Boolean(options?.alreadySentToSession);
|
|
2499
|
+
}
|
|
2444
2500
|
abortController.abort();
|
|
2501
|
+
try {
|
|
2502
|
+
storedConversationIdForRecovery = client.storeConversationForResume() || client.storeSessionForResume();
|
|
2503
|
+
client.interrupt();
|
|
2504
|
+
try {
|
|
2505
|
+
await client.disconnect();
|
|
2506
|
+
} catch (disconnectError) {
|
|
2507
|
+
logger.debug("[Codex] Failed to disconnect Codex MCP after interrupt", disconnectError);
|
|
2508
|
+
}
|
|
2509
|
+
wasCreated = false;
|
|
2510
|
+
currentModeHash = null;
|
|
2511
|
+
} catch (error) {
|
|
2512
|
+
logger.debug("[Codex] Failed to interrupt Codex process on abort", error);
|
|
2513
|
+
}
|
|
2445
2514
|
messageQueue.reset();
|
|
2446
2515
|
permissionHandler.reset();
|
|
2447
2516
|
reasoningProcessor.abort();
|
|
@@ -2479,7 +2548,10 @@ async function runCodex(opts) {
|
|
|
2479
2548
|
process.exit(1);
|
|
2480
2549
|
}
|
|
2481
2550
|
};
|
|
2482
|
-
|
|
2551
|
+
async function handleCancelGeneration(params) {
|
|
2552
|
+
await handleAbort(params);
|
|
2553
|
+
}
|
|
2554
|
+
session.rpcHandlerManager.registerHandler("cancel-generation", handleCancelGeneration);
|
|
2483
2555
|
registerKillSessionHandler(session.rpcHandlerManager, handleKillSession);
|
|
2484
2556
|
const messageBuffer = new MessageBuffer();
|
|
2485
2557
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
@@ -2507,6 +2579,57 @@ async function runCodex(opts) {
|
|
|
2507
2579
|
process.stdin.setEncoding("utf8");
|
|
2508
2580
|
}
|
|
2509
2581
|
const client = new CodexMcpClient();
|
|
2582
|
+
async function buildReplayPromptFromServerMessages() {
|
|
2583
|
+
try {
|
|
2584
|
+
const rows = await session.listMessages();
|
|
2585
|
+
if (!Array.isArray(rows) || rows.length === 0) return null;
|
|
2586
|
+
const lines = [];
|
|
2587
|
+
const push = (role, text) => {
|
|
2588
|
+
const t = String(text || "").trim();
|
|
2589
|
+
if (!t) return;
|
|
2590
|
+
lines.push(`${role === "user" ? "User" : "Assistant"}: ${t}`);
|
|
2591
|
+
};
|
|
2592
|
+
for (const row of rows.slice(-80)) {
|
|
2593
|
+
const content = row?.content;
|
|
2594
|
+
if (!content || typeof content !== "object") continue;
|
|
2595
|
+
const role = content.role;
|
|
2596
|
+
const payload = content.content;
|
|
2597
|
+
if (role === "user") {
|
|
2598
|
+
if (payload && typeof payload === "object" && payload.type === "text" && typeof payload.text === "string") {
|
|
2599
|
+
push("user", payload.text);
|
|
2600
|
+
}
|
|
2601
|
+
continue;
|
|
2602
|
+
}
|
|
2603
|
+
if (role !== "agent") continue;
|
|
2604
|
+
if (!payload || typeof payload !== "object") continue;
|
|
2605
|
+
if (payload.type === "output") {
|
|
2606
|
+
const data = payload.data;
|
|
2607
|
+
if (data && typeof data === "object" && data.type === "assistant") {
|
|
2608
|
+
const blocks = data.message?.content;
|
|
2609
|
+
if (Array.isArray(blocks)) {
|
|
2610
|
+
const txt = blocks.map((b) => b?.type === "text" && typeof b.text === "string" ? b.text : "").join("").trim();
|
|
2611
|
+
if (txt) push("assistant", txt);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
} else if (payload.type === "codex") {
|
|
2615
|
+
const data = payload.data;
|
|
2616
|
+
if (data && typeof data === "object" && data.type === "message" && typeof data.message === "string") {
|
|
2617
|
+
push("assistant", data.message);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
const compact = lines.filter((l) => l.length > 0).slice(-24).join("\n");
|
|
2622
|
+
const clipped = compact.length > 1e4 ? compact.slice(compact.length - 1e4) : compact;
|
|
2623
|
+
if (!clipped.trim()) return null;
|
|
2624
|
+
return [
|
|
2625
|
+
"Conversation so far (most recent last). Continue naturally; do not repeat it verbatim unless asked:",
|
|
2626
|
+
clipped
|
|
2627
|
+
].join("\n");
|
|
2628
|
+
} catch (e) {
|
|
2629
|
+
logger.debug("[Codex] Failed to build replay prompt from server messages", e);
|
|
2630
|
+
return null;
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2510
2633
|
function findCodexResumeFile(conversationId) {
|
|
2511
2634
|
if (!conversationId) return null;
|
|
2512
2635
|
try {
|
|
@@ -2616,9 +2739,13 @@ async function runCodex(opts) {
|
|
|
2616
2739
|
Before doing anything else, call \`mcp__flockbay__read_images\` with:
|
|
2617
2740
|
${toolArgs}
|
|
2618
2741
|
|
|
2619
|
-
Then visually inspect EVERY screenshot and report:
|
|
2620
|
-
|
|
2621
|
-
|
|
2742
|
+
Then visually inspect EVERY screenshot and report (this is for YOUR validation, not ceremony):
|
|
2743
|
+
1) List 2\u20135 concrete acceptance criteria for the user's request.
|
|
2744
|
+
2) One short bullet per image ("Image N: ...") describing what you see.
|
|
2745
|
+
3) For each acceptance criterion: mark it as Verified / Not visible / Failed based ONLY on the screenshots.
|
|
2746
|
+
- If "Not visible", say what evidence is missing.
|
|
2747
|
+
- If "Failed", say what is wrong.
|
|
2748
|
+
4) If anything is not Verified: state the next tool/action you will take to fix or validate it (do not claim completion yet).
|
|
2622
2749
|
|
|
2623
2750
|
Do not run any other tools in this step.
|
|
2624
2751
|
`);
|
|
@@ -2626,6 +2753,28 @@ async function runCodex(opts) {
|
|
|
2626
2753
|
client.setPermissionHandler(permissionHandler);
|
|
2627
2754
|
const execInflight = /* @__PURE__ */ new Set();
|
|
2628
2755
|
const execAliasToCallId = /* @__PURE__ */ new Map();
|
|
2756
|
+
const execToolCallEmitted = /* @__PURE__ */ new Set();
|
|
2757
|
+
const forceCloseInflightExecCalls = (opts2) => {
|
|
2758
|
+
if (execInflight.size === 0) return;
|
|
2759
|
+
for (const callId of Array.from(execInflight)) {
|
|
2760
|
+
try {
|
|
2761
|
+
session.sendCodexMessage({
|
|
2762
|
+
type: "tool-call-result",
|
|
2763
|
+
callId,
|
|
2764
|
+
output: { ok: !opts2.isError, reason: opts2.reason, missing_exec_command_end: true },
|
|
2765
|
+
is_error: opts2.isError,
|
|
2766
|
+
id: randomUUID()
|
|
2767
|
+
});
|
|
2768
|
+
} catch (err) {
|
|
2769
|
+
logger.debug("[codex] Failed to force-close exec tool-call", {
|
|
2770
|
+
callId,
|
|
2771
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2772
|
+
});
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
execInflight.clear();
|
|
2776
|
+
execAliasToCallId.clear();
|
|
2777
|
+
};
|
|
2629
2778
|
client.setHandler((msg) => {
|
|
2630
2779
|
try {
|
|
2631
2780
|
const preview = typeof msg?.type === "string" ? msg.type : "unknown";
|
|
@@ -2735,8 +2884,7 @@ async function runCodex(opts) {
|
|
|
2735
2884
|
const out = [];
|
|
2736
2885
|
const seen = /* @__PURE__ */ new Set();
|
|
2737
2886
|
for (const v of raw) {
|
|
2738
|
-
|
|
2739
|
-
const s = v.trim();
|
|
2887
|
+
const s = typeof v === "string" ? v.trim() : typeof v === "number" && Number.isFinite(v) ? String(v) : typeof v === "bigint" ? String(v) : "";
|
|
2740
2888
|
if (!s || s === "undefined") continue;
|
|
2741
2889
|
if (seen.has(s)) continue;
|
|
2742
2890
|
seen.add(s);
|
|
@@ -3060,30 +3208,30 @@ async function runCodex(opts) {
|
|
|
3060
3208
|
id: randomUUID()
|
|
3061
3209
|
});
|
|
3062
3210
|
}
|
|
3063
|
-
if (msg.type === "exec_command_begin"
|
|
3211
|
+
if (msg.type === "exec_command_begin") {
|
|
3064
3212
|
const callId = resolveExecCallId(msg, true);
|
|
3065
3213
|
if (!callId) {
|
|
3066
|
-
console.error("[codexbash-diag] Missing call id for exec begin
|
|
3067
|
-
type: msg.type,
|
|
3214
|
+
console.error("[codexbash-diag] Missing call id for exec begin event", {
|
|
3068
3215
|
keys: Object.keys(msg || {})
|
|
3069
3216
|
});
|
|
3070
|
-
throw new Error("Missing call id for exec begin
|
|
3217
|
+
throw new Error("Missing call id for exec begin event");
|
|
3071
3218
|
}
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
} catch {
|
|
3076
|
-
}
|
|
3219
|
+
try {
|
|
3220
|
+
console.error("[codexbash-diag] exec begin callId", { callId, aliases: getCallIdAliases(msg) });
|
|
3221
|
+
} catch {
|
|
3077
3222
|
}
|
|
3078
3223
|
markExecStarted(callId, msg);
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3224
|
+
if (!execToolCallEmitted.has(callId)) {
|
|
3225
|
+
execToolCallEmitted.add(callId);
|
|
3226
|
+
let { call_id, callId: _callId, type, ...inputs } = msg;
|
|
3227
|
+
session.sendCodexMessage({
|
|
3228
|
+
type: "tool-call",
|
|
3229
|
+
name: "CodexBash",
|
|
3230
|
+
callId,
|
|
3231
|
+
input: inputs,
|
|
3232
|
+
id: randomUUID()
|
|
3233
|
+
});
|
|
3234
|
+
}
|
|
3087
3235
|
}
|
|
3088
3236
|
if (msg.type === "exec_command_end") {
|
|
3089
3237
|
const callId = resolveExecCallId(msg, false);
|
|
@@ -3098,6 +3246,24 @@ async function runCodex(opts) {
|
|
|
3098
3246
|
console.error("[codexbash-diag] exec end callId", { callId, aliases: getCallIdAliases(msg) });
|
|
3099
3247
|
} catch {
|
|
3100
3248
|
}
|
|
3249
|
+
if (!execToolCallEmitted.has(callId)) {
|
|
3250
|
+
execToolCallEmitted.add(callId);
|
|
3251
|
+
try {
|
|
3252
|
+
let { call_id: call_id2, callId: _callId2, type: type2, ...inputs } = msg;
|
|
3253
|
+
session.sendCodexMessage({
|
|
3254
|
+
type: "tool-call",
|
|
3255
|
+
name: "CodexBash",
|
|
3256
|
+
callId,
|
|
3257
|
+
input: inputs,
|
|
3258
|
+
id: randomUUID()
|
|
3259
|
+
});
|
|
3260
|
+
} catch (err) {
|
|
3261
|
+
logger.debug("[codex] Failed to synthesize exec tool-call begin", {
|
|
3262
|
+
callId,
|
|
3263
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3264
|
+
});
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3101
3267
|
let { call_id, callId: _callId, type, ...output } = msg;
|
|
3102
3268
|
const sanitized = sanitizeExecCommandEndOutput(output);
|
|
3103
3269
|
collectScreenshotsForGate({ ...sanitized, cwd: output?.cwd ?? sanitized?.cwd ?? msg?.cwd });
|
|
@@ -3172,6 +3338,21 @@ async function runCodex(opts) {
|
|
|
3172
3338
|
}
|
|
3173
3339
|
});
|
|
3174
3340
|
const flockbayServer = await startFlockbayServer(session, { elicitationHub });
|
|
3341
|
+
const unsubscribeUnrealIssue = (() => {
|
|
3342
|
+
const onIssue = flockbayServer?.unreal?.onIssue;
|
|
3343
|
+
if (typeof onIssue !== "function") return null;
|
|
3344
|
+
return onIssue((event) => {
|
|
3345
|
+
try {
|
|
3346
|
+
const kind = typeof event?.kind === "string" ? event.kind : "unreachable";
|
|
3347
|
+
const base = typeof event?.message === "string" && event.message.trim() ? event.message.trim() : "Unreal Editor issue detected.";
|
|
3348
|
+
const msg = kind === "process_exit" ? `Unreal Editor crashed. ${base}` : `Unreal Editor is not reachable. ${base}`;
|
|
3349
|
+
session.sendSessionEvent({ type: "message", message: msg });
|
|
3350
|
+
void handleAbort(msg, { alreadySentToSession: true });
|
|
3351
|
+
} catch (err) {
|
|
3352
|
+
logger.debug("[Codex] Failed to handle Unreal issue event", err);
|
|
3353
|
+
}
|
|
3354
|
+
});
|
|
3355
|
+
})();
|
|
3175
3356
|
const bridgeCommand = join(projectPath(), "bin", "flockbay-mcp.mjs");
|
|
3176
3357
|
const mcpServers = {
|
|
3177
3358
|
flockbay: {
|
|
@@ -3205,8 +3386,8 @@ Error: ${message}`,
|
|
|
3205
3386
|
return;
|
|
3206
3387
|
}
|
|
3207
3388
|
logger.debug("[codex]: client.connect done");
|
|
3208
|
-
|
|
3209
|
-
|
|
3389
|
+
wasCreated = false;
|
|
3390
|
+
currentModeHash = null;
|
|
3210
3391
|
let pending = null;
|
|
3211
3392
|
let nextExperimentalResume = null;
|
|
3212
3393
|
while (!shouldExit) {
|
|
@@ -3259,6 +3440,8 @@ Error: ${message}`,
|
|
|
3259
3440
|
messageBuffer.addMessage(message.message, "user");
|
|
3260
3441
|
currentModeHash = message.hash;
|
|
3261
3442
|
let skipAutoFinalize = false;
|
|
3443
|
+
let turnCleanupExecIsError = false;
|
|
3444
|
+
let turnCleanupExecReason = "turn_cleanup";
|
|
3262
3445
|
try {
|
|
3263
3446
|
resetScreenshotGateForTurn();
|
|
3264
3447
|
const overrides = { approvalPolicy: "untrusted", sandbox: "workspace-write" };
|
|
@@ -3298,18 +3481,35 @@ Error: ${message}`,
|
|
|
3298
3481
|
].filter((v) => typeof v === "string" && v.trim().length > 0).join("\n\n")
|
|
3299
3482
|
);
|
|
3300
3483
|
let resumeFile = null;
|
|
3484
|
+
let resumeSource = null;
|
|
3301
3485
|
if (nextExperimentalResume) {
|
|
3302
3486
|
resumeFile = nextExperimentalResume;
|
|
3487
|
+
resumeSource = "mode-change";
|
|
3303
3488
|
nextExperimentalResume = null;
|
|
3304
3489
|
logger.debug("[Codex] Using resume file from mode change:", resumeFile);
|
|
3305
3490
|
} else if (storedConversationIdForRecovery) {
|
|
3306
3491
|
const recoveryResumeFile = findCodexResumeFile(storedConversationIdForRecovery);
|
|
3307
3492
|
if (recoveryResumeFile) {
|
|
3308
3493
|
resumeFile = recoveryResumeFile;
|
|
3494
|
+
resumeSource = "recovery";
|
|
3309
3495
|
logger.debug("[Codex] Using resume file from previous session (error recovery):", resumeFile);
|
|
3310
3496
|
}
|
|
3311
3497
|
storedConversationIdForRecovery = null;
|
|
3312
3498
|
}
|
|
3499
|
+
const replay = await buildReplayPromptFromServerMessages();
|
|
3500
|
+
if (replay) {
|
|
3501
|
+
const escapedUser = String(message.message || "").trim();
|
|
3502
|
+
const replayTrimmed = replay.trimEnd();
|
|
3503
|
+
const needle = escapedUser ? `User: ${escapedUser}` : "";
|
|
3504
|
+
const replayDeduped = needle && replayTrimmed.endsWith(needle) ? replayTrimmed.slice(0, replayTrimmed.length - needle.length).trimEnd() : replayTrimmed;
|
|
3505
|
+
startConfig.prompt = escapedUser ? `${replayDeduped}
|
|
3506
|
+
|
|
3507
|
+
User: ${escapedUser}` : replayDeduped;
|
|
3508
|
+
if (resumeSource === "recovery") {
|
|
3509
|
+
resumeFile = null;
|
|
3510
|
+
resumeSource = null;
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3313
3513
|
if (resumeFile) {
|
|
3314
3514
|
startConfig.config.experimental_resume = resumeFile;
|
|
3315
3515
|
}
|
|
@@ -3336,10 +3536,19 @@ Error: ${message}`,
|
|
|
3336
3536
|
} catch (error) {
|
|
3337
3537
|
logger.warn("Error in codex session:", error);
|
|
3338
3538
|
const isAbortError = error instanceof Error && error.name === "AbortError";
|
|
3339
|
-
|
|
3539
|
+
const treatAsAbort = abortRequested || isAbortError;
|
|
3540
|
+
if (treatAsAbort) {
|
|
3340
3541
|
skipAutoFinalize = true;
|
|
3341
|
-
|
|
3342
|
-
|
|
3542
|
+
turnCleanupExecIsError = true;
|
|
3543
|
+
turnCleanupExecReason = "turn_aborted";
|
|
3544
|
+
const note = abortNote || "Aborted by user";
|
|
3545
|
+
abortNote = null;
|
|
3546
|
+
const alreadySent = abortNoteSentToSession;
|
|
3547
|
+
abortNoteSentToSession = false;
|
|
3548
|
+
abortRequested = false;
|
|
3549
|
+
messageBuffer.addMessage(note, "status");
|
|
3550
|
+
if (!alreadySent) session.sendSessionEvent({ type: "message", message: note });
|
|
3551
|
+
session.sendSessionEvent({ type: "ready" });
|
|
3343
3552
|
if (!client.hasActiveSession()) {
|
|
3344
3553
|
wasCreated = false;
|
|
3345
3554
|
currentModeHash = null;
|
|
@@ -3349,6 +3558,8 @@ Error: ${message}`,
|
|
|
3349
3558
|
logger.debug("[Codex] Abort completed; keeping active session for next message");
|
|
3350
3559
|
}
|
|
3351
3560
|
} else {
|
|
3561
|
+
turnCleanupExecIsError = true;
|
|
3562
|
+
turnCleanupExecReason = "turn_error";
|
|
3352
3563
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3353
3564
|
messageBuffer.addMessage(`Error: ${errorMessage}`, "status");
|
|
3354
3565
|
session.sendSessionEvent({ type: "message", message: `Error: ${errorMessage}` });
|
|
@@ -3364,8 +3575,14 @@ Error: ${message}`,
|
|
|
3364
3575
|
permissionHandler.reset();
|
|
3365
3576
|
reasoningProcessor.abort();
|
|
3366
3577
|
diffProcessor.reset();
|
|
3578
|
+
forceCloseInflightExecCalls({ isError: turnCleanupExecIsError, reason: turnCleanupExecReason });
|
|
3579
|
+
abortRequested = false;
|
|
3367
3580
|
thinking = false;
|
|
3368
3581
|
session.keepAlive(thinking, "remote");
|
|
3582
|
+
try {
|
|
3583
|
+
session.flush();
|
|
3584
|
+
} catch {
|
|
3585
|
+
}
|
|
3369
3586
|
if (!skipAutoFinalize) {
|
|
3370
3587
|
try {
|
|
3371
3588
|
const finalizeRes = await autoFinalizeCoordinationWorkItem({
|
|
@@ -3396,6 +3613,10 @@ Error: ${message}`,
|
|
|
3396
3613
|
} finally {
|
|
3397
3614
|
logger.debug("[codex]: Final cleanup start");
|
|
3398
3615
|
logActiveHandles("cleanup-start");
|
|
3616
|
+
try {
|
|
3617
|
+
if (typeof unsubscribeUnrealIssue === "function") unsubscribeUnrealIssue();
|
|
3618
|
+
} catch {
|
|
3619
|
+
}
|
|
3399
3620
|
try {
|
|
3400
3621
|
logger.debug("[codex]: sendSessionDeath");
|
|
3401
3622
|
session.sendSessionDeath();
|