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
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
(function initStorageRunActions(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory(require('./selectionContext'), require('./writebackIntent'), require('./writingStyle'));
|
|
3
|
+
module.exports = factory(require('./selectionContext'), require('./writebackIntent'), require('./writingStyle'), require('./directoryCleanupProof'), require('./undoOperations'));
|
|
4
4
|
} else {
|
|
5
|
-
root.CodexOverleafModuleRegistry.define('StorageRunActions', ['SelectionContext', 'WritebackIntent', 'WritingStyle'], factory);
|
|
5
|
+
root.CodexOverleafModuleRegistry.define('StorageRunActions', ['SelectionContext', 'WritebackIntent', 'WritingStyle', 'DirectoryCleanupProof', 'UndoOperations'], factory);
|
|
6
6
|
}
|
|
7
|
-
})(typeof globalThis !== 'undefined' ? globalThis : window, function storageRunActionsFactory(SelectionContext, WritebackIntent, WritingStyle) {
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function storageRunActionsFactory(SelectionContext, WritebackIntent, WritingStyle, DirectoryCleanupProof, UndoOperations) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
// buttons vanished after a reload. Two runs per session keep this bounded.
|
|
15
|
-
var MAX_PERSISTED_ACTION_BYTES_PER_RUN = 2 * 1024 * 1024;
|
|
10
|
+
// Share a bounded budget across the retained history, rather than expiring
|
|
11
|
+
// otherwise valid recovery data after two edits. The session builder also
|
|
12
|
+
// reserves room for display metadata within the shared transport limit.
|
|
13
|
+
var MAX_PERSISTED_ACTION_BYTES_PER_SESSION = 16 * 1024 * 1024;
|
|
16
14
|
|
|
17
15
|
function compactRunsForStorage(runs, options, maxRuns, compactRun) {
|
|
18
16
|
if (typeof compactRun !== 'function') {
|
|
@@ -21,22 +19,100 @@
|
|
|
21
19
|
var selectedRuns = (Array.isArray(runs) ? runs : [])
|
|
22
20
|
.filter(function (run) { return run && typeof run.id === 'string'; })
|
|
23
21
|
.slice(-Math.max(0, Number(maxRuns) || 0));
|
|
24
|
-
var
|
|
22
|
+
var payloads = new Map();
|
|
23
|
+
var remaining = Math.min(MAX_PERSISTED_ACTION_BYTES_PER_SESSION,
|
|
24
|
+
Number.isFinite(options?.maxActionPayloadBytes) ? Math.max(0, options.maxActionPayloadBytes) : Infinity);
|
|
25
|
+
var usedBytes = 0, usedChars = 0;
|
|
26
|
+
var fits = (bytes, chars) => bytes <= remaining && (typeof options?.canRetainActionPayload !== 'function'
|
|
27
|
+
|| options.canRetainActionPayload(usedBytes + bytes, usedChars + chars));
|
|
25
28
|
if (options && options.preserveRunActionPayload === true) {
|
|
26
|
-
for (var index = selectedRuns.length - 1;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
for (var index = selectedRuns.length - 1; index >= 0; index -= 1) {
|
|
30
|
+
var run = selectedRuns[index];
|
|
31
|
+
if (!hasReloadableRunActionPayload(withoutDirectoryFacts(run))) continue;
|
|
32
|
+
var payload = compactRunActionPayload(run, true, { includeCaptures: false, includeDirectoryCleanup: false });
|
|
33
|
+
if (payload.recoveryRetention?.state === 'omitted') { payloads.set(run.id, payload); continue; }
|
|
34
|
+
var serialized = JSON.stringify(payload);
|
|
35
|
+
var bytes = getUtf8ByteLength(serialized);
|
|
36
|
+
if (!fits(bytes, serialized.length)) {
|
|
37
|
+
payloads.set(run.id, { ...emptyActionPayload(), recoveryRetention: omitted('session-budget', bytes) });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
remaining -= bytes;
|
|
41
|
+
usedBytes += bytes; usedChars += serialized.length;
|
|
42
|
+
payloads.set(run.id, payload);
|
|
43
|
+
}
|
|
44
|
+
// Captures are optional. They must not crowd out any retained core data.
|
|
45
|
+
for (var run of selectedRuns.slice().reverse()) {
|
|
46
|
+
var payload = payloads.get(run.id);
|
|
47
|
+
if (!payload || payload.recoveryRetention?.state === 'omitted'
|
|
48
|
+
|| run.undoStatus === 'applied' || ['accepted', 'rejected'].includes(run.trackedChangeStatus)) continue;
|
|
49
|
+
var captures = cloneSerializableArray(run.trackedChangeCaptures);
|
|
50
|
+
var extraText = captures.length ? JSON.stringify({ trackedChangeCaptures: captures }) : '';
|
|
51
|
+
var extraBytes = getUtf8ByteLength(extraText);
|
|
52
|
+
if (extraBytes && fits(extraBytes, extraText.length)) {
|
|
53
|
+
payload.trackedChangeCaptures = captures;
|
|
54
|
+
remaining -= extraBytes;
|
|
55
|
+
usedBytes += extraBytes; usedChars += extraText.length;
|
|
31
56
|
}
|
|
32
57
|
}
|
|
33
58
|
}
|
|
59
|
+
// Passive directory history uses only the space left after all original
|
|
60
|
+
// recovery payloads and optional captures have been selected.
|
|
61
|
+
var directoryRemaining = Number.isFinite(options?.maxOptionalDirectoryBytes)
|
|
62
|
+
? Math.max(0, options.maxOptionalDirectoryBytes) : Infinity;
|
|
34
63
|
return selectedRuns.map(function (run) {
|
|
35
|
-
|
|
64
|
+
var payload = payloads.get(run.id) || compactRunActionPayload(run, false, { includeDirectoryCleanup: false });
|
|
65
|
+
if (options?.deferDirectoryCleanup !== true) payload = appendDirectoryFacts(payload, run,
|
|
66
|
+
options?.preserveRunActionPayload === true, function (bytes, chars) {
|
|
67
|
+
if (bytes > directoryRemaining || !fits(bytes, chars)) return false;
|
|
68
|
+
directoryRemaining -= bytes; remaining -= bytes;
|
|
69
|
+
usedBytes += bytes; usedChars += chars;
|
|
70
|
+
return true;
|
|
71
|
+
}, 'session-budget');
|
|
72
|
+
return compactRun(run, payloads.has(run.id) && !coreWasOmitted(payload), payload);
|
|
36
73
|
});
|
|
37
74
|
}
|
|
38
75
|
|
|
76
|
+
// Keep the complete display history while allocating finite recovery space
|
|
77
|
+
// across the current project. A record plus its previous merge baseline is
|
|
78
|
+
// transported together; a readable batch must also fit the response bound.
|
|
79
|
+
function compactSessionBatchActions(records, options = {}, buildSessionRecord, SharedSessionTransfer) {
|
|
80
|
+
var budget = SharedSessionTransfer.MAX_RESPONSE_BYTES - 64 * 1024;
|
|
81
|
+
if (SharedSessionTransfer.byteLength(JSON.stringify(records)) <= budget) return records;
|
|
82
|
+
var summaries = records.map(record => buildSessionRecord(record, { preserveRunActionPayload: false, deferDirectoryCleanup: true }));
|
|
83
|
+
var remaining = Math.max(0, budget - SharedSessionTransfer.byteLength(JSON.stringify(summaries)));
|
|
84
|
+
var allocated = new Map();
|
|
85
|
+
var ordered = records.slice().sort((a, b) => Number(b.id === options.activeSessionId) - Number(a.id === options.activeSessionId)
|
|
86
|
+
|| (Date.parse(b.updatedAt) || 0) - (Date.parse(a.updatedAt) || 0));
|
|
87
|
+
for (var record of ordered) {
|
|
88
|
+
var summary = summaries.find(item => item.id === record.id);
|
|
89
|
+
var next = buildSessionRecord(record, { preserveRunActionPayload: true, maxActionPayloadBytes: remaining, deferDirectoryCleanup: true });
|
|
90
|
+
remaining -= Math.max(0, SharedSessionTransfer.byteLength(JSON.stringify(next)) - SharedSessionTransfer.byteLength(JSON.stringify(summary)));
|
|
91
|
+
allocated.set(record.id, next);
|
|
92
|
+
}
|
|
93
|
+
// Do not let an active session's optional directory facts evict another
|
|
94
|
+
// session's existing Undo core under the shared response bound.
|
|
95
|
+
for (var record of ordered) {
|
|
96
|
+
var core = allocated.get(record.id);
|
|
97
|
+
var sourceRuns = new Map((record.runs || []).map(run => [run.id, run]));
|
|
98
|
+
var withFacts = { ...core, runs: core.runs.map(run => {
|
|
99
|
+
var source = sourceRuns.get(run.id), next = { ...run };
|
|
100
|
+
if (source?.pendingDirectoryCleanup) next.pendingDirectoryCleanup = source.pendingDirectoryCleanup;
|
|
101
|
+
if (source?.recoveryRetention?.directoryCleanup === true) next.recoveryRetention = {
|
|
102
|
+
...(next.recoveryRetention || { ...source.recoveryRetention, coreRetained: true }), directoryCleanup: true };
|
|
103
|
+
return next;
|
|
104
|
+
}) };
|
|
105
|
+
var enriched = buildSessionRecord(withFacts, { preserveRunActionPayload: true, maxOptionalDirectoryBytes: remaining });
|
|
106
|
+
remaining -= Math.max(0, SharedSessionTransfer.byteLength(JSON.stringify(enriched)) - SharedSessionTransfer.byteLength(JSON.stringify(core)));
|
|
107
|
+
allocated.set(record.id, enriched);
|
|
108
|
+
}
|
|
109
|
+
return records.map(record => allocated.get(record.id));
|
|
110
|
+
}
|
|
111
|
+
|
|
39
112
|
function hasReloadableRunActionPayload(run) {
|
|
113
|
+
if (!run || run.forkSnapshot === true) return false;
|
|
114
|
+
if (runDirectoryCleanup(run)) return true;
|
|
115
|
+
if (run.undoStatus === 'applied' || ['accepted', 'rejected'].includes(run.trackedChangeStatus)) return false;
|
|
40
116
|
var trackedStatus = run && run.trackedChangeStatus;
|
|
41
117
|
var trackedLifecycle = (trackedStatus === 'pending' || trackedStatus === 'needs_review')
|
|
42
118
|
&& Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length > 0
|
|
@@ -53,32 +129,99 @@
|
|
|
53
129
|
&& Array.isArray(run.undoExpectedFiles) && run.undoExpectedFiles.length > 0
|
|
54
130
|
&& Array.isArray(run.appliedOperations) && run.appliedOperations.length > 0;
|
|
55
131
|
var legacyUndo = Array.isArray(run && run.undoOperations) && run.undoOperations.length > 0;
|
|
56
|
-
return trackedLifecycle || reviewingEditorUndo || legacyUndo;
|
|
132
|
+
return trackedLifecycle || reviewingEditorUndo || legacyUndo || UndoOperations.getUndoUnavailableFiles(run).length > 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function runDirectoryCleanup(run) {
|
|
136
|
+
var proof = DirectoryCleanupProof.normalize(run?.pendingDirectoryCleanup);
|
|
137
|
+
return proof && proof.runId === run.id && proof.projectId === run.runProjectId ? proof : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function omitted(reason, bytes = 0) {
|
|
141
|
+
return { state: 'omitted', reason, bytes };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function withoutDirectoryFacts(run) {
|
|
145
|
+
var core = { ...run };
|
|
146
|
+
delete core.pendingDirectoryCleanup;
|
|
147
|
+
if (core.recoveryRetention?.directoryCleanup === true) {
|
|
148
|
+
if (core.recoveryRetention.coreRetained === true) delete core.recoveryRetention;
|
|
149
|
+
else {
|
|
150
|
+
core.recoveryRetention = { ...core.recoveryRetention };
|
|
151
|
+
delete core.recoveryRetention.directoryCleanup;
|
|
152
|
+
delete core.recoveryRetention.coreRetained;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return core;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function coreWasOmitted(payload) {
|
|
159
|
+
return payload.recoveryRetention?.state === 'omitted' && payload.recoveryRetention.coreRetained !== true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function appendDirectoryFacts(payload, run, keep, fits, reason) {
|
|
163
|
+
if (run?.forkSnapshot === true) return payload;
|
|
164
|
+
var directory = runDirectoryCleanup(run), previous = run?.recoveryRetention;
|
|
165
|
+
if (!directory && previous?.directoryCleanup !== true) return payload;
|
|
166
|
+
if (directory && keep) {
|
|
167
|
+
var extended = { ...payload, pendingDirectoryCleanup: directory };
|
|
168
|
+
var before = JSON.stringify(payload), after = JSON.stringify(extended);
|
|
169
|
+
if (fits(getUtf8ByteLength(after) - getUtf8ByteLength(before), after.length - before.length)) return extended;
|
|
170
|
+
}
|
|
171
|
+
// The existing omission marker distinguishes optional history from lost
|
|
172
|
+
// recovery authority. Never imply that a retained Undo core was discarded.
|
|
173
|
+
var retention = coreWasOmitted(payload) ? payload.recoveryRetention
|
|
174
|
+
: omitted(!keep ? 'fallback' : directory ? reason : previous.reason,
|
|
175
|
+
directory ? getUtf8ByteLength(JSON.stringify(directory)) : previous.bytes);
|
|
176
|
+
return { ...payload, recoveryRetention: { ...retention, directoryCleanup: true,
|
|
177
|
+
...(!coreWasOmitted(payload) ? { coreRetained: true } : {}) } };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function compactRunActionPayload(run, keepActionPayload, options = {}) {
|
|
181
|
+
var payload = compactCoreActionPayload(withoutDirectoryFacts(run), keepActionPayload, options);
|
|
182
|
+
if (options.includeDirectoryCleanup === false) return payload;
|
|
183
|
+
var serialized = JSON.stringify(payload);
|
|
184
|
+
return appendDirectoryFacts(payload, run, keepActionPayload,
|
|
185
|
+
bytes => getUtf8ByteLength(serialized) + bytes <= MAX_PERSISTED_ACTION_BYTES_PER_SESSION, 'run-budget');
|
|
57
186
|
}
|
|
58
187
|
|
|
59
|
-
function
|
|
60
|
-
var empty = emptyActionPayload();
|
|
188
|
+
function compactCoreActionPayload(run, keepActionPayload, options = {}) {
|
|
189
|
+
var empty = { ...emptyActionPayload(), appliedOperations: UndoOperations.compactUnavailableUndoOperations(run) };
|
|
61
190
|
if (!keepActionPayload || !hasReloadableRunActionPayload(run)) {
|
|
191
|
+
if (hasReloadableRunActionPayload(run)) empty.recoveryRetention = omitted('fallback');
|
|
192
|
+
else if (run?.recoveryRetention?.state === 'omitted' && !run.forkSnapshot
|
|
193
|
+
&& run.undoStatus !== 'applied' && !['accepted', 'rejected'].includes(run.trackedChangeStatus)) {
|
|
194
|
+
empty.recoveryRetention = omitted(
|
|
195
|
+
['run-budget', 'session-budget', 'fallback', 'invalid'].includes(run.recoveryRetention.reason)
|
|
196
|
+
? run.recoveryRetention.reason : 'invalid', Math.max(0, Number(run.recoveryRetention.bytes) || 0));
|
|
197
|
+
}
|
|
62
198
|
return empty;
|
|
63
199
|
}
|
|
64
|
-
var
|
|
200
|
+
var terminal = run.undoStatus === 'applied' || ['accepted', 'rejected'].includes(run.trackedChangeStatus);
|
|
201
|
+
var payload = terminal ? emptyActionPayload() : {
|
|
65
202
|
appliedOperations: cloneSerializableArray(run.appliedOperations),
|
|
66
203
|
undoOperations: cloneSerializableArray(run.undoOperations),
|
|
67
204
|
undoBaseFiles: cloneSerializableArray(run.undoBaseFiles),
|
|
68
205
|
undoTrackedChanges: cloneSerializableArray(run.undoTrackedChanges),
|
|
69
206
|
undoExpectedFiles: cloneSerializableArray(run.undoExpectedFiles)
|
|
70
207
|
};
|
|
208
|
+
if (!terminal && Object.keys(payload).some(key => run[key]?.length && !payload[key].length)) {
|
|
209
|
+
return { ...empty, recoveryRetention: omitted('invalid') };
|
|
210
|
+
}
|
|
71
211
|
var serialized;
|
|
72
212
|
try {
|
|
73
213
|
serialized = JSON.stringify(payload);
|
|
74
214
|
} catch (_error) {
|
|
75
|
-
return empty;
|
|
215
|
+
return { ...empty, recoveryRetention: omitted('invalid') };
|
|
76
216
|
}
|
|
77
|
-
|
|
217
|
+
var bytes = getUtf8ByteLength(serialized);
|
|
218
|
+
if (bytes > MAX_PERSISTED_ACTION_BYTES_PER_SESSION) return { ...empty,
|
|
219
|
+
recoveryRetention: omitted('run-budget', bytes) };
|
|
220
|
+
if (options.includeCaptures === false || terminal) return payload;
|
|
78
221
|
const captures = cloneSerializableArray(run.trackedChangeCaptures);
|
|
79
222
|
if (captures.length) {
|
|
80
223
|
const extended = { ...payload, trackedChangeCaptures: captures };
|
|
81
|
-
if (getUtf8ByteLength(JSON.stringify(extended)) <=
|
|
224
|
+
if (getUtf8ByteLength(JSON.stringify(extended)) <= MAX_PERSISTED_ACTION_BYTES_PER_SESSION) return extended;
|
|
82
225
|
}
|
|
83
226
|
return payload; // Optional capture evidence must never evict a mature Undo payload.
|
|
84
227
|
}
|
|
@@ -165,21 +308,76 @@
|
|
|
165
308
|
return out;
|
|
166
309
|
}
|
|
167
310
|
|
|
168
|
-
|
|
169
|
-
|
|
311
|
+
const REVIEW_FIELDS = ['trackedChangeStatus', 'undoStatus', 'undoOwnerProtocol', 'undoTrackedChanges', 'undoExpectedFiles',
|
|
312
|
+
'undoOperations', 'undoBaseFiles', 'appliedOperations', 'trackedChangeCaptures', 'recoveryRetention',
|
|
313
|
+
'interruptedDraft', 'retryWriteback', 'saveCheck'];
|
|
314
|
+
const REVIEW_FACT_FIELDS = ['documentEffect', 'fileSettlements', 'failures', 'recoveryAvailability', 'recoveryDisposition'];
|
|
315
|
+
const terminalReview = run => ['accepted', 'rejected'].includes(run?.trackedChangeStatus) || run?.undoStatus === 'applied';
|
|
316
|
+
const factsOf = run => run?.settlement || run?.settlementFacts || {};
|
|
317
|
+
|
|
318
|
+
function copyRunReviewState(target, source) {
|
|
319
|
+
const merged = { ...target };
|
|
320
|
+
const copyFields = (into, from, fields) => {
|
|
321
|
+
for (const field of fields) {
|
|
322
|
+
if (Object.hasOwn(from, field)) into[field] = JSON.parse(JSON.stringify(from[field]));
|
|
323
|
+
else delete into[field];
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
copyFields(merged, source, REVIEW_FIELDS);
|
|
327
|
+
const sourceFacts = factsOf(source), targetFacts = factsOf(target);
|
|
328
|
+
const facts = { ...targetFacts };
|
|
329
|
+
copyFields(facts, sourceFacts, REVIEW_FACT_FIELDS);
|
|
330
|
+
const sourceEvidence = sourceFacts.evidence || {};
|
|
331
|
+
const evidence = { ...(targetFacts.evidence || {}) };
|
|
332
|
+
copyFields(evidence, sourceEvidence, [...new Set([...Object.keys(evidence), ...Object.keys(sourceEvidence)])]
|
|
333
|
+
.filter(key => !['mirrored', 'compiled'].includes(key)));
|
|
334
|
+
if (Object.keys(evidence).length) facts.evidence = evidence; else delete facts.evidence;
|
|
335
|
+
delete merged.settlementFacts;
|
|
336
|
+
if (Object.keys(facts).length) merged.settlement = facts; else delete merged.settlement;
|
|
337
|
+
return merged;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function reviewStateSnapshot(run) {
|
|
341
|
+
const facts = factsOf(run);
|
|
342
|
+
return JSON.stringify([REVIEW_FIELDS.map(key => run?.[key]), REVIEW_FACT_FIELDS.map(key => facts[key]),
|
|
343
|
+
Object.entries(facts.evidence || {}).filter(([key]) => !['mirrored', 'compiled'].includes(key))
|
|
344
|
+
.sort(([a], [b]) => a.localeCompare(b))]);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Shared submissions retain the caller's envelope and private baseline. The
|
|
348
|
+
// legacy site-local path explicitly keeps its historical timestamp merge.
|
|
349
|
+
function mergeSessionReviewState(incoming, existing, reviewRunIds, options = {}) {
|
|
170
350
|
if (!existing || incoming.id !== existing.id || incoming.projectId !== existing.projectId
|
|
171
351
|
|| !incoming.accountScopeId || incoming.accountScopeId !== existing.accountScopeId) return incoming;
|
|
172
|
-
var terminal =
|
|
352
|
+
var terminal = terminalReview;
|
|
173
353
|
var incomingRuns = new Map((incoming.runs || []).map(run => [run.id, run]));
|
|
174
354
|
var existingRuns = new Map((existing.runs || []).map(run => [run.id, run]));
|
|
175
355
|
var requestedIds = new Set(reviewRunIds || []);
|
|
176
|
-
var explicitReview = Array.from(requestedIds).some(id =>
|
|
177
|
-
|
|
356
|
+
var explicitReview = Array.from(requestedIds).some(id => {
|
|
357
|
+
var run = incomingRuns.get(id);
|
|
358
|
+
return ['accepted', 'rejected', 'needs_review'].includes(run?.trackedChangeStatus)
|
|
359
|
+
|| ['applied', 'partial'].includes(run?.undoStatus);
|
|
360
|
+
});
|
|
361
|
+
if (options.shared !== false) {
|
|
362
|
+
const runs = (incoming.runs || []).map(run => {
|
|
363
|
+
const previous = existingRuns.get(run.id);
|
|
364
|
+
const source = terminal(previous) ? previous : null;
|
|
365
|
+
if (!source || (source.runProjectId && source.runProjectId !== incoming.projectId)) return run;
|
|
366
|
+
// The same decision can still gain save/recovery evidence. Let the
|
|
367
|
+
// three-way merge retain those edits and reject genuine collisions.
|
|
368
|
+
if (run.trackedChangeStatus === source.trackedChangeStatus && run.undoStatus === source.undoStatus) return run;
|
|
369
|
+
// An absent local settlement has no edits to its metadata or auxiliary
|
|
370
|
+
// evidence. Retain the stored container as well as the terminal fields.
|
|
371
|
+
const target = !run.settlement && !run.settlementFacts ? { ...run, settlement: factsOf(source) } : run;
|
|
372
|
+
return copyRunReviewState(target, source);
|
|
373
|
+
});
|
|
374
|
+
return { ...incoming, runs };
|
|
375
|
+
}
|
|
178
376
|
var newer = (Date.parse(incoming.updatedAt) || 0) >= (Date.parse(existing.updatedAt) || 0);
|
|
179
377
|
if (!newer && !explicitReview) return incoming;
|
|
180
378
|
var base = newer ? incoming : existing;
|
|
181
|
-
var fields = ['trackedChangeStatus', 'undoStatus', 'undoTrackedChanges', 'undoExpectedFiles',
|
|
182
|
-
'undoOperations', 'undoBaseFiles', 'appliedOperations', 'trackedChangeCaptures', 'settlement', 'settlementFacts'];
|
|
379
|
+
var fields = ['trackedChangeStatus', 'undoStatus', 'undoOwnerProtocol', 'undoTrackedChanges', 'undoExpectedFiles',
|
|
380
|
+
'undoOperations', 'undoBaseFiles', 'appliedOperations', 'trackedChangeCaptures', 'recoveryRetention', 'settlement', 'settlementFacts'];
|
|
183
381
|
var changed = false;
|
|
184
382
|
var runs = (base.runs || []).map(function (run) {
|
|
185
383
|
var previous = existingRuns.get(run.id), candidate = incomingRuns.get(run.id);
|
|
@@ -218,9 +416,48 @@
|
|
|
218
416
|
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
219
417
|
}
|
|
220
418
|
|
|
419
|
+
// A successful durable write can omit an oversized checkpoint while the
|
|
420
|
+
// current tab still has it. Warn only the view and exact action revision
|
|
421
|
+
// that was saved; never mutate or remove its in-memory recovery material.
|
|
422
|
+
function projectRetentionUpdates({ liveState, capturedState, written, capturedScope, currentScope } = {}) {
|
|
423
|
+
if (!capturedScope?.accountScopeId || !capturedScope.projectId
|
|
424
|
+
|| !Number.isSafeInteger(capturedScope.generation)
|
|
425
|
+
|| ['accountScopeId', 'projectId', 'generation'].some(key => capturedScope[key] !== currentScope?.[key])) return [];
|
|
426
|
+
var fields = ['appliedOperations', 'undoOperations', 'undoBaseFiles', 'undoTrackedChanges',
|
|
427
|
+
'undoExpectedFiles', 'undoStatus', 'trackedChangeStatus', 'pendingDirectoryCleanup'];
|
|
428
|
+
var fingerprint = run => JSON.stringify(fields.map(field => run[field]));
|
|
429
|
+
var updates = [];
|
|
430
|
+
for (var record of written || []) {
|
|
431
|
+
if (record.accountScopeId !== capturedScope.accountScopeId || record.projectId !== capturedScope.projectId) continue;
|
|
432
|
+
var live = liveState?.sessions?.find(session => session.id === record.id);
|
|
433
|
+
var captured = capturedState?.sessions?.find(session => session.id === record.id);
|
|
434
|
+
for (var storedRun of record.runs || []) {
|
|
435
|
+
var run = live?.runs?.find(run => run.id === storedRun.id);
|
|
436
|
+
var original = captured?.runs?.find(run => run.id === storedRun.id);
|
|
437
|
+
if (!run || !original || run.runProjectId !== capturedScope.projectId
|
|
438
|
+
|| original.runProjectId !== capturedScope.projectId || !hasReloadableRunActionPayload(run)) continue;
|
|
439
|
+
try {
|
|
440
|
+
if (fingerprint(run) !== fingerprint(original)) continue;
|
|
441
|
+
if (storedRun.recoveryRetention?.state === 'omitted') updates.push({ runId: run.id, retention: { ...storedRun.recoveryRetention } });
|
|
442
|
+
else if (fingerprint(storedRun) === fingerprint(original)) updates.push({ runId: run.id, retention: null });
|
|
443
|
+
} catch (_error) { /* Invalid data cannot establish a revision. */ }
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return updates;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function projectRetentionWarnings(input) {
|
|
450
|
+
return projectRetentionUpdates(input).filter(update => update.retention).map(update => update.runId);
|
|
451
|
+
}
|
|
452
|
+
|
|
221
453
|
return {
|
|
454
|
+
projectRetentionUpdates: projectRetentionUpdates,
|
|
455
|
+
projectRetentionWarnings: projectRetentionWarnings,
|
|
456
|
+
compactSessionBatchActions: compactSessionBatchActions,
|
|
222
457
|
compactStructuredEventValue: compactStructuredEventValue,
|
|
223
458
|
mergeSessionReviewState: mergeSessionReviewState,
|
|
459
|
+
copyRunReviewState: copyRunReviewState,
|
|
460
|
+
reviewStateSnapshot: reviewStateSnapshot,
|
|
224
461
|
compactRunsForStorage: compactRunsForStorage,
|
|
225
462
|
compactRunActionPayload: compactRunActionPayload,
|
|
226
463
|
compactProviderSnapshot: compactProviderSnapshot,
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
if (typeof value === 'string' && value) agent[field] = clean(value, sanitize, field === 'task' ? 4096 : 160);
|
|
133
133
|
}
|
|
134
134
|
agent.clipped ||= detail.historyClipped === true;
|
|
135
|
-
agent.historyUnavailable
|
|
135
|
+
if (typeof detail.historyUnavailable === 'boolean') agent.historyUnavailable = detail.historyUnavailable;
|
|
136
136
|
let next = type.endsWith('.queued') ? 'pending' : type.endsWith('.started') ? 'running'
|
|
137
137
|
: type.endsWith('.completed') ? 'completed' : type.endsWith('.rejected') ? 'failed'
|
|
138
138
|
: type.endsWith('.failed') ? (detail.status === 'cancelled' ? 'cancelled' : 'failed') : detail.status;
|