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