flockbay 0.10.21 → 0.10.22

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.
@@ -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-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';
7
+ import { l as logger, b as packageJson, A as ApiClient, r as readSettings, p as projectPath, c as configuration } from './types-CMWcip0F.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-BjZUYSzh.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';
@@ -43,6 +43,17 @@ const KNOWN_TOOL_PATTERNS = {
43
43
  save_memory: ["save_memory", "save-memory"],
44
44
  think: ["think"]
45
45
  };
46
+ const MCP_FLOCKBAY_TOOL_RE = /\bmcp__flockbay__[a-z0-9_]+\b/gi;
47
+ const UNREAL_MCP_TOOL_RE = /\bunreal_mcp_[a-z0-9_]+\b/gi;
48
+ function extractFirstToolNameFromText(text) {
49
+ if (!text) return null;
50
+ const lower = text.toLowerCase();
51
+ const mcpMatch = lower.match(MCP_FLOCKBAY_TOOL_RE);
52
+ if (mcpMatch && mcpMatch[0]) return mcpMatch[0];
53
+ const unrealMatch = lower.match(UNREAL_MCP_TOOL_RE);
54
+ if (unrealMatch && unrealMatch[0]) return `mcp__flockbay__${unrealMatch[0]}`;
55
+ return null;
56
+ }
46
57
  function isInvestigationTool(toolCallId, toolKind) {
47
58
  return toolCallId.includes("codebase_investigator") || toolCallId.includes("investigator") || typeof toolKind === "string" && toolKind.includes("investigator");
48
59
  }
