codex-mobile-re 0.1.120 → 0.1.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist-cli/index.js CHANGED
@@ -3,9 +3,9 @@
3
3
  // src/cli/index.ts
4
4
  import { createServer as createServer2 } from "http";
5
5
  import { chmodSync as chmodSync2, createWriteStream, existsSync as existsSync14, mkdirSync as mkdirSync2 } from "fs";
6
- import { readFile as readFile19, stat as stat18, writeFile as writeFile18 } from "fs/promises";
6
+ import { readFile as readFile19, stat as stat19, writeFile as writeFile19 } from "fs/promises";
7
7
  import { homedir as homedir11, networkInterfaces } from "os";
8
- import { isAbsolute as isAbsolute13, join as join31, resolve as resolve8 } from "path";
8
+ import { isAbsolute as isAbsolute13, join as join32, resolve as resolve8 } from "path";
9
9
  import { spawn as spawn9 } from "child_process";
10
10
  import { createInterface as createInterface2 } from "readline/promises";
11
11
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -341,16 +341,16 @@ function parseApprovalPolicy(value) {
341
341
 
342
342
  // src/server/httpServer.ts
343
343
  import { fileURLToPath } from "url";
344
- import { dirname as dirname12, extname as extname5, isAbsolute as isAbsolute12, join as join30 } from "path";
344
+ import { dirname as dirname12, extname as extname5, isAbsolute as isAbsolute12, join as join31 } from "path";
345
345
  import { existsSync as existsSync13 } from "fs";
346
- import { writeFile as writeFile17, stat as stat17 } from "fs/promises";
346
+ import { writeFile as writeFile18, stat as stat18 } from "fs/promises";
347
347
  import express from "express";
348
348
 
349
349
  // src/server/codexAppServerBridge.ts
350
350
  import { spawn as spawn8 } from "child_process";
351
351
  import { mkdtemp as mkdtemp4, readFile as readFile18 } from "fs/promises";
352
- import { tmpdir as tmpdir6 } from "os";
353
- import { isAbsolute as isAbsolute11, join as join28 } from "path";
352
+ import { tmpdir as tmpdir7 } from "os";
353
+ import { isAbsolute as isAbsolute11, join as join29 } from "path";
354
354
 
355
355
  // src/server/accountRoutes.ts
356
356
  import { spawn as spawn2 } from "child_process";
@@ -9920,7 +9920,7 @@ async function handleProjectHttpRequest(req, res, url, deps) {
9920
9920
 
9921
9921
  // src/server/bridge/threadRoutes.ts
9922
9922
  import { isAbsolute as isAbsolute5 } from "path";
9923
- import { readFile as readFile10, stat as stat10 } from "fs/promises";
9923
+ import { readFile as readFile10, stat as stat11 } from "fs/promises";
9924
9924
 
9925
9925
  // src/server/bridge/session.ts
9926
9926
  import { mkdir as mkdir8, readFile as readFile9, rename as rename2, rm as rm6, stat as stat9, writeFile as writeFile8 } from "fs/promises";
@@ -10899,6 +10899,122 @@ async function mergeSessionCommandsIntoThreadResult(result) {
10899
10899
  }
10900
10900
  }
10901
10901
 
10902
+ // src/server/bridge/payloadSlimming.ts
10903
+ import { createHash as createHash2 } from "crypto";
10904
+ import { mkdir as mkdir9, stat as stat10, writeFile as writeFile9 } from "fs/promises";
10905
+ import { tmpdir as tmpdir5 } from "os";
10906
+ import { join as join19 } from "path";
10907
+ var COMMAND_OUTPUT_INLINE_LIMIT_BYTES = 16 * 1024;
10908
+ var COMMAND_OUTPUT_SPILL_MAX_BYTES = 8 * 1024 * 1024;
10909
+ var COMMAND_OUTPUT_SPILL_DIR_NAME = "codex-web-command-output";
10910
+ var SPILL_REF_PATTERN = /^[0-9a-f]{40}$/u;
10911
+ var HEAD_BYTES_RATIO = 0.6;
10912
+ function getCommandOutputSpillDir() {
10913
+ return join19(tmpdir5(), COMMAND_OUTPUT_SPILL_DIR_NAME);
10914
+ }
10915
+ function resolveCommandOutputSpillPath(ref) {
10916
+ const normalized = ref.trim().toLowerCase();
10917
+ if (!SPILL_REF_PATTERN.test(normalized)) return null;
10918
+ return join19(getCommandOutputSpillDir(), `${normalized}.txt`);
10919
+ }
10920
+ function truncateUtf8Middle(text, limitBytes) {
10921
+ const buffer = Buffer.from(text, "utf8");
10922
+ const headBytes = Math.floor(limitBytes * HEAD_BYTES_RATIO);
10923
+ const tailBytes = Math.max(0, limitBytes - headBytes);
10924
+ const head = buffer.subarray(0, headBytes).toString("utf8").replace(/\uFFFD+$/u, "");
10925
+ const tail = buffer.subarray(Math.max(0, buffer.length - tailBytes)).toString("utf8").replace(/^\uFFFD+/u, "");
10926
+ const keptBytes = Buffer.byteLength(head, "utf8") + Buffer.byteLength(tail, "utf8");
10927
+ return {
10928
+ text: `${head}
10929
+ \u2026
10930
+ ${tail}`,
10931
+ omittedBytes: Math.max(0, buffer.length - keptBytes)
10932
+ };
10933
+ }
10934
+ async function spillCommandOutputToDisk(text) {
10935
+ try {
10936
+ const ref = createHash2("sha1").update(text, "utf8").digest("hex");
10937
+ const spillDir = getCommandOutputSpillDir();
10938
+ await mkdir9(spillDir, { recursive: true });
10939
+ const filePath = join19(spillDir, `${ref}.txt`);
10940
+ try {
10941
+ await stat10(filePath);
10942
+ } catch {
10943
+ await writeFile9(filePath, text, "utf8");
10944
+ }
10945
+ return ref;
10946
+ } catch {
10947
+ return "";
10948
+ }
10949
+ }
10950
+ function slimMcpToolCallItem(item) {
10951
+ if (!("result" in item)) return null;
10952
+ const next = { ...item };
10953
+ delete next.result;
10954
+ return next;
10955
+ }
10956
+ async function slimCommandExecutionItem(item) {
10957
+ const output = item.aggregatedOutput;
10958
+ if (typeof output !== "string" || output.length === 0) return null;
10959
+ const totalBytes = Buffer.byteLength(output, "utf8");
10960
+ if (totalBytes <= COMMAND_OUTPUT_INLINE_LIMIT_BYTES) return null;
10961
+ const { text, omittedBytes } = truncateUtf8Middle(output, COMMAND_OUTPUT_INLINE_LIMIT_BYTES);
10962
+ const ref = totalBytes <= COMMAND_OUTPUT_SPILL_MAX_BYTES ? await spillCommandOutputToDisk(output) : "";
10963
+ return {
10964
+ ...item,
10965
+ aggregatedOutput: text,
10966
+ aggregatedOutputSpill: { ref, totalBytes, omittedBytes }
10967
+ };
10968
+ }
10969
+ async function slimThreadTurnsPayload(method, result) {
10970
+ if (!THREAD_METHODS_WITH_TURNS.has(method)) return result;
10971
+ const record = asRecord2(result);
10972
+ const thread = asRecord2(record?.thread);
10973
+ const turns = Array.isArray(thread?.turns) ? thread.turns : null;
10974
+ if (!record || !thread || !turns || turns.length === 0) return result;
10975
+ let changed = false;
10976
+ const nextTurns = [];
10977
+ for (const turn of turns) {
10978
+ const turnRecord = asRecord2(turn);
10979
+ const items = Array.isArray(turnRecord?.items) ? turnRecord.items : null;
10980
+ if (!turnRecord || !items) {
10981
+ nextTurns.push(turn);
10982
+ continue;
10983
+ }
10984
+ let itemChanged = false;
10985
+ const nextItems = [];
10986
+ for (const item of items) {
10987
+ const itemRecord = asRecord2(item);
10988
+ if (!itemRecord) {
10989
+ nextItems.push(item);
10990
+ continue;
10991
+ }
10992
+ const itemType = itemRecord.type;
10993
+ const slimmedItem = itemType === "mcpToolCall" ? slimMcpToolCallItem(itemRecord) : itemType === "commandExecution" ? await slimCommandExecutionItem(itemRecord) : null;
10994
+ if (!slimmedItem) {
10995
+ nextItems.push(item);
10996
+ continue;
10997
+ }
10998
+ itemChanged = true;
10999
+ nextItems.push(slimmedItem);
11000
+ }
11001
+ if (!itemChanged) {
11002
+ nextTurns.push(turn);
11003
+ continue;
11004
+ }
11005
+ changed = true;
11006
+ nextTurns.push({ ...turnRecord, items: nextItems });
11007
+ }
11008
+ if (!changed) return result;
11009
+ return {
11010
+ ...record,
11011
+ thread: {
11012
+ ...thread,
11013
+ turns: nextTurns
11014
+ }
11015
+ };
11016
+ }
11017
+
10902
11018
  // src/server/bridge/threadRoutes.ts
10903
11019
  function readStreamTurnId(params) {
10904
11020
  const directTurnId = readNonEmptyString(params.turnId) || readNonEmptyString(params.turn_id);
@@ -11085,7 +11201,7 @@ function handleThreadHttpRequest(req, res, url, deps) {
11085
11201
  let sessionSize = 0;
11086
11202
  if (sessionPath && isAbsolute5(sessionPath)) {
11087
11203
  try {
11088
- const s = await stat10(sessionPath);
11204
+ const s = await stat11(sessionPath);
11089
11205
  sessionSize = s.size;
11090
11206
  } catch {
11091
11207
  }
@@ -11163,6 +11279,22 @@ function handleThreadHttpRequest(req, res, url, deps) {
11163
11279
  return true;
11164
11280
  })();
11165
11281
  }
11282
+ if (req.method === "GET" && url.pathname === "/codex-api/command-output") {
11283
+ return (async () => {
11284
+ const ref = url.searchParams.get("ref")?.trim() ?? "";
11285
+ const spillPath = resolveCommandOutputSpillPath(ref);
11286
+ if (!spillPath) {
11287
+ setJson2(res, 400, { error: "Invalid command output reference." });
11288
+ return true;
11289
+ }
11290
+ try {
11291
+ setJson2(res, 200, { text: await readFile10(spillPath, "utf8") });
11292
+ } catch {
11293
+ setJson2(res, 404, { error: "Command output is no longer available." });
11294
+ }
11295
+ return true;
11296
+ })();
11297
+ }
11166
11298
  return Promise.resolve(false);
11167
11299
  }
11168
11300
 
@@ -11273,8 +11405,8 @@ async function runRpcResponsePipeline(deps, method, rpcResult) {
11273
11405
  }
11274
11406
 
11275
11407
  // src/server/bridge/telegramRoutes.ts
11276
- import { join as join19 } from "path";
11277
- import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
11408
+ import { join as join20 } from "path";
11409
+ import { readFile as readFile11, writeFile as writeFile10 } from "fs/promises";
11278
11410
  function normalizeTelegramBridgeConfig(value) {
11279
11411
  const record = asRecord2(value);
11280
11412
  if (!record) return { botToken: "", chatIds: [], allowedUserIds: [] };
@@ -11297,7 +11429,7 @@ function normalizeTelegramBridgeConfig(value) {
11297
11429
  return { botToken, chatIds, allowedUserIds };
11298
11430
  }
11299
11431
  function getTelegramBridgeConfigPath() {
11300
- return join19(getCodexHomeDir2(), "telegram-bridge.json");
11432
+ return join20(getCodexHomeDir2(), "telegram-bridge.json");
11301
11433
  }
11302
11434
  async function readTelegramBridgeConfig() {
11303
11435
  const telegramConfigPath = getTelegramBridgeConfigPath();
@@ -11312,7 +11444,7 @@ async function readTelegramBridgeConfig() {
11312
11444
  async function writeTelegramBridgeConfig(nextState) {
11313
11445
  const normalized = normalizeTelegramBridgeConfig(nextState);
11314
11446
  const telegramConfigPath = getTelegramBridgeConfigPath();
11315
- await writeFile9(telegramConfigPath, JSON.stringify({
11447
+ await writeFile10(telegramConfigPath, JSON.stringify({
11316
11448
  botToken: normalized.botToken,
11317
11449
  chatIds: normalized.chatIds,
11318
11450
  allowedUserIds: normalized.allowedUserIds
@@ -11367,8 +11499,8 @@ async function handleTelegramHttpRequest(req, res, url, deps) {
11367
11499
 
11368
11500
  // src/server/bridge/threadPreferencesRoutes.ts
11369
11501
  import { createReadStream as createReadStream3 } from "fs";
11370
- import { readFile as readFile12, stat as stat11, writeFile as writeFile10 } from "fs/promises";
11371
- import { join as join20 } from "path";
11502
+ import { readFile as readFile12, stat as stat12, writeFile as writeFile11 } from "fs/promises";
11503
+ import { join as join21 } from "path";
11372
11504
  import { createInterface } from "readline";
11373
11505
  var MAX_THREAD_TITLES = 500;
11374
11506
  var MAX_REASONING_MESSAGES_PER_THREAD = 20;
@@ -11383,7 +11515,7 @@ var sessionIndexThreadTitleCacheState = {
11383
11515
  cache: EMPTY_THREAD_TITLE_CACHE
11384
11516
  };
11385
11517
  function getCodexSessionIndexPath() {
11386
- return join20(getCodexHomeDir2(), "session_index.jsonl");
11518
+ return join21(getCodexHomeDir2(), "session_index.jsonl");
11387
11519
  }
11388
11520
  function normalizeThreadTitleCache(value) {
11389
11521
  const record = asRecord2(value);
@@ -11486,7 +11618,7 @@ async function writeThreadTitleCache(cache) {
11486
11618
  payload = {};
11487
11619
  }
11488
11620
  payload["thread-titles"] = cache;
11489
- await writeFile10(statePath, JSON.stringify(payload), "utf8");
11621
+ await writeFile11(statePath, JSON.stringify(payload), "utf8");
11490
11622
  }
11491
11623
  async function readPinnedThreadIds() {
11492
11624
  const statePath = getCodexGlobalStatePath();
@@ -11508,7 +11640,7 @@ async function writePinnedThreadIds(threadIds) {
11508
11640
  payload = {};
11509
11641
  }
11510
11642
  payload[PINNED_THREAD_IDS_KEY] = normalizePinnedThreadIds(threadIds);
11511
- await writeFile10(statePath, JSON.stringify(payload), "utf8");
11643
+ await writeFile11(statePath, JSON.stringify(payload), "utf8");
11512
11644
  }
11513
11645
  async function readThreadReasoningArchive() {
11514
11646
  const statePath = getCodexGlobalStatePath();
@@ -11535,7 +11667,7 @@ async function writeThreadReasoningArchive(archive) {
11535
11667
  } else {
11536
11668
  delete payload[THREAD_REASONING_KEY];
11537
11669
  }
11538
- await writeFile10(statePath, JSON.stringify(payload), "utf8");
11670
+ await writeFile11(statePath, JSON.stringify(payload), "utf8");
11539
11671
  }
11540
11672
  async function mergeThreadReasoningArchive(threadId, messages) {
11541
11673
  const archive = await readThreadReasoningArchive();
@@ -11592,7 +11724,7 @@ async function writeThreadTurnDurations(next) {
11592
11724
  } else {
11593
11725
  delete payload[THREAD_TURN_DURATIONS_KEY];
11594
11726
  }
11595
- await writeFile10(statePath, JSON.stringify(payload), "utf8");
11727
+ await writeFile11(statePath, JSON.stringify(payload), "utf8");
11596
11728
  }
11597
11729
  async function mergeThreadTurnDuration(threadId, turnId, durationMs) {
11598
11730
  const store = await readThreadTurnDurations();
@@ -11636,7 +11768,7 @@ async function writeFirstLaunchPluginsCardDismissed(dismissed) {
11636
11768
  payload = {};
11637
11769
  }
11638
11770
  payload[FIRST_LAUNCH_PLUGINS_CARD_DISMISSED_KEY] = dismissed === true;
11639
- await writeFile10(statePath, JSON.stringify(payload), "utf8");
11771
+ await writeFile11(statePath, JSON.stringify(payload), "utf8");
11640
11772
  }
11641
11773
  function getSessionIndexFileSignature(stats) {
11642
11774
  return `${String(stats.mtimeMs)}:${String(stats.size)}`;
@@ -11678,7 +11810,7 @@ async function parseThreadTitlesFromSessionIndex(sessionIndexPath) {
11678
11810
  async function readThreadTitlesFromSessionIndex() {
11679
11811
  const sessionIndexPath = getCodexSessionIndexPath();
11680
11812
  try {
11681
- const stats = await stat11(sessionIndexPath);
11813
+ const stats = await stat12(sessionIndexPath);
11682
11814
  const fileSignature = getSessionIndexFileSignature(stats);
11683
11815
  if (sessionIndexThreadTitleCacheState.fileSignature === fileSignature) {
11684
11816
  return sessionIndexThreadTitleCacheState.cache;
@@ -11859,14 +11991,14 @@ data: ${JSON.stringify({ ok: true })}
11859
11991
  // src/server/bridge/projectZip.ts
11860
11992
  import { randomUUID as randomUUID2 } from "crypto";
11861
11993
  import { existsSync as existsSync8 } from "fs";
11862
- import { mkdir as mkdir9, readFile as readFile14, realpath as realpath3, utimes, writeFile as writeFile12 } from "fs/promises";
11863
- import { basename as basename7, dirname as dirname6, extname as extname3, isAbsolute as isAbsolute7, join as join22, relative as relative3, resolve as resolve4, sep as sep3 } from "path";
11994
+ import { mkdir as mkdir10, readFile as readFile14, realpath as realpath3, utimes, writeFile as writeFile13 } from "fs/promises";
11995
+ import { basename as basename7, dirname as dirname6, extname as extname3, isAbsolute as isAbsolute7, join as join23, relative as relative3, resolve as resolve4, sep as sep3 } from "path";
11864
11996
 
11865
11997
  // src/server/bridge/importedSessions.ts
11866
11998
  import { spawnSync as spawnSync4 } from "child_process";
11867
11999
  import { existsSync as existsSync7 } from "fs";
11868
12000
  import { readdir as readdir8 } from "fs/promises";
11869
- import { join as join21 } from "path";
12001
+ import { join as join22 } from "path";
11870
12002
  async function* walkFiles(root, current = root) {
11871
12003
  let entries;
11872
12004
  try {
@@ -11875,7 +12007,7 @@ async function* walkFiles(root, current = root) {
11875
12007
  return;
11876
12008
  }
11877
12009
  for (const entry of entries) {
11878
- const absolutePath = join21(current, entry.name);
12010
+ const absolutePath = join22(current, entry.name);
11879
12011
  if (entry.isDirectory()) {
11880
12012
  yield* walkFiles(root, absolutePath);
11881
12013
  } else if (entry.isFile()) {
@@ -11908,7 +12040,7 @@ function readSessionMetaId(raw) {
11908
12040
  }
11909
12041
  }
11910
12042
  function getCurrentImportedSessionModelDefaults() {
11911
- const fmState = ensureDefaultFreeModeStateForMissingAuthSync(join21(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
12043
+ const fmState = ensureDefaultFreeModeStateForMissingAuthSync(join22(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
11912
12044
  if (!fmState?.enabled) return null;
11913
12045
  if (fmState.provider === "opencode-zen") {
11914
12046
  return {
@@ -12038,7 +12170,7 @@ function sqlString(value) {
12038
12170
  return `'${value.replace(/'/g, "''")}'`;
12039
12171
  }
12040
12172
  function sqliteStateDbPath() {
12041
- return join21(getCodexHomeDir2(), "state_5.sqlite");
12173
+ return join22(getCodexHomeDir2(), "state_5.sqlite");
12042
12174
  }
12043
12175
  function ensureImportedThreadsStateDbTable(stateDbPath) {
12044
12176
  const sql = `
@@ -12247,7 +12379,7 @@ function mergeImportedThreadsIntoThreadListResult(result) {
12247
12379
  }
12248
12380
 
12249
12381
  // src/server/bridge/workspaceRoots.ts
12250
- import { readFile as readFile13, realpath as realpath2, rm as rm7, writeFile as writeFile11 } from "fs/promises";
12382
+ import { readFile as readFile13, realpath as realpath2, rm as rm7, writeFile as writeFile12 } from "fs/promises";
12251
12383
  import { isAbsolute as isAbsolute6 } from "path";
12252
12384
  function normalizeRemoteProjects(value) {
12253
12385
  if (!Array.isArray(value)) return [];
@@ -12370,7 +12502,7 @@ async function writeWorkspaceRootsState(nextState) {
12370
12502
  payload["electron-workspace-root-labels"] = normalizeStringRecord(state.labels);
12371
12503
  payload["active-workspace-roots"] = normalizeStringArray(state.active);
12372
12504
  payload["project-order"] = normalizeStringArray(state.projectOrder);
12373
- await writeFile11(statePath, JSON.stringify(payload), "utf8");
12505
+ await writeFile12(statePath, JSON.stringify(payload), "utf8");
12374
12506
  }
12375
12507
  var workspaceRootsMutation = Promise.resolve();
12376
12508
  function queueWorkspaceRootsMutation(mutation) {
@@ -12431,8 +12563,8 @@ async function collectProjectChatZipEntries(projectRoot) {
12431
12563
  const exportedTitles = {};
12432
12564
  const exportedThreads = {};
12433
12565
  const roots = [
12434
- { disk: join22(codexHome, "sessions"), zip: ".codex-project/chats/sessions" },
12435
- { disk: join22(codexHome, "archived_sessions"), zip: ".codex-project/chats/archived_sessions" }
12566
+ { disk: join23(codexHome, "sessions"), zip: ".codex-project/chats/sessions" },
12567
+ { disk: join23(codexHome, "archived_sessions"), zip: ".codex-project/chats/archived_sessions" }
12436
12568
  ];
12437
12569
  const entries = [{
12438
12570
  path: ".codex-project/manifest.json",
@@ -12527,14 +12659,14 @@ async function importProjectZip(buffer, destinationParent) {
12527
12659
  }
12528
12660
  }
12529
12661
  const parent = await realpath3(destinationParent);
12530
- let projectPath = join22(parent, projectName);
12662
+ let projectPath = join23(parent, projectName);
12531
12663
  for (let index = 2; existsSync8(projectPath); index += 1) {
12532
- projectPath = join22(parent, `${projectName}-${index}`);
12664
+ projectPath = join23(parent, `${projectName}-${index}`);
12533
12665
  }
12534
- await mkdir9(projectPath, { recursive: true });
12666
+ await mkdir10(projectPath, { recursive: true });
12535
12667
  let importedSessions = 0;
12536
12668
  const importedSessionRecords = [];
12537
- const importedSessionsRoot = join22(getCodexHomeDir2(), "sessions");
12669
+ const importedSessionsRoot = join23(getCodexHomeDir2(), "sessions");
12538
12670
  const chatEntries = entries.filter((entry) => entry.path.startsWith(".codex-project/chats/") && !entry.isDirectory && extname3(entry.path) === ".jsonl").map((entry) => {
12539
12671
  const importedMetadata = importedThreadMetadata.get(entry.path);
12540
12672
  const sourceSessionRaw = entry.data.toString("utf8");
@@ -12544,10 +12676,10 @@ async function importProjectZip(buffer, destinationParent) {
12544
12676
  }).sort((first, second) => second.updatedAtMs - first.updatedAtMs);
12545
12677
  for (const [index, chatEntry] of chatEntries.entries()) {
12546
12678
  const importedThreadId = randomUUID2();
12547
- const target = join22(importedSessionsRoot, "imported", `${String(index + 1).padStart(6, "0")}-${importedThreadId}.jsonl`);
12548
- await mkdir9(dirname6(target), { recursive: true });
12679
+ const target = join23(importedSessionsRoot, "imported", `${String(index + 1).padStart(6, "0")}-${importedThreadId}.jsonl`);
12680
+ await mkdir10(dirname6(target), { recursive: true });
12549
12681
  const importedSessionRaw = rewriteImportedSession(chatEntry.sourceSessionRaw, projectPath, importedThreadId);
12550
- await writeFile12(target, importedSessionRaw, "utf8");
12682
+ await writeFile13(target, importedSessionRaw, "utf8");
12551
12683
  const importedRecord = readImportedSessionRecord(importedSessionRaw, target, projectPath, importedThreadId, chatEntry.importedMetadata?.title ?? "");
12552
12684
  if (chatEntry.updatedAtMs > 0) {
12553
12685
  importedRecord.updatedAtMs = chatEntry.updatedAtMs;
@@ -12568,13 +12700,13 @@ async function importProjectZip(buffer, destinationParent) {
12568
12700
  if (entry.path.startsWith(".codex-project/chats/")) {
12569
12701
  continue;
12570
12702
  }
12571
- const target = join22(projectPath, entry.path);
12703
+ const target = join23(projectPath, entry.path);
12572
12704
  if (!isSameOrDescendantPath(target, projectPath)) throw new Error("Project ZIP contains an unsafe path");
12573
12705
  if (entry.isDirectory) {
12574
- await mkdir9(target, { recursive: true });
12706
+ await mkdir10(target, { recursive: true });
12575
12707
  } else {
12576
- await mkdir9(dirname6(target), { recursive: true });
12577
- await writeFile12(target, entry.data);
12708
+ await mkdir10(dirname6(target), { recursive: true });
12709
+ await writeFile13(target, entry.data);
12578
12710
  }
12579
12711
  }
12580
12712
  await persistWorkspaceRoot(projectPath, projectName);
@@ -12582,7 +12714,7 @@ async function importProjectZip(buffer, destinationParent) {
12582
12714
  }
12583
12715
 
12584
12716
  // src/server/bridge/threadQueueState.ts
12585
- import { readFile as readFile15, writeFile as writeFile13 } from "fs/promises";
12717
+ import { readFile as readFile15, writeFile as writeFile14 } from "fs/promises";
12586
12718
  var THREAD_QUEUE_STATE_KEY = "thread-queue-state";
12587
12719
  function normalizeStoredQueuedMessage(value) {
12588
12720
  const record = asRecord2(value);
@@ -12662,7 +12794,7 @@ async function writeThreadQueueStateUnlocked(nextState) {
12662
12794
  } else {
12663
12795
  delete payload[THREAD_QUEUE_STATE_KEY];
12664
12796
  }
12665
- await writeFile13(statePath, JSON.stringify(payload), "utf8");
12797
+ await writeFile14(statePath, JSON.stringify(payload), "utf8");
12666
12798
  }
12667
12799
  async function withThreadQueueStateUpdate(update) {
12668
12800
  const run = threadQueueMutationChain.then(async () => {
@@ -12938,10 +13070,10 @@ function isTurnCompletedNotification(notification) {
12938
13070
 
12939
13071
  // src/server/bridge/approvalPolicy.ts
12940
13072
  import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
12941
- import { mkdir as mkdir10, readFile as readFile16, writeFile as writeFile14 } from "fs/promises";
12942
- import { dirname as dirname7, join as join23 } from "path";
13073
+ import { mkdir as mkdir11, readFile as readFile16, writeFile as writeFile15 } from "fs/promises";
13074
+ import { dirname as dirname7, join as join24 } from "path";
12943
13075
  function getCodexConfigPath() {
12944
- return join23(getCodexHomeDir2(), "config.toml");
13076
+ return join24(getCodexHomeDir2(), "config.toml");
12945
13077
  }
12946
13078
  async function resolveEffectiveApprovalPolicy() {
12947
13079
  const envPolicy = parseApprovalPolicy(process.env.CODEXUI_APPROVAL_POLICY ?? "");
@@ -12970,10 +13102,10 @@ function readApprovalPolicyFromConfigFile() {
12970
13102
  var APPROVAL_POLICY_ASSIGNMENT = /^approval_policy\s*=/u;
12971
13103
  async function writeApprovalPolicyToConfigFile(policy) {
12972
13104
  const configPath = getCodexConfigPath();
12973
- await mkdir10(dirname7(configPath), { recursive: true });
13105
+ await mkdir11(dirname7(configPath), { recursive: true });
12974
13106
  const policyLine = `approval_policy = "${policy}"`;
12975
13107
  if (!existsSync9(configPath)) {
12976
- await writeFile14(configPath, `${policyLine}
13108
+ await writeFile15(configPath, `${policyLine}
12977
13109
  `, "utf8");
12978
13110
  return;
12979
13111
  }
@@ -12985,14 +13117,14 @@ async function writeApprovalPolicyToConfigFile(policy) {
12985
13117
  ${body}
12986
13118
  ` : `${policyLine}
12987
13119
  `;
12988
- await writeFile14(configPath, nextContent, "utf8");
13120
+ await writeFile15(configPath, nextContent, "utf8");
12989
13121
  }
12990
13122
 
12991
13123
  // src/server/bridge/inlineImages.ts
12992
- import { createHash as createHash2 } from "crypto";
12993
- import { mkdir as mkdir11, stat as stat12, writeFile as writeFile15 } from "fs/promises";
12994
- import { tmpdir as tmpdir5 } from "os";
12995
- import { join as join24 } from "path";
13124
+ import { createHash as createHash3 } from "crypto";
13125
+ import { mkdir as mkdir12, stat as stat13, writeFile as writeFile16 } from "fs/promises";
13126
+ import { tmpdir as tmpdir6 } from "os";
13127
+ import { join as join25 } from "path";
12996
13128
  var THREAD_METHODS_WITH_TURNS2 = /* @__PURE__ */ new Set(["thread/read", "thread/resume", "thread/fork", "thread/rollback", "thread/revert"]);
12997
13129
  function isInlineDataUrl(value) {
12998
13130
  return /^data:/iu.test(value.trim());
@@ -13081,16 +13213,16 @@ async function persistInlineDataUrlToLocalFile(dataUrl, baseName) {
13081
13213
  return null;
13082
13214
  }
13083
13215
  if (bytes.length === 0) return null;
13084
- const hash = createHash2("sha1").update(bytes).digest("hex");
13216
+ const hash = createHash3("sha1").update(bytes).digest("hex");
13085
13217
  const ext = extensionFromMimeType(mimeType);
13086
- const mediaDir = join24(tmpdir5(), "codex-web-inline-media");
13087
- await mkdir11(mediaDir, { recursive: true });
13218
+ const mediaDir = join25(tmpdir6(), "codex-web-inline-media");
13219
+ await mkdir12(mediaDir, { recursive: true });
13088
13220
  const fileName = `${baseName}-${hash}${ext}`;
13089
- const filePath = join24(mediaDir, fileName);
13221
+ const filePath = join25(mediaDir, fileName);
13090
13222
  try {
13091
- await stat12(filePath);
13223
+ await stat13(filePath);
13092
13224
  } catch {
13093
- await writeFile15(filePath, bytes);
13225
+ await writeFile16(filePath, bytes);
13094
13226
  }
13095
13227
  return filePath;
13096
13228
  }
@@ -13222,10 +13354,11 @@ async function sanitizeInlinePayloadDeep(value, context) {
13222
13354
  }
13223
13355
  async function sanitizeThreadTurnsInlinePayloads(method, result) {
13224
13356
  if (!THREAD_METHODS_WITH_TURNS2.has(method)) return result;
13225
- const record = asRecord2(result);
13357
+ const slimmed = await slimThreadTurnsPayload(method, result);
13358
+ const record = asRecord2(slimmed);
13226
13359
  const thread = asRecord2(record?.thread);
13227
13360
  const turns = Array.isArray(thread?.turns) ? thread.turns : null;
13228
- if (!record || !thread || !turns || turns.length === 0) return result;
13361
+ if (!record || !thread || !turns || turns.length === 0) return slimmed;
13229
13362
  let changed = false;
13230
13363
  const nextTurns = [];
13231
13364
  for (let turnIndex = 0; turnIndex < turns.length; turnIndex += 1) {
@@ -13269,7 +13402,7 @@ async function sanitizeThreadTurnsInlinePayloads(method, result) {
13269
13402
  items: nextItems
13270
13403
  });
13271
13404
  }
13272
- if (!changed) return result;
13405
+ if (!changed) return slimmed;
13273
13406
  return {
13274
13407
  ...record,
13275
13408
  thread: {
@@ -13279,6 +13412,70 @@ async function sanitizeThreadTurnsInlinePayloads(method, result) {
13279
13412
  };
13280
13413
  }
13281
13414
 
13415
+ // src/server/bridge/threadReadCache.ts
13416
+ var THREAD_READ_RESULT_CACHE_TTL_MS = 2e4;
13417
+ var THREAD_READ_RESULT_CACHE_MAX_ENTRIES = 6;
13418
+ var THREAD_READ_INVALIDATING_METHOD_PATTERN = /^(?:turn\/|thread\/(?:start|fork|rollback|revert|resume|archive|unarchive|delete|compact|name\/))/u;
13419
+ function threadReadInvalidatesCache(method) {
13420
+ return THREAD_READ_INVALIDATING_METHOD_PATTERN.test(method);
13421
+ }
13422
+ function buildThreadReadCacheKey(params) {
13423
+ const parts = [];
13424
+ for (const key of Object.keys(params).sort()) {
13425
+ if (key === "threadId") continue;
13426
+ const value = params[key];
13427
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
13428
+ parts.push(`${key}=${String(value)}`);
13429
+ continue;
13430
+ }
13431
+ return "";
13432
+ }
13433
+ return parts.join("&");
13434
+ }
13435
+ var ThreadReadResultCache = class {
13436
+ constructor() {
13437
+ this.entries = /* @__PURE__ */ new Map();
13438
+ }
13439
+ get size() {
13440
+ return this.entries.size;
13441
+ }
13442
+ get(threadId, params) {
13443
+ if (!threadId || !params) return null;
13444
+ const cacheKey = buildThreadReadCacheKey(params);
13445
+ if (!cacheKey) return null;
13446
+ const mapKey = `${threadId}\0${cacheKey}`;
13447
+ const entry = this.entries.get(mapKey);
13448
+ if (!entry) return null;
13449
+ if (entry.expiresAt <= Date.now()) {
13450
+ this.entries.delete(mapKey);
13451
+ return null;
13452
+ }
13453
+ return entry.result;
13454
+ }
13455
+ set(threadId, params, result, now = Date.now()) {
13456
+ if (!threadId || !params) return;
13457
+ const cacheKey = buildThreadReadCacheKey(params);
13458
+ if (!cacheKey) return;
13459
+ const mapKey = `${threadId}\0${cacheKey}`;
13460
+ this.entries.delete(mapKey);
13461
+ this.entries.set(mapKey, { threadId, result, expiresAt: now + THREAD_READ_RESULT_CACHE_TTL_MS });
13462
+ while (this.entries.size > THREAD_READ_RESULT_CACHE_MAX_ENTRIES) {
13463
+ const oldestKey = this.entries.keys().next();
13464
+ if (oldestKey.done) break;
13465
+ this.entries.delete(oldestKey.value);
13466
+ }
13467
+ }
13468
+ invalidate(threadId) {
13469
+ if (!threadId) {
13470
+ this.entries.clear();
13471
+ return;
13472
+ }
13473
+ for (const [mapKey, entry] of this.entries) {
13474
+ if (entry.threadId === threadId) this.entries.delete(mapKey);
13475
+ }
13476
+ }
13477
+ };
13478
+
13282
13479
  // src/server/bridge/apiPerfLogging.ts
13283
13480
  import { readFileSync as readFileSync6 } from "fs";
13284
13481
  var API_PERF_LOGGING_ENV_KEY = "CODEXUI_API_PERF_LOGGING";
@@ -13354,12 +13551,12 @@ function getChunkByteLength(chunk, encoding) {
13354
13551
  }
13355
13552
 
13356
13553
  // src/server/bridge/terminal.ts
13357
- import { readdir as readdir9, readFile as readFile17, stat as stat13 } from "fs/promises";
13358
- import { isAbsolute as isAbsolute8, join as join25, resolve as resolve5 } from "path";
13554
+ import { readdir as readdir9, readFile as readFile17, stat as stat14 } from "fs/promises";
13555
+ import { isAbsolute as isAbsolute8, join as join26, resolve as resolve5 } from "path";
13359
13556
  import { existsSync as existsSync10 } from "fs";
13360
13557
  async function listTerminalQuickCommands(cwd) {
13361
13558
  const normalizedCwd = isAbsolute8(cwd) ? cwd : resolve5(cwd);
13362
- const info = await stat13(normalizedCwd);
13559
+ const info = await stat14(normalizedCwd);
13363
13560
  if (!info.isDirectory()) {
13364
13561
  throw new Error("Terminal cwd is not a directory");
13365
13562
  }
@@ -13378,7 +13575,7 @@ async function listTerminalQuickCommands(cwd) {
13378
13575
  }
13379
13576
  async function addPackageJsonCommands(cwd, addCommand) {
13380
13577
  try {
13381
- const raw = await readFile17(join25(cwd, "package.json"), "utf8");
13578
+ const raw = await readFile17(join26(cwd, "package.json"), "utf8");
13382
13579
  const parsed = JSON.parse(raw);
13383
13580
  const record = asRecord2(parsed);
13384
13581
  const scripts = asRecord2(record?.scripts);
@@ -13397,7 +13594,7 @@ async function addPackageJsonCommands(cwd, addCommand) {
13397
13594
  }
13398
13595
  }
13399
13596
  async function addMakefileCommands(cwd, addCommand) {
13400
- const makefilePath = existsSync10(join25(cwd, "Makefile")) ? join25(cwd, "Makefile") : existsSync10(join25(cwd, "makefile")) ? join25(cwd, "makefile") : "";
13597
+ const makefilePath = existsSync10(join26(cwd, "Makefile")) ? join26(cwd, "Makefile") : existsSync10(join26(cwd, "makefile")) ? join26(cwd, "makefile") : "";
13401
13598
  if (!makefilePath) return;
13402
13599
  try {
13403
13600
  const raw = await readFile17(makefilePath, "utf8");
@@ -13420,7 +13617,7 @@ async function addRootScriptCommands(cwd, addCommand) {
13420
13617
  await addScriptFileCommands(cwd, ".", addCommand);
13421
13618
  }
13422
13619
  async function addScriptsDirectoryCommands(cwd, addCommand) {
13423
- await addScriptFileCommands(join25(cwd, "scripts"), "./scripts", addCommand);
13620
+ await addScriptFileCommands(join26(cwd, "scripts"), "./scripts", addCommand);
13424
13621
  }
13425
13622
  async function addScriptFileCommands(directory, commandPrefix, addCommand) {
13426
13623
  try {
@@ -13439,9 +13636,9 @@ async function addScriptFileCommands(directory, commandPrefix, addCommand) {
13439
13636
  }
13440
13637
  }
13441
13638
  function resolvePackageManager(cwd) {
13442
- if (existsSync10(join25(cwd, "pnpm-lock.yaml"))) return "pnpm";
13443
- if (existsSync10(join25(cwd, "yarn.lock"))) return "yarn";
13444
- if (existsSync10(join25(cwd, "bun.lock")) || existsSync10(join25(cwd, "bun.lockb"))) return "bun";
13639
+ if (existsSync10(join26(cwd, "pnpm-lock.yaml"))) return "pnpm";
13640
+ if (existsSync10(join26(cwd, "yarn.lock"))) return "yarn";
13641
+ if (existsSync10(join26(cwd, "bun.lock")) || existsSync10(join26(cwd, "bun.lockb"))) return "bun";
13445
13642
  return "npm";
13446
13643
  }
13447
13644
  function formatPackageScriptCommand(packageManager, scriptName) {
@@ -13454,13 +13651,13 @@ function formatPackageScriptCommand(packageManager, scriptName) {
13454
13651
 
13455
13652
  // src/server/bridge/routes.ts
13456
13653
  import { randomBytes as randomBytes5 } from "crypto";
13457
- import { stat as stat15, mkdir as mkdir13 } from "fs/promises";
13458
- import { basename as basename8, dirname as dirname9, isAbsolute as isAbsolute10, join as join27, resolve as resolve6 } from "path";
13654
+ import { stat as stat16, mkdir as mkdir14 } from "fs/promises";
13655
+ import { basename as basename8, dirname as dirname9, isAbsolute as isAbsolute10, join as join28, resolve as resolve6 } from "path";
13459
13656
 
13460
13657
  // src/server/bridge/git.ts
13461
13658
  import { existsSync as existsSync11 } from "fs";
13462
- import { mkdir as mkdir12, rename as rename3, rm as rm8, stat as stat14, writeFile as writeFile16 } from "fs/promises";
13463
- import { dirname as dirname8, isAbsolute as isAbsolute9, join as join26 } from "path";
13659
+ import { mkdir as mkdir13, rename as rename3, rm as rm8, stat as stat15, writeFile as writeFile17 } from "fs/promises";
13660
+ import { dirname as dirname8, isAbsolute as isAbsolute9, join as join27 } from "path";
13464
13661
  function isMissingHeadError2(error) {
13465
13662
  const message = getErrorMessage2(error, "").toLowerCase();
13466
13663
  return message.includes("not a valid object name: 'head'") || message.includes("not a valid object name: head") || message.includes("invalid reference: head");
@@ -13470,11 +13667,11 @@ function isNotGitRepositoryError2(error) {
13470
13667
  return message.includes("not a git repository") || message.includes("fatal: not a git repository");
13471
13668
  }
13472
13669
  async function ensureRepoHasInitialCommit(repoRoot) {
13473
- const agentsPath = join26(repoRoot, "AGENTS.md");
13670
+ const agentsPath = join27(repoRoot, "AGENTS.md");
13474
13671
  try {
13475
- await stat14(agentsPath);
13672
+ await stat15(agentsPath);
13476
13673
  } catch {
13477
- await writeFile16(agentsPath, "", "utf8");
13674
+ await writeFile17(agentsPath, "", "utf8");
13478
13675
  }
13479
13676
  await runCommand("git", ["add", "AGENTS.md"], { cwd: repoRoot });
13480
13677
  await runCommand(
@@ -13505,7 +13702,7 @@ function isSafeGitRelativePath2(filePath) {
13505
13702
  return Boolean(filePath) && !isAbsolute9(filePath) && !filePath.split("/").includes("..");
13506
13703
  }
13507
13704
  function resolveGitRelativePath(repoRoot, filePath) {
13508
- return join26(repoRoot, ...filePath.split("/"));
13705
+ return join27(repoRoot, ...filePath.split("/"));
13509
13706
  }
13510
13707
  function gitPathsConflict(left, right) {
13511
13708
  return left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
@@ -13525,7 +13722,7 @@ async function rollbackPreservedUntrackedFiles(entries) {
13525
13722
  for (const entry of entries.slice().reverse()) {
13526
13723
  try {
13527
13724
  if (existsSync11(entry.backupPath) && !existsSync11(entry.sourcePath)) {
13528
- await mkdir12(dirname8(entry.sourcePath), { recursive: true });
13725
+ await mkdir13(dirname8(entry.sourcePath), { recursive: true });
13529
13726
  await rename3(entry.backupPath, entry.sourcePath);
13530
13727
  }
13531
13728
  } catch {
@@ -13540,12 +13737,12 @@ async function preserveUntrackedFilesForGitTarget(repoRoot, targetRef) {
13540
13737
  const targetPaths = splitGitPathList2(targetTreeRaw);
13541
13738
  const conflictingUntrackedPaths = splitGitPathList2(untrackedRaw).filter((filePath) => isSafeGitRelativePath2(filePath) && targetPaths.some((targetPath) => gitPathsConflict(filePath, targetPath)));
13542
13739
  if (conflictingUntrackedPaths.length === 0) return [];
13543
- const backupRoot = join26(repoRoot, HEADER_GIT_UNTRACKED_BACKUP_DIR, (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
13740
+ const backupRoot = join27(repoRoot, HEADER_GIT_UNTRACKED_BACKUP_DIR, (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
13544
13741
  const movedFiles = [];
13545
13742
  for (const filePath of conflictingUntrackedPaths) {
13546
13743
  const sourcePath = resolveGitRelativePath(repoRoot, filePath);
13547
- const backupPath = join26(backupRoot, ...filePath.split("/"));
13548
- await mkdir12(dirname8(backupPath), { recursive: true });
13744
+ const backupPath = join27(backupRoot, ...filePath.split("/"));
13745
+ await mkdir13(dirname8(backupPath), { recursive: true });
13549
13746
  await rename3(sourcePath, backupPath);
13550
13747
  movedFiles.push({ filePath, sourcePath, backupPath });
13551
13748
  await removeEmptyGitRelativeParents(repoRoot, filePath);
@@ -13704,7 +13901,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13704
13901
  }
13705
13902
  const sourceCwd = isAbsolute10(rawSourceCwd) ? rawSourceCwd : resolve6(rawSourceCwd);
13706
13903
  try {
13707
- const sourceInfo = await stat15(sourceCwd);
13904
+ const sourceInfo = await stat16(sourceCwd);
13708
13905
  if (!sourceInfo.isDirectory()) {
13709
13906
  setJson2(res, 400, { error: "sourceCwd is not a directory" });
13710
13907
  return true;
@@ -13723,21 +13920,21 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13723
13920
  gitRoot = await runCommandCapture("git", ["rev-parse", "--show-toplevel"], { cwd: sourceCwd });
13724
13921
  }
13725
13922
  const repoName = basename8(gitRoot) || "repo";
13726
- const worktreesRoot = join27(getCodexHomeDir2(), "worktrees");
13727
- await mkdir13(worktreesRoot, { recursive: true });
13923
+ const worktreesRoot = join28(getCodexHomeDir2(), "worktrees");
13924
+ await mkdir14(worktreesRoot, { recursive: true });
13728
13925
  let worktreeId = "";
13729
13926
  let worktreeParent = "";
13730
13927
  let worktreeCwd = "";
13731
13928
  for (let attempt = 0; attempt < 12; attempt += 1) {
13732
13929
  const candidate = randomBytes5(2).toString("hex");
13733
- const parent = join27(worktreesRoot, candidate);
13930
+ const parent = join28(worktreesRoot, candidate);
13734
13931
  try {
13735
- await stat15(parent);
13932
+ await stat16(parent);
13736
13933
  continue;
13737
13934
  } catch {
13738
13935
  worktreeId = candidate;
13739
13936
  worktreeParent = parent;
13740
- worktreeCwd = join27(parent, repoName);
13937
+ worktreeCwd = join28(parent, repoName);
13741
13938
  break;
13742
13939
  }
13743
13940
  }
@@ -13745,7 +13942,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13745
13942
  throw new Error("Failed to allocate a unique worktree id");
13746
13943
  }
13747
13944
  const startPoint = baseBranch || "HEAD";
13748
- await mkdir13(worktreeParent, { recursive: true });
13945
+ await mkdir14(worktreeParent, { recursive: true });
13749
13946
  try {
13750
13947
  await runCommand("git", ["worktree", "add", "--detach", worktreeCwd, startPoint], { cwd: gitRoot });
13751
13948
  } catch (error) {
@@ -13789,7 +13986,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13789
13986
  }
13790
13987
  const sourceCwd = isAbsolute10(rawSourceCwd) ? rawSourceCwd : resolve6(rawSourceCwd);
13791
13988
  try {
13792
- const sourceInfo = await stat15(sourceCwd);
13989
+ const sourceInfo = await stat16(sourceCwd);
13793
13990
  if (!sourceInfo.isDirectory()) {
13794
13991
  setJson2(res, 400, { error: "sourceCwd is not a directory" });
13795
13992
  return true;
@@ -13807,9 +14004,9 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13807
14004
  await runCommand("git", ["init"], { cwd: sourceCwd });
13808
14005
  gitRoot = await runCommandCapture("git", ["rev-parse", "--show-toplevel"], { cwd: sourceCwd });
13809
14006
  }
13810
- const worktreeCwd = join27(dirname9(gitRoot), rawWorktreeName);
14007
+ const worktreeCwd = join28(dirname9(gitRoot), rawWorktreeName);
13811
14008
  try {
13812
- await stat15(worktreeCwd);
14009
+ await stat16(worktreeCwd);
13813
14010
  setJson2(res, 409, { error: "Worktree folder already exists" });
13814
14011
  return true;
13815
14012
  } catch {
@@ -13848,7 +14045,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13848
14045
  }
13849
14046
  const sourceCwd = isAbsolute10(rawSourceCwd) ? rawSourceCwd : resolve6(rawSourceCwd);
13850
14047
  try {
13851
- const sourceInfo = await stat15(sourceCwd);
14048
+ const sourceInfo = await stat16(sourceCwd);
13852
14049
  if (!sourceInfo.isDirectory()) {
13853
14050
  setJson2(res, 400, { error: "sourceCwd is not a directory" });
13854
14051
  return true;
@@ -13903,7 +14100,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13903
14100
  }
13904
14101
  const cwd = isAbsolute10(rawCwd) ? rawCwd : resolve6(rawCwd);
13905
14102
  try {
13906
- const cwdInfo = await stat15(cwd);
14103
+ const cwdInfo = await stat16(cwd);
13907
14104
  if (!cwdInfo.isDirectory()) {
13908
14105
  setJson2(res, 400, { error: "cwd is not a directory" });
13909
14106
  return true;
@@ -13979,7 +14176,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
13979
14176
  }
13980
14177
  const cwd = isAbsolute10(rawCwd) ? rawCwd : resolve6(rawCwd);
13981
14178
  try {
13982
- const cwdInfo = await stat15(cwd);
14179
+ const cwdInfo = await stat16(cwd);
13983
14180
  if (!cwdInfo.isDirectory()) {
13984
14181
  setJson2(res, 400, { error: "cwd is not a directory" });
13985
14182
  return true;
@@ -14029,7 +14226,7 @@ async function handleGitWorktreeHttpRequest(req, res, url, deps) {
14029
14226
  }
14030
14227
  const cwd = isAbsolute10(rawCwd) ? rawCwd : resolve6(rawCwd);
14031
14228
  try {
14032
- const cwdInfo = await stat15(cwd);
14229
+ const cwdInfo = await stat16(cwd);
14033
14230
  if (!cwdInfo.isDirectory()) {
14034
14231
  setJson2(res, 400, { error: "cwd is not a directory" });
14035
14232
  return true;
@@ -14251,6 +14448,7 @@ var AppServerProcess = class {
14251
14448
  this.lastThreadReadSnapshotByThreadId = /* @__PURE__ */ new Map();
14252
14449
  this.threadTurnPageReadCacheByThreadId = /* @__PURE__ */ new Map();
14253
14450
  this.threadTurnPageReadPromiseByThreadId = /* @__PURE__ */ new Map();
14451
+ this.threadReadResultCache = new ThreadReadResultCache();
14254
14452
  this.capturedItemsByThreadId = /* @__PURE__ */ new Map();
14255
14453
  this.liveStateCache = /* @__PURE__ */ new Map();
14256
14454
  this.chatgptAuthRefreshPromise = null;
@@ -14268,7 +14466,7 @@ var AppServerProcess = class {
14268
14466
  let extraEnv = {};
14269
14467
  const serverPort = parseInt(process.env.CODEXUI_SERVER_PORT ?? "", 10) || void 0;
14270
14468
  args.push(...getProviderCompatibilityConfigArgs(serverPort));
14271
- const statePath = join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
14469
+ const statePath = join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
14272
14470
  try {
14273
14471
  const state = ensureDefaultFreeModeStateForMissingAuthSync(statePath);
14274
14472
  if (state) {
@@ -14331,6 +14529,7 @@ var AppServerProcess = class {
14331
14529
  this.initialized = false;
14332
14530
  this.initializePromise = null;
14333
14531
  this.readBuffer = "";
14532
+ this.invalidateThreadReadResultCache();
14334
14533
  });
14335
14534
  }
14336
14535
  sendLine(payload) {
@@ -14376,6 +14575,7 @@ var AppServerProcess = class {
14376
14575
  if (nThreadId) {
14377
14576
  this.invalidateLiveStateCache(nThreadId);
14378
14577
  this.threadTurnPageReadCacheByThreadId.delete(nThreadId);
14578
+ this.invalidateThreadReadResultCache(nThreadId);
14379
14579
  }
14380
14580
  for (const listener of this.notificationListeners) {
14381
14581
  listener(notification);
@@ -14450,6 +14650,20 @@ var AppServerProcess = class {
14450
14650
  cacheLiveState(threadId, data, turnCount, sessionSize) {
14451
14651
  this.liveStateCache.set(threadId, { data, turnCount, sessionSize });
14452
14652
  }
14653
+ /**
14654
+ * Cache a post-pipeline `thread/read` result. Called by the RPC handler with
14655
+ * exactly what was sent to the client, so a hit skips the app-server call, the
14656
+ * 10-turn trim, the session-log command merge and the payload slimming.
14657
+ */
14658
+ cacheThreadReadResult(threadId, params, result) {
14659
+ this.threadReadResultCache.set(threadId, asRecord2(params), result);
14660
+ }
14661
+ getCachedThreadReadResult(threadId, params) {
14662
+ return this.threadReadResultCache.get(threadId, asRecord2(params));
14663
+ }
14664
+ invalidateThreadReadResultCache(threadId) {
14665
+ this.threadReadResultCache.invalidate(threadId);
14666
+ }
14453
14667
  getCachedLiveState(threadId, turnCount, sessionSize) {
14454
14668
  const cached = this.liveStateCache.get(threadId);
14455
14669
  if (!cached) return null;
@@ -14645,9 +14859,45 @@ var AppServerProcess = class {
14645
14859
  }
14646
14860
  async rpc(method, params) {
14647
14861
  this.disposeIfConfigChanged();
14862
+ if (threadReadInvalidatesCache(method)) {
14863
+ const paramsRecord = asRecord2(params);
14864
+ const threadId = readNonEmptyString(paramsRecord?.threadId);
14865
+ this.invalidateThreadReadResultCache(threadId || void 0);
14866
+ }
14648
14867
  await this.ensureInitialized();
14649
14868
  return this.call(method, params);
14650
14869
  }
14870
+ /**
14871
+ * Spawn + initialize the app-server ahead of the first user request.
14872
+ *
14873
+ * Measured cold start: the first page load fires ~20 startup RPCs that all
14874
+ * queue behind one just-spawned app-server (head-of-line blocking —
14875
+ * free-mode/status 2619ms, meta/methods 1306ms, thread/queue-state 1287ms), so
14876
+ * `thread/list` costs 934ms cold vs 63ms warm.
14877
+ *
14878
+ * Honest scope of the win (measured 2026-09-11, dev server): the frontend's
14879
+ * burst arrives ~1-3s after the Vite dev server reports ready, while
14880
+ * `ensureInitialized()` here needs ~2.1s. So warm-up only *overlaps* part of
14881
+ * the init — the first request still waits for the remainder (observed first
14882
+ * GET 1401ms, meta/methods 2118ms). It does not remove the cold start from
14883
+ * first paint; it removes it from every *later* load, and it is what makes the
14884
+ * warm path (all endpoints <=70ms) reachable without an artificial first
14885
+ * request. Treat this as queue-shifting, not as a first-paint fix.
14886
+ *
14887
+ * Side effect to be aware of: this spawns the app-server eagerly whenever the
14888
+ * bridge is created (dev server and packaged `createServer` alike) instead of
14889
+ * lazily on the first request.
14890
+ *
14891
+ * Best-effort: a failure here must not break the bridge, because the next
14892
+ * request retries through the normal ensureInitialized path.
14893
+ */
14894
+ async warmUp() {
14895
+ try {
14896
+ this.disposeIfConfigChanged();
14897
+ await this.ensureInitialized();
14898
+ } catch {
14899
+ }
14900
+ }
14651
14901
  onNotification(listener) {
14652
14902
  this.notificationListeners.add(listener);
14653
14903
  return () => {
@@ -14688,6 +14938,7 @@ var AppServerProcess = class {
14688
14938
  this.initializePromise = null;
14689
14939
  this.activeConfigSignature = "";
14690
14940
  this.readBuffer = "";
14941
+ this.invalidateThreadReadResultCache();
14691
14942
  const failure = new Error("codex app-server stopped");
14692
14943
  for (const request of this.pending.values()) {
14693
14944
  request.reject(failure);
@@ -14995,9 +15246,9 @@ var MethodCatalog = class {
14995
15246
  if (this.methodCache) {
14996
15247
  return this.methodCache;
14997
15248
  }
14998
- const outDir = await mkdtemp4(join28(tmpdir6(), "codex-web-local-schema-"));
15249
+ const outDir = await mkdtemp4(join29(tmpdir7(), "codex-web-local-schema-"));
14999
15250
  await this.runGenerateSchemaCommand(outDir);
15000
- const clientRequestPath = join28(outDir, "ClientRequest.json");
15251
+ const clientRequestPath = join29(outDir, "ClientRequest.json");
15001
15252
  const raw = await readFile18(clientRequestPath, "utf8");
15002
15253
  const parsed = JSON.parse(raw);
15003
15254
  const methods = this.extractMethodsFromClientRequest(parsed);
@@ -15008,9 +15259,9 @@ var MethodCatalog = class {
15008
15259
  if (this.notificationCache) {
15009
15260
  return this.notificationCache;
15010
15261
  }
15011
- const outDir = await mkdtemp4(join28(tmpdir6(), "codex-web-local-schema-"));
15262
+ const outDir = await mkdtemp4(join29(tmpdir7(), "codex-web-local-schema-"));
15012
15263
  await this.runGenerateSchemaCommand(outDir);
15013
- const serverNotificationPath = join28(outDir, "ServerNotification.json");
15264
+ const serverNotificationPath = join29(outDir, "ServerNotification.json");
15014
15265
  const raw = await readFile18(serverNotificationPath, "utf8");
15015
15266
  const parsed = JSON.parse(raw);
15016
15267
  const methods = this.extractMethodsFromServerNotification(parsed);
@@ -15019,7 +15270,7 @@ var MethodCatalog = class {
15019
15270
  }
15020
15271
  };
15021
15272
  var SHARED_BRIDGE_KEY = "__codexRemoteSharedBridge__";
15022
- var SHARED_BRIDGE_VERSION = "experimental-api-v2";
15273
+ var SHARED_BRIDGE_VERSION = "experimental-api-v3";
15023
15274
  function getSharedBridgeState() {
15024
15275
  const globalScope = globalThis;
15025
15276
  const existing = globalScope[SHARED_BRIDGE_KEY];
@@ -15068,6 +15319,7 @@ function createCodexBridgeMiddleware() {
15068
15319
  }
15069
15320
  return threadSearchIndexPromise;
15070
15321
  }
15322
+ void appServer.warmUp();
15071
15323
  void initializeSkillsSyncOnStartup(appServer);
15072
15324
  void readTelegramBridgeConfig().then((config) => {
15073
15325
  if (!config.botToken) return;
@@ -15128,7 +15380,7 @@ function createCodexBridgeMiddleware() {
15128
15380
  setJson(res, 403, { error: "Zen proxy is only available from localhost" });
15129
15381
  return;
15130
15382
  }
15131
- const statePath = join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15383
+ const statePath = join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15132
15384
  let bearerToken = "";
15133
15385
  let wireApi = "responses";
15134
15386
  try {
@@ -15143,7 +15395,7 @@ function createCodexBridgeMiddleware() {
15143
15395
  return;
15144
15396
  }
15145
15397
  if (url.pathname === "/codex-api/openrouter-proxy/v1/responses" && req.method === "POST") {
15146
- const statePath = join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15398
+ const statePath = join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15147
15399
  let bearerToken = "";
15148
15400
  let wireApi = "responses";
15149
15401
  try {
@@ -15156,7 +15408,7 @@ function createCodexBridgeMiddleware() {
15156
15408
  return;
15157
15409
  }
15158
15410
  if (url.pathname === "/codex-api/custom-proxy/v1/responses" && req.method === "POST") {
15159
- const statePath = join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15411
+ const statePath = join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE);
15160
15412
  let bearerToken = "";
15161
15413
  let wireApi = "responses";
15162
15414
  let baseUrl = "";
@@ -15310,6 +15562,14 @@ function createCodexBridgeMiddleware() {
15310
15562
  setJson(res, 200, { result: null });
15311
15563
  return;
15312
15564
  }
15565
+ const cacheableThreadReadId = body.method === "thread/read" ? readNonEmptyString(asRecord2(body.params)?.threadId) : "";
15566
+ if (cacheableThreadReadId) {
15567
+ const cachedThreadRead = appServer.getCachedThreadReadResult(cacheableThreadReadId, body.params ?? null);
15568
+ if (cachedThreadRead !== null) {
15569
+ setJson(res, 200, { result: cachedThreadRead });
15570
+ return;
15571
+ }
15572
+ }
15313
15573
  let rpcResult;
15314
15574
  try {
15315
15575
  rpcResult = await callRpcWithArchiveRecovery(appServer, body.method, body.params ?? null);
@@ -15354,6 +15614,9 @@ function createCodexBridgeMiddleware() {
15354
15614
  sanitizeThreadTurnsInlinePayloads,
15355
15615
  mergeImportedThreadsIntoThreadListResult
15356
15616
  }, body.method, rpcResult);
15617
+ if (cacheableThreadReadId) {
15618
+ appServer.cacheThreadReadResult(cacheableThreadReadId, body.params ?? null, pipelineResult);
15619
+ }
15357
15620
  setJson(res, 200, { result: pipelineResult });
15358
15621
  return;
15359
15622
  }
@@ -15373,7 +15636,7 @@ function createCodexBridgeMiddleware() {
15373
15636
  const action = readNonEmptyString(body?.action) === "redo" ? "redo" : "undo";
15374
15637
  const scope = readNonEmptyString(body?.scope) === "single_turn" ? "single_turn" : "turn_and_later";
15375
15638
  const patchIds = Array.isArray(body?.patchIds) ? new Set(body.patchIds.filter((value) => typeof value === "string" && value.length > 0)) : void 0;
15376
- const filePaths = Array.isArray(body?.filePaths) ? new Set(body.filePaths.filter((value) => typeof value === "string" && value.length > 0).map((value) => isAbsolute11(value) ? value : join28(cwd, value))) : void 0;
15639
+ const filePaths = Array.isArray(body?.filePaths) ? new Set(body.filePaths.filter((value) => typeof value === "string" && value.length > 0).map((value) => isAbsolute11(value) ? value : join29(cwd, value))) : void 0;
15377
15640
  if (!threadId || !turnId || !cwd) {
15378
15641
  setJson(res, 400, { error: "Missing threadId, turnId, or cwd" });
15379
15642
  return;
@@ -15459,7 +15722,7 @@ function createCodexBridgeMiddleware() {
15459
15722
  const requestedProvider = url.searchParams.get("provider")?.trim() ?? "";
15460
15723
  if (requestedProvider) {
15461
15724
  const normalizedRequestedProvider = requestedProvider.replace(/_/g, "-");
15462
- const fmState2 = ensureDefaultFreeModeStateForMissingAuthSync(join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
15725
+ const fmState2 = ensureDefaultFreeModeStateForMissingAuthSync(join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
15463
15726
  if (fmState2?.enabled && normalizedRequestedProvider === CUSTOM_RUNTIME_PROVIDER_ID.replace(/_/g, "-") && fmState2.provider === "custom" && fmState2.customBaseUrl) {
15464
15727
  setJson(res, 200, {
15465
15728
  data: await fetchCustomEndpointModelIds(fmState2.customBaseUrl, fmState2.apiKey ?? ""),
@@ -15489,7 +15752,7 @@ function createCodexBridgeMiddleware() {
15489
15752
  });
15490
15753
  return;
15491
15754
  }
15492
- const fmState = ensureDefaultFreeModeStateForMissingAuthSync(join28(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
15755
+ const fmState = ensureDefaultFreeModeStateForMissingAuthSync(join29(getCodexHomeDir2(), FREE_MODE_STATE_FILE));
15493
15756
  if (fmState?.enabled) {
15494
15757
  if (fmState.provider === "opencode-zen") {
15495
15758
  try {
@@ -15664,7 +15927,7 @@ function createCodexBridgeMiddleware() {
15664
15927
  import { randomBytes as randomBytes6, timingSafeEqual } from "crypto";
15665
15928
  import { existsSync as existsSync12, mkdirSync, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync2 } from "fs";
15666
15929
  import { homedir as homedir10 } from "os";
15667
- import { dirname as dirname11, join as join29 } from "path";
15930
+ import { dirname as dirname11, join as join30 } from "path";
15668
15931
  var TOKEN_COOKIE = "portal_session";
15669
15932
  var SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
15670
15933
  var SESSION_STORE_FILE = "webui-auth-sessions.json";
@@ -15718,10 +15981,10 @@ function isTrustedTailscaleRemote(remote) {
15718
15981
  }
15719
15982
  function getCodexHomeDir6() {
15720
15983
  const codexHome = process.env.CODEX_HOME?.trim();
15721
- return codexHome && codexHome.length > 0 ? codexHome : join29(homedir10(), ".codex");
15984
+ return codexHome && codexHome.length > 0 ? codexHome : join30(homedir10(), ".codex");
15722
15985
  }
15723
15986
  function getSessionStorePath() {
15724
- return join29(getCodexHomeDir6(), SESSION_STORE_FILE);
15987
+ return join30(getCodexHomeDir6(), SESSION_STORE_FILE);
15725
15988
  }
15726
15989
  function readPersistedSessions() {
15727
15990
  const sessionStorePath = getSessionStorePath();
@@ -15903,8 +16166,8 @@ function createAuthSession(password) {
15903
16166
  // src/server/httpServer.ts
15904
16167
  import { WebSocketServer } from "ws";
15905
16168
  var __dirname = dirname12(fileURLToPath(import.meta.url));
15906
- var distDir = join30(__dirname, "..", "dist");
15907
- var spaEntryFile = join30(distDir, "index.html");
16169
+ var distDir = join31(__dirname, "..", "dist");
16170
+ var spaEntryFile = join31(distDir, "index.html");
15908
16171
  var IMAGE_CONTENT_TYPES = {
15909
16172
  ".avif": "image/avif",
15910
16173
  ".bmp": "image/bmp",
@@ -16008,7 +16271,7 @@ function createServer(options = {}) {
16008
16271
  return;
16009
16272
  }
16010
16273
  try {
16011
- const fileStat = await stat17(localPath);
16274
+ const fileStat = await stat18(localPath);
16012
16275
  if (!fileStat.isDirectory()) {
16013
16276
  res.status(400).json({ error: "Expected directory path." });
16014
16277
  return;
@@ -16027,7 +16290,7 @@ function createServer(options = {}) {
16027
16290
  return;
16028
16291
  }
16029
16292
  try {
16030
- const fileStat = await stat17(localPath);
16293
+ const fileStat = await stat18(localPath);
16031
16294
  if (!fileStat.isDirectory()) {
16032
16295
  res.status(400).json({ error: "Expected directory path." });
16033
16296
  return;
@@ -16046,7 +16309,7 @@ function createServer(options = {}) {
16046
16309
  return;
16047
16310
  }
16048
16311
  try {
16049
- const fileStat = await stat17(localPath);
16312
+ const fileStat = await stat18(localPath);
16050
16313
  if (!fileStat.isFile()) {
16051
16314
  res.status(400).json({ error: "Expected file path." });
16052
16315
  return;
@@ -16066,7 +16329,7 @@ function createServer(options = {}) {
16066
16329
  return;
16067
16330
  }
16068
16331
  try {
16069
- const fileStat = await stat17(localPath);
16332
+ const fileStat = await stat18(localPath);
16070
16333
  res.setHeader("Cache-Control", "private, no-store");
16071
16334
  if (fileStat.isDirectory()) {
16072
16335
  const html = await createDirectoryListingHtml(localPath, { newProjectName });
@@ -16089,7 +16352,7 @@ function createServer(options = {}) {
16089
16352
  return;
16090
16353
  }
16091
16354
  try {
16092
- const fileStat = await stat17(localPath);
16355
+ const fileStat = await stat18(localPath);
16093
16356
  if (!fileStat.isFile()) {
16094
16357
  res.status(400).json({ error: "Expected file path." });
16095
16358
  return;
@@ -16113,7 +16376,7 @@ function createServer(options = {}) {
16113
16376
  }
16114
16377
  const body = typeof req.body === "string" ? req.body : "";
16115
16378
  try {
16116
- await writeFile17(localPath, body, "utf8");
16379
+ await writeFile18(localPath, body, "utf8");
16117
16380
  res.status(200).json({ ok: true });
16118
16381
  } catch {
16119
16382
  res.status(404).json({ error: "File not found." });
@@ -16192,10 +16455,10 @@ var program = new Command().name("codex-mobile-re").description("Web interface f
16192
16455
  var __dirname2 = dirname13(fileURLToPath2(import.meta.url));
16193
16456
  var hasPromptedCloudflaredInstall = false;
16194
16457
  function getCodexHomePath() {
16195
- return process.env.CODEX_HOME?.trim() || join31(homedir11(), ".codex");
16458
+ return process.env.CODEX_HOME?.trim() || join32(homedir11(), ".codex");
16196
16459
  }
16197
16460
  function getCloudflaredPromptMarkerPath() {
16198
- return join31(getCodexHomePath(), ".cloudflared-install-prompted");
16461
+ return join32(getCodexHomePath(), ".cloudflared-install-prompted");
16199
16462
  }
16200
16463
  function hasPromptedCloudflaredInstallPersisted() {
16201
16464
  return existsSync14(getCloudflaredPromptMarkerPath());
@@ -16203,12 +16466,12 @@ function hasPromptedCloudflaredInstallPersisted() {
16203
16466
  async function persistCloudflaredInstallPrompted() {
16204
16467
  const codexHome = getCodexHomePath();
16205
16468
  mkdirSync2(codexHome, { recursive: true });
16206
- await writeFile18(getCloudflaredPromptMarkerPath(), `${Date.now()}
16469
+ await writeFile19(getCloudflaredPromptMarkerPath(), `${Date.now()}
16207
16470
  `, "utf8");
16208
16471
  }
16209
16472
  async function readCliVersion() {
16210
16473
  try {
16211
- const packageJsonPath = join31(__dirname2, "..", "package.json");
16474
+ const packageJsonPath = join32(__dirname2, "..", "package.json");
16212
16475
  const raw = await readFile19(packageJsonPath, "utf8");
16213
16476
  const parsed = JSON.parse(raw);
16214
16477
  return typeof parsed.version === "string" ? parsed.version : "unknown";
@@ -16233,7 +16496,7 @@ function resolveCloudflaredCommand() {
16233
16496
  if (canRunCommand("cloudflared", ["--version"])) {
16234
16497
  return "cloudflared";
16235
16498
  }
16236
- const localCandidate = join31(homedir11(), ".local", "bin", "cloudflared");
16499
+ const localCandidate = join32(homedir11(), ".local", "bin", "cloudflared");
16237
16500
  if (existsSync14(localCandidate) && canRunCommand(localCandidate, ["--version"])) {
16238
16501
  return localCandidate;
16239
16502
  }
@@ -16287,9 +16550,9 @@ async function ensureCloudflaredInstalledLinux() {
16287
16550
  if (!mappedArch) {
16288
16551
  throw new Error(`cloudflared auto-install is not supported for Linux architecture: ${process.arch}`);
16289
16552
  }
16290
- const userBinDir = join31(homedir11(), ".local", "bin");
16553
+ const userBinDir = join32(homedir11(), ".local", "bin");
16291
16554
  mkdirSync2(userBinDir, { recursive: true });
16292
- const destination = join31(userBinDir, "cloudflared");
16555
+ const destination = join32(userBinDir, "cloudflared");
16293
16556
  const downloadUrl = `https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${mappedArch}`;
16294
16557
  console.log("\ncloudflared not found. Installing to ~/.local/bin...\n");
16295
16558
  await downloadFile(downloadUrl, destination);
@@ -16340,7 +16603,7 @@ async function resolveCloudflaredForTunnel() {
16340
16603
  }
16341
16604
  function hasCodexAuth() {
16342
16605
  const codexHome = getCodexHomePath();
16343
- return existsSync14(join31(codexHome, "auth.json"));
16606
+ return existsSync14(join32(codexHome, "auth.json"));
16344
16607
  }
16345
16608
  function ensureCodexInstalled() {
16346
16609
  let codexCommand = resolveCodexCommand();
@@ -16396,13 +16659,13 @@ function resolvePassword(input) {
16396
16659
  return { password: generatePassword(), generated: true };
16397
16660
  }
16398
16661
  function getGeneratedPasswordPath() {
16399
- return join31(getCodexHomePath(), "codexui-password");
16662
+ return join32(getCodexHomePath(), "codexui-password");
16400
16663
  }
16401
16664
  async function persistGeneratedPassword(password) {
16402
16665
  const codexHome = getCodexHomePath();
16403
16666
  mkdirSync2(codexHome, { recursive: true });
16404
16667
  const passwordPath = getGeneratedPasswordPath();
16405
- await writeFile18(passwordPath, `${password}
16668
+ await writeFile19(passwordPath, `${password}
16406
16669
  `, { encoding: "utf8", mode: 384 });
16407
16670
  chmodSync2(passwordPath, 384);
16408
16671
  return passwordPath;
@@ -16541,7 +16804,7 @@ function listenWithFallback(server, startPort) {
16541
16804
  }
16542
16805
  function getCodexGlobalStatePath2() {
16543
16806
  const codexHome = getCodexHomePath();
16544
- return join31(codexHome, ".codex-global-state.json");
16807
+ return join32(codexHome, ".codex-global-state.json");
16545
16808
  }
16546
16809
  function normalizeUniqueStrings(value) {
16547
16810
  if (!Array.isArray(value)) return [];
@@ -16558,7 +16821,7 @@ async function persistLaunchProject(projectPath) {
16558
16821
  const trimmed = projectPath.trim();
16559
16822
  if (!trimmed) return;
16560
16823
  const normalizedPath = isAbsolute13(trimmed) ? trimmed : resolve8(trimmed);
16561
- const directoryInfo = await stat18(normalizedPath);
16824
+ const directoryInfo = await stat19(normalizedPath);
16562
16825
  if (!directoryInfo.isDirectory()) {
16563
16826
  throw new Error(`Not a directory: ${normalizedPath}`);
16564
16827
  }
@@ -16583,7 +16846,7 @@ async function persistLaunchProject(projectPath) {
16583
16846
  normalizedPath,
16584
16847
  ...activeRoots.filter((value) => value !== normalizedPath)
16585
16848
  ];
16586
- await writeFile18(statePath, JSON.stringify(payload), "utf8");
16849
+ await writeFile19(statePath, JSON.stringify(payload), "utf8");
16587
16850
  }
16588
16851
  async function addProjectOnly(projectPath) {
16589
16852
  const trimmed = projectPath.trim();