flockbay 0.10.46 → 0.10.48

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.
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
2
2
  import * as os from 'node:os';
3
3
  import os__default, { homedir } from 'node:os';
4
4
  import { randomUUID, createCipheriv, randomBytes, createHash as createHash$1 } from 'node:crypto';
5
- import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-H7oBEqpR.mjs';
5
+ import { l as logger, b as projectPath, d as backoff, e as delay, R as RawJSONLinesSchema, c as configuration, f as readDaemonState, g as clearDaemonState, p as packageJson, r as readSettings, h as readCredentials, u as updateSettings, o as openBrowser, w as writeCredentials, j as unrealMcpPythonDir, k as acquireDaemonLock, m as writeDaemonState, n as ApiMachineClient, q as releaseDaemonLock, s as sendUnrealMcpTcpCommand, A as ApiClient, v as validatePath, t as run, x as run$1, y as buildShellInvocation, z as clearCredentials, B as clearMachineId, C as authenticateCodex, D as syncCodexCliAuth, E as authenticateClaude, F as authenticateGemini, i as installUnrealMcpPluginToEngine, G as buildAndInstallUnrealMcpPlugin, H as installUnrealMcpPluginToProject, I as getLatestDaemonLog, J as normalizeServerUrlForNode } from './types-KJ7kAYwk.mjs';
6
6
  import { spawn, execFileSync, execSync } from 'node:child_process';
7
7
  import * as path from 'node:path';
8
8
  import path__default, { resolve, join, dirname } from 'node:path';
@@ -793,6 +793,9 @@ async function createSessionScanner(opts) {
793
793
  await sync.invalidateAndAwait();
794
794
  sync.stop();
795
795
  },
