happy-imou-cloud 2.1.44 → 2.1.46

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.
Files changed (25) hide show
  1. package/dist/{BaseReasoningProcessor-CMyFNQ1O.cjs → BaseReasoningProcessor-Bsnew7fc.cjs} +2 -2
  2. package/dist/{BaseReasoningProcessor-DVSN7PCw.mjs → BaseReasoningProcessor-Mrdbmfl3.mjs} +2 -2
  3. package/dist/{ProviderSelectionHandler-2IaDlDBx.mjs → ProviderSelectionHandler-BymmO261.mjs} +2 -2
  4. package/dist/{ProviderSelectionHandler-Dqa4j1pD.cjs → ProviderSelectionHandler-gaUVvyCU.cjs} +2 -2
  5. package/dist/{api-BoWVQeVe.cjs → api-Bekjk9d5.cjs} +104 -1
  6. package/dist/{api-BhMVpzwg.mjs → api-DTSpLLTK.mjs} +104 -2
  7. package/dist/{command-DoF8oaxg.cjs → command-BwhJX0G5.cjs} +2 -2
  8. package/dist/{command-h3Rr4Abu.mjs → command-umgXYSY2.mjs} +2 -2
  9. package/dist/{index-DxF1W0nt.mjs → index-CUVIZLuf.mjs} +270 -29
  10. package/dist/{index-kIN8gN9G.cjs → index-DkaYNlRO.cjs} +274 -30
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/lib.cjs +1 -1
  14. package/dist/lib.d.cts +86 -86
  15. package/dist/lib.d.mts +86 -86
  16. package/dist/lib.mjs +1 -1
  17. package/dist/{registerKillSessionHandler-CBm2WFM0.cjs → registerKillSessionHandler-BYWJJDre.cjs} +10 -5
  18. package/dist/{registerKillSessionHandler-Dsg63Cx6.mjs → registerKillSessionHandler-hQE08yMO.mjs} +10 -6
  19. package/dist/{runClaude-BpwlCyVT.mjs → runClaude-CFeIMCY2.mjs} +11 -8
  20. package/dist/{runClaude-Dq9OISKt.cjs → runClaude-jpo2aFey.cjs} +11 -8
  21. package/dist/{runCodex-BMNR2hNp.mjs → runCodex-ByjUfTyr.mjs} +496 -59
  22. package/dist/{runCodex-BnzErOK_.cjs → runCodex-CrxyWcga.cjs} +496 -59
  23. package/dist/{runGemini-CYc9Ufxo.cjs → runGemini-BhIz1N_b.cjs} +11 -8
  24. package/dist/{runGemini-D4Af8oH1.mjs → runGemini-CihCRgcR.mjs} +11 -8
  25. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
- import { l as logger, q as encodeBase64, c as configuration, t as readCredentials, u as ensureSigningCredentials, r as readSettings, v as updateSettings, w as encodeBase64Url, m as delay, x as buildClientHeaders, y as decodeBase64, z as writeCredentialsLegacy, B as writeCredentialsDataKey, C as readDaemonState, D as HAPPY_CLOUD_DAEMON_PORT, E as clearDaemonState, F as packageJson, i as isAuthenticationRequiredError, G as acquireDaemonLock, I as writeDaemonState, A as ApiClient, J as releaseDaemonLock, K as validateProfileForAgent, L as getProfileEnvironmentVariables, M as clearCredentials, N as clearMachineId, O as readHappyOrgDispatchTruthSnapshot, P as processHappyOrgRepoRequests, Q as readHappyOrgRepoTaskBoard, R as HappyOrgTurnReportSchema, S as recordHappyOrgTurnReport, T as MessageContentSchema, U as buildSocketAuth, V as encrypt, H as HeadTailPreviewBuffer, W as getLatestDaemonLog } from './api-BhMVpzwg.mjs';
2
+ import { l as logger, q as encodeBase64, c as configuration, t as readCredentials, u as ensureSigningCredentials, r as readSettings, v as updateSettings, w as encodeBase64Url, m as delay, x as buildClientHeaders, y as decodeBase64, z as writeCredentialsLegacy, B as writeCredentialsDataKey, C as readDaemonState, D as HAPPY_CLOUD_DAEMON_PORT, E as clearDaemonState, F as packageJson, i as isAuthenticationRequiredError, G as buildSessionRuntimeIndex, I as acquireDaemonLock, J as writeDaemonState, A as ApiClient, K as releaseDaemonLock, L as validateProfileForAgent, M as getProfileEnvironmentVariables, N as clearCredentials, O as clearMachineId, P as readHappyOrgDispatchTruthSnapshot, Q as processHappyOrgRepoRequests, R as readHappyOrgRepoTaskBoard, S as HappyOrgTurnReportSchema, T as recordHappyOrgTurnReport, U as MessageContentSchema, V as buildSocketAuth, W as encrypt, H as HeadTailPreviewBuffer, X as getLatestDaemonLog } from './api-DTSpLLTK.mjs';
3
3
  import { z } from 'zod';
