flockbay 0.10.30 → 0.10.31

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.
@@ -3,7 +3,7 @@
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
5
  var node_crypto = require('node:crypto');
6
- var types = require('./types-DPBm2ycs.cjs');
6
+ var types = require('./types-BWU2O_1A.cjs');
7
7
  var node_child_process = require('node:child_process');
8
8
  var path = require('node:path');
9
9
  var node_readline = require('node:readline');
@@ -345,6 +345,10 @@ const PLATFORM_SYSTEM_PROMPT = trimIdent(`
345
345
  - The platform may detect that Unreal Editor crashed/unreachable and will automatically abort your current run and post a chat message.
346
346
  - When that happens: STOP UnrealMCP calls, fix the project as needed, then (only when ready) relaunch Unreal Editor with \`mcp__flockbay__unreal_editor_launch\`.
347
347
  - Do not \u201Cauto-restart\u201D in a loop. Relaunch is a deliberate action after fixes.
348
+ - After launching Unreal Editor, do not \u201Crapid-retry\u201D reachability checks. Boot times vary by machine and project size.
349
+ - Prefer readiness checks (editor health / plugin reachable) spaced by increasing waits (bounded backoff).
350
+ - Default example ladder for editor boot: wait ~30s, then ~45s, then ~60s between checks (cap any single wait to 60s).
351
+ - Total cap: at most 240s of waiting for editor boot. If still not reachable, stop waiting and ask the user to tell you when the editor finishes booting (or to share what it shows on-screen).
348
352
 
349
353
  ## B) Screenshots (via UnrealMCP)
350
354
  Use UnrealMCP when the user asks for:
@@ -392,6 +396,24 @@ const PLATFORM_SYSTEM_PROMPT = trimIdent(`
392
396
  - Batch related questions into one call when possible.
393
397
  - If a user's request is too broad/unclear, ask him questions to clarify the scope and narrow down the work
394
398
 
399
+ # Timing / Waiting (realistic, increasing, bounded)
400
+
401
+ User machines vary widely (CPU, disk, GPU) and Unreal projects can be large. When you are waiting for something to become ready (editor boot, local server start, build finishing), you must use realistic waits.
402
+
403
+ - Prefer readiness checks over blind sleeps. Use sleeps only to space checks.
404
+ - Do not \u201Crapid-retry\u201D after starting heavyweight actions (editors, IDEs, emulators, big builds). Seconds-scale retry loops are a bad UX.
405
+ - Use bounded backoff:
406
+ - waits must increase between attempts (e.g. 10s \u2192 20s \u2192 40s \u2192 60s \u2026)
407
+ - cap any single wait to 60s
408
+ - cap total waiting to a reasonable maximum
409
+
410
+ Two tiers (keep it simple):
411
+ - Standard actions total cap: ~90s
412
+ - Heavyweight boots total cap: ~240s
413
+
414
+ If you expect something to take longer than the applicable total cap, do not pretend you can wait \u201Ca bit longer\u201D.
415
+ Stop waiting, explain what you\u2019re waiting for and what \u201Cready\u201D looks like, and ask the user to notify you when it completes.
416
+
395
417
  # Platform-provided context blocks
396
418
 
397
419
  The platform may prefix the user message with internal context blocks (machine/project hints, image markers, etc).
@@ -1274,7 +1296,7 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
1274
1296
  env[pathKey] = [...prepend, ...existingParts].join(pathSep);
1275
1297
  return env;
1276
1298
  }
1277
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-b9kiPsW3.cjs', document.baseURI).href)));
1299
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-ClvxzV4_.cjs', document.baseURI).href)));
1278
1300
  const __dirname$1 = path.join(__filename$1, "..");