796
+ flush: async () => {
797
+ await sync.invalidateAndAwait();
798
+ },
796
799
  onNewSession: (sessionId) => {
797
800
  if (currentSessionId === sessionId) {
798
801
  logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
@@ -13953,6 +13956,16 @@ function permissionModeForAgent(agent) {
13953
13956
  if (agent === "claude") return "bypassPermissions";
13954
13957
  return "yolo";
13955
13958
  }
13959
+ function modelOverrideForAgent(agent, args) {
13960
+ const explicitCodexModel = readArgValue$2(args, "--codex-model");
13961
+ const explicitModel = readArgValue$2(args, "--model");
13962
+ const explicitGeminiModel = readArgValue$2(args, "--gemini-model");
13963
+ const explicitClaudeModel = readArgValue$2(args, "--claude-model");
13964
+ if (agent === "codex") return (explicitCodexModel || explicitModel || "gpt-5-codex-medium").trim();
13965
+ if (agent === "gemini") return explicitGeminiModel ? explicitGeminiModel.trim() : null;
13966
+ if (agent === "claude") return explicitClaudeModel ? explicitClaudeModel.trim() : null;
13967
+ return null;
13968
+ }
13956
13969
  function nowIsoCompact() {
13957
13970
  const d = /* @__PURE__ */ new Date();
13958
13971
  const pad = (n) => String(n).padStart(2, "0");
@@ -13990,14 +14003,26 @@ async function ensureDaemonRunning({ skipUnreal }) {
13990
14003
  async function createSmokeWorkspaceDir(baseDir) {
13991
14004
  const root = baseDir?.trim() ? path__default.resolve(baseDir) : path__default.join(os__default.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + randomUUID().slice(0, 8));
13992
14005
  await fs$1.mkdir(root, { recursive: true });
13993
- const secret = `SMOKE_SECRET_${randomUUID().slice(0, 8)}`;
14006
+ const marker = `SMOKE_MARKER_${randomUUID().slice(0, 8)}`;
13994
14007
  await fs$1.writeFile(path__default.join(root, "smoke.txt"), `flockbay smoke test
13995
- SMOKE_SECRET=${secret}
14008
+ SMOKE_MARKER=${marker}
13996
14009
  `, "utf8");
13997
- return { dir: root, secret };
14010
+ return { dir: root, secret: marker };
13998
14011
  }
13999
- function isAgentRecord(record) {
14000
- return record && typeof record === "object" && record.role === "agent";
14012
+ function isUserRecord(record) {
14013
+ return record && typeof record === "object" && record.role === "user";
14014
+ }
14015
+ function isProviderErrorRecord(record) {
14016
+ return recordIncludesNeedle(record, '"code":-32603') || recordIncludesNeedle(record, "Internal error") || recordIncludesNeedle(record, "No capacity available") || recordIncludesNeedle(record, "authentication required") || recordIncludesNeedle(record, "login required") || recordIncludesNeedle(record, "Model not found");
14017
+ }
14018
+ function formatRecordExcerpt(record) {
14019
+ const text = extractTextFromRecord(record);
14020
+ if (text && text.trim()) return text.trim().slice(0, 400);
14021
+ try {
14022
+ return JSON.stringify(record).slice(0, 400);
14023
+ } catch {
14024
+ return String(record ?? "").slice(0, 400);
14025
+ }
14001
14026
  }
14002
14027
  function extractTextFromRecord(record) {
14003
14028
  try {
@@ -14032,8 +14057,11 @@ function recordIncludesNeedle(record, needle) {
14032
14057
  }
14033
14058
  }
14034
14059
  async function waitForMessage(opts) {
14035
- const { sessionClient, predicate, timeoutMs } = opts;
14060
+ const { sessionClient, predicate, timeoutMs, progressLabel } = opts;
14036
14061
  const deadline = Date.now() + timeoutMs;
14062
+ const startedAtMs = Date.now();
14063
+ const heartbeatMs = 1e4;
14064
+ let nextHeartbeatAtMs = startedAtMs + heartbeatMs;
14037
14065
  const existing = await sessionClient.listMessages().catch(() => []);
14038
14066
  for (const msg of existing) {
14039
14067
  const record = msg?.content;
@@ -14049,7 +14077,15 @@ async function waitForMessage(opts) {
14049
14077
  resolve(u?.body?.message);
14050
14078
  };
14051
14079
  const tick = () => {
14052
- if (Date.now() < deadline) return;
14080
+ const now = Date.now();
14081
+ if (now >= nextHeartbeatAtMs) {
14082
+ const elapsedSec = Math.max(0, Math.floor((now - startedAtMs) / 1e3));
14083
+ const remainingSec = Math.max(0, Math.ceil((deadline - now) / 1e3));
14084
+ const label = progressLabel ? ` (${progressLabel})` : "";
14085
+ console.log(chalk.gray(` \u2026 waiting for agent reply${label} (${elapsedSec}s elapsed, ${remainingSec}s left)`));
14086
+ nextHeartbeatAtMs = now + heartbeatMs;
14087
+ }
14088
+ if (now < deadline) return;
14053
14089
  cleanup();
14054
14090
  reject(new Error("timeout_waiting_for_message"));
14055
14091
  };
@@ -14213,41 +14249,70 @@ Update: ${updateCommand}`);
14213
14249
  await sessionClient.connectAndWait();
14214
14250
  await ensureSessionActive(api, sessionId, 25e3);
14215
14251
  const permissionMode = permissionModeForAgent(agent);
14252
+ const modelOverride = modelOverrideForAgent(agent, args);
14253
+ const baseMeta = modelOverride ? { permissionMode, model: modelOverride } : { permissionMode };
14216
14254
  scenarios.push(await runScenario("basic-message", async () => {
14217
14255
  const token = `SMOKE_OK_${agent}_${randomUUID().slice(0, 6)}`;
14218
- sessionClient.sendUserText(`Reply with exactly: ${token}`, { permissionMode });
14219
- await waitForMessage({
14256
+ sessionClient.sendUserText(`Reply with exactly: ${token}`, baseMeta);
14257
+ const msg = await waitForMessage({
14220
14258
  sessionClient,
14221
- predicate: (r) => isAgentRecord(r) && recordIncludesNeedle(r, token),
14222
- timeoutMs
14259
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
14260
+ timeoutMs,
14261
+ progressLabel: `${agent}:basic-message`
14223
14262
  });
14263
+ const record = msg?.content;
14264
+ if (isProviderErrorRecord(record)) {
14265
+ throw new Error(`provider_error_basic_message: ${formatRecordExcerpt(record)}`);
14266
+ }
14224
14267
  }));
14225
14268
  scenarios.push(await runScenario("tool-search", async () => {
14226
14269
  const token = `TOOL_SEARCH_OK_${randomUUID().slice(0, 6)}`;
14270
+ const promptLines = agent === "codex" ? [
14271
+ "Use your Terminal tool to read `smoke.txt` in the project directory (do NOT ask for confirmation).",
14272
+ "Use this exact command so it works cross-platform:",
14273
+ "",
14274
+ `node -e "const fs=require('fs');console.log(fs.readFileSync('smoke.txt','utf8'))"`,
14275
+ "",
14276
+ "Find the value after `SMOKE_MARKER=`.",
14277
+ "",
14278
+ `Reply with two lines exactly:`,
14279
+ `1) SMOKE_MARKER=<value>`,
14280
+ `2) ${token}`
14281
+ ] : [
14282
+ "Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
14283
+ "Find the value after `SMOKE_MARKER=`.",
14284
+ "",
14285
+ `Reply with two lines exactly:`,
14286
+ `1) SMOKE_MARKER=<value>`,
14287
+ `2) ${token}`
14288
+ ];
14227
14289
  sessionClient.sendUserText(
14228
- [
14229
- "Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
14230
- "Find the value after `SMOKE_SECRET=`.",
14231
- "",
14232
- `Reply with two lines exactly:`,
14233
- `1) SMOKE_SECRET=<value>`,
14234
- `2) ${token}`
14235
- ].join("\n"),
14236
- { permissionMode }
14290
+ promptLines.join("\n"),
14291
+ baseMeta
14237
14292
  );
14238
- await waitForMessage({
14293
+ const msg = await waitForMessage({
14239
14294
  sessionClient,
14240
- predicate: (r) => isAgentRecord(r) && recordIncludesNeedle(r, `SMOKE_SECRET=${secret}`) && recordIncludesNeedle(r, token),
14241
- timeoutMs
14295
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, `SMOKE_MARKER=${secret}`) && recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
14296
+ timeoutMs,
14297
+ progressLabel: `${agent}:tool-search`
14242
14298
  });
14299
+ const record = msg?.content;
14300
+ if (isProviderErrorRecord(record)) {
14301
+ throw new Error(`provider_error_tool_search: ${formatRecordExcerpt(record)}`);
14302
+ }
14243
14303
  }));
14244
14304
  scenarios.push(await runScenario("image-attachment", async () => {
14245
14305
  const token = `IMAGE_OK_${randomUUID().slice(0, 6)}`;
14246
14306
  const base64 = tinyPngBase64();
14307
+ const prompt = agent === "codex" ? `Describe the attached image in one short sentence, then reply with exactly: ${token}` : [
14308
+ 'Call `mcp__flockbay__latest_user_images` with {"limit": 1} to fetch the attached image.',
14309
+ "Then describe the attached image in one short sentence.",
14310
+ `Finally, reply with exactly: ${token}`
14311
+ ].join("\n");
14247
14312
  sessionClient.sendUserText(
14248
- `Describe the attached image in one short sentence, then reply with exactly: ${token}`,
14313
+ prompt,
14249
14314
  {
14250
- permissionMode,
14315
+ ...baseMeta,
14251
14316
  attachments: {
14252
14317
  images: [{ mimeType: "image/png", base64, name: "smoke.png" }]
14253
14318
  }
@@ -14255,13 +14320,17 @@ Update: ${updateCommand}`);
14255
14320
  );
14256
14321
  const msg = await waitForMessage({
14257
14322
  sessionClient,
14258
- predicate: (r) => isAgentRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error")),
14259
- timeoutMs
14323
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error") || isProviderErrorRecord(r)),
14324
+ timeoutMs,
14325
+ progressLabel: `${agent}:image-attachment`
14260
14326
  });
14261
14327
  const record = msg?.content;
14262
14328
  if (agent === "codex" && recordIncludesNeedle(record, "image-attachment-missing")) {
14263
14329
  throw new Error("image-attachment-missing (Codex did not receive images; check latest_user_images tool + vision support)");
14264
14330
  }