@@ -77,20 +88,30 @@ function determineToolName(toolName, toolCallId, input, params, context) {
77
88
  if (idToolName) {
78
89
  return idToolName;
79
90
  }
91
+ const idTextToolName = extractFirstToolNameFromText(toolCallId);
92
+ if (idTextToolName) {
93
+ return idTextToolName;
94
+ }
80
95
  if (input && typeof input === "object") {
81
- const inputStr = JSON.stringify(input).toLowerCase();
96
+ const inputStr = JSON.stringify(input);
97
+ const extracted = extractFirstToolNameFromText(inputStr);
98
+ if (extracted) return extracted;
99
+ const inputLower = inputStr.toLowerCase();
82
100
  for (const [toolName2, patterns] of Object.entries(KNOWN_TOOL_PATTERNS)) {
83
101
  for (const pattern of patterns) {
84
- if (inputStr.includes(pattern.toLowerCase())) {
102
+ if (inputLower.includes(pattern.toLowerCase())) {
85
103
  return toolName2;
86
104
  }
87
105
  }
88
106
  }
89
107
  }
90
- const paramsStr = JSON.stringify(params).toLowerCase();
108
+ const paramsStr = JSON.stringify(params);
109
+ const paramsExtracted = extractFirstToolNameFromText(paramsStr);
110
+ if (paramsExtracted) return paramsExtracted;
111
+ const paramsLower = paramsStr.toLowerCase();
91
112
  for (const [toolName2, patterns] of Object.entries(KNOWN_TOOL_PATTERNS)) {
92
113
  for (const pattern of patterns) {
93
- if (paramsStr.includes(pattern.toLowerCase())) {
114
+ if (paramsLower.includes(pattern.toLowerCase())) {
94
115
  return toolName2;
95
116
  }
96
117
  }
@@ -327,7 +348,7 @@ class AcpSdkBackend {
327
348
  this.emit({
328
349
  type: "status",
329
350
  status: "error",
330
- detail: "Model not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite"
351
+ detail: "Model not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-3-pro-preview, gemini-3-flash-preview"
331
352
  });
332
353
  } else if (/authentication required/i.test(text) || /login required/i.test(text) || /invalid.*(api key|key)/i.test(text) || /permission denied/i.test(text)) {
333
354
  const excerpt = this.stderrExcerpt(20);
@@ -1830,7 +1851,7 @@ class GeminiPermissionHandler {
1830
1851
  const decision = result.decision;
1831
1852
  const reason = result.reason;
1832
1853
  const kind = decision === "approved" || decision === "approved_for_session" ? "policy_allow" : decision === "abort" && reason === "permission_prompt_required" ? "policy_prompt" : "policy_block";
1833
- const summary = kind === "policy_allow" ? "Allowed." : kind === "policy_prompt" ? "Waiting for permission to run this tool." : reason ? `Blocked: ${reason}` : "Blocked by policy.";
1854
+ const summary = kind === "policy_allow" ? "Allowed." : kind === "policy_prompt" ? "Waiting for permission to run this tool." : reason ? `Blocked: ${reason}` : "Blocked by Policy.";
1834
1855
  const nextSteps = [];
1835
1856
  if (kind === "policy_block" && typeof reason === "string") {
1836
1857
  if (reason.includes("docs_index_read") || reason.includes("Documentation index")) nextSteps.push("Call `mcp__flockbay__docs_index_read`.");
@@ -2568,6 +2589,30 @@ ${transcript}`;
2568
2589
  logger.debug("[Gemini] Failed to send ready push", pushError);
2569
2590
  }
2570
2591
  };
2592
+ let pendingTurnCompletion = null;
2593
+ const beginTurnCompletionWait = () => {
2594
+ if (pendingTurnCompletion) {
2595
+ logger.debug("[Gemini] beginTurnCompletionWait called while a turn is already pending; replacing pending wait");
2596
+ try {
2597
+ pendingTurnCompletion.resolve("error");
2598
+ } catch {
2599
+ }
2600
+ pendingTurnCompletion = null;
2601
+ }
2602
+ let resolve2;
2603
+ const promise = new Promise((res) => {
2604
+ resolve2 = res;
2605
+ });
2606
+ pendingTurnCompletion = { sawRunning: false, resolve: resolve2, promise };
2607
+ return promise;
2608
+ };
2609
+ const maybeResolveTurnCompletion = (status) => {
2610
+ if (!pendingTurnCompletion) return;
2611
+ if (!pendingTurnCompletion.sawRunning) return;
2612
+ const pending = pendingTurnCompletion;
2613
+ pendingTurnCompletion = null;
2614
+ pending.resolve(status);
2615
+ };
2571
2616
  const emitReadyIfIdle = () => {
2572
2617
  if (shouldExit) {
2573
2618
  return false;
@@ -2595,10 +2640,36 @@ ${transcript}`;
2595
2640
  let wasSessionCreated = false;
2596
2641
  let abortNote = null;
2597
2642
  let abortNoteSentToSession = false;
2643
+ let abortRequested = false;
2644
+ let readySentForAbort = false;
2645
+ function normalizeCancelNote(input) {
2646
+ if (typeof input === "string") return input.trim() ? input.trim() : null;
2647
+ if (!input || typeof input !== "object") return null;
2648
+ const note = typeof input.note === "string" ? String(input.note).trim() : "";
2649
+ if (note) return note;
2650
+ const reason = typeof input.reason === "string" ? String(input.reason).trim() : "";
2651
+ if (reason) return reason;
2652
+ return null;
2653
+ }
2654
+ function makeAbortError(message = "Aborted") {
2655
+ const error = new Error(message);
2656
+ error.name = "AbortError";
2657
+ return error;
2658
+ }
2659
+ function abortable(signal, promise) {
2660
+ if (signal.aborted) return Promise.reject(makeAbortError());
2661
+ return new Promise((resolve2, reject) => {
2662
+ const onAbort = () => reject(makeAbortError());
2663
+ signal.addEventListener("abort", onAbort, { once: true });
2664
+ promise.then(resolve2, reject).finally(() => signal.removeEventListener("abort", onAbort));
2665
+ });
2666
+ }
2598
2667
  async function handleAbort(note, options) {
2599
2668
  logger.debug("[Gemini] Abort requested - stopping current task");
2600
- if (typeof note === "string" && note.trim()) {
2601
- abortNote = note.trim();
2669
+ abortRequested = true;
2670
+ const normalizedNote = normalizeCancelNote(note);
2671
+ if (normalizedNote) {
2672
+ abortNote = normalizedNote;
2602
2673
  abortNoteSentToSession = Boolean(options?.alreadySentToSession);
2603
2674
  }
2604
2675
  session.sendCodexMessage({
@@ -2609,6 +2680,13 @@ ${transcript}`;
2609
2680
  diffProcessor.reset();
2610
2681
  try {
2611
2682
  abortController.abort();
2683
+ if (pendingTurnCompletion) {
2684
+ try {
2685
+ pendingTurnCompletion.resolve("error");
2686
+ } catch {
2687
+ }
2688
+ pendingTurnCompletion = null;
2689
+ }
2612
2690
  messageQueue.reset();
2613
2691
  if (geminiBackend && acpSessionId) {
2614
2692
  await geminiBackend.cancel(acpSessionId);
@@ -2747,6 +2825,7 @@ ${transcript}`;
2747
2825
  };
2748
2826
  let accumulatedResponse = "";
2749
2827
  let isResponseInProgress = false;
2828
+ let currentResponseMessageId = null;
2750
2829
  function setupGeminiMessageHandler(backend) {
2751
2830
  backend.onMessage((msg) => {
2752
2831
  switch (msg.type) {
@@ -2776,6 +2855,9 @@ ${transcript}`;
2776
2855
  if (msg.status === "running") {
2777
2856
  thinking = true;
2778
2857
  session.keepAlive(thinking, "remote");
2858
+ if (pendingTurnCompletion) {
2859
+ pendingTurnCompletion.sawRunning = true;
2860
+ }
2779
2861
  session.sendCodexMessage({
2780
2862
  type: "task_started",
2781
2863
  id: randomUUID()
@@ -2820,11 +2902,14 @@ ${transcript}`;
2820
2902
  accumulatedResponse = "";
2821
2903
  isResponseInProgress = false;
2822
2904
  }
2905
+ maybeResolveTurnCompletion(msg.status);
2823
2906
  } else if (msg.status === "error") {
2824
2907
  thinking = false;
2825
2908
  session.keepAlive(thinking, "remote");
2826
2909
  accumulatedResponse = "";
2827
2910
  isResponseInProgress = false;
2911
+ currentResponseMessageId = null;
2912
+ maybeResolveTurnCompletion("error");
2828
2913
  const errorMessage = stringifyErrorish(msg.detail || "Unknown error");
2829
2914
  messageBuffer.addMessage(`Error: ${errorMessage}`, "status");
2830
2915
  session.sendCodexMessage({
@@ -3048,7 +3133,7 @@ ${transcript}`;
3048
3133
  const actualModel = determineGeminiModel(modelToUse, localConfigForModel);
3049
3134
  logger.debug(`[gemini] Model change - modelToUse=${modelToUse}, actualModel=${actualModel}`);
3050
3135
  logger.debug("[gemini] Starting new ACP session with model:", actualModel);
3051
- const { sessionId } = await geminiBackend.startSession();
3136
+ const { sessionId } = await abortable(abortController.signal, geminiBackend.startSession());
3052
3137
  acpSessionId = sessionId;
3053
3138
  startedSessionThisTurn = true;
3054
3139
  logger.debug(`[gemini] New ACP session started: ${acpSessionId}`);
@@ -3065,6 +3150,15 @@ ${transcript}`;
3065
3150
  let retryThisTurn = false;
3066
3151
  let skipAutoFinalize = false;
3067
3152
  try {
3153
+ const turnSignal = abortController.signal;
3154
+ const sendPromptAndWait = async (prompt) => {
3155
+ if (!geminiBackend || !acpSessionId) {
3156
+ throw new Error("Gemini backend or session not initialized");
3157
+ }
3158
+ const completion = beginTurnCompletionWait();
3159
+ await abortable(turnSignal, geminiBackend.sendPrompt(acpSessionId, prompt));
3160
+ return await abortable(turnSignal, completion);
3161
+ };
3068
3162
  if (first || !wasSessionCreated) {
3069
3163
  if (!geminiBackend) {
3070
3164
  await refreshGeminiCloudToken("before-backend-create");
@@ -3089,7 +3183,7 @@ ${transcript}`;
3089
3183
  if (!acpSessionId) {
3090
3184
  logger.debug("[gemini] Starting ACP session...");
3091
3185
  updatePermissionMode(message.mode.permissionMode);
3092
- const { sessionId } = await geminiBackend.startSession();
3186
+ const { sessionId } = await abortable(turnSignal, geminiBackend.startSession());
3093
3187
  acpSessionId = sessionId;
3094
3188
  startedSessionThisTurn = true;
3095
3189
  logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
@@ -3130,18 +3224,27 @@ ${originalUserMessage}` : originalUserMessage;
3130
3224
  ...promptImages.map((img) => ({ type: "image", data: img.base64, mimeType: img.mimeType }))
3131
3225
  ];
3132
3226
  logger.debug(`[gemini] Sending multimodal prompt blocks (textLength=${promptText.length}, images=${promptImages.length})`);
3133
- await geminiBackend.sendPrompt(acpSessionId, blocks);
3227
+ const status = await sendPromptAndWait(blocks);
3228
+ if (status !== "idle") {
3229
+ skipAutoFinalize = true;
3230
+ }
3134
3231
  } else {
3135
3232
  logger.debug(`[gemini] Sending prompt to Gemini (length: ${promptText.length}): ${promptText.substring(0, 100)}...`);
3136
3233
  logger.debug(`[gemini] Full prompt: ${promptText}`);
3137
- await geminiBackend.sendPrompt(acpSessionId, promptText);
3234
+ const status = await sendPromptAndWait(promptText);
3235
+ if (status !== "idle") {
3236
+ skipAutoFinalize = true;
3237
+ }
3138
3238
  }
3139
3239
  logger.debug("[gemini] Prompt sent successfully");
3140
- if (!screenshotGate.inAutoReview && screenshotGate.paths.length > 0) {
3240
+ if (!skipAutoFinalize && !screenshotGate.inAutoReview && screenshotGate.paths.length > 0) {
3141
3241
  screenshotGate.inAutoReview = true;
3142
3242
  messageBuffer.addMessage("Auto-reviewing screenshots\u2026", "status");
3143
3243
  const blocks = await buildScreenshotReviewBlocks(screenshotGate.paths);
3144
- await geminiBackend.sendPrompt(acpSessionId, blocks);
3244
+ const status = await sendPromptAndWait(blocks);
3245
+ if (status !== "idle") {
3246
+ skipAutoFinalize = true;
3247
+ }
3145
3248
  screenshotGate.inAutoReview = false;
3146
3249
  }
3147
3250
  if (first) {
@@ -3150,14 +3253,21 @@ ${originalUserMessage}` : originalUserMessage;
3150
3253
  } catch (error) {
3151
3254
  logger.debug("[gemini] Error in gemini session:", error);
3152
3255
  const isAbortError = error instanceof Error && error.name === "AbortError";
3153
- if (isAbortError) {
3256
+ const treatAsAbort = abortRequested || isAbortError;
3257
+ if (treatAsAbort) {
3154
3258
  skipAutoFinalize = true;
3155
- const note = abortNote || "Aborted by user";
3259
+ readySentForAbort = true;
3260
+ const note = abortNote || "Canceled by user";
3156
3261
  abortNote = null;
3157
3262
  const alreadySent = abortNoteSentToSession;
3158
3263
  abortNoteSentToSession = false;
3264
+ abortRequested = false;
3265
+ accumulatedResponse = "";
3266
+ isResponseInProgress = false;
3267
+ currentResponseMessageId = null;
3159
3268
  messageBuffer.addMessage(note, "status");
3160
3269
  if (!alreadySent) session.sendSessionEvent({ type: "message", message: note });
3270
+ session.sendSessionEvent({ type: "ready" });
3161
3271
  } else {
3162
3272
  const rawErrorString = error instanceof Error ? error.message : String(error);
3163
3273
  const looksLikeAuthOrQuotaError = /unauthenticated|unauthorized|invalid (api )?key|api key not valid|permission denied|forbidden|expired|quota|usage limit|rate limit|resource exhausted|resource_exhausted|status 401|status 403|status 429|\b401\b|\b403\b|\b429\b/i.test(rawErrorString);
@@ -3189,7 +3299,7 @@ ${originalUserMessage}` : originalUserMessage;
3189
3299
  const errorString = String(error);
3190
3300
  if (errorCode === 404 || errorDetails.includes("notFound") || errorDetails.includes("404") || errorMessage.includes("not found") || errorMessage.includes("404")) {
3191
3301
  const currentModel2 = displayedModel || "gemini-2.5-pro";
3192
- errorMsg = `Model "${currentModel2}" not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite`;
3302
+ errorMsg = `Model "${currentModel2}" not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-3-pro-preview, gemini-3-flash-preview`;
3193
3303
  } else if (errorCode === 429 || errorDetails.includes("429") || errorMessage.includes("429") || errorString.includes("429") || errorDetails.includes("rateLimitExceeded") || errorDetails.includes("RESOURCE_EXHAUSTED") || errorMessage.includes("Rate limit exceeded") || errorMessage.includes("Resource exhausted") || errorString.includes("rateLimitExceeded") || errorString.includes("RESOURCE_EXHAUSTED")) {
3194
3304
  errorMsg = "Gemini API rate limit exceeded. Please wait a moment and try again. The API will retry automatically.";
3195
3305
  } else if (errorDetails.includes("quota") || errorMessage.includes("quota") || errorString.includes("quota")) {
@@ -3213,6 +3323,7 @@ ${originalUserMessage}` : originalUserMessage;
3213
3323
  permissionHandler.reset();
3214
3324
  reasoningProcessor.abort();
3215
3325
  diffProcessor.reset();
3326
+ abortRequested = false;
3216
3327
  thinking = false;
3217
3328
  session.keepAlive(thinking, "remote");
3218
3329
  if (!retryThisTurn) {
@@ -3242,7 +3353,11 @@ ${originalUserMessage}` : originalUserMessage;
3242
3353
  });
3243
3354
  }
3244
3355
  }
3245
- emitReadyIfIdle();
3356
+ if (readySentForAbort) {
3357
+ readySentForAbort = false;
3358
+ } else {
3359
+ emitReadyIfIdle();
3360
+ }
3246
3361
  }
3247
3362
  logger.debug(`[gemini] Main loop: turn completed, continuing to next iteration (queue size: ${messageQueue.size()})`);
3248
3363
  }
@@ -11,7 +11,7 @@ import { readFile, unlink, open, stat, mkdir, writeFile, rename } from 'node:fs/
11
11
  import * as z from 'zod';
12
12
  import { z as z$1 } from 'zod';
13
13
  import { spawn } from 'child_process';
14
- import { realpath, stat as stat$1, readdir, rm, mkdir as mkdir$1, readFile as readFile$1, open as open$1, writeFile as writeFile$1, chmod } from 'fs/promises';
14
+ import { readdir, mkdir as mkdir$1, realpath, stat as stat$1, rm, readFile as readFile$1, open as open$1, writeFile as writeFile$1, chmod } from 'fs/promises';
15
15
  import { randomUUID, createHash } from 'crypto';
16
16
  import { dirname, resolve, join as join$1, relative } from 'path';
17
17
  import { fileURLToPath } from 'url';
@@ -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.21";
24
+ var version = "0.10.22";
25
25
  var description = "Flockbay CLI (local agent + daemon)";
26
26
  var author = "Eduardo Orellana";
27
27
  var license = "UNLICENSED";
@@ -1570,6 +1570,44 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory, coordinatio
1570
1570
  };
1571
1571
  }
1572
1572
  });
1573
+ rpcHandlerManager.registerHandler("fs_list_dir", async (data) => {
1574
+ const p = String(data?.path || "").trim();
1575
+ if (!p) return { success: false, error: "missing_path" };
1576
+ try {
1577
+ const out = [];
1578
+ const items = await readdir(p, { withFileTypes: true });
1579
+ for (const d of items) {
1580
+ out.push({
1581
+ name: d.name,
1582
+ isDir: d.isDirectory(),
1583
+ isFile: d.isFile(),
1584
+ isSymlink: d.isSymbolicLink()
1585
+ });
1586
+ }
1587
+ out.sort((a, b) => {
1588
+ if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
1589
+ return a.name.localeCompare(b.name);
1590
+ });
1591
+ return { success: true, path: p, entries: out };
1592
+ } catch (error) {
1593
+ const e = error;
1594
+ const msg = e?.message ? String(e.message) : String(error);
1595
+ return { success: false, path: p, error: msg };
1596
+ }
1597
+ });
1598
+ rpcHandlerManager.registerHandler("fs_mkdir", async (data) => {
1599
+ const p = String(data?.path || "").trim();
1600
+ if (!p) return { success: false, error: "missing_path" };
1601
+ const recursive = data?.recursive !== false;
1602
+ try {
1603
+ await mkdir$1(p, { recursive });
1604
+ return { success: true, path: p };
1605
+ } catch (error) {
1606
+ const e = error;
1607
+ const msg = e?.message ? String(e.message) : String(error);
1608
+ return { success: false, path: p, error: msg };
1609
+ }
1610
+ });
1573
1611
  rpcHandlerManager.registerHandler(
1574
1612
  "unreal-mcp-bridge-status",
1575
1613
  async (params) => {
@@ -3774,4 +3812,4 @@ const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
3774
3812
  }).passthrough()
3775
3813
  ]);
3776
3814
 
3777
- export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a, packageJson as b, configuration as c, backoff as d, delay as e, readDaemonState as f, clearDaemonState as g, readCredentials as h, unrealMcpPythonDir as i, acquireDaemonLock as j, writeDaemonState as k, logger as l, ApiMachineClient as m, releaseDaemonLock as n, clearCredentials as o, projectPath as p, clearMachineId as q, readSettings as r, sendUnrealMcpTcpCommand as s, installUnrealMcpPluginToEngine as t, updateSettings as u, getLatestDaemonLog as v, writeCredentials as w, normalizeServerUrlForNode as x };
3815
+ export { ApiClient as A, RawJSONLinesSchema as R, ApiSessionClient as a, packageJson as b, configuration as c, backoff as d, delay as e, readDaemonState as f, clearDaemonState as g, readCredentials as h, unrealMcpPythonDir as i, acquireDaemonLock as j, writeDaemonState as k, logger as l, ApiMachineClient as m, releaseDaemonLock as n, clearCredentials as o, projectPath as p, clearMachineId as q, readSettings as r, sendUnrealMcpTcpCommand as s, installUnrealMcpPluginToEngine as t, updateSettings as u, buildAndInstallUnrealMcpPlugin as v, writeCredentials as w, getLatestDaemonLog as x, normalizeServerUrlForNode as y };
@@ -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.21";
45
+ var version = "0.10.22";
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-DeH24uWs.cjs', document.baseURI).href))));
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-Z2OYpI8c.cjs', document.baseURI).href))));
774
774
  function projectPath() {
775
775
  const path = path$1.resolve(__dirname$1, "..");
776
776
  return path;
@@ -1591,6 +1591,44 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory, coordinatio
1591
1591
  };
1592
1592
  }
1593
1593
  });
1594
+ rpcHandlerManager.registerHandler("fs_list_dir", async (data) => {
1595
+ const p = String(data?.path || "").trim();
1596
+ if (!p) return { success: false, error: "missing_path" };
1597
+ try {
1598
+ const out = [];
1599
+ const items = await fs$3.readdir(p, { withFileTypes: true });
1600
+ for (const d of items) {
1601
+ out.push({
1602
+ name: d.name,
1603
+ isDir: d.isDirectory(),
1604
+ isFile: d.isFile(),
1605
+ isSymlink: d.isSymbolicLink()
1606
+ });
1607
+ }
1608
+ out.sort((a, b) => {
1609
+ if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
1610
+ return a.name.localeCompare(b.name);
1611
+ });
1612
+ return { success: true, path: p, entries: out };
1613
+ } catch (error) {
1614
+ const e = error;
1615
+ const msg = e?.message ? String(e.message) : String(error);
1616
+ return { success: false, path: p, error: msg };
1617
+ }
1618
+ });
1619
+ rpcHandlerManager.registerHandler("fs_mkdir", async (data) => {
1620
+ const p = String(data?.path || "").trim();
1621
+ if (!p) return { success: false, error: "missing_path" };
1622
+ const recursive = data?.recursive !== false;
1623
+ try {
1624
+ await fs$3.mkdir(p, { recursive });
1625
+ return { success: true, path: p };
1626
+ } catch (error) {
1627
+ const e = error;
1628
+ const msg = e?.message ? String(e.message) : String(error);
1629
+ return { success: false, path: p, error: msg };
1630
+ }
1631
+ });
1594
1632
  rpcHandlerManager.registerHandler(
1595
1633
  "unreal-mcp-bridge-status",
1596
1634
  async (params) => {
@@ -3801,6 +3839,7 @@ exports.ApiSessionClient = ApiSessionClient;
3801
3839
  exports.RawJSONLinesSchema = RawJSONLinesSchema;
3802
3840
  exports.acquireDaemonLock = acquireDaemonLock;
3803
3841
  exports.backoff = backoff;
3842
+ exports.buildAndInstallUnrealMcpPlugin = buildAndInstallUnrealMcpPlugin;
3804
3843
  exports.clearCredentials = clearCredentials;
3805
3844
  exports.clearDaemonState = clearDaemonState;
3806
3845
  exports.clearMachineId = clearMachineId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flockbay",
3
- "version": "0.10.21",
3
+ "version": "0.10.22",
4
4
  "description": "Flockbay CLI (local agent + daemon)",
5
5
  "author": "Eduardo Orellana",
6
6
  "license": "UNLICENSED",