happy-imou-cloud 2.1.48 → 2.1.50
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-CM3JbXUC.mjs → BaseReasoningProcessor-2qoX8OA1.mjs} +2 -2
- package/dist/{BaseReasoningProcessor-CKtDfihV.cjs → BaseReasoningProcessor-D3q5lh9h.cjs} +2 -2
- package/dist/{ProviderSelectionHandler-BHKIBw4t.cjs → ProviderSelectionHandler-CO5BYEgC.cjs} +2 -2
- package/dist/{ProviderSelectionHandler-vgZ2egD_.mjs → ProviderSelectionHandler-CO6foZET.mjs} +2 -2
- package/dist/{api-CSjP-Z3Y.mjs → api-6B4EMs47.mjs} +1 -1
- package/dist/{api-eaGKJjMt.cjs → api-D4JOaMll.cjs} +1 -1
- package/dist/{command-BzPI4N1n.mjs → command-BbJCdR2t.mjs} +2 -2
- package/dist/{command-DDoz1Eky.cjs → command-DuKDmbdM.cjs} +2 -2
- package/dist/{index-C8X1VlHZ.cjs → index-CZJH0CUT.cjs} +109 -25
- package/dist/{index-BzsBo3_Z.mjs → index-CyGHrYHl.mjs} +106 -22
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/lib.cjs +1 -1
- package/dist/lib.d.cts +2 -0
- package/dist/lib.d.mts +2 -0
- package/dist/lib.mjs +1 -1
- package/dist/{registerKillSessionHandler-CLCYBgZX.cjs → registerKillSessionHandler-Bo_MMbdY.cjs} +2 -2
- package/dist/{registerKillSessionHandler-BHu-3hZQ.mjs → registerKillSessionHandler-ggfGac_S.mjs} +2 -2
- package/dist/{runClaude-BkUbXE2F.cjs → runClaude-B4eoG3Pu.cjs} +4 -4
- package/dist/{runClaude-D3CBLW5o.mjs → runClaude-jDr3i0bO.mjs} +4 -4
- package/dist/{runCodex-DqzdgDwZ.mjs → runCodex-e_D1Jd_w.mjs} +267 -65
- package/dist/{runCodex-CdgrZK7P.cjs → runCodex-hDGeZAh5.cjs} +266 -64
- package/dist/{runGemini-BE05R24D.cjs → runGemini-CeA9aiD1.cjs} +4 -4
- package/dist/{runGemini-UZuiKe59.mjs → runGemini-Cur84FvO.mjs} +4 -4
- package/package.json +1 -1
package/dist/{registerKillSessionHandler-BHu-3hZQ.mjs → registerKillSessionHandler-ggfGac_S.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { m as initialMachineMetadata, R as RuntimeShell, f as formatDisplayMessage, n as resolveCanonicalToolNameV2, o as isTerminalReferenceOnlyPayload, t as truncateDisplayMessage } from './index-
|
|
2
|
-
import { r as readSettings, H as HeadTailPreviewBuffer, e as HAPPY_ORG_REPLY_ACK_VERSION, f as HAPPY_ORG_TURN_REPORT_TAG, g as HAPPY_ORG_SUMMARY_MAX_LENGTH, j as HAPPY_ORG_REPEAT_THRESHOLD, l as logger, n as normalizePreviewableArtifactTarget } from './api-
|
|
1
|
+
import { m as initialMachineMetadata, R as RuntimeShell, f as formatDisplayMessage, n as resolveCanonicalToolNameV2, o as isTerminalReferenceOnlyPayload, t as truncateDisplayMessage } from './index-CyGHrYHl.mjs';
|
|
2
|
+
import { r as readSettings, H as HeadTailPreviewBuffer, e as HAPPY_ORG_REPLY_ACK_VERSION, f as HAPPY_ORG_TURN_REPORT_TAG, g as HAPPY_ORG_SUMMARY_MAX_LENGTH, j as HAPPY_ORG_REPEAT_THRESHOLD, l as logger, n as normalizePreviewableArtifactTarget } from './api-6B4EMs47.mjs';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { basename } from 'node:path';
|
|
5
5
|
import 'axios';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_crypto = require('node:crypto');
|
|
4
|
-
var persistence = require('./api-
|
|
4
|
+
var persistence = require('./api-D4JOaMll.cjs');
|
|
5
5
|
require('cross-spawn');
|
|
6
6
|
require('@agentclientprotocol/sdk');
|
|
7
|
-
var index = require('./index-
|
|
7
|
+
var index = require('./index-CZJH0CUT.cjs');
|
|
8
8
|
require('ps-list');
|
|
9
9
|
require('fs');
|
|
10
10
|
require('path');
|
|
@@ -25,9 +25,9 @@ require('tweetnacl');
|
|
|
25
25
|
require('open');
|
|
26
26
|
var React = require('react');
|
|
27
27
|
var ink = require('ink');
|
|
28
|
-
var ProviderSelectionHandler = require('./ProviderSelectionHandler-
|
|
28
|
+
var ProviderSelectionHandler = require('./ProviderSelectionHandler-CO5BYEgC.cjs');
|
|
29
29
|
var types = require('./types-DVk3crez.cjs');
|
|
30
|
-
var registerKillSessionHandler = require('./registerKillSessionHandler-
|
|
30
|
+
var registerKillSessionHandler = require('./registerKillSessionHandler-Bo_MMbdY.cjs');
|
|
31
31
|
require('socket.io-client');
|
|
32
32
|
require('expo-server-sdk');
|
|
33
33
|
var node_util = require('node:util');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { l as logger, k as backoff, m as delay, d as AssistantMessageStream, o as AsyncLock, c as configuration, s as startOfflineReconnection, b as connectionState, A as ApiClient, i as isAuthenticationRequiredError, h as hashObject } from './api-
|
|
2
|
+
import { l as logger, k as backoff, m as delay, d as AssistantMessageStream, o as AsyncLock, c as configuration, s as startOfflineReconnection, b as connectionState, A as ApiClient, i as isAuthenticationRequiredError, h as hashObject } from './api-6B4EMs47.mjs';
|
|
3
3
|
import 'cross-spawn';
|
|
4
4
|
import '@agentclientprotocol/sdk';
|
|
5
|
-
import { q as getProjectPath, F as Future, u as claudeLocal, E as ExitCodeError, w as trimIdent, x as createClaudeBackend, f as formatDisplayMessage, t as truncateDisplayMessage, y as claudeCheckSession, z as projectPath, B as mapToClaudeMode, P as PushableAsyncIterable, C as query, D as AbortError, e as stopCaffeinate, p as publishSessionRegistration, H as getEnvironmentInfo, a as createSessionMetadata, I as startCaffeinate, b as closeProviderSession } from './index-
|
|
5
|
+
import { q as getProjectPath, F as Future, u as claudeLocal, E as ExitCodeError, w as trimIdent, x as createClaudeBackend, f as formatDisplayMessage, t as truncateDisplayMessage, y as claudeCheckSession, z as projectPath, B as mapToClaudeMode, P as PushableAsyncIterable, C as query, D as AbortError, e as stopCaffeinate, p as publishSessionRegistration, H as getEnvironmentInfo, a as createSessionMetadata, I as startCaffeinate, b as closeProviderSession } from './index-CyGHrYHl.mjs';
|
|
6
6
|
import 'ps-list';
|
|
7
7
|
import 'fs';
|
|
8
8
|
import 'path';
|
|
@@ -23,9 +23,9 @@ import 'tweetnacl';
|
|
|
23
23
|
import 'open';
|
|
24
24
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
25
25
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
26
|
-
import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-
|
|
26
|
+
import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-CO6foZET.mjs';
|
|
27
27
|
import { R as RawJSONLinesSchema } from './types-CiliQpqS.mjs';
|
|
28
|
-
import { B as BasePermissionHandler, d as MessageBuffer, C as ConversationHistory$1, f as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, h as finalizeHappyOrgTurnWithBusinessAck, i as buildTurnResultPushNotification, t as createSessionTranscriptInkRenderer, j as buildReadyPushNotification, l as launchRuntimeHandleWithFactoryResult, n as renderTerminalOutputPreview, p as prepareTerminalOutputForForwarding, q as forwardAgentMessageToProviderSession, m as buildPermissionPushNotification, s as syncControlledByUserState, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, c as registerKillSessionHandler } from './registerKillSessionHandler-
|
|
28
|
+
import { B as BasePermissionHandler, d as MessageBuffer, C as ConversationHistory$1, f as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, h as finalizeHappyOrgTurnWithBusinessAck, i as buildTurnResultPushNotification, t as createSessionTranscriptInkRenderer, j as buildReadyPushNotification, l as launchRuntimeHandleWithFactoryResult, n as renderTerminalOutputPreview, p as prepareTerminalOutputForForwarding, q as forwardAgentMessageToProviderSession, m as buildPermissionPushNotification, s as syncControlledByUserState, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, c as registerKillSessionHandler } from './registerKillSessionHandler-ggfGac_S.mjs';
|
|
29
29
|
import 'socket.io-client';
|
|
30
30
|
import 'expo-server-sdk';
|
|
31
31
|
import { isDeepStrictEqual } from 'node:util';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { p as preserveSessionRuntimeMetadata, l as logger, h as hashObject, d as AssistantMessageStream, b as connectionState, A as ApiClient } from './api-
|
|
2
|
-
import { B as BasePermissionHandler, d as MessageBuffer, C as ConversationHistory$1, f as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, h as finalizeHappyOrgTurnWithBusinessAck, i as buildTurnResultPushNotification, c as registerKillSessionHandler, j as buildReadyPushNotification, l as launchRuntimeHandleWithFactoryResult, t as createSessionTranscriptInkRenderer, k as extractPermissionRequestPushContext, m as buildPermissionPushNotification, n as renderTerminalOutputPreview, p as prepareTerminalOutputForForwarding, o as inferToolResultError, q as forwardAgentMessageToProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, r as resolveHappyOrgQueuedTurn, s as syncControlledByUserState } from './registerKillSessionHandler-
|
|
3
|
-
import { f as formatDisplayMessage, v as validateCodexAcpSpawn, h as createCodexBackend, A as AcpBackend, t as truncateDisplayMessage, b as closeProviderSession, e as stopCaffeinate, i as resolveCodexExecutable, j as shouldUseShellForCodex, F as Future, k as readManagedSessionTag, l as resolveManagedSessionTag } from './index-
|
|
1
|
+
import { p as preserveSessionRuntimeMetadata, l as logger, h as hashObject, d as AssistantMessageStream, b as connectionState, A as ApiClient } from './api-6B4EMs47.mjs';
|
|
2
|
+
import { B as BasePermissionHandler, d as MessageBuffer, C as ConversationHistory$1, f as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, h as finalizeHappyOrgTurnWithBusinessAck, i as buildTurnResultPushNotification, c as registerKillSessionHandler, j as buildReadyPushNotification, l as launchRuntimeHandleWithFactoryResult, t as createSessionTranscriptInkRenderer, k as extractPermissionRequestPushContext, m as buildPermissionPushNotification, n as renderTerminalOutputPreview, p as prepareTerminalOutputForForwarding, o as inferToolResultError, q as forwardAgentMessageToProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, r as resolveHappyOrgQueuedTurn, s as syncControlledByUserState } from './registerKillSessionHandler-ggfGac_S.mjs';
|
|
3
|
+
import { f as formatDisplayMessage, v as validateCodexAcpSpawn, h as createCodexBackend, A as AcpBackend, t as truncateDisplayMessage, b as closeProviderSession, e as stopCaffeinate, i as resolveCodexExecutable, j as shouldUseShellForCodex, F as Future, k as readManagedSessionTag, l as resolveManagedSessionTag } from './index-CyGHrYHl.mjs';
|
|
4
4
|
import 'cross-spawn';
|
|
5
5
|
import '@agentclientprotocol/sdk';
|
|
6
6
|
import { randomUUID } from 'node:crypto';
|
|
@@ -10,7 +10,7 @@ import 'path';
|
|
|
10
10
|
import 'os';
|
|
11
11
|
import 'child_process';
|
|
12
12
|
import fs from 'node:fs';
|
|
13
|
-
import { join,
|
|
13
|
+
import { join, normalize, basename, delimiter } from 'node:path';
|
|
14
14
|
import os from 'node:os';
|
|
15
15
|
import { spawn, execFileSync } from 'node:child_process';
|
|
16
16
|
import 'node:readline';
|
|
@@ -24,8 +24,8 @@ import 'tweetnacl';
|
|
|
24
24
|
import 'open';
|
|
25
25
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
26
26
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
27
|
-
import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-
|
|
28
|
-
import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-
|
|
27
|
+
import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-CO6foZET.mjs';
|
|
28
|
+
import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-2qoX8OA1.mjs';
|
|
29
29
|
import 'zod';
|
|
30
30
|
import 'socket.io-client';
|
|
31
31
|
import 'expo-server-sdk';
|
|
@@ -238,12 +238,19 @@ class CodexSession {
|
|
|
238
238
|
this.sessionId = sessionId;
|
|
239
239
|
this.client.updateMetadata((metadata) => ({
|
|
240
240
|
...metadata,
|
|
241
|
-
codexSessionId: sessionId
|
|
241
|
+
codexSessionId: sessionId,
|
|
242
|
+
codexSessionCwd: this.path
|
|
242
243
|
}));
|
|
243
244
|
logger.debug(`[CodexSession] Session ID ${sessionId} added to metadata`);
|
|
244
245
|
};
|
|
245
246
|
clearSessionId = () => {
|
|
246
247
|
this.sessionId = null;
|
|
248
|
+
this.client.updateMetadata((metadata) => {
|
|
249
|
+
const nextMetadata = { ...metadata };
|
|
250
|
+
delete nextMetadata.codexSessionId;
|
|
251
|
+
delete nextMetadata.codexSessionCwd;
|
|
252
|
+
return nextMetadata;
|
|
253
|
+
});
|
|
247
254
|
logger.debug("[CodexSession] Session ID cleared");
|
|
248
255
|
};
|
|
249
256
|
handleUserObserverEphemeral = (event) => {
|
|
@@ -515,6 +522,113 @@ function getCodexExecutionFingerprint(mode) {
|
|
|
515
522
|
});
|
|
516
523
|
}
|
|
517
524
|
|
|
525
|
+
function getCodexSessionsRoot(options = {}) {
|
|
526
|
+
const codexHomeDir = options.codexHomeDir || process.env.CODEX_HOME || join(os.homedir(), ".codex");
|
|
527
|
+
return join(codexHomeDir, "sessions");
|
|
528
|
+
}
|
|
529
|
+
function collectFilesRecursive(dir, acc = []) {
|
|
530
|
+
let entries;
|
|
531
|
+
try {
|
|
532
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
533
|
+
} catch {
|
|
534
|
+
return acc;
|
|
535
|
+
}
|
|
536
|
+
for (const entry of entries) {
|
|
537
|
+
const full = join(dir, entry.name);
|
|
538
|
+
if (entry.isDirectory()) {
|
|
539
|
+
collectFilesRecursive(full, acc);
|
|
540
|
+
} else if (entry.isFile()) {
|
|
541
|
+
acc.push(full);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return acc;
|
|
545
|
+
}
|
|
546
|
+
function extractCodexSessionIdFromPath(filePath) {
|
|
547
|
+
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$/);
|
|
548
|
+
return match?.[1] ?? null;
|
|
549
|
+
}
|
|
550
|
+
function normalizePathForSessionMatch(path) {
|
|
551
|
+
const normalizedPath = normalize(path).replace(/[\\/]+/g, "/").replace(/\/+$/, "");
|
|
552
|
+
return process.platform === "win32" ? normalizedPath.toLowerCase() : normalizedPath;
|
|
553
|
+
}
|
|
554
|
+
function extractCodexSessionCwdFromFile(filePath) {
|
|
555
|
+
let contents;
|
|
556
|
+
try {
|
|
557
|
+
contents = fs.readFileSync(filePath, "utf8");
|
|
558
|
+
} catch {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
562
|
+
if (!line.trim()) {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
let record;
|
|
566
|
+
try {
|
|
567
|
+
record = JSON.parse(line);
|
|
568
|
+
} catch {
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (record.type !== "session_meta" || typeof record.payload !== "object" || record.payload === null) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
const cwd = record.payload.cwd;
|
|
575
|
+
return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : null;
|
|
576
|
+
}
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
function codexSessionFileMatchesCwd(filePath, cwd) {
|
|
580
|
+
const expectedCwd = cwd?.trim();
|
|
581
|
+
if (!expectedCwd) {
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
const actualCwd = extractCodexSessionCwdFromFile(filePath);
|
|
585
|
+
if (!actualCwd) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
return normalizePathForSessionMatch(actualCwd) === normalizePathForSessionMatch(expectedCwd);
|
|
589
|
+
}
|
|
590
|
+
function findCodexResumeFile(sessionId, options = {}) {
|
|
591
|
+
if (!sessionId) return null;
|
|
592
|
+
try {
|
|
593
|
+
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(`-${sessionId}.jsonl`)).filter((full) => {
|
|
594
|
+
try {
|
|
595
|
+
return fs.statSync(full).isFile();
|
|
596
|
+
} catch {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}).filter((full) => codexSessionFileMatchesCwd(full, options.cwd)).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
600
|
+
return candidates[0] || null;
|
|
601
|
+
} catch {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function isCodexResumeSessionValidForCwd(sessionId, cwd, options = {}) {
|
|
606
|
+
if (!sessionId?.trim()) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
return findCodexResumeFile(sessionId, { ...options, cwd }) !== null;
|
|
610
|
+
}
|
|
611
|
+
function findLatestCodexSessionIdSince(startTimeMs, options = {}) {
|
|
612
|
+
try {
|
|
613
|
+
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(".jsonl")).filter((full) => {
|
|
614
|
+
try {
|
|
615
|
+
return fs.statSync(full).mtimeMs >= startTimeMs;
|
|
616
|
+
} catch {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
}).filter((full) => codexSessionFileMatchesCwd(full, options.cwd)).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
620
|
+
for (const candidate of candidates) {
|
|
621
|
+
const sessionId = extractCodexSessionIdFromPath(candidate);
|
|
622
|
+
if (sessionId) {
|
|
623
|
+
return sessionId;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
} catch {
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
|
|
518
632
|
function delay(ms) {
|
|
519
633
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
520
634
|
}
|
|
@@ -690,6 +804,17 @@ function shouldInjectLargeOutputRecoveryHint(error) {
|
|
|
690
804
|
].filter(Boolean).join("\n").toLowerCase();
|
|
691
805
|
return searchableText.includes("memory allocation of") || searchableText.includes("out of memory") || searchableText.includes("oversized command output");
|
|
692
806
|
}
|
|
807
|
+
function isCodexUnknownResumeSessionError(error) {
|
|
808
|
+
const record = typeof error === "object" && error !== null ? error : null;
|
|
809
|
+
const searchableText = [
|
|
810
|
+
formatDisplayMessage(error).trim(),
|
|
811
|
+
record ? formatDisplayMessage(record.message).trim() : "",
|
|
812
|
+
record ? formatDisplayMessage(record.stderr).trim() : "",
|
|
813
|
+
record ? formatDisplayMessage(record.detail).trim() : "",
|
|
814
|
+
record ? formatDisplayMessage(record.data).trim() : ""
|
|
815
|
+
].filter(Boolean).join("\n");
|
|
816
|
+
return /unknown (session|thread)|session .* not found|thread .* not found|conversation .* not found|missing rollout path for thread|state db missing rollout path|no rollout found for thread id|resource not found/i.test(searchableText);
|
|
817
|
+
}
|
|
693
818
|
function normalizeCodexBackendError(error) {
|
|
694
819
|
const record = typeof error === "object" && error !== null ? error : null;
|
|
695
820
|
const text = formatDisplayMessage(error).trim();
|
|
@@ -1173,6 +1298,11 @@ async function codexRemoteLauncher(session) {
|
|
|
1173
1298
|
};
|
|
1174
1299
|
const createRuntimeHandle = async (mode) => {
|
|
1175
1300
|
const executionMode = resolveCodexAcpExecutionMode(mode);
|
|
1301
|
+
const resumeSessionId = session.sessionId && isCodexResumeSessionValidForCwd(session.sessionId, session.path) ? session.sessionId : null;
|
|
1302
|
+
if (session.sessionId && !resumeSessionId) {
|
|
1303
|
+
logger.debug(`[Codex] Refusing to resume Codex session ${session.sessionId} because its local session file does not match cwd ${session.path}`);
|
|
1304
|
+
session.clearSessionId();
|
|
1305
|
+
}
|
|
1176
1306
|
const validation = validateCodexAcpSpawn({
|
|
1177
1307
|
command: process.env.HAPPY_CODEX_ACP_COMMAND,
|
|
1178
1308
|
model: executionMode.model,
|
|
@@ -1193,7 +1323,7 @@ async function codexRemoteLauncher(session) {
|
|
|
1193
1323
|
sandbox: executionMode.sandbox,
|
|
1194
1324
|
approvalPolicy: executionMode.approvalPolicy,
|
|
1195
1325
|
permissionHandler,
|
|
1196
|
-
resumeSessionId
|
|
1326
|
+
resumeSessionId,
|
|
1197
1327
|
selectionHandler: {
|
|
1198
1328
|
handleSelection: (request) => selectionHandler.requestSelection(request)
|
|
1199
1329
|
}
|
|
@@ -1344,12 +1474,31 @@ async function codexRemoteLauncher(session) {
|
|
|
1344
1474
|
const turnSignal = abortController.signal;
|
|
1345
1475
|
let sentTurnResultPush = false;
|
|
1346
1476
|
let turnStatus = "task_complete";
|
|
1477
|
+
let retryingWithFreshSession = false;
|
|
1347
1478
|
currentHappyOrgTurn = message.mode.happyOrg ?? null;
|
|
1348
1479
|
try {
|
|
1349
1480
|
turnInFlight = true;
|
|
1350
1481
|
shouldCommitAccumulatedResponse = false;
|
|
1351
1482
|
const isNewRuntimeSession = runtimeHandle === null;
|
|
1352
|
-
const
|
|
1483
|
+
const attemptedResumeSessionId = isNewRuntimeSession ? session.sessionId : null;
|
|
1484
|
+
let activeRuntimeHandle;
|
|
1485
|
+
try {
|
|
1486
|
+
activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
if (!isNewRuntimeSession || !attemptedResumeSessionId || !isCodexUnknownResumeSessionError(error) || turnSignal.aborted) {
|
|
1489
|
+
throw error;
|
|
1490
|
+
}
|
|
1491
|
+
logger.debug(`[Codex] Resume session ${attemptedResumeSessionId} failed during ACP startup; retrying with a fresh session`, error);
|
|
1492
|
+
queueHistoryInjectionForRestart("Codex resume session is unavailable. Retrying with a fresh Codex session...");
|
|
1493
|
+
session.clearSessionId();
|
|
1494
|
+
currentModeHash = null;
|
|
1495
|
+
permissionHandler.reset();
|
|
1496
|
+
selectionHandler.reset();
|
|
1497
|
+
resetTurnState();
|
|
1498
|
+
pending = message;
|
|
1499
|
+
retryingWithFreshSession = true;
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1353
1502
|
if (!activeRuntimeHandle) {
|
|
1354
1503
|
throw new Error("Failed to create Codex ACP backend");
|
|
1355
1504
|
}
|
|
@@ -1376,8 +1525,25 @@ ${message.message}` : message.message;
|
|
|
1376
1525
|
promptToSend = buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
|
|
1377
1526
|
}
|
|
1378
1527
|
conversationHistory.addUserMessage(message.message);
|
|
1379
|
-
|
|
1380
|
-
|
|
1528
|
+
try {
|
|
1529
|
+
await activeRuntimeHandle.sendPrompt(promptToSend);
|
|
1530
|
+
await waitForResponseCompleteWithAbort(activeRuntimeHandle.backend, turnSignal);
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
if (!isNewRuntimeSession || !attemptedResumeSessionId || !isCodexUnknownResumeSessionError(error) || turnSignal.aborted) {
|
|
1533
|
+
throw error;
|
|
1534
|
+
}
|
|
1535
|
+
logger.debug(`[Codex] Resume session ${attemptedResumeSessionId} is unavailable; retrying with a fresh ACP session`, error);
|
|
1536
|
+
queueHistoryInjectionForRestart("Codex resume session is unavailable. Retrying with a fresh Codex session...");
|
|
1537
|
+
await disposeRuntimeHandle();
|
|
1538
|
+
session.clearSessionId();
|
|
1539
|
+
currentModeHash = null;
|
|
1540
|
+
permissionHandler.reset();
|
|
1541
|
+
selectionHandler.reset();
|
|
1542
|
+
resetTurnState();
|
|
1543
|
+
pending = message;
|
|
1544
|
+
retryingWithFreshSession = true;
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1381
1547
|
reasoningProcessor.completeCurrent();
|
|
1382
1548
|
shouldCommitAccumulatedResponse = true;
|
|
1383
1549
|
shouldInjectHistoryOnNextSession = false;
|
|
@@ -1407,6 +1573,9 @@ ${message.message}` : message.message;
|
|
|
1407
1573
|
}
|
|
1408
1574
|
} finally {
|
|
1409
1575
|
turnInFlight = false;
|
|
1576
|
+
if (retryingWithFreshSession) {
|
|
1577
|
+
continue;
|
|
1578
|
+
}
|
|
1410
1579
|
const finalizedTurn = await finalizeHappyOrgTurnWithBusinessAck({
|
|
1411
1580
|
metadata: session.runtimeSession.getMetadataSnapshot?.() ?? null,
|
|
1412
1581
|
queuedTurn: message.mode.happyOrg,
|
|
@@ -1502,52 +1671,6 @@ ${message.message}` : message.message;
|
|
|
1502
1671
|
return shouldSwitchToLocal ? "switch" : "exit";
|
|
1503
1672
|
}
|
|
1504
1673
|
|
|
1505
|
-
function getCodexSessionsRoot(options = {}) {
|
|
1506
|
-
const codexHomeDir = options.codexHomeDir || process.env.CODEX_HOME || join(os.homedir(), ".codex");
|
|
1507
|
-
return join(codexHomeDir, "sessions");
|
|
1508
|
-
}
|
|
1509
|
-
function collectFilesRecursive(dir, acc = []) {
|
|
1510
|
-
let entries;
|
|
1511
|
-
try {
|
|
1512
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1513
|
-
} catch {
|
|
1514
|
-
return acc;
|
|
1515
|
-
}
|
|
1516
|
-
for (const entry of entries) {
|
|
1517
|
-
const full = join(dir, entry.name);
|
|
1518
|
-
if (entry.isDirectory()) {
|
|
1519
|
-
collectFilesRecursive(full, acc);
|
|
1520
|
-
} else if (entry.isFile()) {
|
|
1521
|
-
acc.push(full);
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
return acc;
|
|
1525
|
-
}
|
|
1526
|
-
function extractCodexSessionIdFromPath(filePath) {
|
|
1527
|
-
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$/);
|
|
1528
|
-
return match?.[1] ?? null;
|
|
1529
|
-
}
|
|
1530
|
-
function findLatestCodexSessionIdSince(startTimeMs, options = {}) {
|
|
1531
|
-
try {
|
|
1532
|
-
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(".jsonl")).filter((full) => {
|
|
1533
|
-
try {
|
|
1534
|
-
return fs.statSync(full).mtimeMs >= startTimeMs;
|
|
1535
|
-
} catch {
|
|
1536
|
-
return false;
|
|
1537
|
-
}
|
|
1538
|
-
}).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
1539
|
-
for (const candidate of candidates) {
|
|
1540
|
-
const sessionId = extractCodexSessionIdFromPath(candidate);
|
|
1541
|
-
if (sessionId) {
|
|
1542
|
-
return sessionId;
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
} catch {
|
|
1546
|
-
return null;
|
|
1547
|
-
}
|
|
1548
|
-
return null;
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
1674
|
const MANAGED_CODEX_HOME_PREFIX = "happy-codex-home-";
|
|
1552
1675
|
function isManagedCodexHomePath(value) {
|
|
1553
1676
|
const trimmed = value?.trim();
|
|
@@ -1614,12 +1737,17 @@ function terminateCodexLocalChild(pid) {
|
|
|
1614
1737
|
}
|
|
1615
1738
|
async function codexLocal(opts) {
|
|
1616
1739
|
const baseArgs = [...opts.codexArgs ?? []];
|
|
1617
|
-
const args = opts.sessionId ? ["resume", opts.sessionId, ...baseArgs] : baseArgs;
|
|
1618
|
-
const startTime = Date.now();
|
|
1619
|
-
let detectedSessionId = opts.sessionId;
|
|
1620
|
-
const codexExecutable = resolveCodexExecutable();
|
|
1621
1740
|
const codexEnv = buildCodexLocalEnv(process.env);
|
|
1622
1741
|
const codexHomeDir = resolveCodexLocalHomeDir(codexEnv);
|
|
1742
|
+
const resumeSessionId = opts.sessionId && isCodexResumeSessionValidForCwd(opts.sessionId, opts.path, { codexHomeDir }) ? opts.sessionId : null;
|
|
1743
|
+
if (opts.sessionId && !resumeSessionId) {
|
|
1744
|
+
logger.debug(`[CodexLocal] Refusing to resume Codex session ${opts.sessionId} because its local session file does not match cwd ${opts.path}`);
|
|
1745
|
+
opts.onResumeSessionInvalid?.(opts.sessionId);
|
|
1746
|
+
}
|
|
1747
|
+
const args = resumeSessionId ? ["resume", resumeSessionId, ...baseArgs] : baseArgs;
|
|
1748
|
+
const startTime = Date.now();
|
|
1749
|
+
let detectedSessionId = resumeSessionId;
|
|
1750
|
+
const codexExecutable = resolveCodexExecutable();
|
|
1623
1751
|
logger.debug(`[CodexLocal] Spawning ${codexExecutable} with args: ${JSON.stringify(args)}`);
|
|
1624
1752
|
releaseTerminalInputForChild();
|
|
1625
1753
|
clearTerminalForChild();
|
|
@@ -1645,7 +1773,7 @@ async function codexLocal(opts) {
|
|
|
1645
1773
|
if (detectedSessionId) {
|
|
1646
1774
|
return;
|
|
1647
1775
|
}
|
|
1648
|
-
const nextSessionId = findLatestCodexSessionIdSince(startTime, { codexHomeDir });
|
|
1776
|
+
const nextSessionId = findLatestCodexSessionIdSince(startTime, { codexHomeDir, cwd: opts.path });
|
|
1649
1777
|
if (nextSessionId) {
|
|
1650
1778
|
detectedSessionId = nextSessionId;
|
|
1651
1779
|
logger.debug(`[CodexLocal] Detected session ID: ${nextSessionId}`);
|
|
@@ -1788,6 +1916,7 @@ async function codexLocalLauncher(session) {
|
|
|
1788
1916
|
abort: processAbortController.signal,
|
|
1789
1917
|
codexArgs: session.codexArgs,
|
|
1790
1918
|
onSessionFound: recordSessionFound,
|
|
1919
|
+
onResumeSessionInvalid: session.clearSessionId,
|
|
1791
1920
|
onThinkingChange: session.onThinkingChange
|
|
1792
1921
|
});
|
|
1793
1922
|
if (sessionId) {
|
|
@@ -1913,6 +2042,61 @@ function installFatalProcessHandlers(options) {
|
|
|
1913
2042
|
};
|
|
1914
2043
|
}
|
|
1915
2044
|
|
|
2045
|
+
function normalizeResumeSessionId(value) {
|
|
2046
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
2047
|
+
}
|
|
2048
|
+
function normalizeCodexArgsForHappy(options) {
|
|
2049
|
+
const sourceArgs = options.codexArgs ?? [];
|
|
2050
|
+
const codexArgs = [];
|
|
2051
|
+
let resumeSessionId = normalizeResumeSessionId(options.resumeSessionId);
|
|
2052
|
+
for (let index = 0; index < sourceArgs.length; index += 1) {
|
|
2053
|
+
const arg = sourceArgs[index];
|
|
2054
|
+
if (arg === "--resume") {
|
|
2055
|
+
const nextArg = sourceArgs[index + 1];
|
|
2056
|
+
const normalizedNextArg = normalizeResumeSessionId(nextArg);
|
|
2057
|
+
if (!normalizedNextArg || nextArg?.startsWith("-")) {
|
|
2058
|
+
throw new Error("Codex --resume requires a provider session id when used through Happy.");
|
|
2059
|
+
}
|
|
2060
|
+
resumeSessionId ??= normalizedNextArg;
|
|
2061
|
+
index += 1;
|
|
2062
|
+
continue;
|
|
2063
|
+
}
|
|
2064
|
+
if (arg.startsWith("--resume=")) {
|
|
2065
|
+
const normalizedValue = normalizeResumeSessionId(arg.slice("--resume=".length));
|
|
2066
|
+
if (!normalizedValue) {
|
|
2067
|
+
throw new Error("Codex --resume requires a provider session id when used through Happy.");
|
|
2068
|
+
}
|
|
2069
|
+
resumeSessionId ??= normalizedValue;
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2072
|
+
if (index === 0 && arg === "resume") {
|
|
2073
|
+
const nextArg = sourceArgs[index + 1];
|
|
2074
|
+
const normalizedNextArg = normalizeResumeSessionId(nextArg);
|
|
2075
|
+
if (normalizedNextArg && !nextArg?.startsWith("-")) {
|
|
2076
|
+
resumeSessionId ??= normalizedNextArg;
|
|
2077
|
+
index += 1;
|
|
2078
|
+
continue;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
codexArgs.push(arg);
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
codexArgs,
|
|
2085
|
+
resumeSessionId
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
function normalizePathForCodexResumeIdentity(path) {
|
|
2090
|
+
const normalized = path.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "");
|
|
2091
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2092
|
+
}
|
|
2093
|
+
function codexResumeCwdMatches(expected, actual) {
|
|
2094
|
+
const normalizedExpected = expected?.trim();
|
|
2095
|
+
if (!normalizedExpected) {
|
|
2096
|
+
return true;
|
|
2097
|
+
}
|
|
2098
|
+
return normalizePathForCodexResumeIdentity(normalizedExpected) === normalizePathForCodexResumeIdentity(actual);
|
|
2099
|
+
}
|
|
1916
2100
|
function resolveInitialCodexPermissionMode(opts) {
|
|
1917
2101
|
if (opts.permissionMode) {
|
|
1918
2102
|
return opts.permissionMode;
|
|
@@ -1948,6 +2132,10 @@ function resolveIncomingCodexPermissionMode(opts) {
|
|
|
1948
2132
|
};
|
|
1949
2133
|
}
|
|
1950
2134
|
async function runCodex(opts) {
|
|
2135
|
+
const normalizedArgs = normalizeCodexArgsForHappy({
|
|
2136
|
+
codexArgs: opts.codexArgs,
|
|
2137
|
+
resumeSessionId: opts.resumeSessionId
|
|
2138
|
+
});
|
|
1951
2139
|
const managedSessionTag = opts.startedBy === "daemon" ? readManagedSessionTag() : null;
|
|
1952
2140
|
const sessionTag = managedSessionTag ?? resolveManagedSessionTag(
|
|
1953
2141
|
opts.startedBy === "daemon" ? process.env : {}
|
|
@@ -1958,7 +2146,7 @@ async function runCodex(opts) {
|
|
|
1958
2146
|
permissionMode: opts.permissionMode,
|
|
1959
2147
|
startedBy: opts.startedBy,
|
|
1960
2148
|
startingMode: requestedStartingMode,
|
|
1961
|
-
codexArgs:
|
|
2149
|
+
codexArgs: normalizedArgs.codexArgs
|
|
1962
2150
|
});
|
|
1963
2151
|
const preserveCurrentPermissionModeForRemoteDefault = opts.startedBy === "daemon" && requestedStartingMode === "remote";
|
|
1964
2152
|
if (opts.startedBy === "daemon" && requestedStartingMode === "local") {
|
|
@@ -2008,6 +2196,20 @@ async function runCodex(opts) {
|
|
|
2008
2196
|
}
|
|
2009
2197
|
});
|
|
2010
2198
|
sessionClient = initialSession;
|
|
2199
|
+
const metadataCodexSessionCwd = typeof metadata.codexSessionCwd === "string" ? metadata.codexSessionCwd : null;
|
|
2200
|
+
const requestedResumeSessionId = normalizedArgs.resumeSessionId;
|
|
2201
|
+
const requestedResumeCwd = opts.resumeSessionCwd ?? metadataCodexSessionCwd;
|
|
2202
|
+
const resumeSessionMatchesCwd = requestedResumeSessionId ? codexResumeCwdMatches(requestedResumeCwd, metadata.path) && isCodexResumeSessionValidForCwd(requestedResumeSessionId, metadata.path) : false;
|
|
2203
|
+
const initialCodexSessionId = requestedResumeSessionId && resumeSessionMatchesCwd ? requestedResumeSessionId : null;
|
|
2204
|
+
if (requestedResumeSessionId && !resumeSessionMatchesCwd) {
|
|
2205
|
+
logger.debug(`[codex] Ignoring resume session ${requestedResumeSessionId} because it does not match cwd ${metadata.path}`);
|
|
2206
|
+
sessionClient.updateMetadata((currentMetadata) => {
|
|
2207
|
+
const nextMetadata = { ...currentMetadata };
|
|
2208
|
+
delete nextMetadata.codexSessionId;
|
|
2209
|
+
delete nextMetadata.codexSessionCwd;
|
|
2210
|
+
return nextMetadata;
|
|
2211
|
+
});
|
|
2212
|
+
}
|
|
2011
2213
|
const messageQueue = new MessageQueue2(getCodexExecutionFingerprint);
|
|
2012
2214
|
let currentPermissionMode = initialPermissionMode;
|
|
2013
2215
|
let currentModel;
|
|
@@ -2054,10 +2256,10 @@ async function runCodex(opts) {
|
|
|
2054
2256
|
path: metadata.path,
|
|
2055
2257
|
logPath: logger.logFilePath,
|
|
2056
2258
|
startupRolePrompt: happyOrgStartupBinding?.identityPrompt ?? null,
|
|
2057
|
-
sessionId:
|
|
2259
|
+
sessionId: initialCodexSessionId,
|
|
2058
2260
|
mode: requestedStartingMode,
|
|
2059
2261
|
messageQueue,
|
|
2060
|
-
codexArgs:
|
|
2262
|
+
codexArgs: normalizedArgs.codexArgs,
|
|
2061
2263
|
protocolDescriptor,
|
|
2062
2264
|
protocolStateSources: userScopedObserver ? [userScopedObserver] : [],
|
|
2063
2265
|
userObserver: userScopedObserver,
|