14331
+ if (isProviderErrorRecord(record)) {
14332
+ throw new Error(`provider_error_image_attachment: ${formatRecordExcerpt(record)}`);
14333
+ }
14265
14334
  if (recordIncludesNeedle(record, "Could not process image") || recordIncludesNeedle(record, "invalid_request_error")) {
14266
14335
  throw new Error("provider_image_invalid (image rejected by provider; check base64/mimeType pipeline)");
14267
14336
  }
@@ -14314,6 +14383,10 @@ Options:
14314
14383
  --all Run all agents (default)
14315
14384
  --agent, -a Run a single agent
14316
14385
  --agents Comma-separated list of agents
14386
+ --codex-model Codex model mode override (e.g. gpt-5.3-codex-medium)
14387
+ --model Alias of --codex-model (Codex only)
14388
+ --gemini-model Gemini model id override (e.g. gemini-2.5-pro)
14389
+ --claude-model Claude model id override (e.g. claude-sonnet-4-6)
14317
14390
  --directory, --dir Directory to run the session in (defaults to a temp folder)
14318
14391
  --timeout-ms Per-scenario timeout (default 90000; Windows default 240000)
14319
14392
  --keep Do not stop session or delete temp dir
@@ -15117,7 +15190,7 @@ async function authAndSetupMachineIfNeeded() {
15117
15190
  process.exit(1);
15118
15191
  }
