codex-overleaf-link 2.5.0 → 2.6.0
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/README.md +155 -392
- package/README.zh-CN.md +154 -393
- package/extension/bootstrap/background.js +52 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/bootstrap/popup.html +1 -0
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/src/background.js +283 -55
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +129 -16
- package/extension/src/backgroundUpdateCoordinator.js +242 -29
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +171 -8
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +72 -14
- package/extension/src/content/composerAttachments.js +104 -47
- package/extension/src/content/composerPanel.js +110 -12
- package/extension/src/content/contentRuntime.js +1555 -926
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsController.js +122 -96
- package/extension/src/content/diagnosticsExport.js +19 -5
- package/extension/src/content/diagnosticsPanel.js +48 -0
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +11077 -3412
- package/extension/src/content/generated/content.bundle.meta.json +14 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +10 -0
- package/extension/src/content/localSkillsPanel.js +104 -14
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +47 -11
- package/extension/src/content/modelPicker.js +8 -4
- package/extension/src/content/nativeCompatibilityController.js +74 -30
- package/extension/src/content/otWarmMirror.js +5 -6
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +17 -4
- package/extension/src/content/panelMaintenance.js +46 -14
- package/extension/src/content/panelRenderer.js +57 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +67 -6
- package/extension/src/content/providerSettingsCoordinator.js +46 -8
- package/extension/src/content/providerSettingsDialog.js +73 -14
- package/extension/src/content/recentProjects.js +15 -8
- package/extension/src/content/runActivitySummary.js +160 -18
- package/extension/src/content/runCompletionMeta.js +532 -0
- package/extension/src/content/runController.js +39 -15
- package/extension/src/content/runFailureNotice.js +29 -13
- package/extension/src/content/runGuidanceController.js +72 -27
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +157 -47
- package/extension/src/content/runRecoveryActions.js +147 -0
- package/extension/src/content/runResultActions.js +28 -143
- package/extension/src/content/runReviewController.js +633 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +367 -175
- package/extension/src/content/scopedPersistencePanelState.js +134 -20
- package/extension/src/content/selectionContextView.js +1 -1
- package/extension/src/content/sensitivePreflight.js +153 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +50 -4
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +22 -5
- package/extension/src/content/settingsWorkbench.js +132 -89
- package/extension/src/content/sharedSessionViewSync.js +49 -11
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +118 -12
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +53 -4
- package/extension/src/content/writebackOrchestrator.js +116 -94
- package/extension/src/content/writingStyleSettings.js +35 -11
- package/extension/src/page/binaryAssetUploader.js +136 -14
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +1 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +6 -4
- package/extension/src/page/snapshotRouter.js +84 -39
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +114 -26
- package/extension/src/page/trackedChangeCapture.js +12 -2
- package/extension/src/page/trackedChangeOwnership.js +19 -1
- package/extension/src/page/trackedChangeReplay.js +41 -21
- package/extension/src/page/trackedChangesLifecycle.js +217 -199
- package/extension/src/page/treeOperations.js +7 -10
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +2 -0
- package/extension/src/page/writebackRouter.js +103 -155
- package/extension/src/pageBridge.js +126 -69
- package/extension/src/popup.js +62 -10
- package/extension/src/shared/agentTranscript.js +373 -17
- package/extension/src/shared/auditRecords.js +4 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +129 -66
- package/extension/src/shared/composerAttachmentDraft.js +156 -0
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +349 -4
- package/extension/src/shared/globalPreferences.js +30 -13
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +590 -24
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/managedUpdateProjection.js +2 -2
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +5 -4
- package/extension/src/shared/panelIcons.js +39 -0
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +5 -3
- package/extension/src/shared/reviewing.js +130 -1
- package/extension/src/shared/runActivityModel.js +70 -4
- package/extension/src/shared/runExecutionSnapshot.js +13 -0
- package/extension/src/shared/runInputQueue.js +48 -5
- package/extension/src/shared/selectionContext.js +12 -3
- package/extension/src/shared/sessionState.js +132 -28
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +118 -27
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +166 -52
- package/extension/src/shared/storageDb.js +90 -26
- package/extension/src/shared/storageMigration.js +78 -112
- package/extension/src/shared/storageRunActions.js +267 -30
- package/extension/src/shared/subagentActivityModel.js +1 -1
- package/extension/src/shared/undoOperations.js +253 -32
- package/extension/src/shared/updateConsent.js +6 -4
- package/extension/src/shared/updateRuntimeIdentity.js +17 -3
- package/extension/src/shared/writebackIntent.js +16 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +58 -40
- package/extension/styles/panel.css +1123 -493
- package/native-host/src/anthropicBridgeRequest.js +4 -2
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +269 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +20 -1
- package/native-host/src/chatCompletionsBridge.js +48 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexPromptAssembly.js +114 -127
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexSessionRunner.js +234 -198
- package/native-host/src/codexSessionTiming.js +18 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +110 -35
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/processStopBarrier.js +42 -7
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerProfile.js +4 -2
- package/native-host/src/providerReasoning.js +2 -7
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +72 -14
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +36 -8
- package/native-host/src/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +79 -66
- package/native-host/src/subagentTelemetry.js +19 -10
- package/native-host/src/subagentWorkspacePath.js +5 -2
- package/native-host/src/taskRunnerRuntime.js +92 -57
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/updateManager.js +409 -46
- package/native-host/src/writingStyleRuntime.js +57 -29
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +5 -8
- package/scripts/install-managed.mjs +1 -0
|
@@ -26,6 +26,8 @@ if (!globalThis.CodexOverleafStorageRunActions) {
|
|
|
26
26
|
// registry and shared-module imports do not exist in this context.
|
|
27
27
|
const storageDependencies = [
|
|
28
28
|
['CodexOverleafModuleRegistry', 'content/moduleRegistryKernel.js'],
|
|
29
|
+
['CodexOverleafProjectFiles', 'shared/projectFiles.js'],
|
|
30
|
+
['CodexOverleafDirectoryCleanupProof', 'shared/directoryCleanupProof.js'],
|
|
29
31
|
['CodexOverleafUndoOperations', 'shared/undoOperations.js'],
|
|
30
32
|
['CodexOverleafSelectionContext', 'shared/selectionContext.js'],
|
|
31
33
|
['CodexOverleafWritebackIntent', 'shared/writebackIntent.js'],
|
|
@@ -38,6 +40,10 @@ if (!globalThis.CodexOverleafStorageRunActions) {
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
43
|
+
if (!globalThis.CodexOverleafSharedSessionTransfer) {
|
|
44
|
+
const runtimeBase = String(globalThis.__CODEX_OVERLEAF_RUNTIME_BASE__ || '');
|
|
45
|
+
importScripts(runtimeBase ? chrome.runtime.getURL(`${runtimeBase}/src/shared/sharedSessionTransfer.js`) : 'shared/sharedSessionTransfer.js');
|
|
46
|
+
}
|
|
41
47
|
if (!globalThis.CodexOverleafSharedSessionsBackground) {
|
|
42
48
|
const runtimeBase = String(globalThis.__CODEX_OVERLEAF_RUNTIME_BASE__ || '');
|
|
43
49
|
importScripts(runtimeBase ? chrome.runtime.getURL(`${runtimeBase}/src/backgroundSharedSessions.js`) : 'backgroundSharedSessions.js');
|
|
@@ -47,6 +53,14 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
47
53
|
const runtimeBase = String(globalThis.__CODEX_OVERLEAF_RUNTIME_BASE__ || '');
|
|
48
54
|
importScripts(runtimeBase ? chrome.runtime.getURL(`${runtimeBase}/src/shared/updateRuntimeIdentity.js`) : 'shared/updateRuntimeIdentity.js');
|
|
49
55
|
}
|
|
56
|
+
if (!globalThis.CodexOverleafBootstrapMigration) {
|
|
57
|
+
const runtimeBase = String(globalThis.__CODEX_OVERLEAF_RUNTIME_BASE__ || '');
|
|
58
|
+
importScripts(runtimeBase ? chrome.runtime.getURL(`${runtimeBase}/src/backgroundBootstrapMigration.js`) : 'backgroundBootstrapMigration.js');
|
|
59
|
+
}
|
|
60
|
+
if (!globalThis.CodexOverleafBackgroundUpdateSafety) {
|
|
61
|
+
const runtimeBase = String(globalThis.__CODEX_OVERLEAF_RUNTIME_BASE__ || '');
|
|
62
|
+
importScripts(runtimeBase ? chrome.runtime.getURL(`${runtimeBase}/src/backgroundUpdateSafety.js`) : 'backgroundUpdateSafety.js');
|
|
63
|
+
}
|
|
50
64
|
|
|
51
65
|
(function initBackground() {
|
|
52
66
|
'use strict';
|
|
@@ -83,7 +97,12 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
83
97
|
'codex.providers.delete',
|
|
84
98
|
'skills.list',
|
|
85
99
|
'skills.install',
|
|
86
|
-
'skills.remove'
|
|
100
|
+
'skills.remove',
|
|
101
|
+
'writing-style.get',
|
|
102
|
+
'writing-style.set',
|
|
103
|
+
'codex.thread.fork',
|
|
104
|
+
'asset.readChunk',
|
|
105
|
+
'asset.release'
|
|
87
106
|
]);
|
|
88
107
|
const RECOVERABLE_COMPATIBILITY_METHODS = new Set([
|
|
89
108
|
'bridge.ping',
|
|
@@ -99,12 +118,38 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
99
118
|
const pending = new Map();
|
|
100
119
|
const runJournals = new Map();
|
|
101
120
|
const journalWrites = new Map();
|
|
121
|
+
const journalLoads = new Map();
|
|
102
122
|
const ownerBindings = new Map();
|
|
103
123
|
const ownerCancelTimers = new Map();
|
|
104
124
|
const RUN_JOURNAL_PREFIX = 'codex-overleaf:run-journal:';
|
|
105
125
|
const RUN_JOURNAL_MAX_EVENTS = 300;
|
|
106
126
|
const RUN_JOURNAL_MAX_BYTES = 512 * 1024;
|
|
107
127
|
const managedBootstrapRuntime = isManagedBootstrapRuntime();
|
|
128
|
+
const migrationSafety = globalThis.CodexOverleafBackgroundUpdateSafety.create({
|
|
129
|
+
request: payload => sendNativeRequest(payload, null, { skipCompatibility: true }),
|
|
130
|
+
isExecutionLocked: () => managedBootstrapRuntime && managedUpdateExecutionLocked
|
|
131
|
+
});
|
|
132
|
+
let extensionInstallIdentity = { managed: managedBootstrapRuntime };
|
|
133
|
+
let installIdentityRead;
|
|
134
|
+
function readExtensionInstallIdentity() {
|
|
135
|
+
if (!managedBootstrapRuntime) return Promise.resolve(extensionInstallIdentity);
|
|
136
|
+
if (!installIdentityRead) installIdentityRead = (async () => {
|
|
137
|
+
try {
|
|
138
|
+
const response = await fetch(chrome.runtime.getURL('.codex-overleaf-managed-extension.json'));
|
|
139
|
+
const marker = response.ok ? await response.json() : null;
|
|
140
|
+
if (marker?.managedBy === 'codex-overleaf-link' && marker.kind === 'extension'
|
|
141
|
+
&& marker.installIdentity?.extensionId === getCurrentExtensionId())
|
|
142
|
+
extensionInstallIdentity = { ...marker.installIdentity, managed: true };
|
|
143
|
+
} catch (_) { /* Old or missing marker: never guess the installation root. */ }
|
|
144
|
+
return extensionInstallIdentity;
|
|
145
|
+
})();
|
|
146
|
+
return installIdentityRead;
|
|
147
|
+
}
|
|
148
|
+
async function withExtensionInstallIdentity(request, response) {
|
|
149
|
+
return request?.method === 'bridge.ping'
|
|
150
|
+
? { ...response, extensionInstallIdentity: await readExtensionInstallIdentity() } : response;
|
|
151
|
+
}
|
|
152
|
+
|
|
108
153
|
globalThis.CodexOverleafNativeBridge = Object.freeze({
|
|
109
154
|
requestInternal: payload => requestManagedInternal(payload),
|
|
110
155
|
getPendingState: () => ({
|
|
@@ -114,6 +159,14 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
114
159
|
});
|
|
115
160
|
|
|
116
161
|
if (managedBootstrapRuntime) {
|
|
162
|
+
globalThis.CodexOverleafBootstrapMigration.init({
|
|
163
|
+
request: payload => sendNativeRequest(payload, null, { skipCompatibility: true }),
|
|
164
|
+
verifySafety: verifyManagedUpdateSafety,
|
|
165
|
+
protectReloadTabs: transaction => migrationSafety.protectReloadTabs(transaction),
|
|
166
|
+
releaseReloadTabs: (transaction, state) => migrationSafety.releaseReloadTabs(transaction, state),
|
|
167
|
+
hasReplacedReloadDocument: transaction => migrationSafety.hasReplacedReloadDocument(transaction),
|
|
168
|
+
setExecutionLocked: value => { managedUpdateExecutionLocked = value; }
|
|
169
|
+
});
|
|
117
170
|
chrome.storage?.onChanged?.addListener((changes, area) => {
|
|
118
171
|
if (area !== 'local' || !changes[MANAGED_UPDATE_STATE_KEY]?.newValue) {
|
|
119
172
|
return;
|
|
@@ -136,6 +189,17 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
136
189
|
.catch(error => sendResponse({ ok: false, journals: [], error: getErrorMessage(error, 'Journal read failed.') }));
|
|
137
190
|
return true;
|
|
138
191
|
}
|
|
192
|
+
if (message?.type === 'codex-overleaf/run-journal/known') {
|
|
193
|
+
if (!isAllowedOverleafSender(sender)) {
|
|
194
|
+
sendResponse({ ok: false, known: [] });
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
knownRunJournals(Array.isArray(message.requestIds) ? message.requestIds.map(String).slice(0, 64) : [],
|
|
198
|
+
Array.isArray(message.owners) ? message.owners.slice(0, 64) : [])
|
|
199
|
+
.then(result => sendResponse({ ok: true, ...result }))
|
|
200
|
+
.catch(error => sendResponse({ ok: false, known: [], error: getErrorMessage(error, 'Journal read failed.') }));
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
139
203
|
if (message?.type === 'codex-overleaf/run-journal/ack') {
|
|
140
204
|
if (!isAllowedOverleafSender(sender)) {
|
|
141
205
|
sendResponse({ ok: false });
|
|
@@ -193,13 +257,11 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
193
257
|
}
|
|
194
258
|
|
|
195
259
|
sendNativeRequest(message.payload, sender)
|
|
260
|
+
.then(result => withExtensionInstallIdentity(message.payload, result))
|
|
196
261
|
.then(result => sendResponse(result))
|
|
197
262
|
.catch(error => {
|
|
198
263
|
const userFacingError = toUserFacingNativeError(error);
|
|
199
|
-
|
|
200
|
-
ok: false,
|
|
201
|
-
error: userFacingError
|
|
202
|
-
});
|
|
264
|
+
withExtensionInstallIdentity(message.payload, { ok: false, error: userFacingError }).then(sendResponse);
|
|
203
265
|
});
|
|
204
266
|
|
|
205
267
|
return true;
|
|
@@ -215,25 +277,50 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
215
277
|
return;
|
|
216
278
|
}
|
|
217
279
|
if (message.type === 'release') {
|
|
280
|
+
const current = ownerBindings.get(portConnection);
|
|
281
|
+
if (!current || ['requestId', 'projectKey', 'clientRunId', 'sessionId'].some(key => current[key] !== message[key])
|
|
282
|
+
|| (current.browserOnly && current.ownerToken !== message.ownerToken)) return;
|
|
218
283
|
ownerBindings.delete(portConnection);
|
|
219
284
|
clearTimeout(ownerCancelTimers.get(requestId));
|
|
220
285
|
ownerCancelTimers.delete(requestId);
|
|
221
286
|
return;
|
|
222
287
|
}
|
|
223
288
|
if (message.type === 'bind') {
|
|
224
|
-
|
|
289
|
+
const binding = {
|
|
225
290
|
requestId,
|
|
226
291
|
projectKey: String(message.projectKey || ''),
|
|
227
|
-
documentId: String(portConnection.sender?.documentId || '')
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
292
|
+
documentId: String(portConnection.sender?.documentId || ''),
|
|
293
|
+
tabId: portConnection.sender?.tab?.id,
|
|
294
|
+
clientRunId: String(message.clientRunId || ''),
|
|
295
|
+
sessionId: String(message.sessionId || ''),
|
|
296
|
+
browserOnly: message.browserOnly === true,
|
|
297
|
+
ownerToken: String(message.ownerToken || '')
|
|
298
|
+
};
|
|
299
|
+
if (binding.browserOnly && (!binding.projectKey || !binding.clientRunId || !binding.sessionId || !binding.ownerToken)) return;
|
|
300
|
+
if (binding.browserOnly && managedUpdateExecutionLocked) {
|
|
301
|
+
try { portConnection.postMessage?.({ type: 'bound', ...binding, ok: false }); } catch (_error) { /* port disconnected */ }
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
ownerBindings.set(portConnection, binding);
|
|
305
|
+
if (binding.browserOnly) {
|
|
306
|
+
try { portConnection.postMessage?.({ type: 'bound', ...binding }); } catch (_error) { /* port disconnected */ }
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
restoreRunJournal(binding).then(journal => {
|
|
310
|
+
if (ownerBindings.get(portConnection) !== binding || !journal || runJournals.get(requestId) !== journal) return;
|
|
311
|
+
clearTimeout(ownerCancelTimers.get(requestId));
|
|
312
|
+
ownerCancelTimers.delete(requestId);
|
|
313
|
+
if (!journal.ownerLost) return;
|
|
314
|
+
journal.ownerLost = false;
|
|
315
|
+
journal.updatedAt = new Date().toISOString();
|
|
316
|
+
return queueJournalWrite(requestId);
|
|
317
|
+
}).catch(() => {});
|
|
231
318
|
}
|
|
232
319
|
});
|
|
233
320
|
portConnection.onDisconnect.addListener(() => {
|
|
234
321
|
const binding = ownerBindings.get(portConnection);
|
|
235
322
|
ownerBindings.delete(portConnection);
|
|
236
|
-
if (!binding?.requestId) {
|
|
323
|
+
if (!binding?.requestId || binding.browserOnly) {
|
|
237
324
|
return;
|
|
238
325
|
}
|
|
239
326
|
const timer = setTimeout(() => interruptOwnerlessRun(binding), 150);
|
|
@@ -306,6 +393,7 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
306
393
|
resolve,
|
|
307
394
|
reject,
|
|
308
395
|
tabId: sender?.tab?.id,
|
|
396
|
+
documentId: String(sender?.documentId || ''),
|
|
309
397
|
request,
|
|
310
398
|
method: request.method,
|
|
311
399
|
retryClass: getNativeRetryClass(request.method),
|
|
@@ -328,7 +416,12 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
328
416
|
}
|
|
329
417
|
|
|
330
418
|
async function requestManagedInternal(payload) {
|
|
331
|
-
if (managedBootstrapRuntime &&
|
|
419
|
+
if (managedBootstrapRuntime && ['update.status', 'update.confirm'].includes(payload?.method)) {
|
|
420
|
+
payload = { ...payload, params: { ...payload.params,
|
|
421
|
+
bootstrapRevision: String(globalThis.__CODEX_OVERLEAF_BOOTSTRAP_REVISION__ || '') } };
|
|
422
|
+
}
|
|
423
|
+
if (managedBootstrapRuntime && (payload?.method === 'update.apply'
|
|
424
|
+
|| (payload?.method === 'update.rollback' && payload?.params?.reasonCode === 'update_user_rollback'))) {
|
|
332
425
|
const gate = await verifyManagedUpdateSafety();
|
|
333
426
|
if (!gate.ok) {
|
|
334
427
|
return gate;
|
|
@@ -345,15 +438,25 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
345
438
|
throw error;
|
|
346
439
|
}
|
|
347
440
|
}
|
|
348
|
-
|
|
441
|
+
const response = await sendNativeRequest(payload, null, { skipCompatibility: true });
|
|
442
|
+
if (payload?.method === 'update.confirm') {
|
|
443
|
+
globalThis.CodexOverleafBootstrapMigration.observeConfirmation(payload.params, response);
|
|
444
|
+
}
|
|
445
|
+
return response;
|
|
349
446
|
}
|
|
350
447
|
|
|
351
|
-
async function verifyManagedUpdateSafety() {
|
|
352
|
-
const tabs = await chrome.tabs.query({ url: MANAGED_OVERLEAF_MATCHES }).catch(() =>
|
|
353
|
-
const editorTabs = tabs.filter(tab => (
|
|
448
|
+
async function verifyManagedUpdateSafety(migrationOwner) {
|
|
449
|
+
const tabs = await chrome.tabs.query({ url: MANAGED_OVERLEAF_MATCHES }).catch(() => null);
|
|
450
|
+
const editorTabs = (Array.isArray(tabs) ? tabs : []).filter(tab => (
|
|
354
451
|
isManagedEditorTab(tab) && !tab.discarded && tab.status !== 'unloaded'
|
|
355
452
|
));
|
|
356
|
-
const probes = await Promise.all(editorTabs.map(tab =>
|
|
453
|
+
const probes = await Promise.all(editorTabs.map(async tab => {
|
|
454
|
+
const result = await probeManagedUpdateTab(tab.id);
|
|
455
|
+
return migrationOwner && result?.blockers?.includes('tab_probe_unavailable')
|
|
456
|
+
? migrationSafety.probe(tab, migrationOwner) : result;
|
|
457
|
+
}));
|
|
458
|
+
// An unknown inventory cannot establish an idle safe point, even when Native is idle.
|
|
459
|
+
if (!Array.isArray(tabs)) probes.push({ idle: false, blockers: ['tab_inventory_unavailable'] });
|
|
357
460
|
const nativeGate = await sendNativeRequest({
|
|
358
461
|
id: crypto.randomUUID(),
|
|
359
462
|
method: 'update.canApply',
|
|
@@ -365,8 +468,15 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
365
468
|
message: getErrorMessage(error, 'Native Host update safety check failed.')
|
|
366
469
|
}
|
|
367
470
|
}));
|
|
471
|
+
if (migrationOwner) {
|
|
472
|
+
const after = await chrome.tabs.query({ url: MANAGED_OVERLEAF_MATCHES }).catch(() => null);
|
|
473
|
+
const inventory = values => JSON.stringify((values || []).map(tab => [tab.id, tab.url, tab.discarded, tab.status]).sort());
|
|
474
|
+
if (!after || inventory(after) !== inventory(tabs)) probes.push({ idle: false, blockers: ['tab_probe_unavailable'] });
|
|
475
|
+
else if (!await migrationSafety.revalidate(editorTabs, migrationOwner)) probes.push({ idle: false, blockers: ['tab_probe_unavailable'] });
|
|
476
|
+
}
|
|
368
477
|
const pendingState = globalThis.CodexOverleafNativeBridge?.getPendingState?.() || {};
|
|
369
478
|
const backgroundBlockers = Number(pendingState.executionRequests || 0) > 0
|
|
479
|
+
|| Array.from(ownerBindings.values()).some(binding => binding.browserOnly)
|
|
370
480
|
? ['background_execution_pending']
|
|
371
481
|
: [];
|
|
372
482
|
const blockers = [
|
|
@@ -391,13 +501,15 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
391
501
|
return { idle: false, blockers: ['tab_unavailable'] };
|
|
392
502
|
}
|
|
393
503
|
try {
|
|
394
|
-
|
|
504
|
+
const response = await Promise.race([
|
|
395
505
|
chrome.tabs.sendMessage(tabId, { type: 'codex-overleaf/update-idle-probe' }),
|
|
396
506
|
new Promise(resolve => setTimeout(() => resolve({
|
|
397
507
|
idle: false,
|
|
398
508
|
blockers: ['tab_probe_timeout']
|
|
399
509
|
}), 3500))
|
|
400
510
|
]);
|
|
511
|
+
return typeof response?.idle === 'boolean' ? response
|
|
512
|
+
: { idle: false, blockers: ['tab_probe_unavailable'] };
|
|
401
513
|
} catch (_error) {
|
|
402
514
|
return { idle: false, blockers: ['tab_probe_unavailable'] };
|
|
403
515
|
}
|
|
@@ -434,6 +546,11 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
434
546
|
}
|
|
435
547
|
|
|
436
548
|
async function reconcileManagedUpdateTransaction() {
|
|
549
|
+
const migration = await globalThis.CodexOverleafBootstrapMigration.ready();
|
|
550
|
+
if (!migration.continueInitialization) return;
|
|
551
|
+
await globalThis.__CODEX_OVERLEAF_BOOTSTRAP_READY__;
|
|
552
|
+
const coordinator = globalThis.CodexOverleafUpdateCoordinator;
|
|
553
|
+
const recoveryOwner = await coordinator?.captureRecoveryOwner?.();
|
|
437
554
|
const response = await sendNativeRequest({
|
|
438
555
|
id: crypto.randomUUID(),
|
|
439
556
|
method: 'update.status',
|
|
@@ -445,22 +562,7 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
445
562
|
|
|
446
563
|
const transaction = response.result?.transaction || null;
|
|
447
564
|
if (transaction?.state === 'superseded') {
|
|
448
|
-
|
|
449
|
-
await chrome.storage.local.remove([
|
|
450
|
-
MANAGED_UPDATE_CONSENT_KEY,
|
|
451
|
-
MANAGED_UPDATE_TABS_KEY
|
|
452
|
-
]);
|
|
453
|
-
await setManagedUpdateState({
|
|
454
|
-
state: 'idle',
|
|
455
|
-
managed: true,
|
|
456
|
-
currentVersion: activeVersion,
|
|
457
|
-
latestVersion: activeVersion,
|
|
458
|
-
transactionId: '',
|
|
459
|
-
blocker: '',
|
|
460
|
-
blockers: [],
|
|
461
|
-
code: '',
|
|
462
|
-
message: ''
|
|
463
|
-
});
|
|
565
|
+
await coordinator?.settleSupersededTransaction?.(response.result, recoveryOwner);
|
|
464
566
|
return;
|
|
465
567
|
}
|
|
466
568
|
const state = await getManagedUpdateState();
|
|
@@ -521,6 +623,16 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
521
623
|
return null;
|
|
522
624
|
}
|
|
523
625
|
|
|
626
|
+
const params = request.params || {};
|
|
627
|
+
if (request.method === 'codex.run' && params.focusFilesAreLiteral === true
|
|
628
|
+
&& (params.restrictToFocusFiles === true || (Array.isArray(params.focusFiles) && params.focusFiles.length))
|
|
629
|
+
&& evidence?.native?.capabilities?.literalProjectPaths !== true) {
|
|
630
|
+
return { ...createNativeUpdateRequiredBlock(request.method, {
|
|
631
|
+
...evidence, status: 'native_capability_missing', classification: 'incompatible'
|
|
632
|
+
}), message: 'This Native Host does not support literal project paths. Reload the extension after installing the coordinated build.',
|
|
633
|
+
missingCapabilities: ['literalProjectPaths'] };
|
|
634
|
+
}
|
|
635
|
+
|
|
524
636
|
if (isNativeMethodAllowedByCompatibility(request.method, evidence)) {
|
|
525
637
|
return null;
|
|
526
638
|
}
|
|
@@ -621,12 +733,13 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
621
733
|
const command = CodexOverleafCompatibility?.buildInstallCommand?.(
|
|
622
734
|
getNativeRecommendedVersion(evidence),
|
|
623
735
|
evidence.native?.platform || evidence.platform,
|
|
624
|
-
getCurrentExtensionId()
|
|
736
|
+
getCurrentExtensionId(),
|
|
737
|
+
extensionInstallIdentity
|
|
625
738
|
);
|
|
626
739
|
if (command) {
|
|
627
740
|
return command;
|
|
628
741
|
}
|
|
629
|
-
return evidence.updateCommand || evidence.installCommand;
|
|
742
|
+
return managedBootstrapRuntime ? '' : evidence.updateCommand || evidence.installCommand;
|
|
630
743
|
}
|
|
631
744
|
|
|
632
745
|
function getCurrentExtensionId() {
|
|
@@ -909,8 +1022,13 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
909
1022
|
clientRunId: String(params.clientRunId || ''),
|
|
910
1023
|
sessionId: String(params.clientSessionId || ''),
|
|
911
1024
|
task: sanitizeJournalString(params.task).slice(0, 12000),
|
|
1025
|
+
...(params.operation === 'compact' ? {
|
|
1026
|
+
operation: 'compact', threadId: String(params.threadId || '').slice(0, 160)
|
|
1027
|
+
} : {}),
|
|
912
1028
|
mode: String(params.mode || ''),
|
|
913
1029
|
model: String(params.model || ''),
|
|
1030
|
+
ownerTabId: pendingRequest.tabId,
|
|
1031
|
+
ownerDocumentId: pendingRequest.documentId,
|
|
914
1032
|
createdAt: new Date().toISOString(),
|
|
915
1033
|
updatedAt: new Date().toISOString(),
|
|
916
1034
|
terminal: false,
|
|
@@ -918,6 +1036,7 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
918
1036
|
nextSequence: 1,
|
|
919
1037
|
events: []
|
|
920
1038
|
};
|
|
1039
|
+
invalidateJournalLoad(id);
|
|
921
1040
|
runJournals.set(id, journal);
|
|
922
1041
|
pruneInMemoryRunJournals();
|
|
923
1042
|
return queueJournalWrite(id);
|
|
@@ -982,9 +1101,9 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
982
1101
|
}
|
|
983
1102
|
|
|
984
1103
|
function sanitizeJournalString(value) {
|
|
1104
|
+
// Journal replay is conversation recovery. Credential configuration is not
|
|
1105
|
+
// copied by createRunJournal; quoted values in model events stay intact.
|
|
985
1106
|
return String(value || '')
|
|
986
|
-
.replace(/\b(?:sk|hf|glpat|npm|ghp|github_pat|AKIA|AIza)[_-]?[A-Za-z0-9_-]{12,}\b/g, '[REDACTED]')
|
|
987
|
-
.replace(/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, '[REDACTED]')
|
|
988
1107
|
.replace(/(?:file:\/\/)?\/(?:Users|home|private|var|opt|Library)\/[^\s"'<>]+/g, '[local path]')
|
|
989
1108
|
.slice(0, 131072);
|
|
990
1109
|
}
|
|
@@ -994,11 +1113,15 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
994
1113
|
if (!storage || !runJournals.has(id)) {
|
|
995
1114
|
return Promise.resolve();
|
|
996
1115
|
}
|
|
1116
|
+
const journal = runJournals.get(id);
|
|
1117
|
+
const snapshot = JSON.parse(JSON.stringify(journal));
|
|
1118
|
+
return queueJournalStorage(id, () => runJournals.get(id) === journal
|
|
1119
|
+
? storage.set({ [RUN_JOURNAL_PREFIX + id]: snapshot }) : undefined);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function queueJournalStorage(id, operation) {
|
|
997
1123
|
const previous = journalWrites.get(id) || Promise.resolve();
|
|
998
|
-
const
|
|
999
|
-
const next = previous.catch(() => {}).then(() => storage.set({
|
|
1000
|
-
[RUN_JOURNAL_PREFIX + id]: snapshot
|
|
1001
|
-
}));
|
|
1124
|
+
const next = previous.catch(() => {}).then(operation);
|
|
1002
1125
|
journalWrites.set(id, next);
|
|
1003
1126
|
return next.finally(() => {
|
|
1004
1127
|
if (journalWrites.get(id) === next) {
|
|
@@ -1007,7 +1130,67 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
1007
1130
|
});
|
|
1008
1131
|
}
|
|
1009
1132
|
|
|
1133
|
+
function invalidateJournalLoad(id) {
|
|
1134
|
+
const load = journalLoads.get(id);
|
|
1135
|
+
if (load) load.cancelled = true;
|
|
1136
|
+
journalLoads.delete(id);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
function journalMatchesBinding(journal, binding) {
|
|
1140
|
+
return journal?.requestId === binding.requestId && Boolean(binding.projectKey)
|
|
1141
|
+
&& journal.projectKey === binding.projectKey
|
|
1142
|
+
&& (!Number.isInteger(journal.ownerTabId) || journal.ownerTabId === binding.tabId)
|
|
1143
|
+
&& (!journal.ownerDocumentId || journal.ownerDocumentId === binding.documentId)
|
|
1144
|
+
&& (!binding.clientRunId || journal.clientRunId === binding.clientRunId)
|
|
1145
|
+
&& (!binding.sessionId || journal.sessionId === binding.sessionId);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function hasRunOwner(binding) {
|
|
1149
|
+
return Array.from(ownerBindings.values()).some(owner => owner.requestId === binding.requestId
|
|
1150
|
+
&& owner.projectKey === binding.projectKey && owner.tabId === binding.tabId
|
|
1151
|
+
&& owner.documentId === binding.documentId && owner.clientRunId === binding.clientRunId
|
|
1152
|
+
&& owner.sessionId === binding.sessionId);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
async function restoreRunJournal(binding) {
|
|
1156
|
+
const id = binding.requestId;
|
|
1157
|
+
if (runJournals.has(id)) {
|
|
1158
|
+
const journal = runJournals.get(id);
|
|
1159
|
+
return journalMatchesBinding(journal, binding) ? journal : null;
|
|
1160
|
+
}
|
|
1161
|
+
if (!chrome.storage?.session || !binding.projectKey) return null;
|
|
1162
|
+
let load = journalLoads.get(id);
|
|
1163
|
+
if (!load) {
|
|
1164
|
+
load = { cancelled: false };
|
|
1165
|
+
load.promise = (async () => {
|
|
1166
|
+
await (journalWrites.get(id) || Promise.resolve()).catch(() => {});
|
|
1167
|
+
if (load.cancelled) return null;
|
|
1168
|
+
const values = await chrome.storage.session.get(RUN_JOURNAL_PREFIX + id);
|
|
1169
|
+
const stored = values?.[RUN_JOURNAL_PREFIX + id];
|
|
1170
|
+
if (load.cancelled || !journalMatchesBinding(stored, binding) || !Array.isArray(stored.events)) return null;
|
|
1171
|
+
const journal = runJournals.get(id) || stored;
|
|
1172
|
+
trimRunJournal(journal);
|
|
1173
|
+
runJournals.set(id, journal);
|
|
1174
|
+
return journal;
|
|
1175
|
+
})().finally(() => {
|
|
1176
|
+
if (journalLoads.get(id) === load) journalLoads.delete(id);
|
|
1177
|
+
});
|
|
1178
|
+
journalLoads.set(id, load);
|
|
1179
|
+
}
|
|
1180
|
+
const journal = await load.promise;
|
|
1181
|
+
return journalMatchesBinding(journal, binding) ? journal : null;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
function removeRunJournal(id) {
|
|
1185
|
+
invalidateJournalLoad(id);
|
|
1186
|
+
runJournals.delete(id);
|
|
1187
|
+
// Retain the chain until removal completes; old queued writes cannot follow it.
|
|
1188
|
+
return queueJournalStorage(id, () => !runJournals.has(id)
|
|
1189
|
+
? chrome.storage?.session?.remove?.(RUN_JOURNAL_PREFIX + id) : undefined);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1010
1192
|
async function listRunJournals(projectKey) {
|
|
1193
|
+
await Promise.allSettled(Array.from(journalLoads.values(), load => load.promise));
|
|
1011
1194
|
await Promise.allSettled(Array.from(journalWrites.values()));
|
|
1012
1195
|
const storage = chrome.storage?.session;
|
|
1013
1196
|
if (!storage) {
|
|
@@ -1017,11 +1200,57 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
1017
1200
|
const entries = Object.entries(values || {})
|
|
1018
1201
|
.filter(([key, value]) => key.startsWith(RUN_JOURNAL_PREFIX)
|
|
1019
1202
|
&& (!projectKey || value?.projectKey === projectKey)
|
|
1020
|
-
&& (value?.terminal || value?.ownerLost)
|
|
1203
|
+
&& (value?.terminal || value?.ownerLost)
|
|
1204
|
+
&& !Array.from(ownerBindings.values()).some(binding => journalMatchesBinding(value, binding)))
|
|
1021
1205
|
.sort((a, b) => String(a[1]?.createdAt || '').localeCompare(String(b[1]?.createdAt || '')));
|
|
1022
1206
|
return entries.slice(-16).map(([_key, value]) => value);
|
|
1023
1207
|
}
|
|
1024
1208
|
|
|
1209
|
+
// Browser-only retries outlive their original Native journal. Protect only
|
|
1210
|
+
// a live port whose request/project/session/run matches the queried record.
|
|
1211
|
+
async function knownRunJournals(requestIds, owners = []) {
|
|
1212
|
+
await Promise.allSettled(Array.from(journalLoads.values(), load => load.promise));
|
|
1213
|
+
await Promise.allSettled(Array.from(journalWrites.values()));
|
|
1214
|
+
const storage = chrome.storage?.session;
|
|
1215
|
+
if (!storage) throw new Error('Run journal storage is unavailable.');
|
|
1216
|
+
const values = requestIds.length ? await storage.get(requestIds.map(id => RUN_JOURNAL_PREFIX + id)) : {};
|
|
1217
|
+
// A persisted startup snapshot may lag behind its owner's Native dispatch.
|
|
1218
|
+
// Keep that same project/session/run alive through the request-id transition.
|
|
1219
|
+
const matches = (candidate, binding) => (candidate?.preDispatch === true
|
|
1220
|
+
? ['projectKey', 'clientRunId', 'sessionId'] : ['requestId', 'projectKey', 'clientRunId', 'sessionId'])
|
|
1221
|
+
.every(key => Boolean(candidate?.[key]) && candidate[key] === binding?.[key]);
|
|
1222
|
+
const known = requestIds.filter(id => runJournals.has(id) || Boolean(values?.[RUN_JOURNAL_PREFIX + id])
|
|
1223
|
+
|| owners.some(candidate => candidate?.requestId === id && Array.from(ownerBindings.values()).some(binding => matches(candidate, binding))));
|
|
1224
|
+
const missing = owners.filter(candidate => requestIds.includes(candidate?.requestId) && !known.includes(candidate.requestId));
|
|
1225
|
+
if (!missing.length) return { known, ownersChecked: true, preDispatchChecked: true };
|
|
1226
|
+
// A worker restart drops ports before hidden pages can process reconnect
|
|
1227
|
+
// timers. The page's existing health receiver can still report its binding.
|
|
1228
|
+
const unknown = () => ({ known, ownersChecked: false, preDispatchChecked: false, retryAfterMs: 1000 });
|
|
1229
|
+
const tabs = await chrome.tabs.query({ url: MANAGED_OVERLEAF_MATCHES }).catch(() => null);
|
|
1230
|
+
if (!Array.isArray(tabs)) return unknown();
|
|
1231
|
+
const projects = new Set(missing.map(candidate => candidate.projectKey));
|
|
1232
|
+
const relevant = tabs.filter(tab => isManagedEditorTab(tab) && !tab.discarded && tab.status !== 'unloaded'
|
|
1233
|
+
&& projects.has(new URL(tab.url).pathname.split('/')[2]));
|
|
1234
|
+
const responses = await Promise.all(relevant.map(async tab => {
|
|
1235
|
+
let timer;
|
|
1236
|
+
try {
|
|
1237
|
+
return await Promise.race([
|
|
1238
|
+
chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/runtime-health-probe' }, { frameId: 0 }),
|
|
1239
|
+
new Promise(resolve => { timer = setTimeout(() => resolve(null), 1500); })
|
|
1240
|
+
]);
|
|
1241
|
+
} catch (_error) { return null; }
|
|
1242
|
+
finally { clearTimeout(timer); }
|
|
1243
|
+
}));
|
|
1244
|
+
const needsStartupInventory = missing.some(candidate => candidate.preDispatch === true);
|
|
1245
|
+
if (responses.some(response => response?.ok !== true || ![1, 2].includes(response.runOwnerProtocol)
|
|
1246
|
+
|| (needsStartupInventory && response.runOwnerProtocol !== 2) || !Array.isArray(response.runOwners))) return unknown();
|
|
1247
|
+
for (const candidate of missing) {
|
|
1248
|
+
if (responses.some(response => response.runOwners.some(binding => matches(candidate, binding)))
|
|
1249
|
+
|| Array.from(ownerBindings.values()).some(binding => matches(candidate, binding))) known.push(candidate.requestId);
|
|
1250
|
+
}
|
|
1251
|
+
return { known, ownersChecked: true, preDispatchChecked: true };
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1025
1254
|
function pruneInMemoryRunJournals() {
|
|
1026
1255
|
if (runJournals.size <= 16) {
|
|
1027
1256
|
return;
|
|
@@ -1031,9 +1260,7 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
1031
1260
|
.sort((a, b) => String(a.createdAt || '').localeCompare(String(b.createdAt || '')))
|
|
1032
1261
|
.slice(0, runJournals.size - 16);
|
|
1033
1262
|
for (const journal of oldest) {
|
|
1034
|
-
|
|
1035
|
-
journalWrites.delete(journal.requestId);
|
|
1036
|
-
chrome.storage?.session?.remove?.(RUN_JOURNAL_PREFIX + journal.requestId).catch?.(() => {});
|
|
1263
|
+
removeRunJournal(journal.requestId).catch(() => {});
|
|
1037
1264
|
}
|
|
1038
1265
|
}
|
|
1039
1266
|
|
|
@@ -1041,27 +1268,26 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
1041
1268
|
if (!id) {
|
|
1042
1269
|
return;
|
|
1043
1270
|
}
|
|
1044
|
-
await (
|
|
1045
|
-
runJournals.delete(id);
|
|
1046
|
-
journalWrites.delete(id);
|
|
1047
|
-
await chrome.storage?.session?.remove?.(RUN_JOURNAL_PREFIX + id);
|
|
1271
|
+
await removeRunJournal(id);
|
|
1048
1272
|
}
|
|
1049
1273
|
|
|
1050
1274
|
async function interruptOwnerlessRun(binding) {
|
|
1051
1275
|
ownerCancelTimers.delete(binding.requestId);
|
|
1052
|
-
if (
|
|
1276
|
+
if (hasRunOwner(binding)) {
|
|
1053
1277
|
return;
|
|
1054
1278
|
}
|
|
1055
|
-
const journal =
|
|
1279
|
+
const journal = await restoreRunJournal(binding).catch(() => null);
|
|
1280
|
+
if (hasRunOwner(binding)) return;
|
|
1281
|
+
if (journal && runJournals.get(binding.requestId) !== journal) return;
|
|
1056
1282
|
if (journal) {
|
|
1057
1283
|
journal.ownerLost = true;
|
|
1058
1284
|
journal.updatedAt = new Date().toISOString();
|
|
1059
1285
|
await queueJournalWrite(binding.requestId).catch(() => {});
|
|
1060
1286
|
}
|
|
1061
|
-
if (
|
|
1062
|
-
|
|
1063
|
-
}
|
|
1287
|
+
if (hasRunOwner(binding)) return;
|
|
1288
|
+
if (journal && runJournals.get(binding.requestId) !== journal) return;
|
|
1064
1289
|
try {
|
|
1290
|
+
if (!pending.has(binding.requestId) || !journalMatchesBinding(journal, binding)) return;
|
|
1065
1291
|
sendNativeCancel({
|
|
1066
1292
|
method: 'codex.cancel',
|
|
1067
1293
|
params: {
|
|
@@ -1071,6 +1297,8 @@ if (!globalThis.CodexOverleafUpdateRuntimeIdentity) {
|
|
|
1071
1297
|
});
|
|
1072
1298
|
} catch (_error) {
|
|
1073
1299
|
// The original request disconnect path will settle the journal.
|
|
1300
|
+
} finally {
|
|
1301
|
+
pruneInMemoryRunJournals();
|
|
1074
1302
|
}
|
|
1075
1303
|
}
|
|
1076
1304
|
})();
|