1279
1301
  function getGlobalClaudeVersion(claudeExecutable) {
1280
1302
  try {
@@ -13270,7 +13292,7 @@ ${engineRoot}`, {
13270
13292
  } else if (subcommand === "codex") {
13271
13293
  try {
13272
13294
  await chdirToNearestUprojectRootIfPresent();
13273
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Bq_-aYHm.cjs'); });
13295
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-D4m7yDQk.cjs'); });
13274
13296
  let startedBy = void 0;
13275
13297
  let sessionId = void 0;
13276
13298
  for (let i = 1; i < args.length; i++) {
@@ -13372,7 +13394,7 @@ ${engineRoot}`, {
13372
13394
  }
13373
13395
  try {
13374
13396
  await chdirToNearestUprojectRootIfPresent();
13375
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-pQgdPy5x.cjs'); });
13397
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-Dp2Noq-p.cjs'); });
13376
13398
  let startedBy = void 0;
13377
13399
  let sessionId = void 0;
13378
13400
  for (let i = 1; i < args.length; i++) {
@@ -1,7 +1,7 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
2
  import os, { homedir } from 'node:os';
3
3
  import { randomUUID, createCipheriv, randomBytes } from 'node:crypto';
4
- import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as buildAndInstallUnrealMcpPlugin, x as getLatestDaemonLog, y as normalizeServerUrlForNode } from './types-DdJKBH6T.mjs';
4
+ import { l as logger, p as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, b as packageJson, r as readSettings, h as readCredentials, u as updateSettings, w as writeCredentials, i as unrealMcpPythonDir, j as acquireDaemonLock, k as writeDaemonState, m as ApiMachineClient, n as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, o as clearCredentials, q as clearMachineId, t as installUnrealMcpPluginToEngine, v as buildAndInstallUnrealMcpPlugin, x as getLatestDaemonLog, y as normalizeServerUrlForNode } from './types-BOWEIn3h.mjs';
5
5
  import { spawn, execFileSync, execSync } from 'node:child_process';
6
6
  import path, { resolve, join, dirname } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
@@ -323,6 +323,10 @@ const PLATFORM_SYSTEM_PROMPT = trimIdent(`
323
323
  - The platform may detect that Unreal Editor crashed/unreachable and will automatically abort your current run and post a chat message.
324
324
  - When that happens: STOP UnrealMCP calls, fix the project as needed, then (only when ready) relaunch Unreal Editor with \`mcp__flockbay__unreal_editor_launch\`.
325
325
  - Do not \u201Cauto-restart\u201D in a loop. Relaunch is a deliberate action after fixes.
326
+ - After launching Unreal Editor, do not \u201Crapid-retry\u201D reachability checks. Boot times vary by machine and project size.
327
+ - Prefer readiness checks (editor health / plugin reachable) spaced by increasing waits (bounded backoff).
328
+ - Default example ladder for editor boot: wait ~30s, then ~45s, then ~60s between checks (cap any single wait to 60s).
329
+ - Total cap: at most 240s of waiting for editor boot. If still not reachable, stop waiting and ask the user to tell you when the editor finishes booting (or to share what it shows on-screen).
326
330
 
327
331
  ## B) Screenshots (via UnrealMCP)
328
332
  Use UnrealMCP when the user asks for:
@@ -370,6 +374,24 @@ const PLATFORM_SYSTEM_PROMPT = trimIdent(`
370
374
  - Batch related questions into one call when possible.
371
375
  - If a user's request is too broad/unclear, ask him questions to clarify the scope and narrow down the work
372
376
 
377
+ # Timing / Waiting (realistic, increasing, bounded)
378
+
379
+ User machines vary widely (CPU, disk, GPU) and Unreal projects can be large. When you are waiting for something to become ready (editor boot, local server start, build finishing), you must use realistic waits.
380
+
381
+ - Prefer readiness checks over blind sleeps. Use sleeps only to space checks.
382
+ - Do not \u201Crapid-retry\u201D after starting heavyweight actions (editors, IDEs, emulators, big builds). Seconds-scale retry loops are a bad UX.
383
+ - Use bounded backoff:
384
+ - waits must increase between attempts (e.g. 10s \u2192 20s \u2192 40s \u2192 60s \u2026)
385
+ - cap any single wait to 60s
386
+ - cap total waiting to a reasonable maximum
387
+
388
+ Two tiers (keep it simple):
389
+ - Standard actions total cap: ~90s
390
+ - Heavyweight boots total cap: ~240s
391
+
392
+ If you expect something to take longer than the applicable total cap, do not pretend you can wait \u201Ca bit longer\u201D.
393
+ Stop waiting, explain what you\u2019re waiting for and what \u201Cready\u201D looks like, and ask the user to notify you when it completes.
394
+
373
395
  # Platform-provided context blocks
374
396
 
375
397
  The platform may prefix the user message with internal context blocks (machine/project hints, image markers, etc).
@@ -13248,7 +13270,7 @@ ${engineRoot}`, {
13248
13270
  } else if (subcommand === "codex") {
13249
13271
  try {
13250
13272
  await chdirToNearestUprojectRootIfPresent();
13251
- const { runCodex } = await import('./runCodex-B0JRo8YP.mjs');
13273
+ const { runCodex } = await import('./runCodex-Csi1jhMD.mjs');
13252
13274
  let startedBy = void 0;
13253
13275
  let sessionId = void 0;
13254
13276
  for (let i = 1; i < args.length; i++) {
@@ -13350,7 +13372,7 @@ ${engineRoot}`, {
13350
13372
  }
13351
13373
  try {
13352
13374
  await chdirToNearestUprojectRootIfPresent();
13353
- const { runGemini } = await import('./runGemini-DO9xzjyY.mjs');
13375
+ const { runGemini } = await import('./runGemini-CsLa2i5F.mjs');
13354
13376
  let startedBy = void 0;
13355
13377
  let sessionId = void 0;
13356
13378
  for (let i = 1; i < args.length; i++) {
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('chalk');
4
- require('./index-b9kiPsW3.cjs');
5
- require('./types-DPBm2ycs.cjs');
4
+ require('./index-ClvxzV4_.cjs');
5
+ require('./types-BWU2O_1A.cjs');
6
6
  require('zod');
7
7
  require('node:child_process');
8
8
  require('node:fs');
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'chalk';
2
- import './index-DGp07Mik.mjs';
3
- import './types-DdJKBH6T.mjs';
2
+ import './index-DcTQ3012.mjs';
3
+ import './types-BOWEIn3h.mjs';
4
4
  import 'zod';
5
5
  import 'node:child_process';
6
6
  import 'node:fs';
package/dist/lib.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var types = require('./types-DPBm2ycs.cjs');
3
+ var types = require('./types-BWU2O_1A.cjs');
4
4
  require('axios');
5
5
  require('node:fs');
6
6
  require('node:os');
package/dist/lib.d.cts CHANGED
@@ -439,6 +439,7 @@ declare class ApiSessionClient extends EventEmitter {
439
439
  readonly coordinationLeaseGuard: CoordinationLeaseGuard;
440
440
  private coordinationLedgerLastReadAtMs;
441
441
  private readonly outboundQueue;
442
+ private readonly usageReportQueue;
442
443
  constructor(token: string, session: Session);
443
444
  connect(): void;
444
445
  connectAndWait(timeoutMs?: number): Promise<void>;
@@ -455,6 +456,7 @@ declare class ApiSessionClient extends EventEmitter {
455
456
  sendCodexMessage(body: any): void;
456
457
  sendAgentMessage(agentType: 'gemini' | 'codex' | 'claude' | 'opencode', body: any): void;
457
458
  sendClaudeSessionMessage(body: any): void;
459
+ sendUsageReport(report: any): void;
458
460
  updateSessionConfig(opts: {
459
461
  permissionMode?: string | null;
460
462
  modelMode?: string | null;
package/dist/lib.d.mts CHANGED
@@ -439,6 +439,7 @@ declare class ApiSessionClient extends EventEmitter {
439
439
  readonly coordinationLeaseGuard: CoordinationLeaseGuard;
440
440
  private coordinationLedgerLastReadAtMs;
441
441
  private readonly outboundQueue;
442
+ private readonly usageReportQueue;
442
443
  constructor(token: string, session: Session);
443
444
  connect(): void;
444
445
  connectAndWait(timeoutMs?: number): Promise<void>;
@@ -455,6 +456,7 @@ declare class ApiSessionClient extends EventEmitter {
455
456
  sendCodexMessage(body: any): void;
456
457
  sendAgentMessage(agentType: 'gemini' | 'codex' | 'claude' | 'opencode', body: any): void;
457
458
  sendClaudeSessionMessage(body: any): void;
459
+ sendUsageReport(report: any): void;
458
460
  updateSessionConfig(opts: {
459
461
  permissionMode?: string | null;
460
462
  modelMode?: string | null;
package/dist/lib.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-DdJKBH6T.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BOWEIn3h.mjs';
2
2
  import 'axios';
3
3
  import 'node:fs';
4
4
  import 'node:os';
@@ -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-DdJKBH6T.mjs';
3
+ import { l as logger, A as ApiClient, r as readSettings, p as projectPath, c as configuration, b as packageJson } from './types-BOWEIn3h.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 buildProjectCapsule, t as trimIdent, g as autoFinalizeCoordinationWorkItem, j as detectScreenshotsForGate, k as applyCoordinationSideEffectsFromMcpToolResult, l as stopCaffeinate } from './index-DGp07Mik.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 buildProjectCapsule, t as trimIdent, g as autoFinalizeCoordinationWorkItem, j as detectScreenshotsForGate, k as applyCoordinationSideEffectsFromMcpToolResult, l as stopCaffeinate } from './index-DcTQ3012.mjs';
14
14
  import 'axios';
15
15
  import 'node:events';
16
16
  import 'socket.io-client';
@@ -3409,6 +3409,38 @@ async function runCodex(opts) {
3409
3409
  markExecFinished(callId);
3410
3410
  }
3411
3411
  if (msg.type === "token_count") {
3412
+ try {
3413
+ const asNonNegativeInt = (v) => {
3414
+ const n = typeof v === "number" ? v : Number(v);
3415
+ if (!Number.isFinite(n) || n < 0) return null;
3416
+ return Math.floor(n);
3417
+ };
3418
+ const pick = (obj, keys) => {
3419
+ for (const k of keys) {
3420
+ if (obj && typeof obj === "object" && k in obj) return obj[k];
3421
+ }
3422
+ return void 0;
3423
+ };
3424
+ const usageObj = msg?.usage && typeof msg.usage === "object" ? msg.usage : null;
3425
+ const inputTokens = asNonNegativeInt(pick(usageObj, ["input_tokens", "inputTokens"])) ?? asNonNegativeInt(pick(msg, ["input_tokens", "inputTokens", "prompt_tokens", "promptTokens"])) ?? 0;
3426
+ const outputTokens = asNonNegativeInt(pick(usageObj, ["output_tokens", "outputTokens"])) ?? asNonNegativeInt(pick(msg, ["output_tokens", "outputTokens", "completion_tokens", "completionTokens"])) ?? 0;
3427
+ const cacheReadInputTokens = asNonNegativeInt(pick(usageObj, ["cache_read_input_tokens", "cacheReadInputTokens"])) ?? asNonNegativeInt(pick(msg, ["cache_read_input_tokens", "cacheReadInputTokens"])) ?? 0;
3428
+ const cacheCreationInputTokens = asNonNegativeInt(pick(usageObj, ["cache_creation_input_tokens", "cacheCreationInputTokens"])) ?? asNonNegativeInt(pick(msg, ["cache_creation_input_tokens", "cacheCreationInputTokens"])) ?? 0;
3429
+ const model = typeof msg?.model === "string" ? String(msg.model).trim() : null;
3430
+ session.sendUsageReport({
3431
+ provider: "codex",
3432
+ model: model || null,
3433
+ usage: {
3434
+ input_tokens: inputTokens,
3435
+ output_tokens: outputTokens,
3436
+ cache_read_input_tokens: cacheReadInputTokens,
3437
+ cache_creation_input_tokens: cacheCreationInputTokens
3438
+ },
3439
+ source: "codex.token_count",
3440
+ timeMs: Date.now()
3441
+ });
3442
+ } catch {
3443
+ }
3412
3444
  return;
3413
3445
  }
3414
3446
  if (msg.type === "patch_apply_begin") {
@@ -3702,9 +3734,10 @@ User: ${escapedUser}` : replayDeduped;
3702
3734
  }
3703
3735
  if (!skipAutoFinalize) {
3704
3736
  try {
3737
+ const autoFinalizeCwd = String(coordinationProjectRootPath || "").trim() || process.cwd();
3705
3738
  const finalizeRes = await autoFinalizeCoordinationWorkItem({
3706
3739
  token: session.getAuthToken(),
3707
- cwd: process.cwd(),
3740
+ cwd: autoFinalizeCwd,
3708
3741
  summary: message?.message ?? null
3709
3742
  });
3710
3743
  if (!finalizeRes.ok) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-DPBm2ycs.cjs');
5
+ var types = require('./types-BWU2O_1A.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,7 +12,7 @@ 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-b9kiPsW3.cjs');
15
+ var index = require('./index-ClvxzV4_.cjs');
16
16
  require('axios');
17
17
  require('node:events');
18
18
  require('socket.io-client');
@@ -3411,6 +3411,38 @@ async function runCodex(opts) {
3411
3411
  markExecFinished(callId);
3412
3412
  }
3413
3413
  if (msg.type === "token_count") {
3414
+ try {
3415
+ const asNonNegativeInt = (v) => {
3416
+ const n = typeof v === "number" ? v : Number(v);
3417
+ if (!Number.isFinite(n) || n < 0) return null;
3418
+ return Math.floor(n);
3419
+ };
3420
+ const pick = (obj, keys) => {
3421
+ for (const k of keys) {
3422
+ if (obj && typeof obj === "object" && k in obj) return obj[k];
3423
+ }
3424
+ return void 0;
3425
+ };
3426
+ const usageObj = msg?.usage && typeof msg.usage === "object" ? msg.usage : null;
3427
+ const inputTokens = asNonNegativeInt(pick(usageObj, ["input_tokens", "inputTokens"])) ?? asNonNegativeInt(pick(msg, ["input_tokens", "inputTokens", "prompt_tokens", "promptTokens"])) ?? 0;
3428
+ const outputTokens = asNonNegativeInt(pick(usageObj, ["output_tokens", "outputTokens"])) ?? asNonNegativeInt(pick(msg, ["output_tokens", "outputTokens", "completion_tokens", "completionTokens"])) ?? 0;
3429
+ const cacheReadInputTokens = asNonNegativeInt(pick(usageObj, ["cache_read_input_tokens", "cacheReadInputTokens"])) ?? asNonNegativeInt(pick(msg, ["cache_read_input_tokens", "cacheReadInputTokens"])) ?? 0;
3430
+ const cacheCreationInputTokens = asNonNegativeInt(pick(usageObj, ["cache_creation_input_tokens", "cacheCreationInputTokens"])) ?? asNonNegativeInt(pick(msg, ["cache_creation_input_tokens", "cacheCreationInputTokens"])) ?? 0;
3431
+ const model = typeof msg?.model === "string" ? String(msg.model).trim() : null;
3432
+ session.sendUsageReport({
3433
+ provider: "codex",
3434
+ model: model || null,
3435
+ usage: {
3436
+ input_tokens: inputTokens,
3437
+ output_tokens: outputTokens,
3438
+ cache_read_input_tokens: cacheReadInputTokens,
3439
+ cache_creation_input_tokens: cacheCreationInputTokens
3440
+ },
3441
+ source: "codex.token_count",
3442
+ timeMs: Date.now()
3443
+ });
3444
+ } catch {
3445
+ }
3414
3446
  return;
3415
3447
  }
3416
3448
  if (msg.type === "patch_apply_begin") {
@@ -3704,9 +3736,10 @@ User: ${escapedUser}` : replayDeduped;
3704
3736
  }
3705
3737
  if (!skipAutoFinalize) {
3706
3738
  try {
3739
+ const autoFinalizeCwd = String(coordinationProjectRootPath || "").trim() || process.cwd();
3707
3740
  const finalizeRes = await index.autoFinalizeCoordinationWorkItem({
3708
3741
  token: session.getAuthToken(),
3709
- cwd: process.cwd(),
3742
+ cwd: autoFinalizeCwd,
3710
3743
  summary: message?.message ?? null
3711
3744
  });
3712
3745
  if (!finalizeRes.ok) {
@@ -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-DdJKBH6T.mjs';
8
- import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, e as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, m as extractUserImagesMarker, o as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, g as autoFinalizeCoordinationWorkItem, E as ElicitationHub, j as detectScreenshotsForGate, l as stopCaffeinate } from './index-DGp07Mik.mjs';
7
+ import { l as logger, b as packageJson, A as ApiClient, r as readSettings, p as projectPath, c as configuration } from './types-BOWEIn3h.mjs';
8
+ import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, i as initialMachineMetadata, n as notifyDaemonSessionStarted, M as MessageQueue2, e as buildProjectCapsule, a as setLatestUserImages, b as MessageBuffer, w as withUserImagesMarker, r as registerKillSessionHandler, d as startFlockbayServer, m as extractUserImagesMarker, o as getLatestUserImages, P as PLATFORM_SYSTEM_PROMPT, g as autoFinalizeCoordinationWorkItem, E as ElicitationHub, j as detectScreenshotsForGate, l as stopCaffeinate } from './index-DcTQ3012.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';
@@ -2977,6 +2977,36 @@ ${transcript}`;
2977
2977
  break;
2978
2978
  default:
2979
2979
  if (msg.type === "token-count") {
2980
+ try {
2981
+ const asNonNegativeInt = (v) => {
2982
+ const n = typeof v === "number" ? v : Number(v);
2983
+ if (!Number.isFinite(n) || n < 0) return null;
2984
+ return Math.floor(n);
2985
+ };
2986
+ const pick = (obj, keys) => {
2987
+ for (const k of keys) {
2988
+ if (obj && typeof obj === "object" && k in obj) return obj[k];
2989
+ }
2990
+ return void 0;
2991
+ };
2992
+ const raw = msg;
2993
+ const usageObj = raw?.usage && typeof raw.usage === "object" ? raw.usage : raw?.usageMetadata && typeof raw.usageMetadata === "object" ? raw.usageMetadata : null;
2994
+ const inputTokens = asNonNegativeInt(pick(usageObj, ["input_tokens", "inputTokens", "promptTokenCount", "prompt_tokens"])) ?? asNonNegativeInt(pick(raw, ["input_tokens", "inputTokens", "promptTokenCount", "prompt_tokens"])) ?? 0;
2995
+ const outputTokens = asNonNegativeInt(pick(usageObj, ["output_tokens", "outputTokens", "candidatesTokenCount", "completion_tokens"])) ?? asNonNegativeInt(pick(raw, ["output_tokens", "outputTokens", "candidatesTokenCount", "completion_tokens"])) ?? 0;
2996
+ const totalTokens = asNonNegativeInt(pick(usageObj, ["total_tokens", "totalTokens", "totalTokenCount"])) ?? asNonNegativeInt(pick(raw, ["total_tokens", "totalTokens", "totalTokenCount"])) ?? null;
2997
+ session.sendUsageReport({
2998
+ provider: "gemini",
2999
+ model: typeof raw?.model === "string" ? String(raw.model).trim() : null,
3000
+ usage: {
3001
+ input_tokens: inputTokens,
3002
+ output_tokens: outputTokens,
3003
+ ...totalTokens !== null ? { total_tokens: totalTokens } : {}
3004
+ },
3005
+ source: "gemini.token-count",
3006
+ timeMs: Date.now()
3007
+ });
3008
+ } catch {
3009
+ }
2980
3010
  session.sendCodexMessage({
2981
3011
  type: "token_count",
2982
3012
  ...msg,
@@ -3330,9 +3360,10 @@ ${originalUserMessage}` : originalUserMessage;
3330
3360
  if (!retryThisTurn) {
3331
3361
  if (!skipAutoFinalize) {
3332
3362
  try {
3363
+ const autoFinalizeCwd = String(coordinationProjectRootPath || "").trim() || process.cwd();
3333
3364
  const finalizeRes = await autoFinalizeCoordinationWorkItem({
3334
3365
  token: session.getAuthToken(),
3335
- cwd: process.cwd(),
3366
+ cwd: autoFinalizeCwd,
3336
3367
  summary: userMessageToShow
3337
3368
  });
3338
3369
  if (!finalizeRes.ok) {
@@ -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-DPBm2ycs.cjs');
10
- var index = require('./index-b9kiPsW3.cjs');
9
+ var types = require('./types-BWU2O_1A.cjs');
10
+ var index = require('./index-ClvxzV4_.cjs');
11
11
  var node_child_process = require('node:child_process');
12
12
  var sdk = require('@agentclientprotocol/sdk');
13
13
  var fs = require('fs');
@@ -2979,6 +2979,36 @@ ${transcript}`;
2979
2979
  break;
2980
2980
  default:
2981
2981
  if (msg.type === "token-count") {
2982
+ try {
2983
+ const asNonNegativeInt = (v) => {
2984
+ const n = typeof v === "number" ? v : Number(v);
2985
+ if (!Number.isFinite(n) || n < 0) return null;
2986
+ return Math.floor(n);
2987
+ };
2988
+ const pick = (obj, keys) => {
2989
+ for (const k of keys) {
2990
+ if (obj && typeof obj === "object" && k in obj) return obj[k];
2991
+ }
2992
+ return void 0;
2993
+ };
2994
+ const raw = msg;
2995
+ const usageObj = raw?.usage && typeof raw.usage === "object" ? raw.usage : raw?.usageMetadata && typeof raw.usageMetadata === "object" ? raw.usageMetadata : null;
2996
+ const inputTokens = asNonNegativeInt(pick(usageObj, ["input_tokens", "inputTokens", "promptTokenCount", "prompt_tokens"])) ?? asNonNegativeInt(pick(raw, ["input_tokens", "inputTokens", "promptTokenCount", "prompt_tokens"])) ?? 0;
2997
+ const outputTokens = asNonNegativeInt(pick(usageObj, ["output_tokens", "outputTokens", "candidatesTokenCount", "completion_tokens"])) ?? asNonNegativeInt(pick(raw, ["output_tokens", "outputTokens", "candidatesTokenCount", "completion_tokens"])) ?? 0;
2998
+ const totalTokens = asNonNegativeInt(pick(usageObj, ["total_tokens", "totalTokens", "totalTokenCount"])) ?? asNonNegativeInt(pick(raw, ["total_tokens", "totalTokens", "totalTokenCount"])) ?? null;
2999
+ session.sendUsageReport({
3000
+ provider: "gemini",
3001
+ model: typeof raw?.model === "string" ? String(raw.model).trim() : null,
3002
+ usage: {
3003
+ input_tokens: inputTokens,
3004
+ output_tokens: outputTokens,
3005
+ ...totalTokens !== null ? { total_tokens: totalTokens } : {}
3006
+ },
3007
+ source: "gemini.token-count",
3008
+ timeMs: Date.now()
3009
+ });
3010
+ } catch {
3011
+ }
2982
3012
  session.sendCodexMessage({
2983
3013
  type: "token_count",
2984
3014
  ...msg,
@@ -3332,9 +3362,10 @@ ${originalUserMessage}` : originalUserMessage;
3332
3362
  if (!retryThisTurn) {
3333
3363
  if (!skipAutoFinalize) {
3334
3364
  try {
3365
+ const autoFinalizeCwd = String(coordinationProjectRootPath || "").trim() || process.cwd();
3335
3366
  const finalizeRes = await index.autoFinalizeCoordinationWorkItem({
3336
3367
  token: session.getAuthToken(),
3337
- cwd: process.cwd(),
3368
+ cwd: autoFinalizeCwd,
3338
3369
  summary: userMessageToShow
3339
3370
  });
3340
3371
  if (!finalizeRes.ok) {
@@ -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.30";
24
+ var version = "0.10.31";
25
25
  var description = "Flockbay CLI (local agent + daemon)";
26
26
  var author = "Eduardo Orellana";
27
27
  var license = "UNLICENSED";
@@ -2936,6 +2936,7 @@ class ApiSessionClient extends EventEmitter {
2936
2936
  coordinationLeaseGuard = new CoordinationLeaseGuard();
2937
2937
  coordinationLedgerLastReadAtMs = null;
2938
2938
  outboundQueue = [];
2939
+ usageReportQueue = [];
2939
2940
  constructor(token, session) {
2940
2941
  super();
2941
2942
  this.token = token;
@@ -3090,6 +3091,15 @@ class ApiSessionClient extends EventEmitter {
3090
3091
  meta: { sentFrom: "cli" }
3091
3092
  });
3092
3093
  }
3094
+ sendUsageReport(report) {
3095
+ const payload = report && typeof report === "object" ? report : null;
3096
+ if (!payload) return;
3097
+ if (this.socket.connected) {
3098
+ this.socket.emit("usage-report", payload);
3099
+ return;
3100
+ }
3101
+ this.usageReportQueue.push(payload);
3102
+ }
3093
3103
  async updateSessionConfig(opts) {
3094
3104
  await this.connectAndWait(15e3);
3095
3105
  return await new Promise((resolve) => {
@@ -3110,6 +3120,11 @@ class ApiSessionClient extends EventEmitter {
3110
3120
  }
3111
3121
  flush() {
3112
3122
  if (!this.socket.connected) return;
3123
+ while (this.usageReportQueue.length > 0) {
3124
+ const next = this.usageReportQueue.shift();
3125
+ if (!next) continue;
3126
+ this.socket.emit("usage-report", next);
3127
+ }
3113
3128
  while (this.outboundQueue.length > 0) {
3114
3129
  const next = this.outboundQueue.shift();
3115
3130
  if (!next) continue;
@@ -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.30";
45
+ var version = "0.10.31";
46
46
  var description = "Flockbay CLI (local agent + daemon)";
47
47
  var author = "Eduardo Orellana";
48
48
  var license = "UNLICENSED";
@@ -772,7 +772,7 @@ class RpcHandlerManager {
772
772
  }
773
773
  }
774
774
 
775
- 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-DPBm2ycs.cjs', document.baseURI).href))));
775
+ 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-BWU2O_1A.cjs', document.baseURI).href))));
776
776
  function projectPath() {
777
777
  const path = path$1.resolve(__dirname$1, "..");
778
778
  return path;
@@ -2957,6 +2957,7 @@ class ApiSessionClient extends node_events.EventEmitter {
2957
2957
  coordinationLeaseGuard = new CoordinationLeaseGuard();
2958
2958
  coordinationLedgerLastReadAtMs = null;
2959
2959
  outboundQueue = [];
2960
+ usageReportQueue = [];
2960
2961
  constructor(token, session) {
2961
2962
  super();
2962
2963
  this.token = token;
@@ -3111,6 +3112,15 @@ class ApiSessionClient extends node_events.EventEmitter {
3111
3112
  meta: { sentFrom: "cli" }
3112
3113
  });
3113
3114
  }
3115
+ sendUsageReport(report) {
3116
+ const payload = report && typeof report === "object" ? report : null;
3117
+ if (!payload) return;
3118
+ if (this.socket.connected) {
3119
+ this.socket.emit("usage-report", payload);
3120
+ return;
3121
+ }
3122
+ this.usageReportQueue.push(payload);
3123
+ }
3114
3124
  async updateSessionConfig(opts) {
3115
3125
  await this.connectAndWait(15e3);
3116
3126
  return await new Promise((resolve) => {
@@ -3131,6 +3141,11 @@ class ApiSessionClient extends node_events.EventEmitter {
3131
3141
  }
3132
3142
  flush() {
3133
3143
  if (!this.socket.connected) return;
3144
+ while (this.usageReportQueue.length > 0) {
3145
+ const next = this.usageReportQueue.shift();
3146
+ if (!next) continue;
3147
+ this.socket.emit("usage-report", next);
3148
+ }
3134
3149
  while (this.outboundQueue.length > 0) {
3135
3150
  const next = this.outboundQueue.shift();
3136
3151
  if (!next) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flockbay",
3
- "version": "0.10.30",
3
+ "version": "0.10.31",
4
4
  "description": "Flockbay CLI (local agent + daemon)",
5
5
  "author": "Eduardo Orellana",
6
6
  "license": "UNLICENSED",
@@ -56,7 +56,7 @@
56
56
  #include "Components/SceneCaptureComponent2D.h"
57
57
  #include "Engine/TextureRenderTarget2D.h"
58
58
 
59
- static bool SavePngToFile(const FString& FilePath, int32 Width, int32 Height, const TArray<FColor>& Bitmap)
59
+ static bool SavePngToFile(const FString& FilePath, int32 Width, int32 Height, TArray<FColor>& Bitmap)
60
60
  {
61
61
  IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
62
62
  TSharedPtr<IImageWrapper> Wrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
@@ -65,6 +65,12 @@ static bool SavePngToFile(const FString& FilePath, int32 Width, int32 Height, co
65
65
  return false;
66
66
  }
67
67
 
68
+ // Normalize alpha: editor backbuffer alpha can be 0/undefined, which can make PNGs look dark/grey in viewers.
69
+ for (FColor& Pixel : Bitmap)
70
+ {
71
+ Pixel.A = 255;
72
+ }
73
+
68
74
  if (!Wrapper->SetRaw(Bitmap.GetData(), Bitmap.Num() * sizeof(FColor), Width, Height, ERGBFormat::BGRA, 8))
69
75
  {
70
76
  return false;