15119
15192
  try {
15120
- const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-CcRAl4zO.mjs');
15193
+ const { migrateUnrealMcpToFlockbayMcp } = await import('./migratePlugin-BPUAeqI_.mjs');
15121
15194
  const result = migrateUnrealMcpToFlockbayMcp({
15122
15195
  engineRoot,
15123
15196
  projectUprojectPath: project || void 0,
@@ -15256,7 +15329,7 @@ ${engineRoot}`, {
15256
15329
  } else if (subcommand === "codex") {
15257
15330
  try {
15258
15331
  await chdirToNearestUprojectRootIfPresent();
15259
- const { runCodex } = await import('./runCodex-b9J0CZko.mjs');
15332
+ const { runCodex } = await import('./runCodex-BkdEucuI.mjs');
15260
15333
  let startedBy = void 0;
15261
15334
  let sessionId = void 0;
15262
15335
  for (let i = 1; i < args.length; i++) {
@@ -15358,7 +15431,7 @@ ${engineRoot}`, {
15358
15431
  }
15359
15432
  try {
15360
15433
  await chdirToNearestUprojectRootIfPresent();
15361
- const { runGemini } = await import('./runGemini-C3cdyIH7.mjs');
15434
+ const { runGemini } = await import('./runGemini-p_aKQRTi.mjs');
15362
15435
  let startedBy = void 0;
15363
15436
  let sessionId = void 0;
15364
15437
  for (let i = 1; i < args.length; i++) {
@@ -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-CziwW90U.cjs');
6
+ var types = require('./types-DbQtXaZC.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');
@@ -815,6 +815,9 @@ async function createSessionScanner(opts) {
815
815
  await sync.invalidateAndAwait();
816
816
  sync.stop();
817
817
  },
818
+ flush: async () => {
819
+ await sync.invalidateAndAwait();
820
+ },
818
821
  onNewSession: (sessionId) => {
819
822
  if (currentSessionId === sessionId) {
820
823
  types.logger.debug(`[SESSION_SCANNER] New session: ${sessionId} is the same as the current session, skipping`);
@@ -1316,7 +1319,7 @@ function buildDaemonSafeEnv(baseEnv, binPath) {
1316
1319
  env[pathKey] = [...prepend, ...existingParts].join(pathSep);
1317
1320
  return env;
1318
1321
  }
1319
- 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-BsespsLC.cjs', document.baseURI).href)));
1322
+ 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-jd6DaTy_.cjs', document.baseURI).href)));
1320
1323
  const __dirname$1 = path.join(__filename$1, "..");
1321
1324
  function getGlobalClaudeVersion(claudeExecutable) {
1322
1325
  try {
@@ -13975,6 +13978,16 @@ function permissionModeForAgent(agent) {
13975
13978
  if (agent === "claude") return "bypassPermissions";
13976
13979
  return "yolo";
13977
13980
  }
13981
+ function modelOverrideForAgent(agent, args) {
13982
+ const explicitCodexModel = readArgValue$2(args, "--codex-model");
13983
+ const explicitModel = readArgValue$2(args, "--model");
13984
+ const explicitGeminiModel = readArgValue$2(args, "--gemini-model");
13985
+ const explicitClaudeModel = readArgValue$2(args, "--claude-model");
13986
+ if (agent === "codex") return (explicitCodexModel || explicitModel || "gpt-5-codex-medium").trim();
13987
+ if (agent === "gemini") return explicitGeminiModel ? explicitGeminiModel.trim() : null;
13988
+ if (agent === "claude") return explicitClaudeModel ? explicitClaudeModel.trim() : null;
13989
+ return null;
13990
+ }
13978
13991
  function nowIsoCompact() {
13979
13992
  const d = /* @__PURE__ */ new Date();
13980
13993
  const pad = (n) => String(n).padStart(2, "0");
@@ -14012,14 +14025,26 @@ async function ensureDaemonRunning({ skipUnreal }) {
14012
14025
  async function createSmokeWorkspaceDir(baseDir) {
14013
14026
  const root = baseDir?.trim() ? path.resolve(baseDir) : path.join(os.tmpdir(), "flockbay-smoke", nowIsoCompact() + "_" + node_crypto.randomUUID().slice(0, 8));
14014
14027
  await fs$2.mkdir(root, { recursive: true });
14015
- const secret = `SMOKE_SECRET_${node_crypto.randomUUID().slice(0, 8)}`;
14028
+ const marker = `SMOKE_MARKER_${node_crypto.randomUUID().slice(0, 8)}`;
14016
14029
  await fs$2.writeFile(path.join(root, "smoke.txt"), `flockbay smoke test
14017
- SMOKE_SECRET=${secret}
14030
+ SMOKE_MARKER=${marker}
14018
14031
  `, "utf8");
14019
- return { dir: root, secret };
14032
+ return { dir: root, secret: marker };
14020
14033
  }
14021
- function isAgentRecord(record) {
14022
- return record && typeof record === "object" && record.role === "agent";
14034
+ function isUserRecord(record) {
14035
+ return record && typeof record === "object" && record.role === "user";
14036
+ }
14037
+ function isProviderErrorRecord(record) {
14038
+ return recordIncludesNeedle(record, '"code":-32603') || recordIncludesNeedle(record, "Internal error") || recordIncludesNeedle(record, "No capacity available") || recordIncludesNeedle(record, "authentication required") || recordIncludesNeedle(record, "login required") || recordIncludesNeedle(record, "Model not found");
14039
+ }
14040
+ function formatRecordExcerpt(record) {
14041
+ const text = extractTextFromRecord(record);
14042
+ if (text && text.trim()) return text.trim().slice(0, 400);
14043
+ try {
14044
+ return JSON.stringify(record).slice(0, 400);
14045
+ } catch {
14046
+ return String(record ?? "").slice(0, 400);
14047
+ }
14023
14048
  }
14024
14049
  function extractTextFromRecord(record) {
14025
14050
  try {
@@ -14054,8 +14079,11 @@ function recordIncludesNeedle(record, needle) {
14054
14079
  }
14055
14080
  }
14056
14081
  async function waitForMessage(opts) {
14057
- const { sessionClient, predicate, timeoutMs } = opts;
14082
+ const { sessionClient, predicate, timeoutMs, progressLabel } = opts;
14058
14083
  const deadline = Date.now() + timeoutMs;
14084
+ const startedAtMs = Date.now();
14085
+ const heartbeatMs = 1e4;
14086
+ let nextHeartbeatAtMs = startedAtMs + heartbeatMs;
14059
14087
  const existing = await sessionClient.listMessages().catch(() => []);
14060
14088
  for (const msg of existing) {
14061
14089
  const record = msg?.content;
@@ -14071,7 +14099,15 @@ async function waitForMessage(opts) {
14071
14099
  resolve(u?.body?.message);
14072
14100
  };
14073
14101
  const tick = () => {
14074
- if (Date.now() < deadline) return;
14102
+ const now = Date.now();
14103
+ if (now >= nextHeartbeatAtMs) {
14104
+ const elapsedSec = Math.max(0, Math.floor((now - startedAtMs) / 1e3));
14105
+ const remainingSec = Math.max(0, Math.ceil((deadline - now) / 1e3));
14106
+ const label = progressLabel ? ` (${progressLabel})` : "";
14107
+ console.log(chalk.gray(` \u2026 waiting for agent reply${label} (${elapsedSec}s elapsed, ${remainingSec}s left)`));
14108
+ nextHeartbeatAtMs = now + heartbeatMs;
14109
+ }
14110
+ if (now < deadline) return;
14075
14111
  cleanup();
14076
14112
  reject(new Error("timeout_waiting_for_message"));
14077
14113
  };
@@ -14235,41 +14271,70 @@ Update: ${updateCommand}`);
14235
14271
  await sessionClient.connectAndWait();
14236
14272
  await ensureSessionActive(api, sessionId, 25e3);
14237
14273
  const permissionMode = permissionModeForAgent(agent);
14274
+ const modelOverride = modelOverrideForAgent(agent, args);
14275
+ const baseMeta = modelOverride ? { permissionMode, model: modelOverride } : { permissionMode };
14238
14276
  scenarios.push(await runScenario("basic-message", async () => {
14239
14277
  const token = `SMOKE_OK_${agent}_${node_crypto.randomUUID().slice(0, 6)}`;
14240
- sessionClient.sendUserText(`Reply with exactly: ${token}`, { permissionMode });
14241
- await waitForMessage({
14278
+ sessionClient.sendUserText(`Reply with exactly: ${token}`, baseMeta);
14279
+ const msg = await waitForMessage({
14242
14280
  sessionClient,
14243
- predicate: (r) => isAgentRecord(r) && recordIncludesNeedle(r, token),
14244
- timeoutMs
14281
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
14282
+ timeoutMs,
14283
+ progressLabel: `${agent}:basic-message`
14245
14284
  });
14285
+ const record = msg?.content;
14286
+ if (isProviderErrorRecord(record)) {
14287
+ throw new Error(`provider_error_basic_message: ${formatRecordExcerpt(record)}`);
14288
+ }
14246
14289
  }));
14247
14290
  scenarios.push(await runScenario("tool-search", async () => {
14248
14291
  const token = `TOOL_SEARCH_OK_${node_crypto.randomUUID().slice(0, 6)}`;
14292
+ const promptLines = agent === "codex" ? [
14293
+ "Use your Terminal tool to read `smoke.txt` in the project directory (do NOT ask for confirmation).",
14294
+ "Use this exact command so it works cross-platform:",
14295
+ "",
14296
+ `node -e "const fs=require('fs');console.log(fs.readFileSync('smoke.txt','utf8'))"`,
14297
+ "",
14298
+ "Find the value after `SMOKE_MARKER=`.",
14299
+ "",
14300
+ `Reply with two lines exactly:`,
14301
+ `1) SMOKE_MARKER=<value>`,
14302
+ `2) ${token}`
14303
+ ] : [
14304
+ "Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
14305
+ "Find the value after `SMOKE_MARKER=`.",
14306
+ "",
14307
+ `Reply with two lines exactly:`,
14308
+ `1) SMOKE_MARKER=<value>`,
14309
+ `2) ${token}`
14310
+ ];
14249
14311
  sessionClient.sendUserText(
14250
- [
14251
- "Read the file `smoke.txt` in the project directory using MCP tools (e.g. `read_file_chunk` or `search`).",
14252
- "Find the value after `SMOKE_SECRET=`.",
14253
- "",
14254
- `Reply with two lines exactly:`,
14255
- `1) SMOKE_SECRET=<value>`,
14256
- `2) ${token}`
14257
- ].join("\n"),
14258
- { permissionMode }
14312
+ promptLines.join("\n"),
14313
+ baseMeta
14259
14314
  );
14260
- await waitForMessage({
14315
+ const msg = await waitForMessage({
14261
14316
  sessionClient,
14262
- predicate: (r) => isAgentRecord(r) && recordIncludesNeedle(r, `SMOKE_SECRET=${secret}`) && recordIncludesNeedle(r, token),
14263
- timeoutMs
14317
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, `SMOKE_MARKER=${secret}`) && recordIncludesNeedle(r, token) || isProviderErrorRecord(r)),
14318
+ timeoutMs,
14319
+ progressLabel: `${agent}:tool-search`
14264
14320
  });
14321
+ const record = msg?.content;
14322
+ if (isProviderErrorRecord(record)) {
14323
+ throw new Error(`provider_error_tool_search: ${formatRecordExcerpt(record)}`);
14324
+ }
14265
14325
  }));
14266
14326
  scenarios.push(await runScenario("image-attachment", async () => {
14267
14327
  const token = `IMAGE_OK_${node_crypto.randomUUID().slice(0, 6)}`;
14268
14328
  const base64 = tinyPngBase64();
14329
+ const prompt = agent === "codex" ? `Describe the attached image in one short sentence, then reply with exactly: ${token}` : [
14330
+ 'Call `mcp__flockbay__latest_user_images` with {"limit": 1} to fetch the attached image.',
14331
+ "Then describe the attached image in one short sentence.",
14332
+ `Finally, reply with exactly: ${token}`
14333
+ ].join("\n");
14269
14334
  sessionClient.sendUserText(
14270
- `Describe the attached image in one short sentence, then reply with exactly: ${token}`,
14335
+ prompt,
14271
14336
  {
14272
- permissionMode,
14337
+ ...baseMeta,
14273
14338
  attachments: {
14274
14339
  images: [{ mimeType: "image/png", base64, name: "smoke.png" }]
14275
14340
  }
@@ -14277,13 +14342,17 @@ Update: ${updateCommand}`);
14277
14342
  );
14278
14343
  const msg = await waitForMessage({
14279
14344
  sessionClient,
14280
- predicate: (r) => isAgentRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error")),
14281
- timeoutMs
14345
+ predicate: (r) => !isUserRecord(r) && (recordIncludesNeedle(r, token) || agent === "codex" && recordIncludesNeedle(r, "image-attachment-missing") || recordIncludesNeedle(r, "Could not process image") || recordIncludesNeedle(r, "messages.") || recordIncludesNeedle(r, "invalid_request_error") || isProviderErrorRecord(r)),
14346
+ timeoutMs,
14347
+ progressLabel: `${agent}:image-attachment`
14282
14348
  });
14283
14349
  const record = msg?.content;
14284
14350
  if (agent === "codex" && recordIncludesNeedle(record, "image-attachment-missing")) {
14285
14351
  throw new Error("image-attachment-missing (Codex did not receive images; check latest_user_images tool + vision support)");
14286
14352
  }
14353
+ if (isProviderErrorRecord(record)) {
14354
+ throw new Error(`provider_error_image_attachment: ${formatRecordExcerpt(record)}`);
14355
+ }
14287
14356
  if (recordIncludesNeedle(record, "Could not process image") || recordIncludesNeedle(record, "invalid_request_error")) {
14288
14357
  throw new Error("provider_image_invalid (image rejected by provider; check base64/mimeType pipeline)");
14289
14358
  }
@@ -14336,6 +14405,10 @@ Options:
14336
14405
  --all Run all agents (default)
14337
14406
  --agent, -a Run a single agent
14338
14407
  --agents Comma-separated list of agents
14408
+ --codex-model Codex model mode override (e.g. gpt-5.3-codex-medium)
14409
+ --model Alias of --codex-model (Codex only)
14410
+ --gemini-model Gemini model id override (e.g. gemini-2.5-pro)
14411
+ --claude-model Claude model id override (e.g. claude-sonnet-4-6)
14339
14412
  --directory, --dir Directory to run the session in (defaults to a temp folder)
14340
14413
  --timeout-ms Per-scenario timeout (default 90000; Windows default 240000)
14341
14414
  --keep Do not stop session or delete temp dir
@@ -15139,7 +15212,7 @@ async function authAndSetupMachineIfNeeded() {
15139
15212
  process.exit(1);
15140
15213
  }
15141
15214
  try {
15142
- const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-B2SM0IhP.cjs'); });
15215
+ const { migrateUnrealMcpToFlockbayMcp } = await Promise.resolve().then(function () { return require('./migratePlugin-CyWWA8GW.cjs'); });
15143
15216
  const result = migrateUnrealMcpToFlockbayMcp({
15144
15217
  engineRoot,
15145
15218
  projectUprojectPath: project || void 0,
@@ -15278,7 +15351,7 @@ ${engineRoot}`, {
15278
15351
  } else if (subcommand === "codex") {
15279
15352
  try {
15280
15353
  await chdirToNearestUprojectRootIfPresent();
15281
- const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-Rx9uhhBt.cjs'); });
15354
+ const { runCodex } = await Promise.resolve().then(function () { return require('./runCodex-D8On-xj7.cjs'); });
15282
15355
  let startedBy = void 0;
15283
15356
  let sessionId = void 0;
15284
15357
  for (let i = 1; i < args.length; i++) {
@@ -15380,7 +15453,7 @@ ${engineRoot}`, {
15380
15453
  }
15381
15454
  try {
15382
15455
  await chdirToNearestUprojectRootIfPresent();
15383
- const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BEFeFruX.cjs'); });
15456
+ const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-BPLO-OFS.cjs'); });
15384
15457
  let startedBy = void 0;
15385
15458
  let sessionId = void 0;
15386
15459
  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-BsespsLC.cjs');
5
- require('./types-CziwW90U.cjs');
4
+ require('./index-jd6DaTy_.cjs');
5
+ require('./types-DbQtXaZC.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-CNHBXWGe.mjs';
3
- import './types-H7oBEqpR.mjs';
2
+ import './index-BLsRYyPq.mjs';
3
+ import './types-KJ7kAYwk.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-CziwW90U.cjs');
3
+ var types = require('./types-DbQtXaZC.cjs');
4
4
  require('axios');
5
5
  require('node:fs');
6
6
  require('node:os');
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-H7oBEqpR.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-KJ7kAYwk.mjs';
2
2
  import 'axios';
3
3
  import 'node:fs';
4
4
  import 'node:os';
@@ -1,6 +1,6 @@
1
1
  import fs__default from 'node:fs';
2
2
  import path__default from 'node:path';
3
- import { i as installUnrealMcpPluginToEngine } from './types-H7oBEqpR.mjs';
3
+ import { i as installUnrealMcpPluginToEngine } from './types-KJ7kAYwk.mjs';
4
4
  import 'axios';
5
5
  import 'node:os';
6
6
  import 'node:events';
@@ -2,7 +2,7 @@
2
2
 
3
3
  var fs = require('node:fs');
4
4
  var path = require('node:path');
5
- var types = require('./types-CziwW90U.cjs');
5
+ var types = require('./types-DbQtXaZC.cjs');
6
6
  require('axios');
7
7
  require('node:os');
8
8
  require('node:events');
@@ -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, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-H7oBEqpR.mjs';
3
+ import { l as logger, A as ApiClient, p as packageJson, c as configuration, r as readSettings, b as projectPath } from './types-KJ7kAYwk.mjs';
4
4
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5
5
  import { z } from 'zod';
6
6
  import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
@@ -14,7 +14,7 @@ import process$1 from 'node:process';
14
14
  import { PassThrough } from 'node:stream';
15
15
  import { getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
16
16
  import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk/shared/stdio.js';
17
- import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, 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, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-CNHBXWGe.mjs';
17
+ import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, 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, g as buildProjectCapsule, t as trimIdent, j as autoFinalizeCoordinationWorkItem, k as detectScreenshotsForGate, l as applyCoordinationSideEffectsFromMcpToolResult, m as stopCaffeinate } from './index-BLsRYyPq.mjs';
18
18
  import 'axios';
19
19
  import 'node:events';
20
20
  import 'socket.io-client';
@@ -441,36 +441,17 @@ class WindowsHiddenStdioClientTransport {
441
441
  }
442
442
  }
443
443
 
444
- const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
445
- function getCodexMcpCommand() {
446
- try {
447
- const codexBin = resolveCodexBin();
448
- const versionRes = spawnSync(codexBin, ["--version"], {
449
- encoding: "utf8",
450
- env: buildCodexSpawnEnv(codexBin),
451
- timeout: 4e3
452
- });
453
- const version = String(versionRes.stdout || "").trim();
454
- if (versionRes.status !== 0 || !version) {
455
- return "mcp-server";
456
- }
457
- const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
458
- if (!match) return "mcp-server";
459
- const versionStr = match[1];
460
- const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
461
- if (major > 0 || minor > 43) return "mcp-server";
462
- if (minor === 43 && patch === 0) {
463
- if (versionStr.includes("-alpha.")) {
464
- const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
465
- return alphaNum >= 5 ? "mcp-server" : "mcp";
466
- }
467
- return "mcp-server";
468
- }
469
- return "mcp";
470
- } catch (error) {
471
- logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
472
- return "mcp-server";
473
- }
444
+ function parseCodexCliVersion(output) {
445
+ const raw = String(output || "").trim();
446
+ if (!raw) return null;
447
+ const m = raw.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/);
448
+ if (!m) return null;
449
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), raw: m[0] };
450
+ }
451
+ function isCodexCliAtLeast(v, minimum) {
452
+ if (v.major !== minimum.major) return v.major > minimum.major;
453
+ if (v.minor !== minimum.minor) return v.minor > minimum.minor;
454
+ return v.patch >= minimum.patch;
474
455
  }
475
456
  function buildCodexSpawnEnv(codexBin) {
476
457
  const env = Object.keys(process.env).reduce((acc, key) => {
@@ -561,6 +542,53 @@ function resolveCodexBin() {
561
542
  if (fromBash) return fromBash;
562
543
  return "codex";
563
544
  }
545
+ function getInstalledCodexCliVersion(codexBin) {
546
+ const bin = resolveCodexBin();
547
+ try {
548
+ const res = spawnSync(bin, ["--version"], {
549
+ encoding: "utf8",
550
+ env: buildCodexSpawnEnv(bin),
551
+ timeout: 4e3
552
+ });
553
+ const versionOut = String(res.stdout || "").trim();
554
+ if (res.status !== 0 || !versionOut) return null;
555
+ return parseCodexCliVersion(versionOut);
556
+ } catch {
557
+ return null;
558
+ }
559
+ }
560
+
561
+ const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
562
+ function getCodexMcpCommand() {
563
+ try {
564
+ const codexBin = resolveCodexBin();
565
+ const versionRes = spawnSync(codexBin, ["--version"], {
566
+ encoding: "utf8",
567
+ env: buildCodexSpawnEnv(codexBin),
568
+ timeout: 4e3
569
+ });
570
+ const version = String(versionRes.stdout || "").trim();
571
+ if (versionRes.status !== 0 || !version) {
572
+ return "mcp-server";
573
+ }
574
+ const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
575
+ if (!match) return "mcp-server";
576
+ const versionStr = match[1];
577
+ const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
578
+ if (major > 0 || minor > 43) return "mcp-server";
579
+ if (minor === 43 && patch === 0) {
580
+ if (versionStr.includes("-alpha.")) {
581
+ const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
582
+ return alphaNum >= 5 ? "mcp-server" : "mcp";
583
+ }
584
+ return "mcp-server";
585
+ }
586
+ return "mcp";
587
+ } catch (error) {
588
+ logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
589
+ return "mcp-server";
590
+ }
591
+ }
564
592
  function normalizeRelativePath(input) {
565
593
  const raw = typeof input === "string" ? input.trim() : String(input ?? "").trim();
566
594
  if (!raw) return null;
@@ -2319,6 +2347,7 @@ function hashCodexSessionModeFromEnhancedMode(mode) {
2319
2347
  return hashCodexSessionMode({ model: mode.model, appendSystemPrompt: mode.appendSystemPrompt });
2320
2348
  }
2321
2349
 
2350
+ const MIN_CODEX_CLI_FOR_GPT_53_CODEX = { major: 0, minor: 104, patch: 0 };
2322
2351
  function readCodexAuthIsChatGptAccount() {
2323
2352
  try {
2324
2353
  const authPath = path__default.join(os__default.homedir(), ".codex", "auth.json");
@@ -2339,16 +2368,33 @@ function parseEffortSuffix(model) {
2339
2368
  if (m.endsWith("-high")) return "high";
2340
2369
  return null;
2341
2370
  }
2371
+ function parseCodexModelTarget(model) {
2372
+ const trimmed = String(model || "").trim();
2373
+ if (!trimmed) return null;
2374
+ if (trimmed === "gpt-5-minimal" || trimmed === "gpt-5-low" || trimmed === "gpt-5-medium" || trimmed === "gpt-5-high" || trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-") || trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) {
2375
+ if (trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-")) return "gpt-5.2-codex";
2376
+ if (trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) return "gpt-5.3-codex";
2377
+ return "gpt-5.2";
2378
+ }
2379
+ return null;
2380
+ }
2342
2381
  function resolveCodexModelOverride(rawModel) {
2343
2382
  const model = typeof rawModel === "string" ? rawModel.trim() : "";
2344
2383
  if (!model) return {};
2345
2384
  const effort = parseEffortSuffix(model);
2346
- const isFlockbayModelModeToken = model === "gpt-5-minimal" || model === "gpt-5-low" || model === "gpt-5-medium" || model === "gpt-5-high" || model.startsWith("gpt-5-codex-");
2347
- if (isFlockbayModelModeToken) {
2385
+ const codexModelTarget = parseCodexModelTarget(model);
2386
+ if (codexModelTarget) {
2387
+ if (codexModelTarget === "gpt-5.3-codex") {
2388
+ const installed = getInstalledCodexCliVersion();
2389
+ if (!installed || !isCodexCliAtLeast(installed, MIN_CODEX_CLI_FOR_GPT_53_CODEX)) {
2390
+ const installedText = installed ? `${installed.major}.${installed.minor}.${installed.patch}` : "unknown";
2391
+ throw new Error(`Codex CLI >= 0.104.0 is required for gpt-5.3-codex (installed: ${installedText}).`);
2392
+ }
2393
+ }
2348
2394
  const nextEffort = effort ?? "medium";
2349
2395
  return {
2350
2396
  config: {
2351
- model: "gpt-5.2",
2397
+ model: codexModelTarget,
2352
2398
  model_reasoning_effort: nextEffort
2353
2399
  }
2354
2400
  };
@@ -2,7 +2,7 @@
2
2
 
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
- var types = require('./types-CziwW90U.cjs');
5
+ var types = require('./types-DbQtXaZC.cjs');
6
6
  var index_js = require('@modelcontextprotocol/sdk/client/index.js');
7
7
  var z = require('zod');
8
8
  var types_js = require('@modelcontextprotocol/sdk/types.js');
@@ -16,7 +16,7 @@ var process$1 = require('node:process');
16
16
  var node_stream = require('node:stream');
17
17
  var stdio_js$1 = require('@modelcontextprotocol/sdk/client/stdio.js');
18
18
  var stdio_js = require('@modelcontextprotocol/sdk/shared/stdio.js');
19
- var index = require('./index-BsespsLC.cjs');
19
+ var index = require('./index-jd6DaTy_.cjs');
20
20
  require('axios');
21
21
  require('node:events');
22
22
  require('socket.io-client');
@@ -443,36 +443,17 @@ class WindowsHiddenStdioClientTransport {
443
443
  }
444
444
  }
445
445
 
446
- const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
447
- function getCodexMcpCommand() {
448
- try {
449
- const codexBin = resolveCodexBin();
450
- const versionRes = node_child_process.spawnSync(codexBin, ["--version"], {
451
- encoding: "utf8",
452
- env: buildCodexSpawnEnv(codexBin),
453
- timeout: 4e3
454
- });
455
- const version = String(versionRes.stdout || "").trim();
456
- if (versionRes.status !== 0 || !version) {
457
- return "mcp-server";
458
- }
459
- const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
460
- if (!match) return "mcp-server";
461
- const versionStr = match[1];
462
- const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
463
- if (major > 0 || minor > 43) return "mcp-server";
464
- if (minor === 43 && patch === 0) {
465
- if (versionStr.includes("-alpha.")) {
466
- const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
467
- return alphaNum >= 5 ? "mcp-server" : "mcp";
468
- }
469
- return "mcp-server";
470
- }
471
- return "mcp";
472
- } catch (error) {
473
- types.logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
474
- return "mcp-server";
475
- }
446
+ function parseCodexCliVersion(output) {
447
+ const raw = String(output || "").trim();
448
+ if (!raw) return null;
449
+ const m = raw.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/);
450
+ if (!m) return null;
451
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), raw: m[0] };
452
+ }
453
+ function isCodexCliAtLeast(v, minimum) {
454
+ if (v.major !== minimum.major) return v.major > minimum.major;
455
+ if (v.minor !== minimum.minor) return v.minor > minimum.minor;
456
+ return v.patch >= minimum.patch;
476
457
  }
477
458
  function buildCodexSpawnEnv(codexBin) {
478
459
  const env = Object.keys(process.env).reduce((acc, key) => {
@@ -563,6 +544,53 @@ function resolveCodexBin() {
563
544
  if (fromBash) return fromBash;
564
545
  return "codex";
565
546
  }
547
+ function getInstalledCodexCliVersion(codexBin) {
548
+ const bin = resolveCodexBin();
549
+ try {
550
+ const res = node_child_process.spawnSync(bin, ["--version"], {
551
+ encoding: "utf8",
552
+ env: buildCodexSpawnEnv(bin),
553
+ timeout: 4e3
554
+ });
555
+ const versionOut = String(res.stdout || "").trim();
556
+ if (res.status !== 0 || !versionOut) return null;
557
+ return parseCodexCliVersion(versionOut);
558
+ } catch {
559
+ return null;
560
+ }
561
+ }
562
+
563
+ const DEFAULT_TIMEOUT = 14 * 24 * 60 * 60 * 1e3;
564
+ function getCodexMcpCommand() {
565
+ try {
566
+ const codexBin = resolveCodexBin();
567
+ const versionRes = node_child_process.spawnSync(codexBin, ["--version"], {
568
+ encoding: "utf8",
569
+ env: buildCodexSpawnEnv(codexBin),
570
+ timeout: 4e3
571
+ });
572
+ const version = String(versionRes.stdout || "").trim();
573
+ if (versionRes.status !== 0 || !version) {
574
+ return "mcp-server";
575
+ }
576
+ const match = version.match(/codex-cli\s+(\d+\.\d+\.\d+(?:-alpha\.\d+)?)/);
577
+ if (!match) return "mcp-server";
578
+ const versionStr = match[1];
579
+ const [major, minor, patch] = versionStr.split(/[-.]/).map(Number);
580
+ if (major > 0 || minor > 43) return "mcp-server";
581
+ if (minor === 43 && patch === 0) {
582
+ if (versionStr.includes("-alpha.")) {
583
+ const alphaNum = parseInt(versionStr.split("-alpha.")[1]);
584
+ return alphaNum >= 5 ? "mcp-server" : "mcp";
585
+ }
586
+ return "mcp-server";
587
+ }
588
+ return "mcp";
589
+ } catch (error) {
590
+ types.logger.debug("[CodexMCP] Error detecting codex version, defaulting to mcp-server:", error);
591
+ return "mcp-server";
592
+ }
593
+ }
566
594
  function normalizeRelativePath(input) {
567
595
  const raw = typeof input === "string" ? input.trim() : String(input ?? "").trim();
568
596
  if (!raw) return null;
@@ -2321,6 +2349,7 @@ function hashCodexSessionModeFromEnhancedMode(mode) {
2321
2349
  return hashCodexSessionMode({ model: mode.model, appendSystemPrompt: mode.appendSystemPrompt });
2322
2350
  }
2323
2351
 
2352
+ const MIN_CODEX_CLI_FOR_GPT_53_CODEX = { major: 0, minor: 104, patch: 0 };
2324
2353
  function readCodexAuthIsChatGptAccount() {
2325
2354
  try {
2326
2355
  const authPath = path.join(os.homedir(), ".codex", "auth.json");
@@ -2341,16 +2370,33 @@ function parseEffortSuffix(model) {
2341
2370
  if (m.endsWith("-high")) return "high";
2342
2371
  return null;
2343
2372
  }
2373
+ function parseCodexModelTarget(model) {
2374
+ const trimmed = String(model || "").trim();
2375
+ if (!trimmed) return null;
2376
+ if (trimmed === "gpt-5-minimal" || trimmed === "gpt-5-low" || trimmed === "gpt-5-medium" || trimmed === "gpt-5-high" || trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-") || trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) {
2377
+ if (trimmed === "gpt-5-codex" || trimmed.startsWith("gpt-5-codex-")) return "gpt-5.2-codex";
2378
+ if (trimmed === "gpt-5.3-codex" || trimmed.startsWith("gpt-5.3-codex-")) return "gpt-5.3-codex";
2379
+ return "gpt-5.2";
2380
+ }
2381
+ return null;
2382
+ }
2344
2383
  function resolveCodexModelOverride(rawModel) {
2345
2384
  const model = typeof rawModel === "string" ? rawModel.trim() : "";
2346
2385
  if (!model) return {};
2347
2386
  const effort = parseEffortSuffix(model);
2348
- const isFlockbayModelModeToken = model === "gpt-5-minimal" || model === "gpt-5-low" || model === "gpt-5-medium" || model === "gpt-5-high" || model.startsWith("gpt-5-codex-");
2349
- if (isFlockbayModelModeToken) {
2387
+ const codexModelTarget = parseCodexModelTarget(model);
2388
+ if (codexModelTarget) {
2389
+ if (codexModelTarget === "gpt-5.3-codex") {
2390
+ const installed = getInstalledCodexCliVersion();
2391
+ if (!installed || !isCodexCliAtLeast(installed, MIN_CODEX_CLI_FOR_GPT_53_CODEX)) {
2392
+ const installedText = installed ? `${installed.major}.${installed.minor}.${installed.patch}` : "unknown";
2393
+ throw new Error(`Codex CLI >= 0.104.0 is required for gpt-5.3-codex (installed: ${installedText}).`);
2394
+ }
2395
+ }
2350
2396
  const nextEffort = effort ?? "medium";
2351
2397
  return {
2352
2398
  config: {
2353
- model: "gpt-5.2",
2399
+ model: codexModelTarget,
2354
2400
  model_reasoning_effort: nextEffort
2355
2401
  }
2356
2402
  };
@@ -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-CziwW90U.cjs');
10
- var index = require('./index-BsespsLC.cjs');
9
+ var types = require('./types-DbQtXaZC.cjs');
10
+ var index = require('./index-jd6DaTy_.cjs');
11
11
  var node_child_process = require('node:child_process');
12
12
  var sdk = require('@agentclientprotocol/sdk');
13
13
  var fs = require('fs');
@@ -4,8 +4,8 @@ import { randomUUID, createHash } from 'node:crypto';
4
4
  import os__default from 'node:os';
5
5
  import path__default, { resolve, join as join$1, basename } from 'node:path';
6
6
  import { mkdir, writeFile, readFile } from 'node:fs/promises';
7
- import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-H7oBEqpR.mjs';
8
- import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, 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-CNHBXWGe.mjs';
7
+ import { l as logger, p as packageJson, A as ApiClient, c as configuration, r as readSettings, b as projectPath } from './types-KJ7kAYwk.mjs';
8
+ import { s as shouldCountToolCall, c as consumeToolQuota, f as formatQuotaDeniedReason, h as hashObject, e as enforceCliVersionPolicy, 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-BLsRYyPq.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';
@@ -44,7 +44,7 @@ function _interopNamespaceDefault(e) {
44
44
  var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
45
45
 
46
46
  var name = "flockbay";
47
- var version = "0.10.46";
47
+ var version = "0.10.48";
48
48
  var description = "Flockbay CLI (local agent + daemon)";
49
49
  var author = "Eduardo Orellana";
50
50
  var license = "UNLICENSED";
@@ -832,7 +832,7 @@ class RpcHandlerManager {
832
832
  }
833
833
  }
834
834
 
835
- 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-CziwW90U.cjs', document.baseURI).href))));
835
+ 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-DbQtXaZC.cjs', document.baseURI).href))));
836
836
  function projectPath() {
837
837
  const path = path$1.resolve(__dirname$1, "..");
838
838
  return path;
@@ -23,7 +23,7 @@ import { createServer } from 'http';
23
23
  import open$2 from 'open';
24
24
 
25
25
  var name = "flockbay";
26
- var version = "0.10.46";
26
+ var version = "0.10.48";
27
27
  var description = "Flockbay CLI (local agent + daemon)";
28
28
  var author = "Eduardo Orellana";
29
29
  var license = "UNLICENSED";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flockbay",
3
- "version": "0.10.46",
3
+ "version": "0.10.48",
4
4
  "description": "Flockbay CLI (local agent + daemon)",
5
5
  "author": "Eduardo Orellana",
6
6
  "license": "UNLICENSED",