flockbay 0.10.20 → 0.10.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-D_mglYG0.cjs → index-Bhkn02hu.cjs} +125 -22
- package/dist/{index-CX0Z8pmz.mjs → index-By332wvJ.mjs} +124 -21
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{runCodex-CXJW0tzo.cjs → runCodex-CH4lz1QX.cjs} +2 -4
- package/dist/{runCodex-Biis9GFw.mjs → runCodex-d2KQX2mn.mjs} +2 -4
- package/dist/{runGemini-BSH4b0wu.mjs → runGemini-Cn0C7MS1.mjs} +101 -31
- package/dist/{runGemini-FOBXtEU6.cjs → runGemini-DNSymY04.cjs} +101 -31
- package/dist/{types-BYHCKlu_.cjs → types-DeH24uWs.cjs} +2 -2
- package/dist/{types-C4QeUggl.mjs → types-mXJc7o0P.mjs} +1 -1
- package/package.json +1 -1
- package/scripts/claude_version_utils.cjs +66 -12
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +32 -11
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +1 -0
|
@@ -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-mXJc7o0P.mjs';
|
|
4
4
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
5
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
6
6
|
import { z } from 'zod';
|
|
@@ -10,7 +10,7 @@ import fs__default from 'node:fs';
|
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import path, { resolve, join } from 'node:path';
|
|
12
12
|
import { spawnSync } from 'node:child_process';
|
|
13
|
-
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, E as ElicitationHub, n as notifyDaemonSessionStarted, M as MessageQueue2, P as PLATFORM_SYSTEM_PROMPT, a as setLatestUserImages, w as withUserImagesMarker, r as registerKillSessionHandler, b as MessageBuffer, d as startFlockbayServer, e as detectUnrealProject, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-
|
|
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-By332wvJ.mjs';
|
|
14
14
|
import 'axios';
|
|
15
15
|
import 'node:events';
|
|
16
16
|
import 'socket.io-client';
|
|
@@ -3177,11 +3177,9 @@ async function runCodex(opts) {
|
|
|
3177
3177
|
} else if (msg.type === "task_complete") {
|
|
3178
3178
|
messageBuffer.addMessage("Task completed", "status");
|
|
3179
3179
|
flushInflightExecCalls({ isError: false, reason: "task_complete" });
|
|
3180
|
-
sendReady();
|
|
3181
3180
|
} else if (msg.type === "turn_aborted") {
|
|
3182
3181
|
messageBuffer.addMessage("Turn aborted", "status");
|
|
3183
3182
|
flushInflightExecCalls({ isError: true, reason: "turn_aborted" });
|
|
3184
|
-
sendReady();
|
|
3185
3183
|
}
|
|
3186
3184
|
if (msg.type === "task_started") {
|
|
3187
3185
|
if (!thinking) {
|
|
@@ -4,8 +4,8 @@ import { randomUUID, createHash } from 'node:crypto';
|
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path, { resolve, join as join$1, basename } from 'node:path';
|
|
6
6
|
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
|
7
|
-
import { l as logger, b as packageJson, A as ApiClient, r as readSettings, p as projectPath, c as configuration } from './types-
|
|
8
|
-
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker,
|
|
7
|
+
import { l as logger, b as packageJson, A as ApiClient, r as readSettings, p as projectPath, c as configuration } from './types-mXJc7o0P.mjs';
|
|
8
|
+
import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, g as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, o as extractUserImagesMarker, p as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, j as autoFinalizeCoordinationWorkItem, E as ElicitationHub, k as detectScreenshotsForGate, m as stopCaffeinate } from './index-By332wvJ.mjs';
|
|
9
9
|
import { spawn, spawnSync } from 'node:child_process';
|
|
10
10
|
import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
|
|
11
11
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
@@ -55,6 +55,18 @@ function extractToolNameFromId(toolCallId) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
const uuidLike = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(toolCallId);
|
|
59
|
+
if (!uuidLike) {
|
|
60
|
+
const prefix = toolCallId.split(/[-:]/, 1)[0] || "";
|
|
61
|
+
const trimmed = prefix.trim();
|
|
62
|
+
if (trimmed.length >= 2 && trimmed.length <= 160) {
|
|
63
|
+
const hasNonHexAlpha = /[g-z]/i.test(trimmed) || /[A-Z]/.test(trimmed) || /_/.test(trimmed);
|
|
64
|
+
const saneChars = /^[A-Za-z0-9_]+$/.test(trimmed);
|
|
65
|
+
if (saneChars && hasNonHexAlpha) {
|
|
66
|
+
return trimmed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
58
70
|
return null;
|
|
59
71
|
}
|
|
60
72
|
function determineToolName(toolName, toolCallId, input, params, context) {
|
|
@@ -2370,6 +2382,65 @@ async function runGemini(opts) {
|
|
|
2370
2382
|
seen: /* @__PURE__ */ new Set(),
|
|
2371
2383
|
inAutoReview: false
|
|
2372
2384
|
};
|
|
2385
|
+
const conversationTurns = [];
|
|
2386
|
+
const MAX_TURNS_TO_KEEP = 80;
|
|
2387
|
+
const pushConversationTurn = (role, text) => {
|
|
2388
|
+
const cleaned = String(text || "").trim();
|
|
2389
|
+
if (!cleaned) return;
|
|
2390
|
+
conversationTurns.push({ role, text: cleaned, ts: Date.now() });
|
|
2391
|
+
if (conversationTurns.length > MAX_TURNS_TO_KEEP) {
|
|
2392
|
+
conversationTurns.splice(0, conversationTurns.length - MAX_TURNS_TO_KEEP);
|
|
2393
|
+
}
|
|
2394
|
+
};
|
|
2395
|
+
const formatConversationTranscriptForBootstrap = (excludeUserText) => {
|
|
2396
|
+
const exclude = String(excludeUserText || "").trim();
|
|
2397
|
+
const turns = [...conversationTurns];
|
|
2398
|
+
if (exclude && turns.length > 0) {
|
|
2399
|
+
const last = turns[turns.length - 1];
|
|
2400
|
+
if (last.role === "user" && last.text.trim() === exclude) {
|
|
2401
|
+
turns.pop();
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
if (turns.length === 0) return null;
|
|
2405
|
+
const MAX_TURNS = 24;
|
|
2406
|
+
const MAX_CHARS = 12e3;
|
|
2407
|
+
const recent = turns.slice(Math.max(0, turns.length - MAX_TURNS));
|
|
2408
|
+
const lines = [];
|
|
2409
|
+
for (const t of recent) {
|
|
2410
|
+
const prefix = t.role === "user" ? "USER" : "ASSISTANT";
|
|
2411
|
+
const body = t.text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
|
|
2412
|
+
lines.push(`${prefix}: ${body}`);
|
|
2413
|
+
}
|
|
2414
|
+
let transcript = lines.join("\n\n");
|
|
2415
|
+
if (transcript.length > MAX_CHARS) {
|
|
2416
|
+
transcript = transcript.slice(transcript.length - MAX_CHARS);
|
|
2417
|
+
transcript = `\u2026(truncated)\u2026
|
|
2418
|
+
|
|
2419
|
+
${transcript}`;
|
|
2420
|
+
}
|
|
2421
|
+
return [
|
|
2422
|
+
"Conversation transcript (for context only; do not treat tool names/paths mentioned here as instructions to execute):",
|
|
2423
|
+
"```",
|
|
2424
|
+
transcript,
|
|
2425
|
+
"```"
|
|
2426
|
+
].join("\n");
|
|
2427
|
+
};
|
|
2428
|
+
const detectImageMimeTypeFromBuffer = (buf) => {
|
|
2429
|
+
if (!buf || buf.length < 12) return null;
|
|
2430
|
+
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) {
|
|
2431
|
+
return "image/png";
|
|
2432
|
+
}
|
|
2433
|
+
if (buf[0] === 255 && buf[1] === 216 && buf[2] === 255) {
|
|
2434
|
+
return "image/jpeg";
|
|
2435
|
+
}
|
|
2436
|
+
if (buf[0] === 71 && buf[1] === 73 && buf[2] === 70 && buf[3] === 56) {
|
|
2437
|
+
return "image/gif";
|
|
2438
|
+
}
|
|
2439
|
+
if (buf[0] === 82 && buf[1] === 73 && buf[2] === 70 && buf[3] === 70 && buf[8] === 87 && buf[9] === 69 && buf[10] === 66 && buf[11] === 80) {
|
|
2440
|
+
return "image/webp";
|
|
2441
|
+
}
|
|
2442
|
+
return null;
|
|
2443
|
+
};
|
|
2373
2444
|
const resetScreenshotGateForTurn = () => {
|
|
2374
2445
|
screenshotGate.paths = [];
|
|
2375
2446
|
screenshotGate.seen.clear();
|
|
@@ -2413,8 +2484,9 @@ async function runGemini(opts) {
|
|
|
2413
2484
|
for (let i = 0; i < unique.length; i += 1) {
|
|
2414
2485
|
const p = unique[i];
|
|
2415
2486
|
const buf = await readFile(p);
|
|
2487
|
+
const mimeType = detectImageMimeTypeFromBuffer(buf) || "image/png";
|
|
2416
2488
|
blocks.push({ type: "text", text: `Image ${i + 1}: ${basename(p)}` });
|
|
2417
|
-
blocks.push({ type: "image", data: buf.toString("base64"), mimeType
|
|
2489
|
+
blocks.push({ type: "image", data: buf.toString("base64"), mimeType });
|
|
2418
2490
|
}
|
|
2419
2491
|
return blocks;
|
|
2420
2492
|
};
|
|
@@ -2456,29 +2528,15 @@ async function runGemini(opts) {
|
|
|
2456
2528
|
}
|
|
2457
2529
|
}
|
|
2458
2530
|
const originalUserMessage = message.content.text;
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
|
|
2463
|
-
const raw = message.meta.appendSystemPrompt;
|
|
2464
|
-
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
2465
|
-
preambleParts.push(raw);
|
|
2466
|
-
} else {
|
|
2467
|
-
preambleParts.push(PLATFORM_SYSTEM_PROMPT);
|
|
2468
|
-
}
|
|
2469
|
-
} else {
|
|
2470
|
-
preambleParts.push(PLATFORM_SYSTEM_PROMPT);
|
|
2471
|
-
}
|
|
2472
|
-
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
2473
|
-
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
2474
|
-
fullPrompt = preamble.length > 0 ? preamble + "\n\n" + originalUserMessage : originalUserMessage;
|
|
2475
|
-
isFirstMessage = false;
|
|
2476
|
-
}
|
|
2531
|
+
pushConversationTurn("user", originalUserMessage);
|
|
2532
|
+
const appendSystemPrompt = message.meta?.hasOwnProperty("appendSystemPrompt") && typeof message.meta.appendSystemPrompt === "string" ? message.meta.appendSystemPrompt : null;
|
|
2533
|
+
const fullPrompt = originalUserMessage;
|
|
2477
2534
|
const mode = {
|
|
2478
2535
|
permissionMode: messagePermissionMode || "default",
|
|
2479
2536
|
model: messageModel,
|
|
2480
|
-
originalUserMessage
|
|
2537
|
+
originalUserMessage,
|
|
2481
2538
|
// Store original message separately
|
|
2539
|
+
appendSystemPrompt
|
|
2482
2540
|
};
|
|
2483
2541
|
const promptText = images.length > 0 ? withUserImagesMarker(fullPrompt, images.length) : fullPrompt;
|
|
2484
2542
|
messageQueue.push(promptText, mode, images.length > 0 ? { isolate: true } : void 0);
|
|
@@ -2488,19 +2546,14 @@ async function runGemini(opts) {
|
|
|
2488
2546
|
const keepAliveInterval = setInterval(() => {
|
|
2489
2547
|
session.keepAlive(thinking, "remote");
|
|
2490
2548
|
}, 2e3);
|
|
2491
|
-
let isFirstMessage = true;
|
|
2492
2549
|
const autoPrompt = String(process.env.FLOCKBAY_AUTO_PROMPT || "").trim();
|
|
2493
2550
|
const autoExitOnIdle = String(process.env.FLOCKBAY_AUTO_EXIT_ON_IDLE || "").trim() === "1";
|
|
2494
2551
|
if (autoPrompt) {
|
|
2495
|
-
|
|
2496
|
-
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
2497
|
-
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
2498
|
-
const fullPrompt = preamble.length > 0 ? preamble + "\n\n" + autoPrompt : autoPrompt;
|
|
2499
|
-
isFirstMessage = false;
|
|
2500
|
-
messageQueue.push(fullPrompt, {
|
|
2552
|
+
messageQueue.push(autoPrompt, {
|
|
2501
2553
|
permissionMode: "default",
|
|
2502
2554
|
model: void 0,
|
|
2503
|
-
originalUserMessage: autoPrompt
|
|
2555
|
+
originalUserMessage: autoPrompt,
|
|
2556
|
+
appendSystemPrompt: null
|
|
2504
2557
|
});
|
|
2505
2558
|
}
|
|
2506
2559
|
const sendReady = () => {
|
|
@@ -2763,6 +2816,7 @@ async function runGemini(opts) {
|
|
|
2763
2816
|
logger.debug(`[gemini] Sending complete message to mobile (length: ${finalMessageText.length}): ${finalMessageText.substring(0, 100)}...`);
|
|
2764
2817
|
logger.debug(`[gemini] Full message payload:`, JSON.stringify(messagePayload, null, 2));
|
|
2765
2818
|
session.sendCodexMessage(messagePayload);
|
|
2819
|
+
pushConversationTurn("assistant", finalMessageText);
|
|
2766
2820
|
accumulatedResponse = "";
|
|
2767
2821
|
isResponseInProgress = false;
|
|
2768
2822
|
}
|
|
@@ -2967,6 +3021,7 @@ async function runGemini(opts) {
|
|
|
2967
3021
|
if (!message) {
|
|
2968
3022
|
break;
|
|
2969
3023
|
}
|
|
3024
|
+
let startedSessionThisTurn = false;
|
|
2970
3025
|
if (wasSessionCreated && currentModeHash && message.hash !== currentModeHash) {
|
|
2971
3026
|
logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
|
|
2972
3027
|
messageBuffer.addMessage("\u2550".repeat(40), "status");
|
|
@@ -2995,6 +3050,7 @@ async function runGemini(opts) {
|
|
|
2995
3050
|
logger.debug("[gemini] Starting new ACP session with model:", actualModel);
|
|
2996
3051
|
const { sessionId } = await geminiBackend.startSession();
|
|
2997
3052
|
acpSessionId = sessionId;
|
|
3053
|
+
startedSessionThisTurn = true;
|
|
2998
3054
|
logger.debug(`[gemini] New ACP session started: ${acpSessionId}`);
|
|
2999
3055
|
logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
|
|
3000
3056
|
updateDisplayedModel(actualModel, false);
|
|
@@ -3035,6 +3091,7 @@ async function runGemini(opts) {
|
|
|
3035
3091
|
updatePermissionMode(message.mode.permissionMode);
|
|
3036
3092
|
const { sessionId } = await geminiBackend.startSession();
|
|
3037
3093
|
acpSessionId = sessionId;
|
|
3094
|
+
startedSessionThisTurn = true;
|
|
3038
3095
|
logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
|
|
3039
3096
|
wasSessionCreated = true;
|
|
3040
3097
|
currentModeHash = message.hash;
|
|
@@ -3052,8 +3109,21 @@ async function runGemini(opts) {
|
|
|
3052
3109
|
}
|
|
3053
3110
|
const promptToSend = message.message;
|
|
3054
3111
|
const parsedPrompt = extractUserImagesMarker(promptToSend);
|
|
3055
|
-
const promptText = parsedPrompt.text;
|
|
3056
3112
|
const promptImages = parsedPrompt.hasImages ? getLatestUserImages().slice(0, parsedPrompt.count) : [];
|
|
3113
|
+
const originalUserMessage = (message.mode?.originalUserMessage || parsedPrompt.text || "").trim();
|
|
3114
|
+
let promptText = parsedPrompt.text;
|
|
3115
|
+
if (startedSessionThisTurn) {
|
|
3116
|
+
const override = typeof message.mode?.appendSystemPrompt === "string" ? message.mode.appendSystemPrompt.trim() : "";
|
|
3117
|
+
const systemPrompt = override.length > 0 ? override : PLATFORM_SYSTEM_PROMPT;
|
|
3118
|
+
const preambleParts = [systemPrompt];
|
|
3119
|
+
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
3120
|
+
const transcript = formatConversationTranscriptForBootstrap(originalUserMessage);
|
|
3121
|
+
if (transcript) preambleParts.push(transcript);
|
|
3122
|
+
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
3123
|
+
promptText = preamble.length > 0 ? `${preamble}
|
|
3124
|
+
|
|
3125
|
+
${originalUserMessage}` : originalUserMessage;
|
|
3126
|
+
}
|
|
3057
3127
|
if (promptImages.length > 0) {
|
|
3058
3128
|
const blocks = [
|
|
3059
3129
|
{ type: "text", text: promptText },
|
|
@@ -6,8 +6,8 @@ var node_crypto = require('node:crypto');
|
|
|
6
6
|
var os = require('node:os');
|
|
7
7
|
var path = require('node:path');
|
|
8
8
|
var fs$2 = require('node:fs/promises');
|
|
9
|
-
var types = require('./types-
|
|
10
|
-
var index = require('./index-
|
|
9
|
+
var types = require('./types-DeH24uWs.cjs');
|
|
10
|
+
var index = require('./index-Bhkn02hu.cjs');
|
|
11
11
|
var node_child_process = require('node:child_process');
|
|
12
12
|
var sdk = require('@agentclientprotocol/sdk');
|
|
13
13
|
var fs = require('fs');
|
|
@@ -57,6 +57,18 @@ function extractToolNameFromId(toolCallId) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
const uuidLike = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(toolCallId);
|
|
61
|
+
if (!uuidLike) {
|
|
62
|
+
const prefix = toolCallId.split(/[-:]/, 1)[0] || "";
|
|
63
|
+
const trimmed = prefix.trim();
|
|
64
|
+
if (trimmed.length >= 2 && trimmed.length <= 160) {
|
|
65
|
+
const hasNonHexAlpha = /[g-z]/i.test(trimmed) || /[A-Z]/.test(trimmed) || /_/.test(trimmed);
|
|
66
|
+
const saneChars = /^[A-Za-z0-9_]+$/.test(trimmed);
|
|
67
|
+
if (saneChars && hasNonHexAlpha) {
|
|
68
|
+
return trimmed;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
60
72
|
return null;
|
|
61
73
|
}
|
|
62
74
|
function determineToolName(toolName, toolCallId, input, params, context) {
|
|
@@ -2372,6 +2384,65 @@ async function runGemini(opts) {
|
|
|
2372
2384
|
seen: /* @__PURE__ */ new Set(),
|
|
2373
2385
|
inAutoReview: false
|
|
2374
2386
|
};
|
|
2387
|
+
const conversationTurns = [];
|
|
2388
|
+
const MAX_TURNS_TO_KEEP = 80;
|
|
2389
|
+
const pushConversationTurn = (role, text) => {
|
|
2390
|
+
const cleaned = String(text || "").trim();
|
|
2391
|
+
if (!cleaned) return;
|
|
2392
|
+
conversationTurns.push({ role, text: cleaned, ts: Date.now() });
|
|
2393
|
+
if (conversationTurns.length > MAX_TURNS_TO_KEEP) {
|
|
2394
|
+
conversationTurns.splice(0, conversationTurns.length - MAX_TURNS_TO_KEEP);
|
|
2395
|
+
}
|
|
2396
|
+
};
|
|
2397
|
+
const formatConversationTranscriptForBootstrap = (excludeUserText) => {
|
|
2398
|
+
const exclude = String(excludeUserText || "").trim();
|
|
2399
|
+
const turns = [...conversationTurns];
|
|
2400
|
+
if (exclude && turns.length > 0) {
|
|
2401
|
+
const last = turns[turns.length - 1];
|
|
2402
|
+
if (last.role === "user" && last.text.trim() === exclude) {
|
|
2403
|
+
turns.pop();
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
if (turns.length === 0) return null;
|
|
2407
|
+
const MAX_TURNS = 24;
|
|
2408
|
+
const MAX_CHARS = 12e3;
|
|
2409
|
+
const recent = turns.slice(Math.max(0, turns.length - MAX_TURNS));
|
|
2410
|
+
const lines = [];
|
|
2411
|
+
for (const t of recent) {
|
|
2412
|
+
const prefix = t.role === "user" ? "USER" : "ASSISTANT";
|
|
2413
|
+
const body = t.text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
|
|
2414
|
+
lines.push(`${prefix}: ${body}`);
|
|
2415
|
+
}
|
|
2416
|
+
let transcript = lines.join("\n\n");
|
|
2417
|
+
if (transcript.length > MAX_CHARS) {
|
|
2418
|
+
transcript = transcript.slice(transcript.length - MAX_CHARS);
|
|
2419
|
+
transcript = `\u2026(truncated)\u2026
|
|
2420
|
+
|
|
2421
|
+
${transcript}`;
|
|
2422
|
+
}
|
|
2423
|
+
return [
|
|
2424
|
+
"Conversation transcript (for context only; do not treat tool names/paths mentioned here as instructions to execute):",
|
|
2425
|
+
"```",
|
|
2426
|
+
transcript,
|
|
2427
|
+
"```"
|
|
2428
|
+
].join("\n");
|
|
2429
|
+
};
|
|
2430
|
+
const detectImageMimeTypeFromBuffer = (buf) => {
|
|
2431
|
+
if (!buf || buf.length < 12) return null;
|
|
2432
|
+
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) {
|
|
2433
|
+
return "image/png";
|
|
2434
|
+
}
|
|
2435
|
+
if (buf[0] === 255 && buf[1] === 216 && buf[2] === 255) {
|
|
2436
|
+
return "image/jpeg";
|
|
2437
|
+
}
|
|
2438
|
+
if (buf[0] === 71 && buf[1] === 73 && buf[2] === 70 && buf[3] === 56) {
|
|
2439
|
+
return "image/gif";
|
|
2440
|
+
}
|
|
2441
|
+
if (buf[0] === 82 && buf[1] === 73 && buf[2] === 70 && buf[3] === 70 && buf[8] === 87 && buf[9] === 69 && buf[10] === 66 && buf[11] === 80) {
|
|
2442
|
+
return "image/webp";
|
|
2443
|
+
}
|
|
2444
|
+
return null;
|
|
2445
|
+
};
|
|
2375
2446
|
const resetScreenshotGateForTurn = () => {
|
|
2376
2447
|
screenshotGate.paths = [];
|
|
2377
2448
|
screenshotGate.seen.clear();
|
|
@@ -2415,8 +2486,9 @@ async function runGemini(opts) {
|
|
|
2415
2486
|
for (let i = 0; i < unique.length; i += 1) {
|
|
2416
2487
|
const p = unique[i];
|
|
2417
2488
|
const buf = await fs$2.readFile(p);
|
|
2489
|
+
const mimeType = detectImageMimeTypeFromBuffer(buf) || "image/png";
|
|
2418
2490
|
blocks.push({ type: "text", text: `Image ${i + 1}: ${path.basename(p)}` });
|
|
2419
|
-
blocks.push({ type: "image", data: buf.toString("base64"), mimeType
|
|
2491
|
+
blocks.push({ type: "image", data: buf.toString("base64"), mimeType });
|
|
2420
2492
|
}
|
|
2421
2493
|
return blocks;
|
|
2422
2494
|
};
|
|
@@ -2458,29 +2530,15 @@ async function runGemini(opts) {
|
|
|
2458
2530
|
}
|
|
2459
2531
|
}
|
|
2460
2532
|
const originalUserMessage = message.content.text;
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
if (message.meta?.hasOwnProperty("appendSystemPrompt")) {
|
|
2465
|
-
const raw = message.meta.appendSystemPrompt;
|
|
2466
|
-
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
2467
|
-
preambleParts.push(raw);
|
|
2468
|
-
} else {
|
|
2469
|
-
preambleParts.push(index.PLATFORM_SYSTEM_PROMPT);
|
|
2470
|
-
}
|
|
2471
|
-
} else {
|
|
2472
|
-
preambleParts.push(index.PLATFORM_SYSTEM_PROMPT);
|
|
2473
|
-
}
|
|
2474
|
-
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
2475
|
-
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
2476
|
-
fullPrompt = preamble.length > 0 ? preamble + "\n\n" + originalUserMessage : originalUserMessage;
|
|
2477
|
-
isFirstMessage = false;
|
|
2478
|
-
}
|
|
2533
|
+
pushConversationTurn("user", originalUserMessage);
|
|
2534
|
+
const appendSystemPrompt = message.meta?.hasOwnProperty("appendSystemPrompt") && typeof message.meta.appendSystemPrompt === "string" ? message.meta.appendSystemPrompt : null;
|
|
2535
|
+
const fullPrompt = originalUserMessage;
|
|
2479
2536
|
const mode = {
|
|
2480
2537
|
permissionMode: messagePermissionMode || "default",
|
|
2481
2538
|
model: messageModel,
|
|
2482
|
-
originalUserMessage
|
|
2539
|
+
originalUserMessage,
|
|
2483
2540
|
// Store original message separately
|
|
2541
|
+
appendSystemPrompt
|
|
2484
2542
|
};
|
|
2485
2543
|
const promptText = images.length > 0 ? index.withUserImagesMarker(fullPrompt, images.length) : fullPrompt;
|
|
2486
2544
|
messageQueue.push(promptText, mode, images.length > 0 ? { isolate: true } : void 0);
|
|
@@ -2490,19 +2548,14 @@ async function runGemini(opts) {
|
|
|
2490
2548
|
const keepAliveInterval = setInterval(() => {
|
|
2491
2549
|
session.keepAlive(thinking, "remote");
|
|
2492
2550
|
}, 2e3);
|
|
2493
|
-
let isFirstMessage = true;
|
|
2494
2551
|
const autoPrompt = String(process.env.FLOCKBAY_AUTO_PROMPT || "").trim();
|
|
2495
2552
|
const autoExitOnIdle = String(process.env.FLOCKBAY_AUTO_EXIT_ON_IDLE || "").trim() === "1";
|
|
2496
2553
|
if (autoPrompt) {
|
|
2497
|
-
|
|
2498
|
-
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
2499
|
-
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
2500
|
-
const fullPrompt = preamble.length > 0 ? preamble + "\n\n" + autoPrompt : autoPrompt;
|
|
2501
|
-
isFirstMessage = false;
|
|
2502
|
-
messageQueue.push(fullPrompt, {
|
|
2554
|
+
messageQueue.push(autoPrompt, {
|
|
2503
2555
|
permissionMode: "default",
|
|
2504
2556
|
model: void 0,
|
|
2505
|
-
originalUserMessage: autoPrompt
|
|
2557
|
+
originalUserMessage: autoPrompt,
|
|
2558
|
+
appendSystemPrompt: null
|
|
2506
2559
|
});
|
|
2507
2560
|
}
|
|
2508
2561
|
const sendReady = () => {
|
|
@@ -2765,6 +2818,7 @@ async function runGemini(opts) {
|
|
|
2765
2818
|
types.logger.debug(`[gemini] Sending complete message to mobile (length: ${finalMessageText.length}): ${finalMessageText.substring(0, 100)}...`);
|
|
2766
2819
|
types.logger.debug(`[gemini] Full message payload:`, JSON.stringify(messagePayload, null, 2));
|
|
2767
2820
|
session.sendCodexMessage(messagePayload);
|
|
2821
|
+
pushConversationTurn("assistant", finalMessageText);
|
|
2768
2822
|
accumulatedResponse = "";
|
|
2769
2823
|
isResponseInProgress = false;
|
|
2770
2824
|
}
|
|
@@ -2969,6 +3023,7 @@ async function runGemini(opts) {
|
|
|
2969
3023
|
if (!message) {
|
|
2970
3024
|
break;
|
|
2971
3025
|
}
|
|
3026
|
+
let startedSessionThisTurn = false;
|
|
2972
3027
|
if (wasSessionCreated && currentModeHash && message.hash !== currentModeHash) {
|
|
2973
3028
|
types.logger.debug("[Gemini] Mode changed \u2013 restarting Gemini session");
|
|
2974
3029
|
messageBuffer.addMessage("\u2550".repeat(40), "status");
|
|
@@ -2997,6 +3052,7 @@ async function runGemini(opts) {
|
|
|
2997
3052
|
types.logger.debug("[gemini] Starting new ACP session with model:", actualModel);
|
|
2998
3053
|
const { sessionId } = await geminiBackend.startSession();
|
|
2999
3054
|
acpSessionId = sessionId;
|
|
3055
|
+
startedSessionThisTurn = true;
|
|
3000
3056
|
types.logger.debug(`[gemini] New ACP session started: ${acpSessionId}`);
|
|
3001
3057
|
types.logger.debug(`[gemini] Calling updateDisplayedModel with: ${actualModel}`);
|
|
3002
3058
|
updateDisplayedModel(actualModel, false);
|
|
@@ -3037,6 +3093,7 @@ async function runGemini(opts) {
|
|
|
3037
3093
|
updatePermissionMode(message.mode.permissionMode);
|
|
3038
3094
|
const { sessionId } = await geminiBackend.startSession();
|
|
3039
3095
|
acpSessionId = sessionId;
|
|
3096
|
+
startedSessionThisTurn = true;
|
|
3040
3097
|
types.logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
|
|
3041
3098
|
wasSessionCreated = true;
|
|
3042
3099
|
currentModeHash = message.hash;
|
|
@@ -3054,8 +3111,21 @@ async function runGemini(opts) {
|
|
|
3054
3111
|
}
|
|
3055
3112
|
const promptToSend = message.message;
|
|
3056
3113
|
const parsedPrompt = index.extractUserImagesMarker(promptToSend);
|
|
3057
|
-
const promptText = parsedPrompt.text;
|
|
3058
3114
|
const promptImages = parsedPrompt.hasImages ? index.getLatestUserImages().slice(0, parsedPrompt.count) : [];
|
|
3115
|
+
const originalUserMessage = (message.mode?.originalUserMessage || parsedPrompt.text || "").trim();
|
|
3116
|
+
let promptText = parsedPrompt.text;
|
|
3117
|
+
if (startedSessionThisTurn) {
|
|
3118
|
+
const override = typeof message.mode?.appendSystemPrompt === "string" ? message.mode.appendSystemPrompt.trim() : "";
|
|
3119
|
+
const systemPrompt = override.length > 0 ? override : index.PLATFORM_SYSTEM_PROMPT;
|
|
3120
|
+
const preambleParts = [systemPrompt];
|
|
3121
|
+
if (projectCapsule) preambleParts.push(projectCapsule);
|
|
3122
|
+
const transcript = formatConversationTranscriptForBootstrap(originalUserMessage);
|
|
3123
|
+
if (transcript) preambleParts.push(transcript);
|
|
3124
|
+
const preamble = preambleParts.map((p) => String(p || "").trim()).filter(Boolean).join("\n\n");
|
|
3125
|
+
promptText = preamble.length > 0 ? `${preamble}
|
|
3126
|
+
|
|
3127
|
+
${originalUserMessage}` : originalUserMessage;
|
|
3128
|
+
}
|
|
3059
3129
|
if (promptImages.length > 0) {
|
|
3060
3130
|
const blocks = [
|
|
3061
3131
|
{ type: "text", text: promptText },
|
|
@@ -42,7 +42,7 @@ function _interopNamespaceDefault(e) {
|
|
|
42
42
|
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
|
43
43
|
|
|
44
44
|
var name = "flockbay";
|
|
45
|
-
var version = "0.10.
|
|
45
|
+
var version = "0.10.21";
|
|
46
46
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
47
47
|
var author = "Eduardo Orellana";
|
|
48
48
|
var license = "UNLICENSED";
|
|
@@ -770,7 +770,7 @@ class RpcHandlerManager {
|
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
|
|
773
|
-
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-
|
|
773
|
+
const __dirname$1 = path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('types-DeH24uWs.cjs', document.baseURI).href))));
|
|
774
774
|
function projectPath() {
|
|
775
775
|
const path = path$1.resolve(__dirname$1, "..");
|
|
776
776
|
return path;
|
|
@@ -21,7 +21,7 @@ import net from 'node:net';
|
|
|
21
21
|
import { spawn as spawn$1 } from 'node:child_process';
|
|
22
22
|
|
|
23
23
|
var name = "flockbay";
|
|
24
|
-
var version = "0.10.
|
|
24
|
+
var version = "0.10.21";
|
|
25
25
|
var description = "Flockbay CLI (local agent + daemon)";
|
|
26
26
|
var author = "Eduardo Orellana";
|
|
27
27
|
var license = "UNLICENSED";
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - Windows CMD: curl -fsSL https://claude.ai/install.cmd | cmd
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
const { execSync } = require('child_process');
|
|
14
|
+
const { execSync, execFileSync } = require('child_process');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const os = require('os');
|
|
@@ -258,19 +258,53 @@ function findLatestVersionBinary(versionsDir, binaryName = null) {
|
|
|
258
258
|
* @returns {{path: string, source: string}|null} Path and source, or null if not found
|
|
259
259
|
*/
|
|
260
260
|
function findGlobalClaudeCliPath() {
|
|
261
|
-
|
|
261
|
+
const candidates = [];
|
|
262
|
+
|
|
262
263
|
const npmPath = findNpmGlobalCliPath();
|
|
263
|
-
if (npmPath)
|
|
264
|
+
if (npmPath) candidates.push({ path: npmPath, source: 'npm', priority: 3 });
|
|
264
265
|
|
|
265
|
-
// Check Homebrew installation
|
|
266
266
|
const homebrewPath = findHomebrewCliPath();
|
|
267
|
-
if (homebrewPath)
|
|
267
|
+
if (homebrewPath) candidates.push({ path: homebrewPath, source: 'Homebrew', priority: 2 });
|
|
268
268
|
|
|
269
|
-
// Check native installer
|
|
270
269
|
const nativePath = findNativeInstallerCliPath();
|
|
271
|
-
if (nativePath)
|
|
270
|
+
if (nativePath) candidates.push({ path: nativePath, source: 'native installer', priority: 1 });
|
|
272
271
|
|
|
273
|
-
return null;
|
|
272
|
+
if (candidates.length === 0) return null;
|
|
273
|
+
|
|
274
|
+
// Prefer the newest version across installs when we can determine it.
|
|
275
|
+
// If versions are missing/unparseable, fall back to the legacy priority ordering.
|
|
276
|
+
let best = null;
|
|
277
|
+
for (const c of candidates) {
|
|
278
|
+
const version = getVersion(c.path);
|
|
279
|
+
const parsed = parseSemver3(version);
|
|
280
|
+
const score = parsed ? parsed : null;
|
|
281
|
+
|
|
282
|
+
if (!best) {
|
|
283
|
+
best = { ...c, version, score };
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (best.score && score) {
|
|
288
|
+
if (compareVersions(version, best.version) > 0) {
|
|
289
|
+
best = { ...c, version, score };
|
|
290
|
+
}
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// If one has a parseable version and the other doesn't, prefer the parseable one.
|
|
295
|
+
if (!best.score && score) {
|
|
296
|
+
best = { ...c, version, score };
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (best.score && !score) continue;
|
|
300
|
+
|
|
301
|
+
// Neither has a version: use priority.
|
|
302
|
+
if ((c.priority || 0) > (best.priority || 0)) {
|
|
303
|
+
best = { ...c, version, score };
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return best ? { path: best.path, source: best.source } : candidates[0];
|
|
274
308
|
}
|
|
275
309
|
|
|
276
310
|
/**
|
|
@@ -280,15 +314,35 @@ function findGlobalClaudeCliPath() {
|
|
|
280
314
|
*/
|
|
281
315
|
function getVersion(cliPath) {
|
|
282
316
|
try {
|
|
283
|
-
const
|
|
284
|
-
if (
|
|
285
|
-
const
|
|
286
|
-
|
|
317
|
+
const isJsFile = cliPath.endsWith('.js') || cliPath.endsWith('.cjs');
|
|
318
|
+
if (isJsFile) {
|
|
319
|
+
const pkgPath = path.join(path.dirname(cliPath), 'package.json');
|
|
320
|
+
if (fs.existsSync(pkgPath)) {
|
|
321
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
322
|
+
return pkg.version;
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
287
325
|
}
|
|
326
|
+
|
|
327
|
+
// Binary install: try to ask it.
|
|
328
|
+
const out = execFileSync(cliPath, ['--version'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
329
|
+
const m = out.match(/(\d+\.\d+\.\d+)/);
|
|
330
|
+
return m ? m[1] : null;
|
|
288
331
|
} catch (e) {}
|
|
289
332
|
return null;
|
|
290
333
|
}
|
|
291
334
|
|
|
335
|
+
function parseSemver3(v) {
|
|
336
|
+
if (!v || typeof v !== 'string') return null;
|
|
337
|
+
const m = v.trim().match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
338
|
+
if (!m) return null;
|
|
339
|
+
const a = Number(m[1]);
|
|
340
|
+
const b = Number(m[2]);
|
|
341
|
+
const c = Number(m[3]);
|
|
342
|
+
if (!Number.isFinite(a) || !Number.isFinite(b) || !Number.isFinite(c)) return null;
|
|
343
|
+
return [a, b, c];
|
|
344
|
+
}
|
|
345
|
+
|
|
292
346
|
/**
|
|
293
347
|
* Compare semver versions
|
|
294
348
|
* @param {string} a - First version
|