happy-imou-cloud 2.1.44 → 2.1.47
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/{BaseReasoningProcessor-CMyFNQ1O.cjs → BaseReasoningProcessor-CBbzF7oj.cjs} +2 -2
- package/dist/{BaseReasoningProcessor-DVSN7PCw.mjs → BaseReasoningProcessor-KXIi0QF_.mjs} +2 -2
- package/dist/{ProviderSelectionHandler-Dqa4j1pD.cjs → ProviderSelectionHandler-CJLlwlAu.cjs} +2 -2
- package/dist/{ProviderSelectionHandler-2IaDlDBx.mjs → ProviderSelectionHandler-DzYObYrV.mjs} +2 -2
- package/dist/{api-BoWVQeVe.cjs → api-CVuTajTL.cjs} +104 -1
- package/dist/{api-BhMVpzwg.mjs → api-D3vYIva3.mjs} +104 -2
- package/dist/{command-DoF8oaxg.cjs → command-BZRQuZsh.cjs} +2 -3
- package/dist/{command-h3Rr4Abu.mjs → command-fcJ-4Yq3.mjs} +2 -3
- package/dist/{index-DxF1W0nt.mjs → index-Cp1I5I3U.mjs} +345 -59
- package/dist/{index-kIN8gN9G.cjs → index-CyW9A7hx.cjs} +323 -53
- package/dist/index.cjs +2 -3
- package/dist/index.mjs +2 -3
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +86 -86
- package/dist/lib.d.mts +86 -86
- package/dist/lib.mjs +1 -1
- package/dist/{registerKillSessionHandler-CBm2WFM0.cjs → registerKillSessionHandler-8C_Wrgor.cjs} +10 -5
- package/dist/{registerKillSessionHandler-Dsg63Cx6.mjs → registerKillSessionHandler-OhhMUuCQ.mjs} +10 -6
- package/dist/{runClaude-BpwlCyVT.mjs → runClaude-BviM1Wl5.mjs} +11 -9
- package/dist/{runClaude-Dq9OISKt.cjs → runClaude-CfdT_ccS.cjs} +11 -9
- package/dist/{runCodex-BnzErOK_.cjs → runCodex-B-t0yy4k.cjs} +496 -60
- package/dist/{runCodex-BMNR2hNp.mjs → runCodex-Dx3osc7U.mjs} +496 -60
- package/dist/{runGemini-D4Af8oH1.mjs → runGemini-CnJ75Q--.mjs} +11 -9
- package/dist/{runGemini-CYc9Ufxo.cjs → runGemini-DZ5-uzB9.cjs} +11 -9
- package/package.json +1 -1
|
@@ -1,28 +1,27 @@
|
|
|
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
|
|
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-D3vYIva3.mjs';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import fs, { writeFile as writeFile$1, rename, unlink as unlink$1 } from 'fs/promises';
|
|
5
|
-
import os$1, { homedir } from 'os';
|
|
6
|
-
import * as tmp from 'tmp';
|
|
5
|
+
import os$1, { homedir as homedir$1 } from 'os';
|
|
7
6
|
import { randomUUID, randomBytes, createCipheriv } from 'node:crypto';
|
|
8
7
|
import tweetnacl from 'tweetnacl';
|
|
9
8
|
import axios from 'axios';
|
|
10
9
|
import qrcode from 'qrcode-terminal';
|
|
11
10
|
import { writeFile, unlink, readdir, readFile, mkdir } from 'node:fs/promises';
|
|
12
11
|
import { createRequire } from 'node:module';
|
|
13
|
-
import os, { tmpdir, homedir
|
|
14
|
-
import path, { join, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, delimiter, basename } from 'node:path';
|
|
12
|
+
import os, { tmpdir, homedir } from 'node:os';
|
|
13
|
+
import path, { join, resolve as resolve$1, dirname as dirname$1, normalize, isAbsolute, delimiter, relative, basename } from 'node:path';
|
|
15
14
|
import open from 'open';
|
|
16
15
|
import React, { useState } from 'react';
|
|
17
16
|
import { useInput, Box, Text, render } from 'ink';
|
|
18
17
|
import { spawn, execSync, exec } from 'child_process';
|
|
19
18
|
import { dirname, resolve, join as join$1 } from 'path';
|
|
20
19
|
import { fileURLToPath } from 'url';
|
|
21
|
-
import { readFileSync as readFileSync$1, existsSync as existsSync$1, writeFileSync, chmodSync, unlinkSync as unlinkSync$1, mkdirSync } from 'fs';
|
|
20
|
+
import { readFileSync as readFileSync$1, existsSync as existsSync$1, writeFileSync as writeFileSync$1, chmodSync, unlinkSync as unlinkSync$1, mkdirSync as mkdirSync$1 } from 'fs';
|
|
22
21
|
import { execFileSync, spawn as spawn$2, execSync as execSync$1 } from 'node:child_process';
|
|
23
22
|
import psList from 'ps-list';
|
|
24
23
|
import spawn$1 from 'cross-spawn';
|
|
25
|
-
import fs$1, { existsSync, readFileSync, readdirSync, statSync, unlinkSync,
|
|
24
|
+
import fs$1, { existsSync, readFileSync, readdirSync, statSync, unlinkSync, mkdirSync, writeFileSync, cpSync, rmSync, mkdtempSync, realpathSync } from 'node:fs';
|
|
26
25
|
import fastify from 'fastify';
|
|
27
26
|
import { validatorCompiler, serializerCompiler } from 'fastify-type-provider-zod';
|
|
28
27
|
import { randomUUID as randomUUID$1, randomBytes as randomBytes$1, createHash } from 'crypto';
|
|
@@ -2830,16 +2829,27 @@ function createSessionMetadata(opts) {
|
|
|
2830
2829
|
};
|
|
2831
2830
|
}
|
|
2832
2831
|
|
|
2832
|
+
function archiveManagedSessionWithObserver(opts) {
|
|
2833
|
+
if (!opts.userScopedObserver || !opts.sessionIndex) {
|
|
2834
|
+
return false;
|
|
2835
|
+
}
|
|
2836
|
+
return opts.userScopedObserver.syncSessionRuntimeIndex(opts.sessionId, {
|
|
2837
|
+
...opts.sessionIndex,
|
|
2838
|
+
lifecycleState: "archived"
|
|
2839
|
+
}, {
|
|
2840
|
+
markInactive: true
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2833
2843
|
async function archiveManagedSessionById(opts) {
|
|
2834
2844
|
try {
|
|
2835
|
-
const sessionClient = opts.api.sessionSyncClient(
|
|
2845
|
+
const sessionClient = opts.api.sessionSyncClient(opts.session);
|
|
2836
2846
|
await closeProviderSession(sessionClient, {
|
|
2837
2847
|
archiveReason: opts.archiveReason,
|
|
2838
2848
|
archivedBy: "daemon"
|
|
2839
2849
|
});
|
|
2840
2850
|
} catch (error) {
|
|
2841
2851
|
logger.debug(
|
|
2842
|
-
`[DAEMON RUN] Failed to archive managed session ${opts.
|
|
2852
|
+
`[DAEMON RUN] Failed to archive managed session ${opts.session.id}: ${opts.archiveReason}`,
|
|
2843
2853
|
error
|
|
2844
2854
|
);
|
|
2845
2855
|
}
|
|
@@ -2868,7 +2878,7 @@ async function precreateDaemonManagedSession(opts) {
|
|
|
2868
2878
|
async function archivePrecreatedManagedSession(opts) {
|
|
2869
2879
|
await archiveManagedSessionById({
|
|
2870
2880
|
api: opts.api,
|
|
2871
|
-
|
|
2881
|
+
session: opts.session,
|
|
2872
2882
|
archiveReason: opts.archiveReason
|
|
2873
2883
|
});
|
|
2874
2884
|
}
|
|
@@ -2877,11 +2887,15 @@ async function archiveDetachedManagedSessionIfNeeded(opts) {
|
|
|
2877
2887
|
if (trackedSession.startedBy !== "daemon" || !trackedSession.happySessionId || trackedSession.happySessionMetadataFromLocalWebhook || trackedSession.skipDetachedManagedSessionArchive) {
|
|
2878
2888
|
return false;
|
|
2879
2889
|
}
|
|
2880
|
-
|
|
2881
|
-
|
|
2890
|
+
if (!archiveManagedSessionWithObserver({
|
|
2891
|
+
userScopedObserver: opts.userScopedObserver,
|
|
2882
2892
|
sessionId: trackedSession.happySessionId,
|
|
2883
|
-
|
|
2884
|
-
})
|
|
2893
|
+
sessionIndex: trackedSession.sessionIndex
|
|
2894
|
+
})) {
|
|
2895
|
+
logger.debug(
|
|
2896
|
+
`[DAEMON RUN] Detached managed session ${trackedSession.happySessionId} cannot be archived because runtime index sync is unavailable`
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2885
2899
|
return true;
|
|
2886
2900
|
}
|
|
2887
2901
|
|
|
@@ -2959,6 +2973,7 @@ function createTrackedSessionFromRemoteIndexEntry(entry) {
|
|
|
2959
2973
|
return {
|
|
2960
2974
|
startedBy,
|
|
2961
2975
|
happySessionId: entry.id,
|
|
2976
|
+
sessionIndex: entry.sessionIndex ?? null,
|
|
2962
2977
|
pid: entry.sessionIndex?.hostPid ?? 0
|
|
2963
2978
|
};
|
|
2964
2979
|
}
|
|
@@ -2985,6 +3000,7 @@ async function recoverTrackedSessionsFromRemoteIndex({
|
|
|
2985
3000
|
machineId,
|
|
2986
3001
|
trackedSessionPids,
|
|
2987
3002
|
trackSession,
|
|
3003
|
+
removeTrackedSession,
|
|
2988
3004
|
userScopedObserver,
|
|
2989
3005
|
lookupHappyProcessByPid = findHappyProcessByPid,
|
|
2990
3006
|
archiveStaleSessions = true,
|
|
@@ -2999,7 +3015,13 @@ async function recoverTrackedSessionsFromRemoteIndex({
|
|
|
2999
3015
|
for (const session of sessions) {
|
|
3000
3016
|
const sessionIndex = session.sessionIndex;
|
|
3001
3017
|
const pid = sessionIndex?.hostPid;
|
|
3002
|
-
if (!sessionIndex || sessionIndex.machineId !== machineId || typeof pid !== "number"
|
|
3018
|
+
if (!sessionIndex || sessionIndex.machineId !== machineId || typeof pid !== "number") {
|
|
3019
|
+
continue;
|
|
3020
|
+
}
|
|
3021
|
+
if (sessionIndex.lifecycleState === "archived" || session.active === false) {
|
|
3022
|
+
if (alreadyTracked.has(pid)) {
|
|
3023
|
+
removeTrackedSession?.(pid, session.id);
|
|
3024
|
+
}
|
|
3003
3025
|
continue;
|
|
3004
3026
|
}
|
|
3005
3027
|
if (alreadyTracked.has(pid)) {
|
|
@@ -3039,6 +3061,7 @@ async function recoverTrackedSessionsFromRemoteIndex({
|
|
|
3039
3061
|
}
|
|
3040
3062
|
const archived = await archiveStaleRemoteSession(userScopedObserver, session);
|
|
3041
3063
|
if (archived) {
|
|
3064
|
+
removeTrackedSession?.(pid, session.id);
|
|
3042
3065
|
archivedStaleCount++;
|
|
3043
3066
|
} else {
|
|
3044
3067
|
skippedStaleCount++;
|
|
@@ -3107,6 +3130,7 @@ function createTrackedSessionFromRegistryEntry(entry) {
|
|
|
3107
3130
|
startedBy: metadata.startedBy === "daemon" ? "daemon" : "happy directly - likely by user from terminal",
|
|
3108
3131
|
happySessionId: entry.sessionId,
|
|
3109
3132
|
happySessionMetadataFromLocalWebhook: metadata,
|
|
3133
|
+
sessionIndex: buildSessionRuntimeIndex(metadata),
|
|
3110
3134
|
pid: entry.pid
|
|
3111
3135
|
};
|
|
3112
3136
|
}
|
|
@@ -3384,6 +3408,50 @@ function resolveTrackedHappySessionId(opts) {
|
|
|
3384
3408
|
return opts.precreatedSessionId ?? opts.requestedSessionId;
|
|
3385
3409
|
}
|
|
3386
3410
|
|
|
3411
|
+
const CODEX_HOME_CONFIG_FILES = [
|
|
3412
|
+
"config.toml",
|
|
3413
|
+
"cap_sid",
|
|
3414
|
+
"version.json",
|
|
3415
|
+
"MEMORY.md"
|
|
3416
|
+
];
|
|
3417
|
+
const CODEX_HOME_CONFIG_DIRS = [
|
|
3418
|
+
"rules",
|
|
3419
|
+
"skills"
|
|
3420
|
+
];
|
|
3421
|
+
function copyCodexHomeEntry$1(sourcePath, destPath) {
|
|
3422
|
+
if (!existsSync(sourcePath)) {
|
|
3423
|
+
return;
|
|
3424
|
+
}
|
|
3425
|
+
mkdirSync(dirname$1(destPath), { recursive: true });
|
|
3426
|
+
cpSync(sourcePath, destPath, {
|
|
3427
|
+
recursive: true,
|
|
3428
|
+
force: true,
|
|
3429
|
+
dereference: false,
|
|
3430
|
+
verbatimSymlinks: true
|
|
3431
|
+
});
|
|
3432
|
+
}
|
|
3433
|
+
function createDaemonCodexAuthHome(options) {
|
|
3434
|
+
const sourceHomeDir = options.sourceHomeDir ?? join(homedir(), ".codex");
|
|
3435
|
+
const targetHomeDir = options.tempDir;
|
|
3436
|
+
mkdirSync(targetHomeDir, { recursive: true });
|
|
3437
|
+
for (const fileName of CODEX_HOME_CONFIG_FILES) {
|
|
3438
|
+
try {
|
|
3439
|
+
copyCodexHomeEntry$1(join(sourceHomeDir, fileName), join(targetHomeDir, fileName));
|
|
3440
|
+
} catch (error) {
|
|
3441
|
+
logger.debug(`[codex] Failed to copy source CODEX_HOME file ${fileName} into daemon auth home`, error);
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
for (const dirName of CODEX_HOME_CONFIG_DIRS) {
|
|
3445
|
+
try {
|
|
3446
|
+
copyCodexHomeEntry$1(join(sourceHomeDir, dirName), join(targetHomeDir, dirName));
|
|
3447
|
+
} catch (error) {
|
|
3448
|
+
logger.debug(`[codex] Failed to copy source CODEX_HOME directory ${dirName} into daemon auth home`, error);
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
writeFileSync(join(targetHomeDir, "auth.json"), options.authJson, "utf8");
|
|
3452
|
+
return targetHomeDir;
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3387
3455
|
const DEFAULT_SESSION_WEBHOOK_TIMEOUT_MS = 45e3;
|
|
3388
3456
|
const DEFAULT_TRACKED_SESSION_SWEEP_INTERVAL_MS = 5e3;
|
|
3389
3457
|
function resolveSessionWebhookTimeoutMs() {
|
|
@@ -3499,11 +3567,13 @@ async function startDaemon() {
|
|
|
3499
3567
|
const pidToTrackedSession = /* @__PURE__ */ new Map();
|
|
3500
3568
|
const pidToAwaiter = /* @__PURE__ */ new Map();
|
|
3501
3569
|
const getCurrentChildren = () => Array.from(pidToTrackedSession.values());
|
|
3570
|
+
let userScopedObserver = null;
|
|
3502
3571
|
const removeTrackedSession = (pid, archiveReason) => {
|
|
3503
3572
|
const trackedSession = pidToTrackedSession.get(pid);
|
|
3504
3573
|
if (trackedSession && api) {
|
|
3505
3574
|
void archiveDetachedManagedSessionIfNeeded({
|
|
3506
3575
|
api,
|
|
3576
|
+
userScopedObserver,
|
|
3507
3577
|
trackedSession,
|
|
3508
3578
|
archiveReason
|
|
3509
3579
|
});
|
|
@@ -3523,6 +3593,7 @@ async function startDaemon() {
|
|
|
3523
3593
|
if (existingSession && existingSession.startedBy === "daemon") {
|
|
3524
3594
|
existingSession.happySessionId = sessionId;
|
|
3525
3595
|
existingSession.happySessionMetadataFromLocalWebhook = sessionMetadata;
|
|
3596
|
+
existingSession.sessionIndex = buildSessionRuntimeIndex(sessionMetadata);
|
|
3526
3597
|
logger.debug(`[DAEMON RUN] Updated daemon-spawned session ${sessionId} with metadata`);
|
|
3527
3598
|
const awaiter = pidToAwaiter.get(pid);
|
|
3528
3599
|
if (awaiter) {
|
|
@@ -3538,6 +3609,7 @@ async function startDaemon() {
|
|
|
3538
3609
|
startedBy: "happy directly - likely by user from terminal",
|
|
3539
3610
|
happySessionId: sessionId,
|
|
3540
3611
|
happySessionMetadataFromLocalWebhook: sessionMetadata,
|
|
3612
|
+
sessionIndex: buildSessionRuntimeIndex(sessionMetadata),
|
|
3541
3613
|
pid
|
|
3542
3614
|
};
|
|
3543
3615
|
pidToTrackedSession.set(pid, trackedSession);
|
|
@@ -3590,9 +3662,11 @@ async function startDaemon() {
|
|
|
3590
3662
|
const authEnv = {};
|
|
3591
3663
|
if (options.token) {
|
|
3592
3664
|
if (options.agent === "codex") {
|
|
3593
|
-
const codexHomeDir =
|
|
3594
|
-
|
|
3595
|
-
|
|
3665
|
+
const codexHomeDir = await fs.mkdtemp(join$1(os$1.tmpdir(), "happy-codex-daemon-home-"));
|
|
3666
|
+
authEnv.CODEX_HOME = createDaemonCodexAuthHome({
|
|
3667
|
+
authJson: options.token,
|
|
3668
|
+
tempDir: codexHomeDir
|
|
3669
|
+
});
|
|
3596
3670
|
} else {
|
|
3597
3671
|
authEnv.CLAUDE_CODE_OAUTH_TOKEN = options.token;
|
|
3598
3672
|
}
|
|
@@ -3696,6 +3770,7 @@ async function startDaemon() {
|
|
|
3696
3770
|
requestedSessionId: options.sessionId,
|
|
3697
3771
|
precreatedSessionId: precreatedCodexSession?.id
|
|
3698
3772
|
}),
|
|
3773
|
+
sessionIndex: buildSessionRuntimeIndex(precreatedCodexSession?.metadata),
|
|
3699
3774
|
skipDetachedManagedSessionArchive: reuseExistingManagedSession,
|
|
3700
3775
|
pid: tmuxResult.pid,
|
|
3701
3776
|
// Real PID from tmux -P flag
|
|
@@ -3840,6 +3915,7 @@ ${stderrSnapshot}`);
|
|
|
3840
3915
|
requestedSessionId: options.sessionId,
|
|
3841
3916
|
precreatedSessionId: precreatedCodexSession?.id
|
|
3842
3917
|
}),
|
|
3918
|
+
sessionIndex: buildSessionRuntimeIndex(precreatedCodexSession?.metadata),
|
|
3843
3919
|
skipDetachedManagedSessionArchive: reuseExistingManagedSession,
|
|
3844
3920
|
pid: happyProcess.pid,
|
|
3845
3921
|
childProcess: happyProcess,
|
|
@@ -4028,7 +4104,6 @@ ${stderrSnapshot}`);
|
|
|
4028
4104
|
};
|
|
4029
4105
|
api = await ApiClient.create(credentials);
|
|
4030
4106
|
const activeApi = api;
|
|
4031
|
-
let userScopedObserver = null;
|
|
4032
4107
|
if (credentials.signing) {
|
|
4033
4108
|
try {
|
|
4034
4109
|
userScopedObserver = activeApi.userScopedObserverClient?.() ?? null;
|
|
@@ -4063,6 +4138,13 @@ ${stderrSnapshot}`);
|
|
|
4063
4138
|
trackSession: (pid, trackedSession) => {
|
|
4064
4139
|
pidToTrackedSession.set(pid, trackedSession);
|
|
4065
4140
|
},
|
|
4141
|
+
removeTrackedSession: (pid, sessionId) => {
|
|
4142
|
+
const trackedSession = pidToTrackedSession.get(pid);
|
|
4143
|
+
if (trackedSession?.happySessionId === sessionId) {
|
|
4144
|
+
pidToTrackedSession.delete(pid);
|
|
4145
|
+
logger.debug(`[DAEMON RUN] Removed archived remote session ${sessionId} from tracking`);
|
|
4146
|
+
}
|
|
4147
|
+
},
|
|
4066
4148
|
userScopedObserver,
|
|
4067
4149
|
archiveStaleSessions: opts.archiveStaleSessions,
|
|
4068
4150
|
skipArchivalSessionIds: pendingManagedRespawnSessionIds
|
|
@@ -4300,7 +4382,7 @@ async function install$1() {
|
|
|
4300
4382
|
</dict>
|
|
4301
4383
|
</plist>
|
|
4302
4384
|
`);
|
|
4303
|
-
writeFileSync(PLIST_FILE$1, plistContent);
|
|
4385
|
+
writeFileSync$1(PLIST_FILE$1, plistContent);
|
|
4304
4386
|
chmodSync(PLIST_FILE$1, 420);
|
|
4305
4387
|
logger.info(`Created daemon plist at ${PLIST_FILE$1}`);
|
|
4306
4388
|
execSync(`launchctl load ${PLIST_FILE$1}`, { stdio: "inherit" });
|
|
@@ -5153,10 +5235,10 @@ async function handleConnectStatus() {
|
|
|
5153
5235
|
}
|
|
5154
5236
|
function updateLocalGeminiCredentials(tokens) {
|
|
5155
5237
|
try {
|
|
5156
|
-
const geminiDir = join$1(homedir(), ".gemini");
|
|
5238
|
+
const geminiDir = join$1(homedir$1(), ".gemini");
|
|
5157
5239
|
const credentialsPath = join$1(geminiDir, "oauth_creds.json");
|
|
5158
5240
|
if (!existsSync$1(geminiDir)) {
|
|
5159
|
-
mkdirSync(geminiDir, { recursive: true });
|
|
5241
|
+
mkdirSync$1(geminiDir, { recursive: true });
|
|
5160
5242
|
}
|
|
5161
5243
|
const credentials = {
|
|
5162
5244
|
access_token: tokens.access_token,
|
|
@@ -5166,7 +5248,7 @@ function updateLocalGeminiCredentials(tokens) {
|
|
|
5166
5248
|
...tokens.id_token && { id_token: tokens.id_token },
|
|
5167
5249
|
...tokens.expires_in && { expires_in: tokens.expires_in }
|
|
5168
5250
|
};
|
|
5169
|
-
writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), "utf-8");
|
|
5251
|
+
writeFileSync$1(credentialsPath, JSON.stringify(credentials, null, 2), "utf-8");
|
|
5170
5252
|
console.log(chalk.gray(` Updated local credentials: ${credentialsPath}`));
|
|
5171
5253
|
} catch (error) {
|
|
5172
5254
|
console.log(chalk.yellow(` \u26A0\uFE0F Could not update local credentials: ${error}`));
|
|
@@ -6074,7 +6156,7 @@ function getProjectPath(workingDirectory, claudeConfigDirOverride) {
|
|
|
6074
6156
|
const projectId = resolve$1(workingDirectory).replace(/[^a-zA-Z0-9-]/g, "-");
|
|
6075
6157
|
const claudeConfigDirRaw = process.env.CLAUDE_CONFIG_DIR ?? "";
|
|
6076
6158
|
const claudeConfigDirTrimmed = claudeConfigDirRaw.trim();
|
|
6077
|
-
const claudeConfigDir = claudeConfigDirTrimmed ? claudeConfigDirTrimmed : join(homedir
|
|
6159
|
+
const claudeConfigDir = claudeConfigDirTrimmed ? claudeConfigDirTrimmed : join(homedir(), ".claude");
|
|
6078
6160
|
return join(claudeConfigDir, "projects", projectId);
|
|
6079
6161
|
}
|
|
6080
6162
|
|
|
@@ -6139,7 +6221,7 @@ class ExitCodeError extends Error {
|
|
|
6139
6221
|
const claudeCliPath = resolve$1(join(projectPath(), "scripts", "claude_local_launcher.cjs"));
|
|
6140
6222
|
async function claudeLocal(opts) {
|
|
6141
6223
|
const projectDir = getProjectPath(opts.path);
|
|
6142
|
-
mkdirSync
|
|
6224
|
+
mkdirSync(projectDir, { recursive: true });
|
|
6143
6225
|
const hasContinueFlag = opts.claudeArgs?.includes("--continue");
|
|
6144
6226
|
const hasResumeFlag = opts.claudeArgs?.includes("--resume");
|
|
6145
6227
|
const hasUserSessionControl = hasContinueFlag || hasResumeFlag;
|
|
@@ -8609,11 +8691,15 @@ class AcpBackend {
|
|
|
8609
8691
|
transport;
|
|
8610
8692
|
sessionPreferences;
|
|
8611
8693
|
sessionConfigOptions = null;
|
|
8694
|
+
agentCapabilities = null;
|
|
8612
8695
|
/** Keep a short rolling stderr buffer so startup failures can surface the real cause. */
|
|
8613
8696
|
recentStderrLines = [];
|
|
8614
8697
|
acpMaxMultilineStdoutBytes;
|
|
8615
8698
|
oversizedStdoutNoticeEmittedForCurrentTurn = false;
|
|
8616
8699
|
resourceCleanupDone = false;
|
|
8700
|
+
getProviderSessionId() {
|
|
8701
|
+
return this.acpSessionId;
|
|
8702
|
+
}
|
|
8617
8703
|
recordRecentStderr(text) {
|
|
8618
8704
|
const normalized = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
8619
8705
|
if (normalized.length === 0) {
|
|
@@ -8650,6 +8736,14 @@ class AcpBackend {
|
|
|
8650
8736
|
updateSessionConfigOptions(configOptions) {
|
|
8651
8737
|
this.sessionConfigOptions = Array.isArray(configOptions) ? configOptions : null;
|
|
8652
8738
|
}
|
|
8739
|
+
supportsLoadSession() {
|
|
8740
|
+
const capabilities = this.agentCapabilities;
|
|
8741
|
+
return capabilities?.loadSession === true;
|
|
8742
|
+
}
|
|
8743
|
+
supportsResumeSession() {
|
|
8744
|
+
const capabilities = this.agentCapabilities;
|
|
8745
|
+
return capabilities?.sessionCapabilities?.resume != null;
|
|
8746
|
+
}
|
|
8653
8747
|
syncSessionConfigOptionsFromUpdate(update) {
|
|
8654
8748
|
const configOptions = update.configOptions;
|
|
8655
8749
|
if (!Array.isArray(configOptions)) {
|
|
@@ -9231,7 +9325,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
|
|
|
9231
9325
|
await delay(initDelayMs);
|
|
9232
9326
|
}
|
|
9233
9327
|
logger.debug(`[AcpBackend] Initializing connection (timeout: ${initTimeout}ms)...`);
|
|
9234
|
-
await withRetry(
|
|
9328
|
+
const initializeResponse = await withRetry(
|
|
9235
9329
|
async () => {
|
|
9236
9330
|
let timeoutHandle = null;
|
|
9237
9331
|
try {
|
|
@@ -9272,6 +9366,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
|
|
|
9272
9366
|
shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
|
|
9273
9367
|
}
|
|
9274
9368
|
);
|
|
9369
|
+
this.agentCapabilities = initializeResponse.agentCapabilities ?? null;
|
|
9275
9370
|
logger.debug(`[AcpBackend] Initialize completed`);
|
|
9276
9371
|
const mcpServers = this.options.mcpServers ? Object.entries(this.options.mcpServers).map(([name, config]) => ({
|
|
9277
9372
|
name,
|
|
@@ -9283,7 +9378,21 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
|
|
|
9283
9378
|
cwd: this.options.cwd,
|
|
9284
9379
|
mcpServers
|
|
9285
9380
|
};
|
|
9286
|
-
|
|
9381
|
+
const requestedResumeSessionId = typeof this.options.resumeSessionId === "string" && this.options.resumeSessionId.trim() ? this.options.resumeSessionId.trim() : null;
|
|
9382
|
+
const sessionOperation = requestedResumeSessionId && this.supportsResumeSession() ? "resume" : requestedResumeSessionId && this.supportsLoadSession() ? "load" : "new";
|
|
9383
|
+
const sessionRequest = sessionOperation === "resume" ? {
|
|
9384
|
+
cwd: this.options.cwd,
|
|
9385
|
+
mcpServers,
|
|
9386
|
+
sessionId: requestedResumeSessionId
|
|
9387
|
+
} : sessionOperation === "load" ? {
|
|
9388
|
+
cwd: this.options.cwd,
|
|
9389
|
+
mcpServers,
|
|
9390
|
+
sessionId: requestedResumeSessionId
|
|
9391
|
+
} : newSessionRequest;
|
|
9392
|
+
if (requestedResumeSessionId && sessionOperation === "new") {
|
|
9393
|
+
throw new Error("ACP agent does not support session resume/load; refusing to fork the Codex conversation");
|
|
9394
|
+
}
|
|
9395
|
+
logger.debug(`[AcpBackend] ${sessionOperation === "new" ? "Creating new" : `${sessionOperation === "resume" ? "Resuming" : "Loading"} existing`} session...`);
|
|
9287
9396
|
const sessionResponse = await withRetry(
|
|
9288
9397
|
async () => {
|
|
9289
9398
|
let timeoutHandle = null;
|
|
@@ -9291,7 +9400,7 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
|
|
|
9291
9400
|
const result = await raceWithProcessExit(
|
|
9292
9401
|
this.process,
|
|
9293
9402
|
() => Promise.race([
|
|
9294
|
-
this.connection.newSession(
|
|
9403
|
+
(sessionOperation === "resume" ? this.connection.resumeSession(sessionRequest) : sessionOperation === "load" ? this.connection.loadSession(sessionRequest) : this.connection.newSession(sessionRequest)).then((res) => {
|
|
9295
9404
|
if (timeoutHandle) {
|
|
9296
9405
|
clearTimeout(timeoutHandle);
|
|
9297
9406
|
timeoutHandle = null;
|
|
@@ -9318,14 +9427,14 @@ Recent stderr: ${recentStderrSummaryLine}` : `Signal: ${signal}`;
|
|
|
9318
9427
|
}
|
|
9319
9428
|
},
|
|
9320
9429
|
{
|
|
9321
|
-
operationName: "NewSession",
|
|
9430
|
+
operationName: sessionOperation === "resume" ? "ResumeSession" : sessionOperation === "load" ? "LoadSession" : "NewSession",
|
|
9322
9431
|
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
9323
9432
|
baseDelayMs: RETRY_CONFIG.baseDelayMs,
|
|
9324
9433
|
maxDelayMs: RETRY_CONFIG.maxDelayMs,
|
|
9325
9434
|
shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
|
|
9326
9435
|
}
|
|
9327
9436
|
);
|
|
9328
|
-
this.acpSessionId = sessionResponse.sessionId;
|
|
9437
|
+
this.acpSessionId = requestedResumeSessionId ?? sessionResponse.sessionId;
|
|
9329
9438
|
this.updateSessionConfigOptions(sessionResponse.configOptions);
|
|
9330
9439
|
logger.debug(`[AcpBackend] Session created: ${this.acpSessionId}`);
|
|
9331
9440
|
await this.applySessionConfigPresets();
|
|
@@ -9718,12 +9827,12 @@ function readGeminiLocalConfig() {
|
|
|
9718
9827
|
let googleCloudProject = null;
|
|
9719
9828
|
let googleCloudProjectEmail = null;
|
|
9720
9829
|
const possiblePaths = [
|
|
9721
|
-
join$1(homedir(), ".gemini", "oauth_creds.json"),
|
|
9830
|
+
join$1(homedir$1(), ".gemini", "oauth_creds.json"),
|
|
9722
9831
|
// Main OAuth credentials file
|
|
9723
|
-
join$1(homedir(), ".gemini", "config.json"),
|
|
9724
|
-
join$1(homedir(), ".config", "gemini", "config.json"),
|
|
9725
|
-
join$1(homedir(), ".gemini", "auth.json"),
|
|
9726
|
-
join$1(homedir(), ".config", "gemini", "auth.json")
|
|
9832
|
+
join$1(homedir$1(), ".gemini", "config.json"),
|
|
9833
|
+
join$1(homedir$1(), ".config", "gemini", "config.json"),
|
|
9834
|
+
join$1(homedir$1(), ".gemini", "auth.json"),
|
|
9835
|
+
join$1(homedir$1(), ".config", "gemini", "auth.json")
|
|
9727
9836
|
];
|
|
9728
9837
|
for (const configPath of possiblePaths) {
|
|
9729
9838
|
if (existsSync$1(configPath)) {
|
|
@@ -9801,10 +9910,10 @@ function determineGeminiModel(explicitModel, localConfig) {
|
|
|
9801
9910
|
}
|
|
9802
9911
|
function saveGeminiModelToConfig(model) {
|
|
9803
9912
|
try {
|
|
9804
|
-
const configDir = join$1(homedir(), ".gemini");
|
|
9913
|
+
const configDir = join$1(homedir$1(), ".gemini");
|
|
9805
9914
|
const configPath = join$1(configDir, "config.json");
|
|
9806
9915
|
if (!existsSync$1(configDir)) {
|
|
9807
|
-
mkdirSync(configDir, { recursive: true });
|
|
9916
|
+
mkdirSync$1(configDir, { recursive: true });
|
|
9808
9917
|
}
|
|
9809
9918
|
let config = {};
|
|
9810
9919
|
if (existsSync$1(configPath)) {
|
|
@@ -9816,7 +9925,7 @@ function saveGeminiModelToConfig(model) {
|
|
|
9816
9925
|
}
|
|
9817
9926
|
}
|
|
9818
9927
|
config.model = model;
|
|
9819
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9928
|
+
writeFileSync$1(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9820
9929
|
logger.debug(`[Gemini] Saved model "${model}" to ${configPath}`);
|
|
9821
9930
|
} catch (error) {
|
|
9822
9931
|
logger.debug(`[Gemini] Failed to save model to config:`, error);
|
|
@@ -9824,10 +9933,10 @@ function saveGeminiModelToConfig(model) {
|
|
|
9824
9933
|
}
|
|
9825
9934
|
function saveGoogleCloudProjectToConfig(projectId, email) {
|
|
9826
9935
|
try {
|
|
9827
|
-
const configDir = join$1(homedir(), ".gemini");
|
|
9936
|
+
const configDir = join$1(homedir$1(), ".gemini");
|
|
9828
9937
|
const configPath = join$1(configDir, "config.json");
|
|
9829
9938
|
if (!existsSync$1(configDir)) {
|
|
9830
|
-
mkdirSync(configDir, { recursive: true });
|
|
9939
|
+
mkdirSync$1(configDir, { recursive: true });
|
|
9831
9940
|
}
|
|
9832
9941
|
let config = {};
|
|
9833
9942
|
if (existsSync$1(configPath)) {
|
|
@@ -9841,7 +9950,7 @@ function saveGoogleCloudProjectToConfig(projectId, email) {
|
|
|
9841
9950
|
if (email) {
|
|
9842
9951
|
config.googleCloudProjectEmail = email;
|
|
9843
9952
|
}
|
|
9844
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9953
|
+
writeFileSync$1(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9845
9954
|
logger.debug(`[Gemini] Saved Google Cloud Project "${projectId}"${email ? ` for ${email}` : ""} to ${configPath}`);
|
|
9846
9955
|
} catch (error) {
|
|
9847
9956
|
logger.debug(`[Gemini] Failed to save Google Cloud Project to config:`, error);
|
|
@@ -10004,8 +10113,23 @@ function readCodexAcpConfigOverrides() {
|
|
|
10004
10113
|
const raw = readFirstEnv("HAPPY_CODEX_ACP_CONFIG_OVERRIDES", "HAPPIER_CODEX_ACP_CONFIG_OVERRIDES");
|
|
10005
10114
|
return raw.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
10006
10115
|
}
|
|
10116
|
+
function sanitizeCodexAcpBaseArgs(baseArgs = []) {
|
|
10117
|
+
const sanitized = [];
|
|
10118
|
+
for (let index = 0; index < baseArgs.length; index += 1) {
|
|
10119
|
+
const arg = baseArgs[index];
|
|
10120
|
+
if (arg === "--dangerously-bypass-approvals-and-sandbox" || arg === "--yolo" || arg.startsWith("--ask-for-approval=") || arg.startsWith("--approval-policy=") || arg.startsWith("--sandbox=")) {
|
|
10121
|
+
continue;
|
|
10122
|
+
}
|
|
10123
|
+
if (arg === "--ask-for-approval" || arg === "--approval-policy" || arg === "--sandbox") {
|
|
10124
|
+
index += 1;
|
|
10125
|
+
continue;
|
|
10126
|
+
}
|
|
10127
|
+
sanitized.push(arg);
|
|
10128
|
+
}
|
|
10129
|
+
return sanitized;
|
|
10130
|
+
}
|
|
10007
10131
|
function buildCodexAcpConfigArgs(options) {
|
|
10008
|
-
const args =
|
|
10132
|
+
const args = sanitizeCodexAcpBaseArgs(options.baseArgs);
|
|
10009
10133
|
const overrides = [...readCodexAcpConfigOverrides()];
|
|
10010
10134
|
if (options.model) {
|
|
10011
10135
|
overrides.push(`model=${JSON.stringify(options.model)}`);
|
|
@@ -10134,6 +10258,9 @@ function resolveCodexExecutable() {
|
|
|
10134
10258
|
}
|
|
10135
10259
|
return "codex";
|
|
10136
10260
|
}
|
|
10261
|
+
function shouldUseShellForCodex(executable) {
|
|
10262
|
+
return process.platform === "win32" && /\.(cmd|bat|ps1)$/i.test(executable);
|
|
10263
|
+
}
|
|
10137
10264
|
|
|
10138
10265
|
const CODEX_HOME_SEED_FILES = [
|
|
10139
10266
|
"auth.json",
|
|
@@ -10147,6 +10274,24 @@ const CODEX_HOME_SEED_DIRS = [
|
|
|
10147
10274
|
];
|
|
10148
10275
|
const MAX_CODEX_SKILL_DESCRIPTION_LENGTH = 1024;
|
|
10149
10276
|
const MANAGED_CODEX_HOME_PREFIX = "happy-codex-home-";
|
|
10277
|
+
function isPlainObject(value) {
|
|
10278
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10279
|
+
}
|
|
10280
|
+
function isApiKeyOnlyCodexAuth(value) {
|
|
10281
|
+
if (!isPlainObject(value)) {
|
|
10282
|
+
return false;
|
|
10283
|
+
}
|
|
10284
|
+
const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0 && entryValue !== null);
|
|
10285
|
+
return entries.length === 1 && typeof value.OPENAI_API_KEY === "string" && value.OPENAI_API_KEY.trim().length > 0;
|
|
10286
|
+
}
|
|
10287
|
+
function shouldUseSourceCodexHomeForMutableAuth(sourceHomeDir) {
|
|
10288
|
+
try {
|
|
10289
|
+
const auth = JSON.parse(readFileSync(join(sourceHomeDir, "auth.json"), "utf8"));
|
|
10290
|
+
return !isApiKeyOnlyCodexAuth(auth);
|
|
10291
|
+
} catch {
|
|
10292
|
+
return false;
|
|
10293
|
+
}
|
|
10294
|
+
}
|
|
10150
10295
|
function getCodexPlatformTarget(platform, arch) {
|
|
10151
10296
|
if (platform === "win32" && arch === "x64") {
|
|
10152
10297
|
return {
|
|
@@ -10310,7 +10455,7 @@ function copyCodexHomeEntry(sourcePath, destPath) {
|
|
|
10310
10455
|
if (!existsSync(sourcePath)) {
|
|
10311
10456
|
return;
|
|
10312
10457
|
}
|
|
10313
|
-
mkdirSync
|
|
10458
|
+
mkdirSync(dirname$1(destPath), { recursive: true });
|
|
10314
10459
|
cpSync(sourcePath, destPath, {
|
|
10315
10460
|
recursive: true,
|
|
10316
10461
|
force: true,
|
|
@@ -10394,7 +10539,7 @@ function seedCodexSkillEntries(sourceSkillsDir, isolatedHomeDir, sourceLabel) {
|
|
|
10394
10539
|
return;
|
|
10395
10540
|
}
|
|
10396
10541
|
const destSkillsDir = join(isolatedHomeDir, "skills");
|
|
10397
|
-
mkdirSync
|
|
10542
|
+
mkdirSync(destSkillsDir, { recursive: true });
|
|
10398
10543
|
for (const entryName of readdirSync(sourceSkillsDir)) {
|
|
10399
10544
|
const sourceEntryPath = join(sourceSkillsDir, entryName);
|
|
10400
10545
|
if (!shouldSeedCodexSkillEntry(sourceEntryPath)) {
|
|
@@ -10410,7 +10555,135 @@ function seedCodexSkillEntries(sourceSkillsDir, isolatedHomeDir, sourceLabel) {
|
|
|
10410
10555
|
}
|
|
10411
10556
|
}
|
|
10412
10557
|
}
|
|
10413
|
-
function
|
|
10558
|
+
function isWithinDirectory(parentDir, childPath, platform) {
|
|
10559
|
+
const normalizedParent = normalizePathForComparison(parentDir, platform);
|
|
10560
|
+
const normalizedChild = normalizePathForComparison(childPath, platform);
|
|
10561
|
+
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}/`);
|
|
10562
|
+
}
|
|
10563
|
+
function extractCodexSessionIdFromFilePath(filePath) {
|
|
10564
|
+
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$/);
|
|
10565
|
+
return match?.[1] ?? null;
|
|
10566
|
+
}
|
|
10567
|
+
function findCodexSessionFile(sourceHomeDir, resumeSessionId, platform) {
|
|
10568
|
+
const sessionsRoot = join(sourceHomeDir, "sessions");
|
|
10569
|
+
const stack = [sessionsRoot];
|
|
10570
|
+
let bestMatch = null;
|
|
10571
|
+
while (stack.length > 0) {
|
|
10572
|
+
const currentDir = stack.pop();
|
|
10573
|
+
let entries;
|
|
10574
|
+
try {
|
|
10575
|
+
entries = readdirSync(currentDir, { withFileTypes: true });
|
|
10576
|
+
} catch {
|
|
10577
|
+
continue;
|
|
10578
|
+
}
|
|
10579
|
+
for (const entry of entries) {
|
|
10580
|
+
const fullPath = join(currentDir, entry.name);
|
|
10581
|
+
if (!isWithinDirectory(sessionsRoot, fullPath, platform)) {
|
|
10582
|
+
continue;
|
|
10583
|
+
}
|
|
10584
|
+
if (entry.isDirectory()) {
|
|
10585
|
+
stack.push(fullPath);
|
|
10586
|
+
continue;
|
|
10587
|
+
}
|
|
10588
|
+
if (!entry.isFile() || extractCodexSessionIdFromFilePath(fullPath) !== resumeSessionId) {
|
|
10589
|
+
continue;
|
|
10590
|
+
}
|
|
10591
|
+
try {
|
|
10592
|
+
const mtimeMs = statSync(fullPath).mtimeMs;
|
|
10593
|
+
if (!bestMatch || mtimeMs > bestMatch.mtimeMs) {
|
|
10594
|
+
bestMatch = { path: fullPath, mtimeMs };
|
|
10595
|
+
}
|
|
10596
|
+
} catch {
|
|
10597
|
+
}
|
|
10598
|
+
}
|
|
10599
|
+
}
|
|
10600
|
+
return bestMatch?.path ?? null;
|
|
10601
|
+
}
|
|
10602
|
+
function seedCodexResumeSessionFile(sourceHomeDir, isolatedHomeDir, resumeSessionId, platform) {
|
|
10603
|
+
const normalizedResumeSessionId = typeof resumeSessionId === "string" && resumeSessionId.trim() ? resumeSessionId.trim() : null;
|
|
10604
|
+
if (!normalizedResumeSessionId) {
|
|
10605
|
+
return;
|
|
10606
|
+
}
|
|
10607
|
+
const sourceSessionFile = findCodexSessionFile(sourceHomeDir, normalizedResumeSessionId, platform);
|
|
10608
|
+
if (!sourceSessionFile) {
|
|
10609
|
+
logger.debug(`[codex] No source CODEX_HOME session file found for resume id ${normalizedResumeSessionId}`);
|
|
10610
|
+
return;
|
|
10611
|
+
}
|
|
10612
|
+
const sourceSessionsRoot = join(sourceHomeDir, "sessions");
|
|
10613
|
+
const relativeSessionPath = relative(sourceSessionsRoot, sourceSessionFile);
|
|
10614
|
+
if (!relativeSessionPath || relativeSessionPath.startsWith("..") || isAbsolute(relativeSessionPath)) {
|
|
10615
|
+
logger.debug(`[codex] Refusing to seed CODEX_HOME session outside sessions root: ${sourceSessionFile}`);
|
|
10616
|
+
return;
|
|
10617
|
+
}
|
|
10618
|
+
try {
|
|
10619
|
+
copyCodexHomeEntry(
|
|
10620
|
+
sourceSessionFile,
|
|
10621
|
+
join(isolatedHomeDir, "sessions", relativeSessionPath)
|
|
10622
|
+
);
|
|
10623
|
+
} catch (error) {
|
|
10624
|
+
logger.debug(`[codex] Failed to seed CODEX_HOME session file for ${normalizedResumeSessionId}`, error);
|
|
10625
|
+
}
|
|
10626
|
+
}
|
|
10627
|
+
function shouldSyncCodexSessionFileBack(sourcePath, destPath) {
|
|
10628
|
+
let sourceStat;
|
|
10629
|
+
try {
|
|
10630
|
+
sourceStat = statSync(sourcePath);
|
|
10631
|
+
} catch {
|
|
10632
|
+
return false;
|
|
10633
|
+
}
|
|
10634
|
+
if (!sourceStat.isFile()) {
|
|
10635
|
+
return false;
|
|
10636
|
+
}
|
|
10637
|
+
let destStat;
|
|
10638
|
+
try {
|
|
10639
|
+
destStat = statSync(destPath);
|
|
10640
|
+
} catch {
|
|
10641
|
+
return true;
|
|
10642
|
+
}
|
|
10643
|
+
return sourceStat.mtimeMs >= destStat.mtimeMs || sourceStat.size !== destStat.size;
|
|
10644
|
+
}
|
|
10645
|
+
function syncCodexSessionFilesBackToSource(isolatedHomeDir, sourceHomeDir, platform) {
|
|
10646
|
+
const isolatedSessionsRoot = join(isolatedHomeDir, "sessions");
|
|
10647
|
+
const sourceSessionsRoot = join(sourceHomeDir, "sessions");
|
|
10648
|
+
const stack = [isolatedSessionsRoot];
|
|
10649
|
+
while (stack.length > 0) {
|
|
10650
|
+
const currentDir = stack.pop();
|
|
10651
|
+
let entries;
|
|
10652
|
+
try {
|
|
10653
|
+
entries = readdirSync(currentDir, { withFileTypes: true });
|
|
10654
|
+
} catch {
|
|
10655
|
+
continue;
|
|
10656
|
+
}
|
|
10657
|
+
for (const entry of entries) {
|
|
10658
|
+
const fullPath = join(currentDir, entry.name);
|
|
10659
|
+
if (!isWithinDirectory(isolatedSessionsRoot, fullPath, platform)) {
|
|
10660
|
+
continue;
|
|
10661
|
+
}
|
|
10662
|
+
if (entry.isDirectory()) {
|
|
10663
|
+
stack.push(fullPath);
|
|
10664
|
+
continue;
|
|
10665
|
+
}
|
|
10666
|
+
if (!entry.isFile() || extractCodexSessionIdFromFilePath(fullPath) === null) {
|
|
10667
|
+
continue;
|
|
10668
|
+
}
|
|
10669
|
+
const relativeSessionPath = relative(isolatedSessionsRoot, fullPath);
|
|
10670
|
+
if (!relativeSessionPath || relativeSessionPath.startsWith("..") || isAbsolute(relativeSessionPath)) {
|
|
10671
|
+
logger.debug(`[codex] Refusing to sync CODEX_HOME session outside sessions root: ${fullPath}`);
|
|
10672
|
+
continue;
|
|
10673
|
+
}
|
|
10674
|
+
const destPath = join(sourceSessionsRoot, relativeSessionPath);
|
|
10675
|
+
if (!shouldSyncCodexSessionFileBack(fullPath, destPath)) {
|
|
10676
|
+
continue;
|
|
10677
|
+
}
|
|
10678
|
+
try {
|
|
10679
|
+
copyCodexHomeEntry(fullPath, destPath);
|
|
10680
|
+
} catch (error) {
|
|
10681
|
+
logger.debug(`[codex] Failed to sync CODEX_HOME session file back to source: ${fullPath}`, error);
|
|
10682
|
+
}
|
|
10683
|
+
}
|
|
10684
|
+
}
|
|
10685
|
+
}
|
|
10686
|
+
function seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir, resumeSessionId, platform) {
|
|
10414
10687
|
if (existsSync(sourceHomeDir)) {
|
|
10415
10688
|
for (const fileName of CODEX_HOME_SEED_FILES) {
|
|
10416
10689
|
try {
|
|
@@ -10431,6 +10704,7 @@ function seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir)
|
|
|
10431
10704
|
seedCodexSkillEntries(bundledSkillsDir, isolatedHomeDir, "bundled skills");
|
|
10432
10705
|
}
|
|
10433
10706
|
seedCodexSkillEntries(join(sourceHomeDir, "skills"), isolatedHomeDir, "source CODEX_HOME");
|
|
10707
|
+
seedCodexResumeSessionFile(sourceHomeDir, isolatedHomeDir, resumeSessionId, platform);
|
|
10434
10708
|
}
|
|
10435
10709
|
function prepareCodexAcpEnvironment(overrides = {}, options = {}) {
|
|
10436
10710
|
const env = buildCodexAcpEnv(overrides, options);
|
|
@@ -10448,17 +10722,26 @@ function prepareCodexAcpEnvironment(overrides = {}, options = {}) {
|
|
|
10448
10722
|
return { env };
|
|
10449
10723
|
}
|
|
10450
10724
|
}
|
|
10725
|
+
const sourceHomeDir = options.sourceHomeDir ?? join(homedir(), ".codex");
|
|
10726
|
+
const bundledSkillsDir = options.bundledSkillsDir ?? join(projectPath(), "skills");
|
|
10727
|
+
if (shouldUseSourceCodexHomeForMutableAuth(sourceHomeDir)) {
|
|
10728
|
+
logger.debug("[codex] Using source CODEX_HOME for mutable Codex auth credentials");
|
|
10729
|
+
env.CODEX_HOME = sourceHomeDir;
|
|
10730
|
+
return {
|
|
10731
|
+
env,
|
|
10732
|
+
codexHomePath: sourceHomeDir
|
|
10733
|
+
};
|
|
10734
|
+
}
|
|
10451
10735
|
const tempDirFactory = options.tempDirFactory ?? mkdtempSync;
|
|
10452
10736
|
const isolatedHomeDir = tempDirFactory(join(tmpdir(), "happy-codex-home-"));
|
|
10453
|
-
mkdirSync
|
|
10454
|
-
|
|
10455
|
-
const bundledSkillsDir = options.bundledSkillsDir ?? join(projectPath(), "skills");
|
|
10456
|
-
seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir);
|
|
10737
|
+
mkdirSync(isolatedHomeDir, { recursive: true });
|
|
10738
|
+
seedIsolatedCodexHome(sourceHomeDir, isolatedHomeDir, bundledSkillsDir, options.resumeSessionId, platform);
|
|
10457
10739
|
env.CODEX_HOME = isolatedHomeDir;
|
|
10458
10740
|
return {
|
|
10459
10741
|
env,
|
|
10460
10742
|
codexHomePath: isolatedHomeDir,
|
|
10461
10743
|
cleanup: () => {
|
|
10744
|
+
syncCodexSessionFilesBackToSource(isolatedHomeDir, sourceHomeDir, platform);
|
|
10462
10745
|
rmSync(isolatedHomeDir, { recursive: true, force: true });
|
|
10463
10746
|
}
|
|
10464
10747
|
};
|
|
@@ -10491,6 +10774,8 @@ function createCodexBackend(options) {
|
|
|
10491
10774
|
const preparedEnv = prepareCodexAcpEnvironment({
|
|
10492
10775
|
...options.env,
|
|
10493
10776
|
NODE_ENV: "production"
|
|
10777
|
+
}, {
|
|
10778
|
+
resumeSessionId: options.resumeSessionId
|
|
10494
10779
|
});
|
|
10495
10780
|
const backendOptions = {
|
|
10496
10781
|
agentName: "codex",
|
|
@@ -10501,7 +10786,8 @@ function createCodexBackend(options) {
|
|
|
10501
10786
|
permissionHandler: options.permissionHandler,
|
|
10502
10787
|
selectionHandler: options.selectionHandler,
|
|
10503
10788
|
transportHandler: resolveCodexTransport(spawn.command),
|
|
10504
|
-
resourceCleanup: preparedEnv.cleanup
|
|
10789
|
+
resourceCleanup: preparedEnv.cleanup,
|
|
10790
|
+
resumeSessionId: options.resumeSessionId
|
|
10505
10791
|
};
|
|
10506
10792
|
return {
|
|
10507
10793
|
backend: new AcpBackend(backendOptions),
|
|
@@ -10618,7 +10904,7 @@ function getGlobalClaudeVersion() {
|
|
|
10618
10904
|
const output = execSync$1("claude --version", {
|
|
10619
10905
|
encoding: "utf8",
|
|
10620
10906
|
stdio: ["pipe", "pipe", "pipe"],
|
|
10621
|
-
cwd: homedir
|
|
10907
|
+
cwd: homedir(),
|
|
10622
10908
|
env: cleanEnv,
|
|
10623
10909
|
windowsHide: true
|
|
10624
10910
|
}).trim();
|
|
@@ -10655,7 +10941,7 @@ function getCleanEnv() {
|
|
|
10655
10941
|
return env;
|
|
10656
10942
|
}
|
|
10657
10943
|
function findGlobalClaudePath() {
|
|
10658
|
-
const homeDir = homedir
|
|
10944
|
+
const homeDir = homedir();
|
|
10659
10945
|
const cleanEnv = getCleanEnv();
|
|
10660
10946
|
try {
|
|
10661
10947
|
execSync$1("claude --version", {
|
|
@@ -11935,14 +12221,14 @@ var launch = /*#__PURE__*/Object.freeze({
|
|
|
11935
12221
|
const unifiedProviderExecutors = {
|
|
11936
12222
|
claude: async (opts) => {
|
|
11937
12223
|
const claudeOptions = opts.claudeOptions ?? {};
|
|
11938
|
-
const { runClaude } = await import('./runClaude-
|
|
12224
|
+
const { runClaude } = await import('./runClaude-BviM1Wl5.mjs');
|
|
11939
12225
|
await runClaude(opts.credentials, {
|
|
11940
12226
|
...claudeOptions,
|
|
11941
12227
|
startingMode: claudeOptions.startingMode ?? (claudeOptions.startedBy === "daemon" ? "remote" : void 0)
|
|
11942
12228
|
});
|
|
11943
12229
|
},
|
|
11944
12230
|
codex: async (opts) => {
|
|
11945
|
-
const { runCodex } = await import('./runCodex-
|
|
12231
|
+
const { runCodex } = await import('./runCodex-Dx3osc7U.mjs');
|
|
11946
12232
|
await runCodex({
|
|
11947
12233
|
credentials: opts.credentials,
|
|
11948
12234
|
startedBy: opts.startedBy,
|
|
@@ -11951,7 +12237,7 @@ const unifiedProviderExecutors = {
|
|
|
11951
12237
|
});
|
|
11952
12238
|
},
|
|
11953
12239
|
gemini: async (opts) => {
|
|
11954
|
-
const { runGemini } = await import('./runGemini-
|
|
12240
|
+
const { runGemini } = await import('./runGemini-CnJ75Q--.mjs');
|
|
11955
12241
|
await runGemini({
|
|
11956
12242
|
credentials: opts.credentials,
|
|
11957
12243
|
startedBy: opts.startedBy
|
|
@@ -12034,7 +12320,7 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
12034
12320
|
return;
|
|
12035
12321
|
} else if (subcommand === "runtime") {
|
|
12036
12322
|
if (args[1] === "providers") {
|
|
12037
|
-
const { renderRuntimeProviders } = await import('./command-
|
|
12323
|
+
const { renderRuntimeProviders } = await import('./command-fcJ-4Yq3.mjs');
|
|
12038
12324
|
console.log(renderRuntimeProviders());
|
|
12039
12325
|
return;
|
|
12040
12326
|
}
|
|
@@ -12240,8 +12526,8 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
12240
12526
|
const projectId = args[3];
|
|
12241
12527
|
try {
|
|
12242
12528
|
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
|
|
12243
|
-
const { readCredentials: readCredentials2 } = await import('./api-
|
|
12244
|
-
const { ApiClient: ApiClient2 } = await import('./api-
|
|
12529
|
+
const { readCredentials: readCredentials2 } = await import('./api-D3vYIva3.mjs').then(function (n) { return n.Y; });
|
|
12530
|
+
const { ApiClient: ApiClient2 } = await import('./api-D3vYIva3.mjs').then(function (n) { return n.Z; });
|
|
12245
12531
|
let userEmail = void 0;
|
|
12246
12532
|
try {
|
|
12247
12533
|
const credentials = await readCredentials2();
|
|
@@ -12659,4 +12945,4 @@ ${chalk.bold("Examples:")}
|
|
|
12659
12945
|
}
|
|
12660
12946
|
}
|
|
12661
12947
|
|
|
12662
|
-
export {
|
|
12948
|
+
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 };
|