4
4
  import fs, { writeFile as writeFile$1, rename, unlink as unlink$1 } from 'fs/promises';
5
5
  import os$1, { homedir } from 'os';
@@ -11,7 +11,7 @@ import qrcode from 'qrcode-terminal';
11
11
  import { writeFile, unlink, readdir, readFile, mkdir } from 'node:fs/promises';
12
12
  import { createRequire } from 'node:module';
13
13
  import os, { tmpdir, homedir as homedir$1 } from 'node:os';
14
- import path, { join, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, delimiter, basename } from 'node:path';
14
+ import path, { join, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, delimiter, relative, basename } from 'node:path';
15
15
  import open from 'open';
16
16
  import React, { useState } from 'react';
17
17
  import { useInput, Box, Text, render } from 'ink';
@@ -2830,16 +2830,27 @@ function createSessionMetadata(opts) {
2830
2830
  };
2831
2831
  }
2832
2832
 
2833
+ function archiveManagedSessionWithObserver(opts) {
2834
+ if (!opts.userScopedObserver || !opts.sessionIndex) {
2835
+ return false;
2836
+ }
2837
+ return opts.userScopedObserver.syncSessionRuntimeIndex(opts.sessionId, {
2838
+ ...opts.sessionIndex,
2839
+ lifecycleState: "archived"
2840
+ }, {
2841
+ markInactive: true
2842
+ });
2843
+ }
2833
2844
  async function archiveManagedSessionById(opts) {
2834
2845
  try {
2835
- const sessionClient = opts.api.sessionSyncClient({ id: opts.sessionId });
2846
+ const sessionClient = opts.api.sessionSyncClient(opts.session);
2836
2847
  await closeProviderSession(sessionClient, {
2837
2848
  archiveReason: opts.archiveReason,
2838
2849
  archivedBy: "daemon"
2839
2850
  });
2840
2851
  } catch (error) {
2841
2852
  logger.debug(
2842
- `[DAEMON RUN] Failed to archive managed session ${opts.sessionId}: ${opts.archiveReason}`,
2853
+ `[DAEMON RUN] Failed to archive managed session ${opts.session.id}: ${opts.archiveReason}`,
2843
2854
  error
2844
2855
  );
2845
2856
  }
@@ -2868,7 +2879,7 @@ async function precreateDaemonManagedSession(opts) {
2868
2879
  async function archivePrecreatedManagedSession(opts) {
2869
2880
  await archiveManagedSessionById({
2870
2881
  api: opts.api,
2871
- sessionId: opts.session.id,
2882
+ session: opts.session,
2872
2883
  archiveReason: opts.archiveReason
2873
2884
  });
2874
2885
  }
@@ -2877,11 +2888,15 @@ async function archiveDetachedManagedSessionIfNeeded(opts) {
2877
2888
  if (trackedSession.startedBy !== "daemon" || !trackedSession.happySessionId || trackedSession.happySessionMetadataFromLocalWebhook || trackedSession.skipDetachedManagedSessionArchive) {
2878
2889
  return false;
2879
2890
  }
2880
- await archiveManagedSessionById({
2881
- api: opts.api,
2891
+ if (!archiveManagedSessionWithObserver({
2892
+ userScopedObserver: opts.userScopedObserver,
2882
2893
  sessionId: trackedSession.happySessionId,
2883
- archiveReason: opts.archiveReason
2884
- });
2894
+ sessionIndex: trackedSession.sessionIndex
2895
+ })) {
2896
+ logger.debug(
2897
+ `[DAEMON RUN] Detached managed session ${trackedSession.happySessionId} cannot be archived because runtime index sync is unavailable`
2898
+ );
2899
+ }
2885
2900
  return true;
2886
2901
  }
2887
2902
 
@@ -2959,6 +2974,7 @@ function createTrackedSessionFromRemoteIndexEntry(entry) {
2959
2974
  return {
2960
2975
  startedBy,
2961
2976
  happySessionId: entry.id,
2977
+ sessionIndex: entry.sessionIndex ?? null,
2962
2978
  pid: entry.sessionIndex?.hostPid ?? 0
2963
2979
  };
2964
2980
  }
@@ -2985,6 +3001,7 @@ async function recoverTrackedSessionsFromRemoteIndex({
2985
3001
  machineId,
2986
3002
  trackedSessionPids,
2987
3003
  trackSession,
3004
+ removeTrackedSession,
2988
3005
  userScopedObserver,
2989
3006
  lookupHappyProcessByPid = findHappyProcessByPid,
2990
3007
  archiveStaleSessions = true,
@@ -2999,7 +3016,13 @@ async function recoverTrackedSessionsFromRemoteIndex({
2999
3016
  for (const session of sessions) {
3000
3017
  const sessionIndex = session.sessionIndex;
3001
3018
  const pid = sessionIndex?.hostPid;
3002
- if (!sessionIndex || sessionIndex.machineId !== machineId || typeof pid !== "number" || sessionIndex.lifecycleState === "archived") {
3019
+ if (!sessionIndex || sessionIndex.machineId !== machineId || typeof pid !== "number") {
3020
+ continue;
3021
+ }
3022
+ if (sessionIndex.lifecycleState === "archived" || session.active === false) {
3023
+ if (alreadyTracked.has(pid)) {
3024
+ removeTrackedSession?.(pid, session.id);
3025
+ }
3003
3026
  continue;
3004
3027
  }
3005
3028
  if (alreadyTracked.has(pid)) {
@@ -3039,6 +3062,7 @@ async function recoverTrackedSessionsFromRemoteIndex({
3039
3062
  }
3040
3063
  const archived = await archiveStaleRemoteSession(userScopedObserver, session);
3041
3064
  if (archived) {
3065
+ removeTrackedSession?.(pid, session.id);
3042
3066
  archivedStaleCount++;
3043
3067
  } else {
3044
3068
  skippedStaleCount++;
@@ -3107,6 +3131,7 @@ function createTrackedSessionFromRegistryEntry(entry) {
3107
3131
  startedBy: metadata.startedBy === "daemon" ? "daemon" : "happy directly - likely by user from terminal",
3108
3132
  happySessionId: entry.sessionId,
3109
3133
  happySessionMetadataFromLocalWebhook: metadata,
3134
+ sessionIndex: buildSessionRuntimeIndex(metadata),
3110
3135
  pid: entry.pid
3111
3136
  };
3112
3137
  }
@@ -3499,11 +3524,13 @@ async function startDaemon() {
3499
3524
  const pidToTrackedSession = /* @__PURE__ */ new Map();
3500
3525
  const pidToAwaiter = /* @__PURE__ */ new Map();
3501
3526
  const getCurrentChildren = () => Array.from(pidToTrackedSession.values());
3527
+ let userScopedObserver = null;
3502
3528
  const removeTrackedSession = (pid, archiveReason) => {
3503
3529
  const trackedSession = pidToTrackedSession.get(pid);
3504
3530
  if (trackedSession && api) {
3505
3531
  void archiveDetachedManagedSessionIfNeeded({
3506
3532
  api,
3533
+ userScopedObserver,
3507
3534
  trackedSession,
3508
3535
  archiveReason
3509
3536
  });
@@ -3523,6 +3550,7 @@ async function startDaemon() {
3523
3550
  if (existingSession && existingSession.startedBy === "daemon") {
3524
3551
  existingSession.happySessionId = sessionId;
3525
3552
  existingSession.happySessionMetadataFromLocalWebhook = sessionMetadata;
3553
+ existingSession.sessionIndex = buildSessionRuntimeIndex(sessionMetadata);
3526
3554
  logger.debug(`[DAEMON RUN] Updated daemon-spawned session ${sessionId} with metadata`);
3527
3555
  const awaiter = pidToAwaiter.get(pid);
3528
3556
  if (awaiter) {
@@ -3538,6 +3566,7 @@ async function startDaemon() {
3538
3566
  startedBy: "happy directly - likely by user from terminal",
3539
3567
  happySessionId: sessionId,
3540
3568
  happySessionMetadataFromLocalWebhook: sessionMetadata,
3569
+ sessionIndex: buildSessionRuntimeIndex(sessionMetadata),
3541
3570
  pid
3542
3571
  };
3543
3572
  pidToTrackedSession.set(pid, trackedSession);
@@ -3696,6 +3725,7 @@ async function startDaemon() {
3696
3725
  requestedSessionId: options.sessionId,
3697
3726
  precreatedSessionId: precreatedCodexSession?.id
3698
3727
  }),
3728
+ sessionIndex: buildSessionRuntimeIndex(precreatedCodexSession?.metadata),
3699
3729
  skipDetachedManagedSessionArchive: reuseExistingManagedSession,
3700
3730
  pid: tmuxResult.pid,
3701
3731
  // Real PID from tmux -P flag
@@ -3840,6 +3870,7 @@ ${stderrSnapshot}`);
3840
3870
  requestedSessionId: options.sessionId,
3841
3871
  precreatedSessionId: precreatedCodexSession?.id
3842
3872
  }),
3873
+ sessionIndex: buildSessionRuntimeIndex(precreatedCodexSession?.metadata),
3843
3874
  skipDetachedManagedSessionArchive: reuseExistingManagedSession,
3844
3875
  pid: happyProcess.pid,
3845
3876
  childProcess: happyProcess,
@@ -4028,7 +4059,6 @@ ${stderrSnapshot}`);
4028
4059
  };
4029
4060
  api = await ApiClient.create(credentials);
4030
4061
  const activeApi = api;
4031
- let userScopedObserver = null;
4032
4062
  if (credentials.signing) {
4033
4063
  try {
4034
4064
  userScopedObserver = activeApi.userScopedObserverClient?.() ?? null;
@@ -4063,6 +4093,13 @@ ${stderrSnapshot}`);
4063
4093
  trackSession: (pid, trackedSession) => {
4064
4094
  pidToTrackedSession.set(pid, trackedSession);
4065
4095
  },
4096
+ removeTrackedSession: (pid, sessionId) => {
4097
+ const trackedSession = pidToTrackedSession.get(pid);
4098
+ if (trackedSession?.happySessionId === sessionId) {
4099
+ pidToTrackedSession.delete(pid);
4100
+ logger.debug(`[DAEMON RUN] Removed archived remote session ${sessionId} from tracking`);
4101
+ }
4102
+ },
4066
4103
  userScopedObserver,
4067
4104
  archiveStaleSessions: opts.archiveStaleSessions,
4068
4105
  skipArchivalSessionIds: pendingManagedRespawnSessionIds
@@ -8609,11 +8646,15 @@ class AcpBackend {
8609
8646
  transport;
8610
8647
  sessionPreferences;
8611
8648
  sessionConfigOptions = null;
8649
+ agentCapabilities = null;
8612
8650
  /** Keep a short rolling stderr buffer so startup failures can surface the real cause. */
8613
8651
  recentStderrLines = [];
8614
8652
  acpMaxMultilineStdoutBytes;
8615
8653
  oversizedStdoutNoticeEmittedForCurrentTurn = false;
8616
8654
  resourceCleanupDone = false;
8655
+ getProviderSessionId() {
8656
+ return this.acpSessionId;
8657
+ }
8617
8658
  recordRecentStderr(text) {
8618
8659
  const normalized = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
8619
8660
  if (normalized.length === 0) {
@@ -8650,6 +8691,14 @@ class AcpBackend {
8650
8691
  updateSessionConfigOptions(configOptions) {
8651
8692
  this.sessionConfigOptions = Array.isArray(configOptions) ? configOptions : null;
8652
8693
  }
8694
+ supportsLoadSession() {
8695
+ const capabilities = this.agentCapabilities;
8696
+ return capabilities?.loadSession === true;
8697
+ }
8698
+ supportsResumeSession() {
8699
+ const capabilities = this.agentCapabilities;
8700
+ return capabilities?.sessionCapabilities?.resume != null;
8701
+ }
8653
8702
  syncSessionConfigOptionsFromUpdate(update) {
8654
8703
  const configOptions = update.configOptions;
8655
8704
  if (!Array.isArray(configOptions)) {
@@ -9231,7 +9280,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9231
9280
  await delay(initDelayMs);
9232
9281
  }
9233
9282
  logger.debug(`[AcpBackend] Initializing connection (timeout: ${initTimeout}ms)...`);
9234
- await withRetry(
9283
+ const initializeResponse = await withRetry(
9235
9284
  async () => {
9236
9285
  let timeoutHandle = null;
9237
9286
  try {
@@ -9272,6 +9321,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9272
9321
  shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
9273
9322
  }
9274
9323
  );
9324
+ this.agentCapabilities = initializeResponse.agentCapabilities ?? null;
9275
9325
  logger.debug(`[AcpBackend] Initialize completed`);
9276
9326
  const mcpServers = this.options.mcpServers ? Object.entries(this.options.mcpServers).map(([name, config]) => ({
9277
9327
  name,
@@ -9283,7 +9333,21 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9283
9333
  cwd: this.options.cwd,
9284
9334
  mcpServers
9285
9335
  };
9286
- logger.debug(`[AcpBackend] Creating new session...`);
9336
+ const requestedResumeSessionId = typeof this.options.resumeSessionId === "string" && this.options.resumeSessionId.trim() ? this.options.resumeSessionId.trim() : null;
9337
+ const sessionOperation = requestedResumeSessionId && this.supportsResumeSession() ? "resume" : requestedResumeSessionId && this.supportsLoadSession() ? "load" : "new";
9338
+ const sessionRequest = sessionOperation === "resume" ? {
9339
+ cwd: this.options.cwd,
9340
+ mcpServers,
9341
+ sessionId: requestedResumeSessionId
9342
+ } : sessionOperation === "load" ? {
9343
+ cwd: this.options.cwd,
9344
+ mcpServers,
9345
+ sessionId: requestedResumeSessionId
9346
+ } : newSessionRequest;
9347
+ if (requestedResumeSessionId && sessionOperation === "new") {
9348
+ throw new Error("ACP agent does not support session resume/load; refusing to fork the Codex conversation");
9349
+ }
9350
+ logger.debug(`[AcpBackend] ${sessionOperation === "new" ? "Creating new" : `${sessionOperation === "resume" ? "Resuming" : "Loading"} existing`} session...`);
9287
9351
  const sessionResponse = await withRetry(
9288
9352
  async () => {
9289
9353
  let timeoutHandle = null;
@@ -9291,7 +9355,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9291
9355
  const result = await raceWithProcessExit(
9292
9356
  this.process,
9293
9357
  () => Promise.race([
9294
- this.connection.newSession(newSessionRequest).then((res) => {
9358
+ (sessionOperation === "resume" ? this.connection.resumeSession(sessionRequest) : sessionOperation === "load" ? this.connection.loadSession(sessionRequest) : this.connection.newSession(sessionRequest)).then((res) => {
9295
9359
  if (timeoutHandle) {
9296
9360
  clearTimeout(timeoutHandle);
9297
9361
  timeoutHandle = null;
@@ -9318,14 +9382,14 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
9318
9382
  }
9319
9383
  },
9320
9384
  {
9321
- operationName: "NewSession",
9385
+ operationName: sessionOperation === "resume" ? "ResumeSession" : sessionOperation === "load" ? "LoadSession" : "NewSession",
9322
9386
  maxAttempts: RETRY_CONFIG.maxAttempts,
9323
9387
  baseDelayMs: RETRY_CONFIG.baseDelayMs,
9324
9388
  maxDelayMs: RETRY_CONFIG.maxDelayMs,
9325
9389
  shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
9326
9390
  }
9327
9391
  );
9328
- this.acpSessionId = sessionResponse.sessionId;
9392
+ this.acpSessionId = requestedResumeSessionId ?? sessionResponse.sessionId;
9329
9393
  this.updateSessionConfigOptions(sessionResponse.configOptions);
9330
9394
  logger.debug(`[AcpBackend] Session created: ${this.acpSessionId}`);
9331
9395
  await this.applySessionConfigPresets();
@@ -10004,8 +10068,23 @@ function readCodexAcpConfigOverrides() {
10004
10068
  const raw = readFirstEnv("HAPPY_CODEX_ACP_CONFIG_OVERRIDES", "HAPPIER_CODEX_ACP_CONFIG_OVERRIDES");
10005
10069
  return raw.split("\n").map((line) => line.trim()).filter(Boolean);
10006
10070
  }
10071
+ function sanitizeCodexAcpBaseArgs(baseArgs = []) {
10072
+ const sanitized = [];
10073
+ for (let index = 0; index < baseArgs.length; index += 1) {
10074
+ const arg = baseArgs[index];
10075
+ if (arg === "--dangerously-bypass-approvals-and-sandbox" || arg === "--yolo" || arg.startsWith("--ask-for-approval=") || arg.startsWith("--approval-policy=") || arg.startsWith("--sandbox=")) {
10076
+ continue;
10077
+ }
10078
+ if (arg === "--ask-for-approval" || arg === "--approval-policy" || arg === "--sandbox") {
10079
+ index += 1;
10080
+ continue;
10081
+ }
10082
+ sanitized.push(arg);
10083
+ }
10084
+ return sanitized;
10085
+ }
10007
10086
  function buildCodexAcpConfigArgs(options) {
10008
- const args = [...options.baseArgs ?? []];
10087
+ const args = sanitizeCodexAcpBaseArgs(options.baseArgs);
10009
10088
  const overrides = [...readCodexAcpConfigOverrides()];
10010
10089
  if (options.model) {
10011
10090
  overrides.push(`model=${JSON.stringify(options.model)}`);
@@ -10134,6 +10213,9 @@ function resolveCodexExecutable() {
10134
10213
  }
10135
10214
  return "codex";
10136
10215
  }
10216
+ function shouldUseShellForCodex(executable) {
10217
+ return process.platform === "win32" && /\.(cmd|bat|ps1)$/i.test(executable);
10218
+ }
10137
10219
 
10138
10220
  const CODEX_HOME_SEED_FILES = [
10139
10221
  "auth.json",
@@ -10147,6 +10229,24 @@ const CODEX_HOME_SEED_DIRS = [
10147
10229
  ];
10148
10230
  const MAX_CODEX_SKILL_DESCRIPTION_LENGTH = 1024;
10149
10231
  const MANAGED_CODEX_HOME_PREFIX = "happy-codex-home-";
10232
+ function isPlainObject(value) {
10233
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10234
+ }
10235
+ function isApiKeyOnlyCodexAuth(value) {
10236
+ if (!isPlainObject(value)) {
10237
+ return false;
10238
+ }
10239
+ const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0 && entryValue !== null);
10240
+ return entries.length === 1 && typeof value.OPENAI_API_KEY === "string" && value.OPENAI_API_KEY.trim().length > 0;
10241
+ }
10242
+ function shouldUseSourceCodexHomeForMutableAuth(sourceHomeDir) {
10243
+ try {
10244
+ const auth = JSON.parse(readFileSync(join(sourceHomeDir, "auth.json"), "utf8"));
10245
+ return !isApiKeyOnlyCodexAuth(auth);
10246
+ } catch {
10247
+ return false;
10248
+ }
10249
+ }
10150
10250
  function getCodexPlatformTarget(platform, arch) {
10151
10251
  if (platform === "win32" && arch === "x64") {
10152
10252
  return {
@@ -10410,7 +10510,135 @@ function seedCodexSkillEntries(sourceSkillsDir, isolatedHomeDir, sourceLabel) {
10410
10510
  }
10411
10511
  }
10412
10512
  }
10413
- function seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir) {
10513
+ function isWithinDirectory(parentDir, childPath, platform) {
10514
+ const normalizedParent = normalizePathForComparison(parentDir, platform);
10515
+ const normalizedChild = normalizePathForComparison(childPath, platform);
10516
+ return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}/`);
10517
+ }
10518
+ function extractCodexSessionIdFromFilePath(filePath) {
10519
+ const match = filePath.match(/-([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\.jsonl$/);
10520
+ return match?.[1] ?? null;
10521
+ }
10522
+ function findCodexSessionFile(sourceHomeDir, resumeSessionId, platform) {
10523
+ const sessionsRoot = join(sourceHomeDir, "sessions");
10524
+ const stack = [sessionsRoot];
10525
+ let bestMatch = null;
10526
+ while (stack.length > 0) {
10527
+ const currentDir = stack.pop();
10528
+ let entries;
10529
+ try {
10530
+ entries = readdirSync(currentDir, { withFileTypes: true });
10531
+ } catch {
10532
+ continue;
10533
+ }
10534
+ for (const entry of entries) {
10535
+ const fullPath = join(currentDir, entry.name);
10536
+ if (!isWithinDirectory(sessionsRoot, fullPath, platform)) {
10537
+ continue;
10538
+ }
10539
+ if (entry.isDirectory()) {
10540
+ stack.push(fullPath);
10541
+ continue;
10542
+ }
10543
+ if (!entry.isFile() || extractCodexSessionIdFromFilePath(fullPath) !== resumeSessionId) {
10544
+ continue;
10545
+ }
10546
+ try {
10547
+ const mtimeMs = statSync(fullPath).mtimeMs;
10548
+ if (!bestMatch || mtimeMs > bestMatch.mtimeMs) {
10549
+ bestMatch = { path: fullPath, mtimeMs };
10550
+ }
10551
+ } catch {
10552
+ }
10553
+ }
10554
+ }
10555
+ return bestMatch?.path ?? null;
10556
+ }
10557
+ function seedCodexResumeSessionFile(sourceHomeDir, isolatedHomeDir, resumeSessionId, platform) {
10558
+ const normalizedResumeSessionId = typeof resumeSessionId === "string" && resumeSessionId.trim() ? resumeSessionId.trim() : null;
10559
+ if (!normalizedResumeSessionId) {
10560
+ return;
10561
+ }
10562
+ const sourceSessionFile = findCodexSessionFile(sourceHomeDir, normalizedResumeSessionId, platform);
10563
+ if (!sourceSessionFile) {
10564
+ logger.debug(`[codex] No source CODEX_HOME session file found for resume id ${normalizedResumeSessionId}`);
10565
+ return;
10566
+ }
10567
+ const sourceSessionsRoot = join(sourceHomeDir, "sessions");
10568
+ const relativeSessionPath = relative(sourceSessionsRoot, sourceSessionFile);
10569
+ if (!relativeSessionPath || relativeSessionPath.startsWith("..") || isAbsolute(relativeSessionPath)) {
10570
+ logger.debug(`[codex] Refusing to seed CODEX_HOME session outside sessions root: ${sourceSessionFile}`);
10571
+ return;
10572
+ }
10573
+ try {
10574
+ copyCodexHomeEntry(
10575
+ sourceSessionFile,
10576
+ join(isolatedHomeDir, "sessions", relativeSessionPath)
10577
+ );
10578
+ } catch (error) {
10579
+ logger.debug(`[codex] Failed to seed CODEX_HOME session file for ${normalizedResumeSessionId}`, error);
10580
+ }
10581
+ }
10582
+ function shouldSyncCodexSessionFileBack(sourcePath, destPath) {
10583
+ let sourceStat;
10584
+ try {
10585
+ sourceStat = statSync(sourcePath);
10586
+ } catch {
10587
+ return false;
10588
+ }
10589
+ if (!sourceStat.isFile()) {
10590
+ return false;
10591
+ }
10592
+ let destStat;
10593
+ try {
10594
+ destStat = statSync(destPath);
10595
+ } catch {
10596
+ return true;
10597
+ }
10598
+ return sourceStat.mtimeMs >= destStat.mtimeMs || sourceStat.size !== destStat.size;
10599
+ }
10600
+ function syncCodexSessionFilesBackToSource(isolatedHomeDir, sourceHomeDir, platform) {
10601
+ const isolatedSessionsRoot = join(isolatedHomeDir, "sessions");
10602
+ const sourceSessionsRoot = join(sourceHomeDir, "sessions");
10603
+ const stack = [isolatedSessionsRoot];
10604
+ while (stack.length > 0) {
10605
+ const currentDir = stack.pop();
10606
+ let entries;
10607
+ try {
10608
+ entries = readdirSync(currentDir, { withFileTypes: true });
10609
+ } catch {
10610
+ continue;
10611
+ }
10612
+ for (const entry of entries) {
10613
+ const fullPath = join(currentDir, entry.name);
10614
+ if (!isWithinDirectory(isolatedSessionsRoot, fullPath, platform)) {
10615
+ continue;
10616
+ }
10617
+ if (entry.isDirectory()) {
10618
+ stack.push(fullPath);
10619
+ continue;
10620
+ }
10621
+ if (!entry.isFile() || extractCodexSessionIdFromFilePath(fullPath) === null) {
10622
+ continue;
10623
+ }
10624
+ const relativeSessionPath = relative(isolatedSessionsRoot, fullPath);
10625
+ if (!relativeSessionPath || relativeSessionPath.startsWith("..") || isAbsolute(relativeSessionPath)) {
10626
+ logger.debug(`[codex] Refusing to sync CODEX_HOME session outside sessions root: ${fullPath}`);
10627
+ continue;
10628
+ }
10629
+ const destPath = join(sourceSessionsRoot, relativeSessionPath);
10630
+ if (!shouldSyncCodexSessionFileBack(fullPath, destPath)) {
10631
+ continue;
10632
+ }
10633
+ try {
10634
+ copyCodexHomeEntry(fullPath, destPath);
10635
+ } catch (error) {
10636
+ logger.debug(`[codex] Failed to sync CODEX_HOME session file back to source: ${fullPath}`, error);
10637
+ }
10638
+ }
10639
+ }
10640
+ }
10641
+ function seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir, resumeSessionId, platform) {
10414
10642
  if (existsSync(sourceHomeDir)) {
10415
10643
  for (const fileName of CODEX_HOME_SEED_FILES) {
10416
10644
  try {
@@ -10431,6 +10659,7 @@ function seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir)
10431
10659
  seedCodexSkillEntries(bundledSkillsDir, isolatedHomeDir, "bundled skills");
10432
10660
  }
10433
10661
  seedCodexSkillEntries(join(sourceHomeDir, "skills"), isolatedHomeDir, "source CODEX_HOME");
10662
+ seedCodexResumeSessionFile(sourceHomeDir, isolatedHomeDir, resumeSessionId, platform);
10434
10663
  }
10435
10664
  function prepareCodexAcpEnvironment(overrides = {}, options = {}) {
10436
10665
  const env = buildCodexAcpEnv(overrides, options);
@@ -10448,17 +10677,26 @@ function prepareCodexAcpEnvironment(overrides = {}, options = {}) {
10448
10677
  return { env };
10449
10678
  }
10450
10679
  }
10680
+ const sourceHomeDir = options.sourceHomeDir ?? join(homedir$1(), ".codex");
10681
+ const bundledSkillsDir = options.bundledSkillsDir ?? join(projectPath(), "skills");
10682
+ if (shouldUseSourceCodexHomeForMutableAuth(sourceHomeDir)) {
10683
+ logger.debug("[codex] Using source CODEX_HOME for mutable Codex auth credentials");
10684
+ env.CODEX_HOME = sourceHomeDir;
10685
+ return {
10686
+ env,
10687
+ codexHomePath: sourceHomeDir
10688
+ };
10689
+ }
10451
10690
  const tempDirFactory = options.tempDirFactory ?? mkdtempSync;
10452
10691
  const isolatedHomeDir = tempDirFactory(join(tmpdir(), "happy-codex-home-"));
10453
10692
  mkdirSync$1(isolatedHomeDir, { recursive: true });
10454
- const sourceHomeDir = options.sourceHomeDir ?? join(homedir$1(), ".codex");
10455
- const bundledSkillsDir = options.bundledSkillsDir ?? join(projectPath(), "skills");
10456
- seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir);
10693
+ seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir, options.resumeSessionId, platform);
10457
10694
  env.CODEX_HOME = isolatedHomeDir;
10458
10695
  return {
10459
10696
  env,
10460
10697
  codexHomePath: isolatedHomeDir,
10461
10698
  cleanup: () => {
10699
+ syncCodexSessionFilesBackToSource(isolatedHomeDir, sourceHomeDir, platform);
10462
10700
  rmSync(isolatedHomeDir, { recursive: true, force: true });
10463
10701
  }
10464
10702
  };
@@ -10491,6 +10729,8 @@ function createCodexBackend(options) {
10491
10729
  const preparedEnv = prepareCodexAcpEnvironment({
10492
10730
  ...options.env,
10493
10731
  NODE_ENV: "production"
10732
+ }, {
10733
+ resumeSessionId: options.resumeSessionId
10494
10734
  });
10495
10735
  const backendOptions = {
10496
10736
  agentName: "codex",
@@ -10501,7 +10741,8 @@ function createCodexBackend(options) {
10501
10741
  permissionHandler: options.permissionHandler,
10502
10742
  selectionHandler: options.selectionHandler,
10503
10743
  transportHandler: resolveCodexTransport(spawn.command),
10504
- resourceCleanup: preparedEnv.cleanup
10744
+ resourceCleanup: preparedEnv.cleanup,
10745
+ resumeSessionId: options.resumeSessionId
10505
10746
  };
10506
10747
  return {
10507
10748
  backend: new AcpBackend(backendOptions),
@@ -11935,14 +12176,14 @@ var launch = /*#__PURE__*/Object.freeze({
11935
12176
  const unifiedProviderExecutors = {
11936
12177
  claude: async (opts) => {
11937
12178
  const claudeOptions = opts.claudeOptions ?? {};
11938
- const { runClaude } = await import('./runClaude-BpwlCyVT.mjs');
12179
+ const { runClaude } = await import('./runClaude-CFeIMCY2.mjs');
11939
12180
  await runClaude(opts.credentials, {
11940
12181
  ...claudeOptions,
11941
12182
  startingMode: claudeOptions.startingMode ?? (claudeOptions.startedBy === "daemon" ? "remote" : void 0)
11942
12183
  });
11943
12184
  },
11944
12185
  codex: async (opts) => {
11945
- const { runCodex } = await import('./runCodex-BMNR2hNp.mjs');
12186
+ const { runCodex } = await import('./runCodex-ByjUfTyr.mjs');
11946
12187
  await runCodex({
11947
12188
  credentials: opts.credentials,
11948
12189
  startedBy: opts.startedBy,
@@ -11951,7 +12192,7 @@ const unifiedProviderExecutors = {
11951
12192
  });
11952
12193
  },
11953
12194
  gemini: async (opts) => {
11954
- const { runGemini } = await import('./runGemini-D4Af8oH1.mjs');
12195
+ const { runGemini } = await import('./runGemini-CihCRgcR.mjs');
11955
12196
  await runGemini({
11956
12197
  credentials: opts.credentials,
11957
12198
  startedBy: opts.startedBy
@@ -12034,7 +12275,7 @@ function shouldRunMainClaudeFlow(opts) {
12034
12275
  return;
12035
12276
  } else if (subcommand === "runtime") {
12036
12277
  if (args[1] === "providers") {
12037
- const { renderRuntimeProviders } = await import('./command-h3Rr4Abu.mjs');
12278
+ const { renderRuntimeProviders } = await import('./command-umgXYSY2.mjs');
12038
12279
  console.log(renderRuntimeProviders());
12039
12280
  return;
12040
12281
  }
@@ -12240,8 +12481,8 @@ function shouldRunMainClaudeFlow(opts) {
12240
12481
  const projectId = args[3];
12241
12482
  try {
12242
12483
  const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
12243
- const { readCredentials: readCredentials2 } = await import('./api-BhMVpzwg.mjs').then(function (n) { return n.X; });
12244
- const { ApiClient: ApiClient2 } = await import('./api-BhMVpzwg.mjs').then(function (n) { return n.Y; });
12484
+ const { readCredentials: readCredentials2 } = await import('./api-DTSpLLTK.mjs').then(function (n) { return n.Y; });
12485
+ const { ApiClient: ApiClient2 } = await import('./api-DTSpLLTK.mjs').then(function (n) { return n.Z; });
12245
12486
  let userEmail = void 0;
12246
12487
  try {
12247
12488
  const credentials = await readCredentials2();
@@ -12659,4 +12900,4 @@ ${chalk.bold("Examples:")}
12659
12900
  }
12660
12901
  }
12661
12902
 
12662
- export { AbortError as A, getEnvironmentInfo as B, startCaffeinate as C, ExitCodeError as E, Future as F, GEMINI_MODEL_ENV as G, PushableAsyncIterable as P, RuntimeShell as R, createSessionMetadata as a, closeProviderSession as b, createDefaultRuntimeShell as c, createGeminiBackend as d, stopCaffeinate as e, formatDisplayMessage as f, getInitialGeminiModel as g, createCodexBackend as h, readManagedSessionTag as i, resolveManagedSessionTag as j, initialMachineMetadata as k, resolveCanonicalToolNameV2 as l, isTerminalReferenceOnlyPayload as m, getProjectPath as n, claudeLocal as o, publishSessionRegistration as p, trimIdent as q, readGeminiLocalConfig as r, saveGeminiModelToConfig as s, truncateDisplayMessage as t, createClaudeBackend as u, validateCodexAcpSpawn as v, claudeCheckSession as w, projectPath as x, mapToClaudeMode as y, query as z };
12903
+ export { AcpBackend as A, mapToClaudeMode as B, query as C, AbortError as D, ExitCodeError as E, Future as F, GEMINI_MODEL_ENV as G, getEnvironmentInfo as H, startCaffeinate as I, PushableAsyncIterable as P, RuntimeShell as R, createSessionMetadata as a, closeProviderSession as b, createDefaultRuntimeShell as c, createGeminiBackend as d, stopCaffeinate as e, formatDisplayMessage as f, getInitialGeminiModel as g, createCodexBackend as h, resolveCodexExecutable as i, shouldUseShellForCodex as j, readManagedSessionTag as k, resolveManagedSessionTag as l, initialMachineMetadata as m, resolveCanonicalToolNameV2 as n, isTerminalReferenceOnlyPayload as o, publishSessionRegistration as p, getProjectPath as q, readGeminiLocalConfig as r, saveGeminiModelToConfig as s, truncateDisplayMessage as t, claudeLocal as u, validateCodexAcpSpawn as v, trimIdent as w, createClaudeBackend as x, claudeCheckSession as y, projectPath as z };