happy-imou-cloud 2.1.49 → 2.1.51
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/AcpBackend-CqO3D07V.mjs +2619 -0
- package/dist/AcpBackend-XPiTd6ph.cjs +2621 -0
- package/dist/{BaseReasoningProcessor-Dn9NcoHz.cjs → BaseReasoningProcessor-BD9tiwep.cjs} +1 -144
- package/dist/{BaseReasoningProcessor-CAVeOdyo.mjs → BaseReasoningProcessor-CjlayL2f.mjs} +2 -144
- package/dist/ConversationHistory-Bl2doTA-.cjs +780 -0
- package/dist/ConversationHistory-CI5bBfuA.mjs +771 -0
- package/dist/{ProviderSelectionHandler-BJJc7qOR.cjs → ProviderSelectionHandler-C7GE5QjX.cjs} +6 -6
- package/dist/{ProviderSelectionHandler-DIYidT13.mjs → ProviderSelectionHandler-uQ8jzdzr.mjs} +2 -2
- package/dist/RuntimeShell-BDt42io_.mjs +252 -0
- package/dist/RuntimeShell-D_Te12wq.cjs +258 -0
- package/dist/bootstrapManagedProviderSession-Bln-TwyB.cjs +147 -0
- package/dist/bootstrapManagedProviderSession-D2Z6YU3n.mjs +145 -0
- package/dist/claude-BKNT-2fG.cjs +1080 -0
- package/dist/claude-CnN5WCWj.mjs +1073 -0
- package/dist/codex-DLGP8WF6.mjs +577 -0
- package/dist/codex-Fv2eali8.cjs +582 -0
- package/dist/{command-VcH4hbhi.cjs → command-BWPlJyCN.cjs} +16 -8
- package/dist/{command-CzfRRhVe.mjs → command-CELwsYoG.mjs} +15 -7
- package/dist/config-CFL0Gkqt.cjs +184 -0
- package/dist/config-ChSPe7p9.mjs +174 -0
- package/dist/createDefaultRuntimeShell-BXu3vCvT.cjs +33 -0
- package/dist/createDefaultRuntimeShell-DOg6g3-G.mjs +31 -0
- package/dist/cursor-Blq1cHdr.cjs +91 -0
- package/dist/cursor-CwPNSy_A.mjs +88 -0
- package/dist/future-Dq4Ha1Dn.cjs +24 -0
- package/dist/future-xRdLl3vf.mjs +22 -0
- package/dist/{index-xa1kwZoj.cjs → index-B_JYgMUS.cjs} +189 -5352
- package/dist/{index-7Z93BoVn.mjs → index-CX-F_fuk.mjs} +177 -5331
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/installFatalProcessHandlers-0vaw9MAz.mjs +55 -0
- package/dist/installFatalProcessHandlers-CyURn5Bp.cjs +57 -0
- package/dist/launch-BoCCEd5p.mjs +63 -0
- package/dist/launch-wZA5BcvS.cjs +66 -0
- package/dist/lib.cjs +2 -3
- package/dist/lib.d.cts +20 -17
- package/dist/lib.d.mts +20 -17
- package/dist/lib.mjs +1 -2
- package/dist/resolveCommand-B3BGyBE2.mjs +189 -0
- package/dist/resolveCommand-DYMd9PNC.cjs +193 -0
- package/dist/{runClaude-zCwRhpOw.mjs → runClaude-Be0myF9k.mjs} +8 -5
- package/dist/{runClaude-BBGNmGj6.cjs → runClaude-DZJt5er7.cjs} +46 -43
- package/dist/{runCodex-BbgLVjb9.mjs → runCodex-BSnyN4m7.mjs} +226 -117
- package/dist/{runCodex-jUU6U2tZ.cjs → runCodex-DTCcGRue.cjs} +269 -160
- package/dist/runCursor-Bn1PuwJy.cjs +506 -0
- package/dist/runCursor-M6dQ6bGF.mjs +504 -0
- package/dist/{runGemini-DcwNsudA.mjs → runGemini-BNm4vYKA.mjs} +279 -5
- package/dist/{runGemini-C0NT8MHK.cjs → runGemini-Bn3lFhz6.cjs} +309 -35
- package/dist/{registerKillSessionHandler-DLDg2EES.mjs → sessionControl-1bT_7OI6.mjs} +1643 -2405
- package/dist/{registerKillSessionHandler-CfCya6si.cjs → sessionControl-flKnQrx0.cjs} +1647 -2417
- package/dist/{api-DnqaNvyV.mjs → types-B5vtxa38.mjs} +55 -5
- package/dist/{api-D7nAeZi7.cjs → types-CttABk32.cjs} +55 -4
- package/package.json +2 -2
- package/dist/types-CiliQpqS.mjs +0 -52
- package/dist/types-DVk3crez.cjs +0 -54
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var persistence = require('./
|
|
4
|
-
var
|
|
5
|
-
var index = require('./index-
|
|
3
|
+
var persistence = require('./types-CttABk32.cjs');
|
|
4
|
+
var sessionControl = require('./sessionControl-flKnQrx0.cjs');
|
|
5
|
+
var index = require('./index-B_JYgMUS.cjs');
|
|
6
6
|
require('cross-spawn');
|
|
7
7
|
require('@agentclientprotocol/sdk');
|
|
8
8
|
var node_crypto = require('node:crypto');
|
|
@@ -26,12 +26,19 @@ require('tweetnacl');
|
|
|
26
26
|
require('open');
|
|
27
27
|
var React = require('react');
|
|
28
28
|
var ink = require('ink');
|
|
29
|
-
var ProviderSelectionHandler = require('./ProviderSelectionHandler-
|
|
30
|
-
var BaseReasoningProcessor = require('./BaseReasoningProcessor-Dn9NcoHz.cjs');
|
|
31
|
-
require('zod');
|
|
29
|
+
var ProviderSelectionHandler = require('./ProviderSelectionHandler-C7GE5QjX.cjs');
|
|
32
30
|
require('socket.io-client');
|
|
33
31
|
require('expo-server-sdk');
|
|
34
|
-
require('./
|
|
32
|
+
var ConversationHistory = require('./ConversationHistory-Bl2doTA-.cjs');
|
|
33
|
+
var RuntimeShell = require('./RuntimeShell-D_Te12wq.cjs');
|
|
34
|
+
var AcpBackend = require('./AcpBackend-XPiTd6ph.cjs');
|
|
35
|
+
var resolveCommand = require('./resolveCommand-DYMd9PNC.cjs');
|
|
36
|
+
var codex = require('./codex-Fv2eali8.cjs');
|
|
37
|
+
var BaseReasoningProcessor = require('./BaseReasoningProcessor-BD9tiwep.cjs');
|
|
38
|
+
var future = require('./future-Dq4Ha1Dn.cjs');
|
|
39
|
+
var bootstrapManagedProviderSession = require('./bootstrapManagedProviderSession-Bln-TwyB.cjs');
|
|
40
|
+
var installFatalProcessHandlers = require('./installFatalProcessHandlers-CyURn5Bp.cjs');
|
|
41
|
+
require('zod');
|
|
35
42
|
require('qrcode-terminal');
|
|
36
43
|
require('node:module');
|
|
37
44
|
require('url');
|
|
@@ -240,12 +247,19 @@ class CodexSession {
|
|
|
240
247
|
this.sessionId = sessionId;
|
|
241
248
|
this.client.updateMetadata((metadata) => ({
|
|
242
249
|
...metadata,
|
|
243
|
-
codexSessionId: sessionId
|
|
250
|
+
codexSessionId: sessionId,
|
|
251
|
+
codexSessionCwd: this.path
|
|
244
252
|
}));
|
|
245
253
|
persistence.logger.debug(`[CodexSession] Session ID ${sessionId} added to metadata`);
|
|
246
254
|
};
|
|
247
255
|
clearSessionId = () => {
|
|
248
256
|
this.sessionId = null;
|
|
257
|
+
this.client.updateMetadata((metadata) => {
|
|
258
|
+
const nextMetadata = { ...metadata };
|
|
259
|
+
delete nextMetadata.codexSessionId;
|
|
260
|
+
delete nextMetadata.codexSessionCwd;
|
|
261
|
+
return nextMetadata;
|
|
262
|
+
});
|
|
249
263
|
persistence.logger.debug("[CodexSession] Session ID cleared");
|
|
250
264
|
};
|
|
251
265
|
handleUserObserverEphemeral = (event) => {
|
|
@@ -360,7 +374,7 @@ const CodexDisplay = ({ messageBuffer, logPath, onExit, onSwitchToLocal, title }
|
|
|
360
374
|
}
|
|
361
375
|
};
|
|
362
376
|
const formatMessage = (msg) => {
|
|
363
|
-
const lines =
|
|
377
|
+
const lines = RuntimeShell.formatDisplayMessage(msg.content).split("\n");
|
|
364
378
|
const maxLineLength = terminalWidth - 10;
|
|
365
379
|
return lines.map((line) => {
|
|
366
380
|
if (line.length <= maxLineLength) return line;
|
|
@@ -402,7 +416,7 @@ const CodexDisplay = ({ messageBuffer, logPath, onExit, onSwitchToLocal, title }
|
|
|
402
416
|
));
|
|
403
417
|
};
|
|
404
418
|
|
|
405
|
-
class CodexPermissionHandler extends
|
|
419
|
+
class CodexPermissionHandler extends sessionControl.BasePermissionHandler {
|
|
406
420
|
constructor(session) {
|
|
407
421
|
super(session);
|
|
408
422
|
}
|
|
@@ -517,6 +531,113 @@ function getCodexExecutionFingerprint(mode) {
|
|
|
517
531
|
});
|
|
518
532
|
}
|
|
519
533
|
|
|
534
|
+
function getCodexSessionsRoot(options = {}) {
|
|
535
|
+
const codexHomeDir = options.codexHomeDir || process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
536
|
+
return path.join(codexHomeDir, "sessions");
|
|
537
|
+
}
|
|
538
|
+
function collectFilesRecursive(dir, acc = []) {
|
|
539
|
+
let entries;
|
|
540
|
+
try {
|
|
541
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
542
|
+
} catch {
|
|
543
|
+
return acc;
|
|
544
|
+
}
|
|
545
|
+
for (const entry of entries) {
|
|
546
|
+
const full = path.join(dir, entry.name);
|
|
547
|
+
if (entry.isDirectory()) {
|
|
548
|
+
collectFilesRecursive(full, acc);
|
|
549
|
+
} else if (entry.isFile()) {
|
|
550
|
+
acc.push(full);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return acc;
|
|
554
|
+
}
|
|
555
|
+
function extractCodexSessionIdFromPath(filePath) {
|
|
556
|
+
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$/);
|
|
557
|
+
return match?.[1] ?? null;
|
|
558
|
+
}
|
|
559
|
+
function normalizePathForSessionMatch(path$1) {
|
|
560
|
+
const normalizedPath = path.normalize(path$1).replace(/[\\/]+/g, "/").replace(/\/+$/, "");
|
|
561
|
+
return process.platform === "win32" ? normalizedPath.toLowerCase() : normalizedPath;
|
|
562
|
+
}
|
|
563
|
+
function extractCodexSessionCwdFromFile(filePath) {
|
|
564
|
+
let contents;
|
|
565
|
+
try {
|
|
566
|
+
contents = fs.readFileSync(filePath, "utf8");
|
|
567
|
+
} catch {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
571
|
+
if (!line.trim()) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
let record;
|
|
575
|
+
try {
|
|
576
|
+
record = JSON.parse(line);
|
|
577
|
+
} catch {
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
if (record.type !== "session_meta" || typeof record.payload !== "object" || record.payload === null) {
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
const cwd = record.payload.cwd;
|
|
584
|
+
return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : null;
|
|
585
|
+
}
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
function codexSessionFileMatchesCwd(filePath, cwd) {
|
|
589
|
+
const expectedCwd = cwd?.trim();
|
|
590
|
+
if (!expectedCwd) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
const actualCwd = extractCodexSessionCwdFromFile(filePath);
|
|
594
|
+
if (!actualCwd) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
return normalizePathForSessionMatch(actualCwd) === normalizePathForSessionMatch(expectedCwd);
|
|
598
|
+
}
|
|
599
|
+
function findCodexResumeFile(sessionId, options = {}) {
|
|
600
|
+
if (!sessionId) return null;
|
|
601
|
+
try {
|
|
602
|
+
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(`-${sessionId}.jsonl`)).filter((full) => {
|
|
603
|
+
try {
|
|
604
|
+
return fs.statSync(full).isFile();
|
|
605
|
+
} catch {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
}).filter((full) => codexSessionFileMatchesCwd(full, options.cwd)).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
609
|
+
return candidates[0] || null;
|
|
610
|
+
} catch {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
function isCodexResumeSessionValidForCwd(sessionId, cwd, options = {}) {
|
|
615
|
+
if (!sessionId?.trim()) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
return findCodexResumeFile(sessionId, { ...options, cwd }) !== null;
|
|
619
|
+
}
|
|
620
|
+
function findLatestCodexSessionIdSince(startTimeMs, options = {}) {
|
|
621
|
+
try {
|
|
622
|
+
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(".jsonl")).filter((full) => {
|
|
623
|
+
try {
|
|
624
|
+
return fs.statSync(full).mtimeMs >= startTimeMs;
|
|
625
|
+
} catch {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}).filter((full) => codexSessionFileMatchesCwd(full, options.cwd)).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
629
|
+
for (const candidate of candidates) {
|
|
630
|
+
const sessionId = extractCodexSessionIdFromPath(candidate);
|
|
631
|
+
if (sessionId) {
|
|
632
|
+
return sessionId;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
} catch {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
|
|
520
641
|
function delay(ms) {
|
|
521
642
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
522
643
|
}
|
|
@@ -622,8 +743,8 @@ function appendCodexAuthScopeHint(message, searchableLower) {
|
|
|
622
743
|
}
|
|
623
744
|
function extractLocalProcessExit(error) {
|
|
624
745
|
const record = typeof error === "object" && error !== null ? error : null;
|
|
625
|
-
const text =
|
|
626
|
-
const stderrTextFromRecord = record ?
|
|
746
|
+
const text = RuntimeShell.formatDisplayMessage(error).trim();
|
|
747
|
+
const stderrTextFromRecord = record ? RuntimeShell.formatDisplayMessage(record.stderr).trim() : "";
|
|
627
748
|
const stderrFromTextMatch = text.match(/Recent stderr:\s*([\s\S]+)$/i);
|
|
628
749
|
const stderrText = stderrTextFromRecord || stderrFromTextMatch?.[1]?.trim() || "";
|
|
629
750
|
let exitCode = typeof record?.exitCode === "number" && Number.isFinite(record.exitCode) ? record.exitCode : null;
|
|
@@ -685,19 +806,30 @@ function formatCodexLocalProcessExit(error) {
|
|
|
685
806
|
function shouldInjectLargeOutputRecoveryHint(error) {
|
|
686
807
|
const record = typeof error === "object" && error !== null ? error : null;
|
|
687
808
|
const searchableText = [
|
|
688
|
-
|
|
689
|
-
record ?
|
|
690
|
-
record ?
|
|
691
|
-
record ?
|
|
809
|
+
RuntimeShell.formatDisplayMessage(error).trim(),
|
|
810
|
+
record ? RuntimeShell.formatDisplayMessage(record.stderr).trim() : "",
|
|
811
|
+
record ? RuntimeShell.formatDisplayMessage(record.detail).trim() : "",
|
|
812
|
+
record ? RuntimeShell.formatDisplayMessage(record.data).trim() : ""
|
|
692
813
|
].filter(Boolean).join("\n").toLowerCase();
|
|
693
814
|
return searchableText.includes("memory allocation of") || searchableText.includes("out of memory") || searchableText.includes("oversized command output");
|
|
694
815
|
}
|
|
816
|
+
function isCodexUnknownResumeSessionError(error) {
|
|
817
|
+
const record = typeof error === "object" && error !== null ? error : null;
|
|
818
|
+
const searchableText = [
|
|
819
|
+
RuntimeShell.formatDisplayMessage(error).trim(),
|
|
820
|
+
record ? RuntimeShell.formatDisplayMessage(record.message).trim() : "",
|
|
821
|
+
record ? RuntimeShell.formatDisplayMessage(record.stderr).trim() : "",
|
|
822
|
+
record ? RuntimeShell.formatDisplayMessage(record.detail).trim() : "",
|
|
823
|
+
record ? RuntimeShell.formatDisplayMessage(record.data).trim() : ""
|
|
824
|
+
].filter(Boolean).join("\n");
|
|
825
|
+
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);
|
|
826
|
+
}
|
|
695
827
|
function normalizeCodexBackendError(error) {
|
|
696
828
|
const record = typeof error === "object" && error !== null ? error : null;
|
|
697
|
-
const text =
|
|
698
|
-
const stderrText = record ?
|
|
699
|
-
const detailText = record ?
|
|
700
|
-
const dataText = record ?
|
|
829
|
+
const text = RuntimeShell.formatDisplayMessage(error).trim();
|
|
830
|
+
const stderrText = record ? RuntimeShell.formatDisplayMessage(record.stderr).trim() : "";
|
|
831
|
+
const detailText = record ? RuntimeShell.formatDisplayMessage(record.detail).trim() : "";
|
|
832
|
+
const dataText = record ? RuntimeShell.formatDisplayMessage(record.data).trim() : "";
|
|
701
833
|
const searchableText = [text, stderrText, detailText, dataText].filter(Boolean).join("\n");
|
|
702
834
|
const prefix = buildErrorPrefix(record);
|
|
703
835
|
const searchableLower = searchableText.toLowerCase();
|
|
@@ -781,12 +913,12 @@ function shouldEmitCodexReadyAfterWait(opts) {
|
|
|
781
913
|
function registerCodexRemoteRpcHandlers(clientSession, handlers) {
|
|
782
914
|
clientSession.rpcHandlerManager.registerHandler("abort", handlers.handleAbort);
|
|
783
915
|
clientSession.rpcHandlerManager.registerHandler("switch", handlers.handleSwitchToLocal);
|
|
784
|
-
|
|
916
|
+
sessionControl.registerKillSessionHandler(clientSession.rpcHandlerManager, handlers.handleKillSession);
|
|
785
917
|
}
|
|
786
918
|
async function codexRemoteLauncher(session) {
|
|
787
919
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
788
|
-
const messageBuffer = new
|
|
789
|
-
const renderSessionTranscript =
|
|
920
|
+
const messageBuffer = new ConversationHistory.MessageBuffer({ enabled: hasTTY });
|
|
921
|
+
const renderSessionTranscript = ConversationHistory.createSessionTranscriptInkRenderer({ messageBuffer });
|
|
790
922
|
let inkInstance = null;
|
|
791
923
|
let shouldExit = false;
|
|
792
924
|
let shouldSwitchToLocal = false;
|
|
@@ -812,7 +944,7 @@ async function codexRemoteLauncher(session) {
|
|
|
812
944
|
const assistantMessageStream = new persistence.AssistantMessageStream();
|
|
813
945
|
const permissionHandler = new CodexPermissionHandler(session.client);
|
|
814
946
|
const selectionHandler = new CodexSelectionHandler(session.client);
|
|
815
|
-
const conversationHistory = new
|
|
947
|
+
const conversationHistory = new ConversationHistory.ConversationHistory({ maxMessages: 20, maxCharacters: 5e4 });
|
|
816
948
|
const reasoningProcessor = new ReasoningProcessor((message) => {
|
|
817
949
|
session.runtimeSession.sendCodexMessage(message);
|
|
818
950
|
});
|
|
@@ -827,7 +959,7 @@ async function codexRemoteLauncher(session) {
|
|
|
827
959
|
return;
|
|
828
960
|
}
|
|
829
961
|
try {
|
|
830
|
-
const notification =
|
|
962
|
+
const notification = ConversationHistory.buildReadyPushNotification({
|
|
831
963
|
providerLabel: "Codex",
|
|
832
964
|
metadata: session.runtimeSession.getMetadataSnapshot?.() ?? null,
|
|
833
965
|
sessionId: session.runtimeSession.sessionId
|
|
@@ -997,7 +1129,7 @@ async function codexRemoteLauncher(session) {
|
|
|
997
1129
|
};
|
|
998
1130
|
const setupRuntimeMessageHandler = (activeRuntimeHandle) => {
|
|
999
1131
|
const forwardAgentMessage = (agentMessage) => {
|
|
1000
|
-
|
|
1132
|
+
sessionControl.forwardAgentMessageToProviderSession(agentMessage, {
|
|
1001
1133
|
provider: "codex",
|
|
1002
1134
|
send: (body) => session.runtimeSession.sendCodexMessage(body),
|
|
1003
1135
|
toolResultType: "tool-call-result"
|
|
@@ -1063,7 +1195,7 @@ async function codexRemoteLauncher(session) {
|
|
|
1063
1195
|
}
|
|
1064
1196
|
case "tool-call": {
|
|
1065
1197
|
commitActiveAssistantMessageStream();
|
|
1066
|
-
const toolArgs = hasRenderableToolPayload(msg.args) ?
|
|
1198
|
+
const toolArgs = hasRenderableToolPayload(msg.args) ? RuntimeShell.truncateDisplayMessage(msg.args, 100) : "";
|
|
1067
1199
|
messageBuffer.addMessage(
|
|
1068
1200
|
`Executing: ${msg.toolName}${toolArgs ? ` ${toolArgs}` : ""}`,
|
|
1069
1201
|
"tool"
|
|
@@ -1072,8 +1204,8 @@ async function codexRemoteLauncher(session) {
|
|
|
1072
1204
|
return;
|
|
1073
1205
|
}
|
|
1074
1206
|
case "tool-result": {
|
|
1075
|
-
const isError =
|
|
1076
|
-
const resultText = hasRenderableToolPayload(msg.result) ?
|
|
1207
|
+
const isError = sessionControl.inferToolResultError(msg.result);
|
|
1208
|
+
const resultText = hasRenderableToolPayload(msg.result) ? RuntimeShell.truncateDisplayMessage(msg.result, 200) : "";
|
|
1077
1209
|
if (isError || resultText) {
|
|
1078
1210
|
messageBuffer.addMessage(
|
|
1079
1211
|
`${isError ? "Error:" : "Result:"} ${resultText || "Unknown error"}`.trim(),
|
|
@@ -1089,12 +1221,12 @@ async function codexRemoteLauncher(session) {
|
|
|
1089
1221
|
return;
|
|
1090
1222
|
}
|
|
1091
1223
|
case "terminal-output": {
|
|
1092
|
-
const terminalOutput =
|
|
1224
|
+
const terminalOutput = sessionControl.renderTerminalOutputPreview(msg.data);
|
|
1093
1225
|
if (!terminalOutput) {
|
|
1094
1226
|
return;
|
|
1095
1227
|
}
|
|
1096
1228
|
messageBuffer.addMessage(terminalOutput, "result");
|
|
1097
|
-
const forwardedOutput =
|
|
1229
|
+
const forwardedOutput = sessionControl.prepareTerminalOutputForForwarding(msg.data);
|
|
1098
1230
|
if (forwardedOutput) {
|
|
1099
1231
|
forwardAgentMessage({
|
|
1100
1232
|
...msg,
|
|
@@ -1105,8 +1237,8 @@ async function codexRemoteLauncher(session) {
|
|
|
1105
1237
|
}
|
|
1106
1238
|
case "permission-request": {
|
|
1107
1239
|
try {
|
|
1108
|
-
const permissionRequest =
|
|
1109
|
-
const notification =
|
|
1240
|
+
const permissionRequest = ConversationHistory.extractPermissionRequestPushContext(msg);
|
|
1241
|
+
const notification = ConversationHistory.buildPermissionPushNotification({
|
|
1110
1242
|
providerLabel: "Codex",
|
|
1111
1243
|
metadata: session.runtimeSession.getMetadataSnapshot?.() ?? null,
|
|
1112
1244
|
sessionId: session.runtimeSession.sessionId,
|
|
@@ -1139,9 +1271,9 @@ async function codexRemoteLauncher(session) {
|
|
|
1139
1271
|
}
|
|
1140
1272
|
case "patch-apply-end": {
|
|
1141
1273
|
if (msg.success) {
|
|
1142
|
-
messageBuffer.addMessage(
|
|
1274
|
+
messageBuffer.addMessage(RuntimeShell.truncateDisplayMessage(msg.stdout || "Files modified successfully", 200), "result");
|
|
1143
1275
|
} else {
|
|
1144
|
-
messageBuffer.addMessage(`Error: ${
|
|
1276
|
+
messageBuffer.addMessage(`Error: ${RuntimeShell.truncateDisplayMessage(msg.stderr || "Failed to modify files", 200)}`, "result");
|
|
1145
1277
|
}
|
|
1146
1278
|
forwardAgentMessage(msg);
|
|
1147
1279
|
return;
|
|
@@ -1175,7 +1307,12 @@ async function codexRemoteLauncher(session) {
|
|
|
1175
1307
|
};
|
|
1176
1308
|
const createRuntimeHandle = async (mode) => {
|
|
1177
1309
|
const executionMode = resolveCodexAcpExecutionMode(mode);
|
|
1178
|
-
const
|
|
1310
|
+
const resumeSessionId = session.sessionId && isCodexResumeSessionValidForCwd(session.sessionId, session.path) ? session.sessionId : null;
|
|
1311
|
+
if (session.sessionId && !resumeSessionId) {
|
|
1312
|
+
persistence.logger.debug(`[Codex] Refusing to resume Codex session ${session.sessionId} because its local session file does not match cwd ${session.path}`);
|
|
1313
|
+
session.clearSessionId();
|
|
1314
|
+
}
|
|
1315
|
+
const validation = resolveCommand.validateCodexAcpSpawn({
|
|
1179
1316
|
command: process.env.HAPPY_CODEX_ACP_COMMAND,
|
|
1180
1317
|
model: executionMode.model,
|
|
1181
1318
|
sandbox: executionMode.sandbox,
|
|
@@ -1185,17 +1322,17 @@ async function codexRemoteLauncher(session) {
|
|
|
1185
1322
|
if (!validation.ok) {
|
|
1186
1323
|
throw new Error(validation.errorMessage);
|
|
1187
1324
|
}
|
|
1188
|
-
const { session: nextRuntimeHandle } = await
|
|
1325
|
+
const { session: nextRuntimeHandle } = await ConversationHistory.launchRuntimeHandleWithFactoryResult({
|
|
1189
1326
|
provider: "codex",
|
|
1190
1327
|
cwd: session.path,
|
|
1191
|
-
createBackendResult: (opts) =>
|
|
1328
|
+
createBackendResult: (opts) => codex.createCodexBackend({
|
|
1192
1329
|
...opts,
|
|
1193
1330
|
baseArgs: session.codexArgs,
|
|
1194
1331
|
model: executionMode.model,
|
|
1195
1332
|
sandbox: executionMode.sandbox,
|
|
1196
1333
|
approvalPolicy: executionMode.approvalPolicy,
|
|
1197
1334
|
permissionHandler,
|
|
1198
|
-
resumeSessionId
|
|
1335
|
+
resumeSessionId,
|
|
1199
1336
|
selectionHandler: {
|
|
1200
1337
|
handleSelection: (request) => selectionHandler.requestSelection(request)
|
|
1201
1338
|
}
|
|
@@ -1203,7 +1340,7 @@ async function codexRemoteLauncher(session) {
|
|
|
1203
1340
|
});
|
|
1204
1341
|
runtimeHandle = nextRuntimeHandle;
|
|
1205
1342
|
setupRuntimeMessageHandler(nextRuntimeHandle);
|
|
1206
|
-
const providerSessionId = nextRuntimeHandle.backend instanceof
|
|
1343
|
+
const providerSessionId = nextRuntimeHandle.backend instanceof AcpBackend.AcpBackend ? nextRuntimeHandle.backend.getProviderSessionId() : null;
|
|
1207
1344
|
session.onSessionFound(providerSessionId ?? nextRuntimeHandle.sessionId);
|
|
1208
1345
|
return nextRuntimeHandle;
|
|
1209
1346
|
};
|
|
@@ -1346,12 +1483,31 @@ async function codexRemoteLauncher(session) {
|
|
|
1346
1483
|
const turnSignal = abortController.signal;
|
|
1347
1484
|
let sentTurnResultPush = false;
|
|
1348
1485
|
let turnStatus = "task_complete";
|
|
1486
|
+
let retryingWithFreshSession = false;
|
|
1349
1487
|
currentHappyOrgTurn = message.mode.happyOrg ?? null;
|
|
1350
1488
|
try {
|
|
1351
1489
|
turnInFlight = true;
|
|
1352
1490
|
shouldCommitAccumulatedResponse = false;
|
|
1353
1491
|
const isNewRuntimeSession = runtimeHandle === null;
|
|
1354
|
-
const
|
|
1492
|
+
const attemptedResumeSessionId = isNewRuntimeSession ? session.sessionId : null;
|
|
1493
|
+
let activeRuntimeHandle;
|
|
1494
|
+
try {
|
|
1495
|
+
activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
|
|
1496
|
+
} catch (error) {
|
|
1497
|
+
if (!isNewRuntimeSession || !attemptedResumeSessionId || !isCodexUnknownResumeSessionError(error) || turnSignal.aborted) {
|
|
1498
|
+
throw error;
|
|
1499
|
+
}
|
|
1500
|
+
persistence.logger.debug(`[Codex] Resume session ${attemptedResumeSessionId} failed during ACP startup; retrying with a fresh session`, error);
|
|
1501
|
+
queueHistoryInjectionForRestart("Codex resume session is unavailable. Retrying with a fresh Codex session...");
|
|
1502
|
+
session.clearSessionId();
|
|
1503
|
+
currentModeHash = null;
|
|
1504
|
+
permissionHandler.reset();
|
|
1505
|
+
selectionHandler.reset();
|
|
1506
|
+
resetTurnState();
|
|
1507
|
+
pending = message;
|
|
1508
|
+
retryingWithFreshSession = true;
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1355
1511
|
if (!activeRuntimeHandle) {
|
|
1356
1512
|
throw new Error("Failed to create Codex ACP backend");
|
|
1357
1513
|
}
|
|
@@ -1375,11 +1531,28 @@ async function codexRemoteLauncher(session) {
|
|
|
1375
1531
|
|
|
1376
1532
|
${message.message}` : message.message;
|
|
1377
1533
|
if (message.mode.happyOrg) {
|
|
1378
|
-
promptToSend =
|
|
1534
|
+
promptToSend = sessionControl.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
|
|
1379
1535
|
}
|
|
1380
1536
|
conversationHistory.addUserMessage(message.message);
|
|
1381
|
-
|
|
1382
|
-
|
|
1537
|
+
try {
|
|
1538
|
+
await activeRuntimeHandle.sendPrompt(promptToSend);
|
|
1539
|
+
await sessionControl.waitForResponseCompleteWithAbort(activeRuntimeHandle.backend, turnSignal);
|
|
1540
|
+
} catch (error) {
|
|
1541
|
+
if (!isNewRuntimeSession || !attemptedResumeSessionId || !isCodexUnknownResumeSessionError(error) || turnSignal.aborted) {
|
|
1542
|
+
throw error;
|
|
1543
|
+
}
|
|
1544
|
+
persistence.logger.debug(`[Codex] Resume session ${attemptedResumeSessionId} is unavailable; retrying with a fresh ACP session`, error);
|
|
1545
|
+
queueHistoryInjectionForRestart("Codex resume session is unavailable. Retrying with a fresh Codex session...");
|
|
1546
|
+
await disposeRuntimeHandle();
|
|
1547
|
+
session.clearSessionId();
|
|
1548
|
+
currentModeHash = null;
|
|
1549
|
+
permissionHandler.reset();
|
|
1550
|
+
selectionHandler.reset();
|
|
1551
|
+
resetTurnState();
|
|
1552
|
+
pending = message;
|
|
1553
|
+
retryingWithFreshSession = true;
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1383
1556
|
reasoningProcessor.completeCurrent();
|
|
1384
1557
|
shouldCommitAccumulatedResponse = true;
|
|
1385
1558
|
shouldInjectHistoryOnNextSession = false;
|
|
@@ -1409,7 +1582,10 @@ ${message.message}` : message.message;
|
|
|
1409
1582
|
}
|
|
1410
1583
|
} finally {
|
|
1411
1584
|
turnInFlight = false;
|
|
1412
|
-
|
|
1585
|
+
if (retryingWithFreshSession) {
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
const finalizedTurn = await sessionControl.finalizeHappyOrgTurnWithBusinessAck({
|
|
1413
1589
|
metadata: session.runtimeSession.getMetadataSnapshot?.() ?? null,
|
|
1414
1590
|
queuedTurn: message.mode.happyOrg,
|
|
1415
1591
|
responseText: accumulatedResponse,
|
|
@@ -1435,7 +1611,7 @@ ${message.message}` : message.message;
|
|
|
1435
1611
|
emitFinalAssistantMessage(finalizedTurn.cleanedText);
|
|
1436
1612
|
if (!shouldExit && !shouldSwitchToLocal) {
|
|
1437
1613
|
try {
|
|
1438
|
-
const notification =
|
|
1614
|
+
const notification = ConversationHistory.buildTurnResultPushNotification({
|
|
1439
1615
|
providerLabel: "Codex",
|
|
1440
1616
|
metadata: finalizedTurn.nextMetadata ?? session.runtimeSession.getMetadataSnapshot?.() ?? null,
|
|
1441
1617
|
sessionId: session.runtimeSession.sessionId,
|
|
@@ -1504,52 +1680,6 @@ ${message.message}` : message.message;
|
|
|
1504
1680
|
return shouldSwitchToLocal ? "switch" : "exit";
|
|
1505
1681
|
}
|
|
1506
1682
|
|
|
1507
|
-
function getCodexSessionsRoot(options = {}) {
|
|
1508
|
-
const codexHomeDir = options.codexHomeDir || process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
1509
|
-
return path.join(codexHomeDir, "sessions");
|
|
1510
|
-
}
|
|
1511
|
-
function collectFilesRecursive(dir, acc = []) {
|
|
1512
|
-
let entries;
|
|
1513
|
-
try {
|
|
1514
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1515
|
-
} catch {
|
|
1516
|
-
return acc;
|
|
1517
|
-
}
|
|
1518
|
-
for (const entry of entries) {
|
|
1519
|
-
const full = path.join(dir, entry.name);
|
|
1520
|
-
if (entry.isDirectory()) {
|
|
1521
|
-
collectFilesRecursive(full, acc);
|
|
1522
|
-
} else if (entry.isFile()) {
|
|
1523
|
-
acc.push(full);
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
return acc;
|
|
1527
|
-
}
|
|
1528
|
-
function extractCodexSessionIdFromPath(filePath) {
|
|
1529
|
-
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$/);
|
|
1530
|
-
return match?.[1] ?? null;
|
|
1531
|
-
}
|
|
1532
|
-
function findLatestCodexSessionIdSince(startTimeMs, options = {}) {
|
|
1533
|
-
try {
|
|
1534
|
-
const candidates = collectFilesRecursive(getCodexSessionsRoot(options)).filter((full) => full.endsWith(".jsonl")).filter((full) => {
|
|
1535
|
-
try {
|
|
1536
|
-
return fs.statSync(full).mtimeMs >= startTimeMs;
|
|
1537
|
-
} catch {
|
|
1538
|
-
return false;
|
|
1539
|
-
}
|
|
1540
|
-
}).sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
1541
|
-
for (const candidate of candidates) {
|
|
1542
|
-
const sessionId = extractCodexSessionIdFromPath(candidate);
|
|
1543
|
-
if (sessionId) {
|
|
1544
|
-
return sessionId;
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
} catch {
|
|
1548
|
-
return null;
|
|
1549
|
-
}
|
|
1550
|
-
return null;
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
1683
|
const MANAGED_CODEX_HOME_PREFIX = "happy-codex-home-";
|
|
1554
1684
|
function isManagedCodexHomePath(value) {
|
|
1555
1685
|
const trimmed = value?.trim();
|
|
@@ -1616,12 +1746,17 @@ function terminateCodexLocalChild(pid) {
|
|
|
1616
1746
|
}
|
|
1617
1747
|
async function codexLocal(opts) {
|
|
1618
1748
|
const baseArgs = [...opts.codexArgs ?? []];
|
|
1619
|
-
const args = opts.sessionId ? ["resume", opts.sessionId, ...baseArgs] : baseArgs;
|
|
1620
|
-
const startTime = Date.now();
|
|
1621
|
-
let detectedSessionId = opts.sessionId;
|
|
1622
|
-
const codexExecutable = index.resolveCodexExecutable();
|
|
1623
1749
|
const codexEnv = buildCodexLocalEnv(process.env);
|
|
1624
1750
|
const codexHomeDir = resolveCodexLocalHomeDir(codexEnv);
|
|
1751
|
+
const resumeSessionId = opts.sessionId && isCodexResumeSessionValidForCwd(opts.sessionId, opts.path, { codexHomeDir }) ? opts.sessionId : null;
|
|
1752
|
+
if (opts.sessionId && !resumeSessionId) {
|
|
1753
|
+
persistence.logger.debug(`[CodexLocal] Refusing to resume Codex session ${opts.sessionId} because its local session file does not match cwd ${opts.path}`);
|
|
1754
|
+
opts.onResumeSessionInvalid?.(opts.sessionId);
|
|
1755
|
+
}
|
|
1756
|
+
const args = resumeSessionId ? ["resume", resumeSessionId, ...baseArgs] : baseArgs;
|
|
1757
|
+
const startTime = Date.now();
|
|
1758
|
+
let detectedSessionId = resumeSessionId;
|
|
1759
|
+
const codexExecutable = codex.resolveCodexExecutable();
|
|
1625
1760
|
persistence.logger.debug(`[CodexLocal] Spawning ${codexExecutable} with args: ${JSON.stringify(args)}`);
|
|
1626
1761
|
releaseTerminalInputForChild();
|
|
1627
1762
|
clearTerminalForChild();
|
|
@@ -1631,7 +1766,7 @@ async function codexLocal(opts) {
|
|
|
1631
1766
|
cwd: opts.path,
|
|
1632
1767
|
env: codexEnv,
|
|
1633
1768
|
stdio: "inherit",
|
|
1634
|
-
shell:
|
|
1769
|
+
shell: codex.shouldUseShellForCodex(codexExecutable)
|
|
1635
1770
|
});
|
|
1636
1771
|
const abortChild = () => {
|
|
1637
1772
|
if (child.exitCode === null) {
|
|
@@ -1647,7 +1782,7 @@ async function codexLocal(opts) {
|
|
|
1647
1782
|
if (detectedSessionId) {
|
|
1648
1783
|
return;
|
|
1649
1784
|
}
|
|
1650
|
-
const nextSessionId = findLatestCodexSessionIdSince(startTime, { codexHomeDir });
|
|
1785
|
+
const nextSessionId = findLatestCodexSessionIdSince(startTime, { codexHomeDir, cwd: opts.path });
|
|
1651
1786
|
if (nextSessionId) {
|
|
1652
1787
|
detectedSessionId = nextSessionId;
|
|
1653
1788
|
persistence.logger.debug(`[CodexLocal] Detected session ID: ${nextSessionId}`);
|
|
@@ -1705,7 +1840,7 @@ async function codexLocalLauncher(session) {
|
|
|
1705
1840
|
let switchWithoutSessionTimer = null;
|
|
1706
1841
|
let reportedSessionId = session.sessionId;
|
|
1707
1842
|
const processAbortController = new AbortController();
|
|
1708
|
-
const exitFuture = new
|
|
1843
|
+
const exitFuture = new future.Future();
|
|
1709
1844
|
try {
|
|
1710
1845
|
let clearSwitchWithoutSessionTimer2 = function() {
|
|
1711
1846
|
if (switchWithoutSessionTimer) {
|
|
@@ -1790,6 +1925,7 @@ async function codexLocalLauncher(session) {
|
|
|
1790
1925
|
abort: processAbortController.signal,
|
|
1791
1926
|
codexArgs: session.codexArgs,
|
|
1792
1927
|
onSessionFound: recordSessionFound,
|
|
1928
|
+
onResumeSessionInvalid: session.clearSessionId,
|
|
1793
1929
|
onThinkingChange: session.onThinkingChange
|
|
1794
1930
|
});
|
|
1795
1931
|
if (sessionId) {
|
|
@@ -1863,58 +1999,6 @@ async function codexLoop(opts) {
|
|
|
1863
1999
|
});
|
|
1864
2000
|
}
|
|
1865
2001
|
|
|
1866
|
-
function normalizeFatalProcessError(error) {
|
|
1867
|
-
if (error instanceof Error) {
|
|
1868
|
-
return error;
|
|
1869
|
-
}
|
|
1870
|
-
const message = typeof error === "string" ? error : (() => {
|
|
1871
|
-
try {
|
|
1872
|
-
const serialized = JSON.stringify(error);
|
|
1873
|
-
return serialized && serialized !== "{}" ? serialized : String(error);
|
|
1874
|
-
} catch {
|
|
1875
|
-
return String(error);
|
|
1876
|
-
}
|
|
1877
|
-
})();
|
|
1878
|
-
return new Error(message || "Unknown fatal process error");
|
|
1879
|
-
}
|
|
1880
|
-
function installFatalProcessHandlers(options) {
|
|
1881
|
-
const target = options.target ?? process;
|
|
1882
|
-
const exit = options.exit ?? process.exit;
|
|
1883
|
-
let shuttingDown = false;
|
|
1884
|
-
let disposed = false;
|
|
1885
|
-
const handleFatalEvent = async (event, reason) => {
|
|
1886
|
-
const error = normalizeFatalProcessError(reason);
|
|
1887
|
-
persistence.logger.debug(`[${options.label}] Fatal ${event}`, error);
|
|
1888
|
-
if (shuttingDown) {
|
|
1889
|
-
persistence.logger.debug(`[${options.label}] Ignoring duplicate fatal ${event} while shutdown is already in progress`);
|
|
1890
|
-
return;
|
|
1891
|
-
}
|
|
1892
|
-
shuttingDown = true;
|
|
1893
|
-
try {
|
|
1894
|
-
await options.cleanup({ event, error });
|
|
1895
|
-
} catch (cleanupError) {
|
|
1896
|
-
persistence.logger.debug(`[${options.label}] Fatal cleanup failed`, cleanupError);
|
|
1897
|
-
}
|
|
1898
|
-
exit(1);
|
|
1899
|
-
};
|
|
1900
|
-
const onUncaughtException = (error) => {
|
|
1901
|
-
void handleFatalEvent("uncaughtException", error);
|
|
1902
|
-
};
|
|
1903
|
-
const onUnhandledRejection = (reason) => {
|
|
1904
|
-
void handleFatalEvent("unhandledRejection", reason);
|
|
1905
|
-
};
|
|
1906
|
-
target.on("uncaughtException", onUncaughtException);
|
|
1907
|
-
target.on("unhandledRejection", onUnhandledRejection);
|
|
1908
|
-
return () => {
|
|
1909
|
-
if (disposed) {
|
|
1910
|
-
return;
|
|
1911
|
-
}
|
|
1912
|
-
disposed = true;
|
|
1913
|
-
target.off("uncaughtException", onUncaughtException);
|
|
1914
|
-
target.off("unhandledRejection", onUnhandledRejection);
|
|
1915
|
-
};
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
2002
|
function normalizeResumeSessionId(value) {
|
|
1919
2003
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
1920
2004
|
}
|
|
@@ -1959,6 +2043,17 @@ function normalizeCodexArgsForHappy(options) {
|
|
|
1959
2043
|
};
|
|
1960
2044
|
}
|
|
1961
2045
|
|
|
2046
|
+
function normalizePathForCodexResumeIdentity(path) {
|
|
2047
|
+
const normalized = path.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "");
|
|
2048
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2049
|
+
}
|
|
2050
|
+
function codexResumeCwdMatches(expected, actual) {
|
|
2051
|
+
const normalizedExpected = expected?.trim();
|
|
2052
|
+
if (!normalizedExpected) {
|
|
2053
|
+
return true;
|
|
2054
|
+
}
|
|
2055
|
+
return normalizePathForCodexResumeIdentity(normalizedExpected) === normalizePathForCodexResumeIdentity(actual);
|
|
2056
|
+
}
|
|
1962
2057
|
function resolveInitialCodexPermissionMode(opts) {
|
|
1963
2058
|
if (opts.permissionMode) {
|
|
1964
2059
|
return opts.permissionMode;
|
|
@@ -2027,12 +2122,12 @@ async function runCodex(opts) {
|
|
|
2027
2122
|
}
|
|
2028
2123
|
let machineId;
|
|
2029
2124
|
try {
|
|
2030
|
-
machineId = await
|
|
2125
|
+
machineId = await sessionControl.ensureManagedProviderMachine({
|
|
2031
2126
|
api,
|
|
2032
2127
|
missingMachineIdMessage: "[START] No machine ID found in settings."
|
|
2033
2128
|
});
|
|
2034
2129
|
} catch (error) {
|
|
2035
|
-
if (error instanceof
|
|
2130
|
+
if (error instanceof sessionControl.MissingMachineIdError) {
|
|
2036
2131
|
console.error(error.message);
|
|
2037
2132
|
process.exit(1);
|
|
2038
2133
|
}
|
|
@@ -2040,7 +2135,7 @@ async function runCodex(opts) {
|
|
|
2040
2135
|
}
|
|
2041
2136
|
let sessionClient;
|
|
2042
2137
|
let codexSession = null;
|
|
2043
|
-
const { metadata, session: initialSession, reconnectionHandle, happyOrgStartupBinding } = await
|
|
2138
|
+
const { metadata, session: initialSession, reconnectionHandle, happyOrgStartupBinding } = await bootstrapManagedProviderSession.bootstrapManagedProviderSession({
|
|
2044
2139
|
api,
|
|
2045
2140
|
sessionTag,
|
|
2046
2141
|
flavor: "codex",
|
|
@@ -2051,18 +2146,32 @@ async function runCodex(opts) {
|
|
|
2051
2146
|
onSessionSwap: (newSession) => {
|
|
2052
2147
|
sessionClient = newSession;
|
|
2053
2148
|
codexSession?.updateClient(newSession);
|
|
2054
|
-
void
|
|
2149
|
+
void sessionControl.syncControlledByUserState(
|
|
2055
2150
|
newSession,
|
|
2056
2151
|
(codexSession?.mode ?? requestedStartingMode) === "local"
|
|
2057
2152
|
);
|
|
2058
2153
|
}
|
|
2059
2154
|
});
|
|
2060
2155
|
sessionClient = initialSession;
|
|
2061
|
-
const
|
|
2156
|
+
const metadataCodexSessionCwd = typeof metadata.codexSessionCwd === "string" ? metadata.codexSessionCwd : null;
|
|
2157
|
+
const requestedResumeSessionId = normalizedArgs.resumeSessionId;
|
|
2158
|
+
const requestedResumeCwd = opts.resumeSessionCwd ?? metadataCodexSessionCwd;
|
|
2159
|
+
const resumeSessionMatchesCwd = requestedResumeSessionId ? codexResumeCwdMatches(requestedResumeCwd, metadata.path) && isCodexResumeSessionValidForCwd(requestedResumeSessionId, metadata.path) : false;
|
|
2160
|
+
const initialCodexSessionId = requestedResumeSessionId && resumeSessionMatchesCwd ? requestedResumeSessionId : null;
|
|
2161
|
+
if (requestedResumeSessionId && !resumeSessionMatchesCwd) {
|
|
2162
|
+
persistence.logger.debug(`[codex] Ignoring resume session ${requestedResumeSessionId} because it does not match cwd ${metadata.path}`);
|
|
2163
|
+
sessionClient.updateMetadata((currentMetadata) => {
|
|
2164
|
+
const nextMetadata = { ...currentMetadata };
|
|
2165
|
+
delete nextMetadata.codexSessionId;
|
|
2166
|
+
delete nextMetadata.codexSessionCwd;
|
|
2167
|
+
return nextMetadata;
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2170
|
+
const messageQueue = new sessionControl.MessageQueue2(getCodexExecutionFingerprint);
|
|
2062
2171
|
let currentPermissionMode = initialPermissionMode;
|
|
2063
2172
|
let currentModel;
|
|
2064
2173
|
sessionClient.onUserMessage((message) => {
|
|
2065
|
-
const happyOrgResult =
|
|
2174
|
+
const happyOrgResult = sessionControl.resolveHappyOrgQueuedTurn({
|
|
2066
2175
|
metadata: sessionClient.getMetadataSnapshot?.() ?? metadata,
|
|
2067
2176
|
message,
|
|
2068
2177
|
sessionId: sessionClient.sessionId
|
|
@@ -2104,7 +2213,7 @@ async function runCodex(opts) {
|
|
|
2104
2213
|
path: metadata.path,
|
|
2105
2214
|
logPath: persistence.logger.logFilePath,
|
|
2106
2215
|
startupRolePrompt: happyOrgStartupBinding?.identityPrompt ?? null,
|
|
2107
|
-
sessionId:
|
|
2216
|
+
sessionId: initialCodexSessionId,
|
|
2108
2217
|
mode: requestedStartingMode,
|
|
2109
2218
|
messageQueue,
|
|
2110
2219
|
codexArgs: normalizedArgs.codexArgs,
|
|
@@ -2113,7 +2222,7 @@ async function runCodex(opts) {
|
|
|
2113
2222
|
userObserver: userScopedObserver,
|
|
2114
2223
|
onModeChange: async (mode) => {
|
|
2115
2224
|
sessionClient.sendSessionEvent({ type: "switch", mode });
|
|
2116
|
-
await
|
|
2225
|
+
await sessionControl.syncControlledByUserState(sessionClient, mode === "local");
|
|
2117
2226
|
}
|
|
2118
2227
|
});
|
|
2119
2228
|
let exitCode = null;
|
|
@@ -2142,7 +2251,7 @@ async function runCodex(opts) {
|
|
|
2142
2251
|
reconnectionHandle?.cancel();
|
|
2143
2252
|
codexSession?.cleanup();
|
|
2144
2253
|
};
|
|
2145
|
-
const disposeFatalProcessHandlers = installFatalProcessHandlers({
|
|
2254
|
+
const disposeFatalProcessHandlers = installFatalProcessHandlers.installFatalProcessHandlers({
|
|
2146
2255
|
label: "codex",
|
|
2147
2256
|
cleanup: async ({ event, error }) => {
|
|
2148
2257
|
await cleanupResources({
|