codex-overleaf-link 2.5.0 → 2.5.1
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 +38 -26
- package/README.zh-CN.md +39 -27
- 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 +206 -53
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +74 -14
- package/extension/src/backgroundUpdateCoordinator.js +118 -21
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +8 -2
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +72 -14
- package/extension/src/content/composerAttachments.js +93 -45
- package/extension/src/content/composerPanel.js +18 -0
- package/extension/src/content/contentRuntime.js +661 -676
- package/extension/src/content/diagnosticsController.js +122 -96
- package/extension/src/content/diagnosticsExport.js +19 -5
- package/extension/src/content/diagnosticsPanel.js +30 -0
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +6879 -2786
- package/extension/src/content/generated/content.bundle.meta.json +11 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +6 -0
- package/extension/src/content/localSkillsPanel.js +102 -12
- package/extension/src/content/markdownText.js +5 -6
- package/extension/src/content/modelPicker.js +7 -4
- package/extension/src/content/nativeCompatibilityController.js +45 -20
- package/extension/src/content/otWarmMirror.js +4 -5
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +15 -2
- package/extension/src/content/panelMaintenance.js +40 -12
- package/extension/src/content/panelRenderer.js +6 -0
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +39 -2
- package/extension/src/content/providerSettingsCoordinator.js +46 -8
- package/extension/src/content/providerSettingsDialog.js +71 -13
- package/extension/src/content/recentProjects.js +11 -5
- package/extension/src/content/runActivitySummary.js +40 -6
- package/extension/src/content/runCompletionMeta.js +344 -0
- package/extension/src/content/runController.js +37 -14
- package/extension/src/content/runFailureNotice.js +21 -12
- package/extension/src/content/runGuidanceController.js +72 -27
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runQueueScheduler.js +148 -42
- package/extension/src/content/runRecoveryActions.js +146 -0
- package/extension/src/content/runResultActions.js +8 -125
- package/extension/src/content/runReviewController.js +574 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +146 -153
- package/extension/src/content/scopedPersistencePanelState.js +51 -6
- package/extension/src/content/selectionContextView.js +1 -1
- package/extension/src/content/sensitivePreflight.js +140 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +1 -1
- package/extension/src/content/settingsPanel.js +7 -3
- package/extension/src/content/settingsWorkbench.js +5 -0
- package/extension/src/content/sharedSessionViewSync.js +45 -8
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +60 -8
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +53 -4
- package/extension/src/content/writebackOrchestrator.js +82 -73
- package/extension/src/content/writingStyleSettings.js +35 -11
- package/extension/src/page/binaryAssetUploader.js +136 -14
- package/extension/src/page/fileMover.js +256 -0
- 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/textFileCreator.js +105 -25
- 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 +80 -79
- package/extension/src/pageBridge.js +19 -3
- package/extension/src/popup.js +62 -10
- package/extension/src/shared/agentTranscript.js +23 -0
- package/extension/src/shared/auditRecords.js +2 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +79 -57
- package/extension/src/shared/composerAttachmentDraft.js +151 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +309 -3
- package/extension/src/shared/globalPreferences.js +30 -13
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +298 -2
- 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/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +5 -3
- package/extension/src/shared/runInputQueue.js +48 -5
- package/extension/src/shared/selectionContext.js +12 -3
- package/extension/src/shared/sessionState.js +72 -27
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +37 -14
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +118 -13
- package/extension/src/shared/storageDb.js +58 -26
- package/extension/src/shared/storageMigration.js +71 -111
- package/extension/src/shared/storageRunActions.js +209 -26
- package/extension/src/shared/subagentActivityModel.js +1 -1
- package/extension/src/shared/undoOperations.js +136 -13
- package/extension/src/shared/updateConsent.js +6 -4
- package/extension/src/shared/updateRuntimeIdentity.js +1 -1
- package/extension/src/shared/writebackIntent.js +16 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +38 -38
- package/extension/styles/panel.css +19 -5
- 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 +233 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeResponse.js +10 -0
- package/native-host/src/chatCompletionsBridge.js +21 -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 +31 -12
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexSessionRunner.js +110 -183
- 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/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 +77 -54
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/updateManager.js +297 -39
- package/native-host/src/writingStyleRuntime.js +57 -29
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +1 -1
- package/scripts/install-managed.mjs +1 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
(function initUndoOperations(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory();
|
|
3
|
+
module.exports = factory(require('./staleGuard'));
|
|
4
4
|
} else {
|
|
5
|
-
root.CodexOverleafUndoOperations = factory();
|
|
5
|
+
root.CodexOverleafUndoOperations = factory(root.CodexOverleafStaleGuard);
|
|
6
6
|
}
|
|
7
|
-
})(typeof globalThis !== 'undefined' ? globalThis : window, function undoOperationsFactory() {
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function undoOperationsFactory(StaleGuard) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
function buildUndoOperations(project, appliedOperations) {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
const sourceFilesByPath = new Map(workingFilesByPath);
|
|
18
19
|
const undo = [];
|
|
19
20
|
const fullRestoreEditPaths = new Set();
|
|
20
21
|
|
|
@@ -29,7 +30,8 @@
|
|
|
29
30
|
}
|
|
30
31
|
const currentBeforeEdit = workingFilesByPath.get(operation.path);
|
|
31
32
|
if (!fullRestoreEditPaths.has(operation.path)) {
|
|
32
|
-
const inversePatches = buildInverseTextPatches(
|
|
33
|
+
const inversePatches = buildInverseTextPatches(sourceFilesByPath.get(operation.path), operation.patches,
|
|
34
|
+
operation.verifiedContent, operation.path);
|
|
33
35
|
if (inversePatches.length) {
|
|
34
36
|
undo.push(normalizeUndoOperation({
|
|
35
37
|
type: 'edit',
|
|
@@ -70,10 +72,13 @@
|
|
|
70
72
|
if (!operation.path || !operation.to) {
|
|
71
73
|
continue;
|
|
72
74
|
}
|
|
75
|
+
if (operation.moveProof && !operation.moveProof.targetEntityId) continue;
|
|
73
76
|
undo.push(normalizeUndoOperation({
|
|
74
77
|
type: 'move',
|
|
75
78
|
path: operation.to,
|
|
76
79
|
to: operation.path,
|
|
80
|
+
...(operation.moveProof ? { moveProof: { ...operation.moveProof,
|
|
81
|
+
sourceEntityId: operation.moveProof.targetEntityId, targetEntityId: operation.moveProof.sourceEntityId } } : {}),
|
|
77
82
|
reason: 'Undo move'
|
|
78
83
|
}));
|
|
79
84
|
} else if (operation.type === 'delete') {
|
|
@@ -89,12 +94,13 @@
|
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
applyOperationToFiles(workingFilesByPath, operation);
|
|
97
|
+
applyOperationToFiles(sourceFilesByPath, { ...operation, verifiedContent: undefined });
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
return undo.reverse();
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
function buildInverseTextPatches(textBeforeEdit, patches) {
|
|
103
|
+
function buildInverseTextPatches(textBeforeEdit, patches, verifiedContent, path) {
|
|
98
104
|
if (!Array.isArray(patches) || !patches.length) {
|
|
99
105
|
return [];
|
|
100
106
|
}
|
|
@@ -108,7 +114,7 @@
|
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
let offset = 0;
|
|
111
|
-
|
|
117
|
+
const inverse = normalized.patches.map(patch => {
|
|
112
118
|
const from = patch.from + offset;
|
|
113
119
|
const to = from + patch.insert.length;
|
|
114
120
|
offset += patch.insert.length - (patch.to - patch.from);
|
|
@@ -119,6 +125,41 @@
|
|
|
119
125
|
insert: patch.expected
|
|
120
126
|
};
|
|
121
127
|
});
|
|
128
|
+
if (typeof verifiedContent !== 'string' || verifiedContent === applied.text) return inverse;
|
|
129
|
+
// The stored checkpoint uses the verified editor post-image. Its inverse
|
|
130
|
+
// must use those same offsets, while Native patches retain their source
|
|
131
|
+
// representation for later operations in the batch.
|
|
132
|
+
const prepared = StaleGuard.prepareOperationPatches({ type: 'edit', path, patches: inverse }, verifiedContent,
|
|
133
|
+
StaleGuard.buildBaseFileLookup([{ path, content: applied.text }]));
|
|
134
|
+
return prepared.ok && applyTextPatches(verifiedContent, prepared.patches).ok ? prepared.patches : [];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function selectExpectedFilesForTrackedUndo(project, operations = [], trackedChanges = [], previousExpectedFiles = []) {
|
|
138
|
+
const paths = new Set();
|
|
139
|
+
for (const change of trackedChanges || []) if (change?.path) paths.add(change.path);
|
|
140
|
+
for (const operation of operations || []) {
|
|
141
|
+
if (operation?.path) paths.add(operation.path);
|
|
142
|
+
if (operation?.to) paths.add(operation.to);
|
|
143
|
+
}
|
|
144
|
+
const expectedByPath = new Map();
|
|
145
|
+
for (const file of previousExpectedFiles || []) {
|
|
146
|
+
if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
|
|
147
|
+
expectedByPath.set(file.path, { path: file.path, content: file.content });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Reconstruct the pre-image with the same inverse patches as plain Undo.
|
|
151
|
+
// This preserves the editor's unchanged line endings and collaborator
|
|
152
|
+
// content, including when the ZIP baseline used a different representation.
|
|
153
|
+
const hasVerifiedPatches = operations.some(operation => typeof operation?.verifiedContent === 'string'
|
|
154
|
+
&& Array.isArray(operation.patches) && operation.patches.length);
|
|
155
|
+
const checkpoint = hasVerifiedPatches ? buildUndoCheckpoint(project, operations) : null;
|
|
156
|
+
const restored = checkpoint ? buildExpectedFilesAfterOperations({ files: checkpoint.undoBaseFiles }, checkpoint.undoOperations) : new Map();
|
|
157
|
+
for (const file of project?.files || []) {
|
|
158
|
+
if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
|
|
159
|
+
expectedByPath.set(file.path, { path: file.path, content: restored.get(file.path) ?? file.content });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return Array.from(expectedByPath.values());
|
|
122
163
|
}
|
|
123
164
|
|
|
124
165
|
function buildUndoCheckpoint(project, appliedOperations) {
|
|
@@ -140,9 +181,9 @@
|
|
|
140
181
|
const proof = operation?.undoCreatedFile;
|
|
141
182
|
if (operation?.type !== 'delete' || proof?.v !== 1) continue;
|
|
142
183
|
if (proof.kind === 'text' && priorFiles.has(operation.path)) {
|
|
143
|
-
created.set(operation.path, { kind: 'text', content: priorFiles.get(operation.path) });
|
|
184
|
+
created.set(operation.path, { kind: 'text', content: priorFiles.get(operation.path), createdDirectories: proof.createdDirectories });
|
|
144
185
|
} else if (proof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(proof.sha256 || '')) {
|
|
145
|
-
created.set(operation.path, { kind: 'binary', sha256: proof.sha256.toLowerCase() });
|
|
186
|
+
created.set(operation.path, { kind: 'binary', sha256: proof.sha256.toLowerCase(), createdDirectories: proof.createdDirectories });
|
|
146
187
|
}
|
|
147
188
|
}
|
|
148
189
|
for (const operation of appliedOperations || []) {
|
|
@@ -152,17 +193,17 @@
|
|
|
152
193
|
if (originalPaths.has(path) && !created.has(path)) continue;
|
|
153
194
|
if (operation.type === 'create' && typeof operation.content === 'string') {
|
|
154
195
|
created.set(path, { kind: 'text', content: typeof operation.verifiedContent === 'string'
|
|
155
|
-
? operation.verifiedContent : operation.content });
|
|
196
|
+
? operation.verifiedContent : operation.content, createdDirectories: operation.createdDirectories });
|
|
156
197
|
} else {
|
|
157
198
|
const hash = operation.sha256 || operation.assetRef?.sha256;
|
|
158
199
|
if (operation.previousExists !== true && /^[a-f0-9]{64}$/i.test(hash || '')) {
|
|
159
|
-
created.set(path, { kind: 'binary', sha256: hash.toLowerCase() });
|
|
200
|
+
created.set(path, { kind: 'binary', sha256: hash.toLowerCase(), createdDirectories: operation.createdDirectories });
|
|
160
201
|
}
|
|
161
202
|
}
|
|
162
203
|
} else if (operation.type === 'edit' && created.get(path)?.kind === 'text') {
|
|
163
204
|
const files = new Map([[path, created.get(path).content]]);
|
|
164
205
|
applyOperationToFiles(files, operation);
|
|
165
|
-
created.set(path, { kind: 'text', content: files.get(path) });
|
|
206
|
+
created.set(path, { ...created.get(path), kind: 'text', content: files.get(path) });
|
|
166
207
|
} else if (['delete', 'rename', 'move', 'overwrite-binary'].includes(operation.type)) {
|
|
167
208
|
// Existing rename/overwrite recovery retains ownership of these cases.
|
|
168
209
|
created.delete(path);
|
|
@@ -173,17 +214,78 @@
|
|
|
173
214
|
for (const [path, proof] of Array.from(created).reverse()) {
|
|
174
215
|
const undoCreatedFile = proof.kind === 'binary'
|
|
175
216
|
? { v: 1, kind: 'binary', sha256: proof.sha256 } : { v: 1, kind: 'text' };
|
|
217
|
+
if (Array.isArray(proof.createdDirectories) && proof.createdDirectories.length) {
|
|
218
|
+
undoCreatedFile.createdDirectories = proof.createdDirectories.map(item => ({ ...item }));
|
|
219
|
+
}
|
|
176
220
|
undoOperations.push({ ...normalizeUndoOperation({ type: 'delete', path, reason: 'Undo create' }), undoCreatedFile });
|
|
177
221
|
if (proof.kind === 'text') undoBaseFiles.push({ path, content: proof.content });
|
|
178
222
|
}
|
|
223
|
+
// Reviewing has no text insertion/deletion refs for a native metadata move.
|
|
224
|
+
// Keep its identity-bound inverse with the other file-level proofs.
|
|
225
|
+
undoOperations.push(...buildUndoOperations(project, appliedOperations).filter(operation => operation.type === 'move' && operation.moveProof));
|
|
179
226
|
return { undoOperations, undoBaseFiles };
|
|
180
227
|
}
|
|
181
228
|
|
|
229
|
+
function isFileUndoOperation(operation) {
|
|
230
|
+
return operation?.undoCreatedFile?.v === 1
|
|
231
|
+
|| (operation?.type === 'move' && operation.moveProof?.v === 1)
|
|
232
|
+
|| (operation?.type === 'create' && typeof operation.content === 'string');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// A deleted original has no editor post-image. Its inverse is a guarded
|
|
236
|
+
// file creation, backed by both the forward delete and the captured original.
|
|
237
|
+
// This also recovers older Track-on records that omitted that inverse.
|
|
238
|
+
function getFileUndoOperations(run = {}) {
|
|
239
|
+
const operations = (run.undoOperations || []).filter(isFileUndoOperation);
|
|
240
|
+
const before = filesListToMap(run.undoExpectedFiles);
|
|
241
|
+
const after = buildExpectedFilesAfterOperations({ files: run.undoExpectedFiles }, run.appliedOperations);
|
|
242
|
+
const deleted = new Set((run.appliedOperations || []).filter(operation => operation?.type === 'delete'
|
|
243
|
+
&& before.has(operation.path) && !after.has(operation.path)).map(operation => operation.path));
|
|
244
|
+
return [...operations.filter(operation => !deleted.has(operation.path)), ...Array.from(deleted, path =>
|
|
245
|
+
normalizeUndoOperation({ type: 'create', path, content: before.get(path), reason: 'Undo delete' }))];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function prepareRunUndo(run = {}) {
|
|
249
|
+
const files = getFileUndoOperations(run);
|
|
250
|
+
const restored = new Set(files.filter(operation => operation.type === 'create').map(operation => operation.path));
|
|
251
|
+
const pending = [...files], operations = [];
|
|
252
|
+
for (const operation of run.undoOperations || []) {
|
|
253
|
+
if (isFileUndoOperation(operation)) {
|
|
254
|
+
const index = pending.findIndex(file => file.path === operation.path && file.type === operation.type);
|
|
255
|
+
if (index >= 0) operations.push(...pending.splice(index, 1));
|
|
256
|
+
} else if (!restored.has(operation.path)) operations.push(operation);
|
|
257
|
+
}
|
|
258
|
+
return { ...run, undoOperations: [...operations, ...pending] };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function textUndoRun(run = {}) {
|
|
262
|
+
const restored = new Set(getFileUndoOperations(run).flatMap(operation => operation.type === 'create' ? [operation.path]
|
|
263
|
+
: operation.type === 'move' ? [operation.path, operation.to] : []));
|
|
264
|
+
return { ...run,
|
|
265
|
+
undoExpectedFiles: (run.undoExpectedFiles || []).filter(file => !restored.has(file.path)),
|
|
266
|
+
undoTrackedChanges: (run.undoTrackedChanges || []).filter(ref => !restored.has(ref.path))
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function mergeFileUndoResult(textResult, fileResult, operations) {
|
|
271
|
+
const applied = [...(textResult.applied || []), ...(fileResult.applied || [])];
|
|
272
|
+
const skipped = [...(textResult.skipped || []), ...(fileResult.skipped || [])];
|
|
273
|
+
for (const operation of operations) {
|
|
274
|
+
if (!(fileResult.applied || []).some(entry => entry.operation?.path === operation.path
|
|
275
|
+
&& entry.operation?.type === operation.type && entry.result?.ok === true && entry.result?.verified === true
|
|
276
|
+
&& entry.result.verification === 'overleaf-zip')
|
|
277
|
+
&& !(fileResult.skipped || []).some(entry => entry.operation?.path === operation.path)) {
|
|
278
|
+
skipped.push({ operation, result: { ok: false, code: 'undo_operation_failed',
|
|
279
|
+
reason: 'The file restoration has no verified server receipt.' } });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return { ...textResult, ok: textResult.ok !== false && fileResult.ok !== false && !skipped.length, applied, skipped };
|
|
283
|
+
}
|
|
284
|
+
|
|
182
285
|
// Consume only independently verified rollback receipts. Forward writes
|
|
183
286
|
// remain audit evidence; recovery arrays describe only unfinished work.
|
|
184
287
|
function advanceUndoCheckpoint(run = {}, result = {}, verifyText = () => false) {
|
|
185
288
|
const operations = Array.isArray(run?.undoOperations) ? run.undoOperations : [];
|
|
186
|
-
if (!operations.some(operation => operation?.undoCreatedFile?.v === 1)) return run;
|
|
187
289
|
const applied = Array.isArray(result.applied) ? result.applied : [];
|
|
188
290
|
const skipped = Array.isArray(result.skipped) ? result.skipped : [];
|
|
189
291
|
const failed = path => skipped.some(entry => {
|
|
@@ -201,8 +303,22 @@
|
|
|
201
303
|
&& JSON.stringify(entry.operation.undoCreatedFile) === JSON.stringify(operation.undoCreatedFile)
|
|
202
304
|
&& entry.result?.ok === true && entry.result.verified === true
|
|
203
305
|
&& entry.result.verification === 'overleaf-zip')).map(operation => operation.path));
|
|
306
|
+
const restoredPaths = new Set(operations.filter(operation => operation?.type === 'create'
|
|
307
|
+
&& !failed(operation.path) && applied.some(entry => entry?.operation?.type === 'create'
|
|
308
|
+
&& entry.operation.path === operation.path && entry.operation.content === operation.content
|
|
309
|
+
&& entry.result?.ok === true && entry.result.verified === true
|
|
310
|
+
&& entry.result.verification === 'overleaf-zip')).map(operation => operation.path));
|
|
311
|
+
const movedPaths = new Set(operations.filter(operation => operation?.type === 'move' && operation.moveProof?.v === 1
|
|
312
|
+
&& !failed(operation.path) && applied.some(entry => entry?.operation?.type === 'move'
|
|
313
|
+
&& entry.operation.path === operation.path && entry.operation.to === operation.to
|
|
314
|
+
&& JSON.stringify(entry.operation.moveProof) === JSON.stringify(operation.moveProof)
|
|
315
|
+
&& entry.result?.ok === true && entry.result.verified === true && entry.result.verification === 'overleaf-zip'))
|
|
316
|
+
.flatMap(operation => [operation.path, operation.to]));
|
|
317
|
+
for (const path of restoredPaths) textPaths.add(path);
|
|
318
|
+
for (const path of movedPaths) textPaths.add(path);
|
|
204
319
|
if (!textPaths.size && !deletedPaths.size) return run;
|
|
205
|
-
const pending = operations.filter(operation => !(operation?.type === 'edit' && textPaths.has(operation.path))
|
|
320
|
+
const pending = operations.filter(operation => !restoredPaths.has(operation.path) && !(operation?.type === 'edit' && textPaths.has(operation.path))
|
|
321
|
+
&& !(operation?.type === 'move' && movedPaths.has(operation.path))
|
|
206
322
|
&& !(operation?.type === 'delete' && operation.undoCreatedFile?.v === 1 && deletedPaths.has(operation.path)));
|
|
207
323
|
const needed = new Set(pending.flatMap(operation => [operation?.path, operation?.to]).filter(Boolean));
|
|
208
324
|
return { ...run,
|
|
@@ -396,6 +512,7 @@
|
|
|
396
512
|
insert: String(patch.insert ?? '')
|
|
397
513
|
}));
|
|
398
514
|
}
|
|
515
|
+
if (operation.type === 'move' && operation.moveProof?.v === 1) normalized.moveProof = JSON.parse(JSON.stringify(operation.moveProof));
|
|
399
516
|
return normalized;
|
|
400
517
|
}
|
|
401
518
|
|
|
@@ -454,11 +571,17 @@
|
|
|
454
571
|
}
|
|
455
572
|
|
|
456
573
|
return {
|
|
574
|
+
isFileUndoOperation,
|
|
575
|
+
getFileUndoOperations,
|
|
576
|
+
prepareRunUndo,
|
|
577
|
+
textUndoRun,
|
|
578
|
+
mergeFileUndoResult,
|
|
457
579
|
buildUndoCheckpoint,
|
|
458
580
|
buildCreatedFileUndoCheckpoint,
|
|
459
581
|
advanceUndoCheckpoint,
|
|
460
582
|
buildExpectedFilesAfterOperations,
|
|
461
583
|
buildUndoOperations,
|
|
584
|
+
selectExpectedFilesForTrackedUndo,
|
|
462
585
|
buildSnapshotRestoreUndo
|
|
463
586
|
};
|
|
464
587
|
});
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
deadlineAt: finiteNumber(value.deadlineAt),
|
|
79
79
|
heartbeatAt: finiteNumber(value.heartbeatAt),
|
|
80
80
|
postponeUntil: finiteNumber(value.postponeUntil),
|
|
81
|
+
cooldownUntil: finiteNumber(value.cooldownUntil),
|
|
81
82
|
code: safeToken(value.code),
|
|
82
83
|
message: String(value.message || '').replace(/\s+/g, ' ').trim().slice(0, 300),
|
|
83
84
|
manualReason: normalizeManualReason(value.manualReason)
|
|
@@ -118,9 +119,6 @@
|
|
|
118
119
|
const state = normalizeUpdateState(updateValue, options.currentVersion);
|
|
119
120
|
const consent = normalizeConsentState(consentValue);
|
|
120
121
|
const newer = compareStableVersions(state.latestVersion, state.currentVersion) > 0;
|
|
121
|
-
const snoozed = newer &&
|
|
122
|
-
consent.snoozedVersion === state.latestVersion &&
|
|
123
|
-
consent.snoozedUntil > now;
|
|
124
122
|
const execution = EXECUTION_STATES.has(state.state);
|
|
125
123
|
const available = state.state === 'update_available' && newer;
|
|
126
124
|
// A newer release that only a reinstall can apply. It is shown even after
|
|
@@ -129,7 +127,11 @@
|
|
|
129
127
|
// still names the old one, and the notice must clear by itself.
|
|
130
128
|
const runningVersion = safeVersion(options.currentVersion) || state.currentVersion;
|
|
131
129
|
const manualInstall = state.state === 'manual_install_required'
|
|
132
|
-
&& compareStableVersions(state.latestVersion, runningVersion) > 0
|
|
130
|
+
&& (compareStableVersions(state.latestVersion, runningVersion) > 0
|
|
131
|
+
|| (state.code === 'prerelease_promotion_requires_manual_update'
|
|
132
|
+
&& state.latestVersion === runningVersion));
|
|
133
|
+
const snoozed = (newer || manualInstall) &&
|
|
134
|
+
consent.snoozedVersion === state.latestVersion && consent.snoozedUntil > now;
|
|
133
135
|
const progress = getProgressModel(state);
|
|
134
136
|
const quietFailure = state.state === 'failed' &&
|
|
135
137
|
state.initiatedBy !== 'manual' &&
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
if (!status.managed || !result.installedVersion || !result.nativeVersion ||
|
|
19
19
|
!result.extensionVersion || !result.runtimeVersion) return result;
|
|
20
20
|
if (['authorized', 'bound'].includes(status.authorization?.state) ||
|
|
21
|
-
['staged', 'activation_pending', 'applying', 'awaiting_health'].includes(status.transaction?.state)) {
|
|
21
|
+
['staged', 'activation_pending', 'applying', 'bootstrap_pending', 'bootstrap_rolling_back', 'awaiting_health', 'rolling_back'].includes(status.transaction?.state)) {
|
|
22
22
|
return { ...result, state: 'transaction_active' };
|
|
23
23
|
}
|
|
24
24
|
if (status.installedAligned !== true) return { ...result, state: 'repair_required' };
|
|
@@ -18,6 +18,22 @@
|
|
|
18
18
|
if (typeof input[key] === 'string') op[key] = input[key];
|
|
19
19
|
}
|
|
20
20
|
if (Number.isSafeInteger(input.size)) op.size = input.size;
|
|
21
|
+
if (input.moveProof !== undefined) {
|
|
22
|
+
const proof = input.moveProof;
|
|
23
|
+
if (input.type !== 'move' || proof?.v !== 1 || !['text', 'binary'].includes(proof.kind)
|
|
24
|
+
|| !/^[a-f0-9]{64}$/i.test(proof.sha256 || '')) return null;
|
|
25
|
+
op.moveProof = { v: 1, kind: proof.kind, sha256: proof.sha256.toLowerCase() };
|
|
26
|
+
if (proof.entityType !== undefined) {
|
|
27
|
+
if (!['doc', 'file'].includes(proof.entityType)) return null;
|
|
28
|
+
op.moveProof.entityType = proof.entityType;
|
|
29
|
+
}
|
|
30
|
+
for (const key of ['sourceEntityId', 'targetEntityId']) {
|
|
31
|
+
if (proof[key] !== undefined) {
|
|
32
|
+
if (typeof proof[key] !== 'string' || !proof[key] || proof[key].length > 160 || /[\0\r\n]/.test(proof[key])) return null;
|
|
33
|
+
op.moveProof[key] = proof[key];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
21
37
|
if (Array.isArray(input.patches)) {
|
|
22
38
|
if (input.patches.length > 1000) return null;
|
|
23
39
|
op.patches = input.patches.map(p => ({ from: p.from, to: p.to, expected: String(p.expected ?? ''), insert: String(p.insert ?? '') }));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
(function initCodexOverleafWritebackOperationEvidence(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory();
|
|
3
|
+
module.exports = factory(require('./failureReasons'));
|
|
4
4
|
} else {
|
|
5
|
-
root.CodexOverleafModuleRegistry.define('WritebackOperationEvidence', [], factory);
|
|
5
|
+
root.CodexOverleafModuleRegistry.define('WritebackOperationEvidence', ['FailureReasons'], factory);
|
|
6
6
|
}
|
|
7
|
-
})(typeof window !== 'undefined' ? window : globalThis, function writebackOperationEvidenceFactory() {
|
|
7
|
+
})(typeof window !== 'undefined' ? window : globalThis, function writebackOperationEvidenceFactory(FailureReasons) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
function normalizeOperationEvidence(operations = [], applyResult = {}) {
|
|
@@ -99,18 +99,7 @@
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
function normalizeFailure(result, operation) {
|
|
102
|
-
|
|
103
|
-
if (!result?.code) return null;
|
|
104
|
-
return {
|
|
105
|
-
code: result.code,
|
|
106
|
-
stage: result.stage || 'write',
|
|
107
|
-
severity: result.severity || 'error',
|
|
108
|
-
userMessage: result.reason || result.message || result.code,
|
|
109
|
-
retryable: result.retryable === true,
|
|
110
|
-
file: operation?.path || operation?.to || '',
|
|
111
|
-
changedDocument: result.changedDocument === true,
|
|
112
|
-
terminalState: result.terminalState || ''
|
|
113
|
-
};
|
|
102
|
+
return FailureReasons.normalizeWritebackFailure(result, operation);
|
|
114
103
|
}
|
|
115
104
|
|
|
116
105
|
function normalizeTrackedChanges(value) {
|
|
@@ -4,21 +4,24 @@
|
|
|
4
4
|
require('./failureReasons'),
|
|
5
5
|
require('./settlementFacts'),
|
|
6
6
|
require('./writebackEvidenceProjection'),
|
|
7
|
-
require('./writebackOperationEvidence')
|
|
7
|
+
require('./writebackOperationEvidence'),
|
|
8
|
+
require('./undoOperations')
|
|
8
9
|
);
|
|
9
10
|
} else {
|
|
10
11
|
root.CodexOverleafModuleRegistry.define('WritebackSettlement', [
|
|
11
12
|
'FailureReasons',
|
|
12
13
|
'SettlementFacts',
|
|
13
14
|
'WritebackEvidenceProjection',
|
|
14
|
-
'WritebackOperationEvidence'
|
|
15
|
+
'WritebackOperationEvidence',
|
|
16
|
+
'UndoOperations'
|
|
15
17
|
], factory);
|
|
16
18
|
}
|
|
17
19
|
})(typeof window !== 'undefined' ? window : globalThis, function writebackSettlementFactory(
|
|
18
20
|
DefaultFailureReasons,
|
|
19
21
|
SettlementFacts,
|
|
20
22
|
EvidenceProjection,
|
|
21
|
-
OperationEvidence
|
|
23
|
+
OperationEvidence,
|
|
24
|
+
UndoOperations
|
|
22
25
|
) {
|
|
23
26
|
'use strict';
|
|
24
27
|
|
|
@@ -212,7 +215,7 @@
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
function deriveSettledEvidence(primaryFailure, fileSettlements = []) {
|
|
215
|
-
if (primaryFailure?.terminalState === 'needs_review'
|
|
218
|
+
if (primaryFailure?.terminalState === 'needs_review' || DefaultFailureReasons.isUnconfirmedWriteFailure?.(primaryFailure)
|
|
216
219
|
|| fileSettlements.some(file => file.readBack === 'mismatch')) {
|
|
217
220
|
return 'needs-review';
|
|
218
221
|
}
|
|
@@ -336,7 +339,8 @@
|
|
|
336
339
|
}
|
|
337
340
|
|
|
338
341
|
function settleLegacyUndo(input = {}) {
|
|
339
|
-
const status = input.status === 'applied'
|
|
342
|
+
const status = input.status === 'applied'
|
|
343
|
+
&& isUndoResultEffectivelyApplied(input.run, input.result, input.run?.undoOperations) ? 'applied' : 'partial';
|
|
340
344
|
const recovery = preserveRecovery();
|
|
341
345
|
return {
|
|
342
346
|
statePatch: { undoStatus: status },
|
|
@@ -441,7 +445,8 @@
|
|
|
441
445
|
}
|
|
442
446
|
|
|
443
447
|
function isUndoResultEffectivelyApplied(run, result, undoOperations = []) {
|
|
444
|
-
if (
|
|
448
|
+
if (result?.saveVerification?.ok === false || result?.receiptUnconfirmed === true) return false;
|
|
449
|
+
if (!result?.skipped?.length) return result?.ok === true;
|
|
445
450
|
const expectedByPath = new Map((run?.undoExpectedFiles || [])
|
|
446
451
|
.filter(file => file?.path && typeof file.content === 'string')
|
|
447
452
|
.map(file => [normalizeSettlementPath(file.path), file.content])
|
|
@@ -467,10 +472,12 @@
|
|
|
467
472
|
if (entry?.operation?.type === 'edit' && operationPath === normalizedPath) {
|
|
468
473
|
return inner.verifiedContent === expectedContent;
|
|
469
474
|
}
|
|
470
|
-
|
|
471
475
|
const trackedPath = normalizeSettlementPath(entry?.trackedChange?.path);
|
|
472
476
|
if (trackedPath !== normalizedPath) return false;
|
|
473
477
|
const key = String(entry?.trackedChange?.key || '');
|
|
478
|
+
if (['overleaf-review-reject', 'overleaf-review-reject-sweep'].includes(inner.method))
|
|
479
|
+
return /^(?:id:|pos:|sig:)/.test(key) && inner.verified === true
|
|
480
|
+
&& inner.verifiedContent === expectedContent;
|
|
474
481
|
if (key === `editor-undo:${normalizedPath}`) {
|
|
475
482
|
return inner.method === 'overleaf-editor-undo'
|
|
476
483
|
&& inner.verified === true
|
|
@@ -492,14 +499,12 @@
|
|
|
492
499
|
}
|
|
493
500
|
return false;
|
|
494
501
|
}
|
|
495
|
-
|
|
496
502
|
function normalizeSettlementPath(value) {
|
|
497
503
|
return String(value || '')
|
|
498
504
|
.replace(/\\/g, '/')
|
|
499
505
|
.replace(/\/+/g, '/')
|
|
500
506
|
.replace(/^\/+|\/+$/g, '');
|
|
501
507
|
}
|
|
502
|
-
|
|
503
508
|
function attachAcceptNotVerifiedFailure(run, result, options = {}) {
|
|
504
509
|
if (!result || typeof result !== 'object' || result.ok === false) return result;
|
|
505
510
|
if (Array.isArray(result.skipped) && result.skipped.length > 0) return result;
|
|
@@ -580,8 +585,9 @@
|
|
|
580
585
|
const inner = entry?.result || entry;
|
|
581
586
|
if (!inner || inner.ok === true) continue;
|
|
582
587
|
const operation = entry?.operation || (entry?.trackedChange ? { path: entry.trackedChange.path } : undefined);
|
|
583
|
-
|
|
584
|
-
|
|
588
|
+
const normalize = failureReasons?.normalizeWritebackFailure || failureReasons?.normalizeFailureReason;
|
|
589
|
+
failures.push(normalize instanceof Function
|
|
590
|
+
? normalize(inner, operation)
|
|
585
591
|
: normalizeFailure(inner, operation));
|
|
586
592
|
}
|
|
587
593
|
return failures.filter(Boolean);
|
|
@@ -630,9 +636,22 @@
|
|
|
630
636
|
|
|
631
637
|
function attachVerifiedContentToOperation(operation, result) {
|
|
632
638
|
if (!operation || typeof operation !== 'object') return operation;
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
639
|
+
const createdDirectories = (Array.isArray(result?.createdDirectories) ? result.createdDirectories
|
|
640
|
+
: Array.isArray(result?.moveProof?.createdDirectories) ? result.moveProof.createdDirectories : [])
|
|
641
|
+
.filter(proof => proof?.v === 1 && typeof proof.projectId === 'string' && proof.projectId
|
|
642
|
+
&& typeof proof.path === 'string' && proof.path && !proof.path.split('/').some(part => !part || part === '.' || part === '..')
|
|
643
|
+
&& typeof proof.nativeFolderId === 'string')
|
|
644
|
+
.map(proof => ({ v: 1, projectId: proof.projectId, path: proof.path, nativeFolderId: proof.nativeFolderId,
|
|
645
|
+
ownershipConfirmed: false, observedAfterCreate: proof.observedAfterCreate === true }));
|
|
646
|
+
const rawMove = result?.moveProof;
|
|
647
|
+
const moveProof = rawMove?.v === 1 && ['text', 'binary'].includes(rawMove.kind) && /^[a-f0-9]{64}$/i.test(rawMove.sha256 || '')
|
|
648
|
+
&& typeof rawMove.sourceEntityId === 'string' && rawMove.sourceEntityId
|
|
649
|
+
&& typeof rawMove.targetEntityId === 'string' && rawMove.targetEntityId
|
|
650
|
+
? { v: 1, kind: rawMove.kind, sha256: rawMove.sha256.toLowerCase(), sourceEntityId: rawMove.sourceEntityId,
|
|
651
|
+
targetEntityId: rawMove.targetEntityId, ...(['doc', 'file'].includes(rawMove.entityType) ? { entityType: rawMove.entityType } : {}), ...(createdDirectories.length ? { createdDirectories } : {}) } : null;
|
|
652
|
+
if (!(operation.type === 'edit' && typeof result?.verifiedContent === 'string') && !createdDirectories.length && !moveProof) return operation;
|
|
653
|
+
return { ...operation, ...(operation.type === 'edit' && typeof result?.verifiedContent === 'string' ? { verifiedContent: result.verifiedContent } : {}),
|
|
654
|
+
...(createdDirectories.length ? { createdDirectories } : {}), ...(moveProof ? { moveProof } : {}) };
|
|
636
655
|
}
|
|
637
656
|
|
|
638
657
|
function selectExpectedFilesForTrackedUndo(
|
|
@@ -641,26 +660,7 @@
|
|
|
641
660
|
trackedChanges = [],
|
|
642
661
|
previousExpectedFiles = []
|
|
643
662
|
) {
|
|
644
|
-
|
|
645
|
-
for (const change of trackedChanges || []) {
|
|
646
|
-
if (change?.path) paths.add(change.path);
|
|
647
|
-
}
|
|
648
|
-
for (const operation of operations || []) {
|
|
649
|
-
if (operation?.path) paths.add(operation.path);
|
|
650
|
-
if (operation?.to) paths.add(operation.to);
|
|
651
|
-
}
|
|
652
|
-
const expectedByPath = new Map();
|
|
653
|
-
for (const file of previousExpectedFiles || []) {
|
|
654
|
-
if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
|
|
655
|
-
expectedByPath.set(file.path, { path: file.path, content: file.content });
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
for (const file of project?.files || []) {
|
|
659
|
-
if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
|
|
660
|
-
expectedByPath.set(file.path, { path: file.path, content: file.content });
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return Array.from(expectedByPath.values());
|
|
663
|
+
return UndoOperations.selectExpectedFilesForTrackedUndo(project, operations, trackedChanges, previousExpectedFiles);
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
function acceptDiagnosticStatus(step, info) {
|
|
@@ -674,10 +674,9 @@
|
|
|
674
674
|
return 'info';
|
|
675
675
|
}
|
|
676
676
|
|
|
677
|
-
function selectPrimaryFailure(failures, failureReasons) {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
: failures[0] || null;
|
|
677
|
+
function selectPrimaryFailure(failures, failureReasons = DefaultFailureReasons) {
|
|
678
|
+
const select = failureReasons?.selectPrimaryWritebackFailure || failureReasons?.selectPrimaryFailure;
|
|
679
|
+
return select instanceof Function ? select(failures) : failures[0] || null;
|
|
681
680
|
}
|
|
682
681
|
|
|
683
682
|
function appendSyntheticFailure(result, failure, path, code, type) {
|
|
@@ -749,6 +748,7 @@
|
|
|
749
748
|
normalizeOperationEvidence,
|
|
750
749
|
normalizeSaveEvidence,
|
|
751
750
|
projectRunSettlement,
|
|
751
|
+
selectPrimaryFailure,
|
|
752
752
|
selectExpectedFilesForTrackedUndo,
|
|
753
753
|
settle,
|
|
754
754
|
settleLegacyUndo,
|
|
@@ -3420,7 +3420,6 @@
|
|
|
3420
3420
|
|
|
3421
3421
|
#codex-overleaf-panel .run-guidance-message {
|
|
3422
3422
|
display: block;
|
|
3423
|
-
border-top: 2px solid var(--tl-accent, #55b9f3);
|
|
3424
3423
|
margin: 7px 0 4px auto;
|
|
3425
3424
|
animation: tl-slide-in 140ms ease-out;
|
|
3426
3425
|
}
|
|
@@ -3432,6 +3431,13 @@
|
|
|
3432
3431
|
overflow-wrap: anywhere;
|
|
3433
3432
|
}
|
|
3434
3433
|
|
|
3434
|
+
#codex-overleaf-panel .run-guidance-label {
|
|
3435
|
+
margin-top: 3px;
|
|
3436
|
+
color: var(--tl-fg-3);
|
|
3437
|
+
font-size: 10px;
|
|
3438
|
+
line-height: 1.4;
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3435
3441
|
/* A right-aligned toolbar: buttons sit together at the end of the row. Each
|
|
3436
3442
|
button used to claim margin-left:auto, so two visible buttons split the free
|
|
3437
3443
|
space and Undo drifted into the middle. */
|
|
@@ -4037,9 +4043,8 @@
|
|
|
4037
4043
|
}
|
|
4038
4044
|
#codex-overleaf-panel .run-presentation-workflow .run-process:not([open]) + .run-activity-list { display: grid; }
|
|
4039
4045
|
#codex-overleaf-panel .run-workflow-list { gap: 0; margin-top: 5px; }
|
|
4040
|
-
#codex-overleaf-panel .run-workflow-list[data-expanded="false"] > .run-work-block
|
|
4041
|
-
#codex-overleaf-panel .run-presentation-workflow .run-guidance-list:empty
|
|
4042
|
-
#codex-overleaf-panel .run-workflow-guidance:empty { display: none; }
|
|
4046
|
+
#codex-overleaf-panel .run-workflow-list[data-expanded="false"] > .run-work-block { display: none; }
|
|
4047
|
+
#codex-overleaf-panel .run-presentation-workflow .run-guidance-list:empty { display: none; }
|
|
4043
4048
|
#codex-overleaf-panel .run-workflow-message {
|
|
4044
4049
|
color: var(--tl-fg-1);
|
|
4045
4050
|
font-size: 13px;
|
|
@@ -4133,7 +4138,6 @@
|
|
|
4133
4138
|
#codex-overleaf-panel .run-workflow-thought-full > :first-child { margin-top: 0; }
|
|
4134
4139
|
#codex-overleaf-panel .run-workflow-thought-full > :last-child { margin-bottom: 0; }
|
|
4135
4140
|
#codex-overleaf-panel .run-workflow-message > :last-child { margin-bottom: 0; }
|
|
4136
|
-
#codex-overleaf-panel .run-workflow-guidance { margin: 15px 0; min-width: 0; }
|
|
4137
4141
|
#codex-overleaf-panel .run-workflow-tool { min-width: 0; max-width: 100%; margin: 3px 0; }
|
|
4138
4142
|
#codex-overleaf-panel .run-workflow-tool-summary {
|
|
4139
4143
|
display: flex;
|
|
@@ -4538,7 +4542,14 @@
|
|
|
4538
4542
|
bottom: calc(100% + 6px);
|
|
4539
4543
|
z-index: 2147483647;
|
|
4540
4544
|
display: grid;
|
|
4545
|
+
grid-auto-rows: max-content;
|
|
4546
|
+
align-content: start;
|
|
4541
4547
|
gap: 2px;
|
|
4548
|
+
box-sizing: border-box;
|
|
4549
|
+
max-height: min(360px, var(--codex-slash-menu-space, 50vh));
|
|
4550
|
+
overflow-y: auto;
|
|
4551
|
+
overflow-x: hidden;
|
|
4552
|
+
overscroll-behavior: contain;
|
|
4542
4553
|
border: 1px solid var(--tl-border-strong);
|
|
4543
4554
|
border-radius: 8px;
|
|
4544
4555
|
background: var(--tl-surface-2);
|
|
@@ -4554,12 +4565,15 @@
|
|
|
4554
4565
|
display: grid;
|
|
4555
4566
|
gap: 2px;
|
|
4556
4567
|
width: 100%;
|
|
4568
|
+
min-width: 0;
|
|
4557
4569
|
border: 0;
|
|
4558
4570
|
border-radius: 6px;
|
|
4559
4571
|
background: transparent;
|
|
4560
4572
|
color: var(--tl-fg-1);
|
|
4561
4573
|
padding: 7px 8px;
|
|
4562
4574
|
text-align: left;
|
|
4575
|
+
white-space: normal;
|
|
4576
|
+
overflow-wrap: anywhere;
|
|
4563
4577
|
}
|
|
4564
4578
|
|
|
4565
4579
|
#codex-overleaf-panel .codex-slash-menu button[data-active="true"],
|
|
@@ -34,7 +34,7 @@ function buildAnthropicRequest({ requestBody = {}, launch = {}, historyMessages
|
|
|
34
34
|
model,
|
|
35
35
|
max_tokens: maxTokens,
|
|
36
36
|
messages,
|
|
37
|
-
stream: requestBody.stream !== false
|
|
37
|
+
stream: requestBody.stream !== false && launch.upstreamResponseMode !== 'buffered'
|
|
38
38
|
};
|
|
39
39
|
if (systemParts.length) {
|
|
40
40
|
body.system = launch.anthropicPromptCaching
|
|
@@ -218,8 +218,10 @@ function rectifyAnthropicRequestForRetry(body, errorText) {
|
|
|
218
218
|
return changed;
|
|
219
219
|
}
|
|
220
220
|
if (/budget_tokens|thinking budget|must be less than max_tokens|at least 1024/i.test(message)) {
|
|
221
|
+
// Keep this existing compatibility retry only when its budget fits the
|
|
222
|
+
// caller's maximum. Otherwise expose the original upstream rejection.
|
|
223
|
+
if (!Number.isFinite(Number(body.max_tokens)) || Number(body.max_tokens) < 64000) return false;
|
|
221
224
|
body.thinking = { type: 'enabled', budget_tokens: 32000 };
|
|
222
|
-
body.max_tokens = Math.max(Number(body.max_tokens) || 0, 64000);
|
|
223
225
|
delete body.output_config;
|
|
224
226
|
return true;
|
|
225
227
|
}
|