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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
const MAX_TEXT_CHARS = 12000;
|
|
12
12
|
const MAX_QUEUE_BYTES = 128 * 1024;
|
|
13
13
|
const MAX_PERSISTED_QUEUE_BYTES = 512 * 1024;
|
|
14
|
+
const MAX_CUSTOM_INSTRUCTIONS_CHARS = 12000;
|
|
14
15
|
const ACTIVE_STATUSES = new Set(['claimed', 'executing', 'steering']);
|
|
15
16
|
const VALID_STATUSES = new Set(['queued', 'paused', ...ACTIVE_STATUSES]);
|
|
16
17
|
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
claimToken: status === 'claimed' || status === 'executing' ? String(raw.claimToken || '') : '',
|
|
42
43
|
pauseReason: status === 'paused' ? String(raw.pauseReason || '') : '',
|
|
43
44
|
executionSnapshot: RunExecutionSnapshot.cloneSnapshot(executionSnapshot),
|
|
44
|
-
payload:
|
|
45
|
+
payload: buildPayload(executionSnapshot, raw.payload?.submissionContext)
|
|
45
46
|
});
|
|
46
47
|
if (normalized.length >= MAX_ITEMS) {
|
|
47
48
|
break;
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
claimToken: '',
|
|
80
81
|
pauseReason: input.status === 'paused' ? String(input.pauseReason || '') : '',
|
|
81
82
|
executionSnapshot: RunExecutionSnapshot.cloneSnapshot(executionSnapshot),
|
|
82
|
-
payload:
|
|
83
|
+
payload: buildPayload(executionSnapshot, input.payload?.submissionContext)
|
|
83
84
|
};
|
|
84
85
|
const next = [...queue, item];
|
|
85
86
|
if (estimateLegacyBytes(next) > MAX_QUEUE_BYTES || estimateBytes(next) > MAX_PERSISTED_QUEUE_BYTES) {
|
|
@@ -137,7 +138,7 @@
|
|
|
137
138
|
item = {
|
|
138
139
|
...item,
|
|
139
140
|
executionSnapshot: RunExecutionSnapshot.cloneSnapshot(snapshot),
|
|
140
|
-
payload:
|
|
141
|
+
payload: buildPayload(snapshot, item.payload?.submissionContext)
|
|
141
142
|
};
|
|
142
143
|
} catch (error) {
|
|
143
144
|
return {
|
|
@@ -199,6 +200,46 @@
|
|
|
199
200
|
);
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
// Queue inputs persist only these submitted extras. Attachments stay unsupported,
|
|
204
|
+
// and older items must not acquire a later draft's one-turn context on promotion.
|
|
205
|
+
function normalizeSubmissionContext(value = {}, helpers = {}) {
|
|
206
|
+
const input = value && typeof value === 'object' ? value : {};
|
|
207
|
+
const normalizeText = (value, maxChars) => {
|
|
208
|
+
const text = typeof value === 'string' ? value : '';
|
|
209
|
+
return String(helpers.normalizeDisplay ? helpers.normalizeDisplay(text, maxChars) : text).slice(0, maxChars);
|
|
210
|
+
};
|
|
211
|
+
const safeId = value => typeof value === 'string'
|
|
212
|
+
&& /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(value) && !value.includes('..')
|
|
213
|
+
&& !['__proto__', 'prototype', 'constructor'].includes(value);
|
|
214
|
+
const rawSkill = input.skillInvocation;
|
|
215
|
+
const installer = rawSkill?.id === 'skill-installer' && (rawSkill.scope == null || rawSkill.scope === 'builtin');
|
|
216
|
+
const skillInvocation = safeId(rawSkill?.id)
|
|
217
|
+
&& (installer || ['codex-overleaf', 'codex-local'].includes(rawSkill.scope))
|
|
218
|
+
? { id: rawSkill.id, title: normalizeText(rawSkill.title || rawSkill.id, 80),
|
|
219
|
+
...(installer ? {} : { scope: rawSkill.scope }) }
|
|
220
|
+
: null;
|
|
221
|
+
return {
|
|
222
|
+
customInstructions: normalizeText(input.customInstructions, MAX_CUSTOM_INSTRUCTIONS_CHARS),
|
|
223
|
+
skillLoadingSettings: {
|
|
224
|
+
loadCodexLocalSkills: input.skillLoadingSettings?.loadCodexLocalSkills === true,
|
|
225
|
+
loadCodexOverleafSkills: input.skillLoadingSettings?.loadCodexOverleafSkills === true
|
|
226
|
+
},
|
|
227
|
+
skillInvocation,
|
|
228
|
+
...(Array.isArray(input.enabledCodexLocalSkillIds) ? {
|
|
229
|
+
enabledCodexLocalSkillIds: [...new Set(input.enabledCodexLocalSkillIds.filter(safeId))]
|
|
230
|
+
} : {}),
|
|
231
|
+
enabledCodexOverleafSkillIds: [...new Set((Array.isArray(input.enabledCodexOverleafSkillIds)
|
|
232
|
+
? input.enabledCodexOverleafSkillIds : []).filter(safeId))]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function buildPayload(snapshot, submissionContext, helpers) {
|
|
237
|
+
const payload = RunExecutionSnapshot.toQueuePayload(snapshot);
|
|
238
|
+
// Keep legacy absence compact; safe defaults are applied only at execution.
|
|
239
|
+
if (submissionContext == null) return payload;
|
|
240
|
+
return { ...payload, submissionContext: normalizeSubmissionContext(submissionContext, helpers) };
|
|
241
|
+
}
|
|
242
|
+
|
|
202
243
|
function normalizeTimestamp(value) {
|
|
203
244
|
return typeof value === 'string' && value ? value : new Date().toISOString();
|
|
204
245
|
}
|
|
@@ -237,7 +278,8 @@
|
|
|
237
278
|
speedTier: item.payload.speedTier,
|
|
238
279
|
autoRecompile: item.payload.autoRecompile,
|
|
239
280
|
requireReviewing: item.payload.requireReviewing,
|
|
240
|
-
focusFiles: item.payload.focusFiles
|
|
281
|
+
focusFiles: item.payload.focusFiles,
|
|
282
|
+
submissionContext: item.payload.submissionContext
|
|
241
283
|
}
|
|
242
284
|
: {}
|
|
243
285
|
};
|
|
@@ -269,7 +311,7 @@
|
|
|
269
311
|
claimToken: normalizeField(item?.claimToken, 160),
|
|
270
312
|
pauseReason: normalizeField(item?.pauseReason, 160),
|
|
271
313
|
executionSnapshot: compactSnapshot,
|
|
272
|
-
payload:
|
|
314
|
+
payload: buildPayload(compactSnapshot, payload.submissionContext, { normalizeDisplay })
|
|
273
315
|
};
|
|
274
316
|
})
|
|
275
317
|
.filter(item => item.id && item.text);
|
|
@@ -292,6 +334,7 @@
|
|
|
292
334
|
markExecuting,
|
|
293
335
|
markSteering,
|
|
294
336
|
normalizeQueue,
|
|
337
|
+
normalizeSubmissionContext,
|
|
295
338
|
pauseAll,
|
|
296
339
|
remove,
|
|
297
340
|
resumeAll,
|
|
@@ -6,20 +6,29 @@
|
|
|
6
6
|
const MAX_TEXT = 20000;
|
|
7
7
|
function normalize(value) {
|
|
8
8
|
if (!value || typeof value !== 'object') return null;
|
|
9
|
-
const path = typeof value.path === 'string' ? value.path
|
|
10
|
-
if (!path || path.
|
|
9
|
+
const path = typeof value.path === 'string' ? value.path : '';
|
|
10
|
+
if (!path || path.length > 2048 || path.trim() !== path || path.includes('\\')
|
|
11
|
+
|| /[\u0000-\u001f\u007f]/.test(path) || path.startsWith('/') || /^[A-Za-z]:/.test(path)
|
|
11
12
|
|| path.split('/').some(part => !part || part === '.' || part === '..')) return null;
|
|
12
13
|
if (typeof value.projectId !== 'string' || !value.projectId
|
|
13
14
|
|| typeof value.text !== 'string' || !value.text.length || value.text.length > MAX_TEXT
|
|
15
|
+
|| /[\uD800-\uDFFF]/u.test(value.text)
|
|
14
16
|
|| !Number.isSafeInteger(value.from) || !Number.isSafeInteger(value.to)
|
|
15
17
|
|| value.from < 0 || value.to <= value.from || value.to - value.from !== value.text.length
|
|
16
18
|
|| !/^[a-f0-9]{64}$/i.test(value.documentHash || '')) return null;
|
|
19
|
+
const proof = value.rebaseEvidence;
|
|
20
|
+
const rebaseEvidence = proof?.v === 1 && Number.isSafeInteger(proof.documentLength)
|
|
21
|
+
&& proof.documentLength >= value.to && /^[a-f0-9]{64}$/i.test(proof.prefixHash || '')
|
|
22
|
+
&& /^[a-f0-9]{64}$/i.test(proof.suffixHash || '')
|
|
23
|
+
? Object.freeze({ v: 1, documentLength: proof.documentLength,
|
|
24
|
+
prefixHash: proof.prefixHash.toLowerCase(), suffixHash: proof.suffixHash.toLowerCase() }) : null;
|
|
17
25
|
return Object.freeze({
|
|
18
|
-
projectId: value.projectId.slice(0, 160), path
|
|
26
|
+
projectId: value.projectId.slice(0, 160), path,
|
|
19
27
|
from: value.from, to: value.to, text: value.text,
|
|
20
28
|
lineStart: Number.isSafeInteger(value.lineStart) && value.lineStart > 0 ? value.lineStart : 1,
|
|
21
29
|
lineEnd: Number.isSafeInteger(value.lineEnd) && value.lineEnd > 0 ? value.lineEnd : 1,
|
|
22
30
|
documentHash: value.documentHash.toLowerCase(),
|
|
31
|
+
...(rebaseEvidence ? { rebaseEvidence } : {}),
|
|
23
32
|
mode: value.mode === 'edit' ? 'edit' : 'reference',
|
|
24
33
|
capturedAt: typeof value.capturedAt === 'string' ? value.capturedAt.slice(0, 64) : ''
|
|
25
34
|
});
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
require('./sessionTitle'),
|
|
11
11
|
require('./runActivityModel'),
|
|
12
12
|
require('./subagentActivityModel'),
|
|
13
|
-
require('./writebackIntent')
|
|
13
|
+
require('./writebackIntent'),
|
|
14
|
+
require('./directoryCleanupProof'),
|
|
15
|
+
require('./undoOperations')
|
|
14
16
|
);
|
|
15
17
|
} else {
|
|
16
18
|
root.CodexOverleafModuleRegistry.define(
|
|
17
19
|
'SessionState',
|
|
18
|
-
['I18n', 'SettlementFacts', 'RunInputQueue', 'SelectionContext', 'LineReferences', 'PathRedaction', 'SessionTitle', 'RunActivityModel', 'SubagentActivityModel', 'WritebackIntent'],
|
|
20
|
+
['I18n', 'SettlementFacts', 'RunInputQueue', 'SelectionContext', 'LineReferences', 'PathRedaction', 'SessionTitle', 'RunActivityModel', 'SubagentActivityModel', 'WritebackIntent', 'DirectoryCleanupProof', 'UndoOperations'],
|
|
19
21
|
factory
|
|
20
22
|
);
|
|
21
23
|
}
|
|
@@ -29,7 +31,9 @@
|
|
|
29
31
|
SessionTitle,
|
|
30
32
|
RunActivityModel,
|
|
31
33
|
SubagentActivityModel,
|
|
32
|
-
WritebackIntent
|
|
34
|
+
WritebackIntent,
|
|
35
|
+
DirectoryCleanupProof,
|
|
36
|
+
UndoOperations
|
|
33
37
|
) {
|
|
34
38
|
'use strict';
|
|
35
39
|
|
|
@@ -46,6 +50,7 @@
|
|
|
46
50
|
loadCodexLocalSkills: true,
|
|
47
51
|
loadCodexOverleafSkills: true,
|
|
48
52
|
codexOverleafSkillEnabled: {},
|
|
53
|
+
codexLocalSkillEnabled: {},
|
|
49
54
|
theme: 'dark',
|
|
50
55
|
panelWidth: 380,
|
|
51
56
|
task: '',
|
|
@@ -120,7 +125,6 @@
|
|
|
120
125
|
statusTextChars: 400,
|
|
121
126
|
attachmentPreviewChars: 160 * 1024
|
|
122
127
|
};
|
|
123
|
-
const REDACTED_SECRET = '[REDACTED_SECRET]';
|
|
124
128
|
const SECRET_REDACTION_PATTERNS = [
|
|
125
129
|
/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,
|
|
126
130
|
/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi,
|
|
@@ -153,6 +157,7 @@
|
|
|
153
157
|
state.loadCodexLocalSkills = state.loadCodexLocalSkills !== false;
|
|
154
158
|
state.loadCodexOverleafSkills = state.loadCodexOverleafSkills !== false;
|
|
155
159
|
state.codexOverleafSkillEnabled = normalizeCodexOverleafSkillEnabled(state.codexOverleafSkillEnabled);
|
|
160
|
+
state.codexLocalSkillEnabled = normalizeCodexLocalSkillEnabled(state.codexLocalSkillEnabled);
|
|
156
161
|
state.theme = ['dark', 'light', 'auto'].includes(state.theme) ? state.theme : 'dark';
|
|
157
162
|
state.panelWidth = normalizePanelWidth(state.panelWidth);
|
|
158
163
|
state.task = typeof state.task === 'string' ? state.task : '';
|
|
@@ -213,6 +218,8 @@
|
|
|
213
218
|
const history = normalizeHistoryEntries(session.history);
|
|
214
219
|
const normalizedRuns = normalizeRuns(session.runs, options);
|
|
215
220
|
const runs = normalizedRuns.length ? normalizedRuns : recoverRunsFromHistory(session, history);
|
|
221
|
+
for (const run of runs) pruneRunRecoveryScope(run, session);
|
|
222
|
+
|
|
216
223
|
const rawTitle = typeof session.title === 'string' ? session.title.trim() : '';
|
|
217
224
|
const derivedTitle = deriveSessionTitle(runs, session.task);
|
|
218
225
|
const titleSource = normalizeTitleSource(session.titleSource, rawTitle, derivedTitle);
|
|
@@ -642,6 +649,22 @@
|
|
|
642
649
|
finishedAt: Number.isFinite(Date.parse(run.finishedAt)) ? run.finishedAt : event.timestamp };
|
|
643
650
|
}
|
|
644
651
|
|
|
652
|
+
function pruneRunRecoveryScope(run, session = {}) {
|
|
653
|
+
const wrongAccount = proof => Object.prototype.hasOwnProperty.call(session, 'accountScopeId')
|
|
654
|
+
&& proof.accountScopeId !== session.accountScopeId;
|
|
655
|
+
const wrongProject = value => Boolean(session.projectId && value !== session.projectId);
|
|
656
|
+
if (run.pendingDirectoryCleanup && (run.pendingDirectoryCleanup.sessionId !== session.id
|
|
657
|
+
|| wrongAccount(run.pendingDirectoryCleanup) || wrongProject(run.pendingDirectoryCleanup.projectId))) delete run.pendingDirectoryCleanup;
|
|
658
|
+
applyTrackedChangeStatus(run, run.trackedChangeStatus);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function normalizeRecoveryRetention(value) {
|
|
662
|
+
if (value?.state !== 'omitted') return undefined;
|
|
663
|
+
return { state: 'omitted', reason: ['run-budget', 'session-budget', 'fallback', 'invalid'].includes(value.reason)
|
|
664
|
+
? value.reason : 'invalid', bytes: Number.isSafeInteger(value.bytes) && value.bytes >= 0 ? value.bytes : 0,
|
|
665
|
+
...(value.directoryCleanup === true ? { directoryCleanup: true, ...(value.coreRetained === true ? { coreRetained: true } : {}) } : {}) };
|
|
666
|
+
}
|
|
667
|
+
|
|
645
668
|
function normalizeRun(run, options = {}) {
|
|
646
669
|
if (options.restoreRunningRuns === true || options.recoverSettledRuns === true) run = recoverSettledRunningRun(run);
|
|
647
670
|
run = recoverRecordedRunFailure(run, options.locale);
|
|
@@ -687,7 +710,10 @@
|
|
|
687
710
|
undoBaseFiles: normalizeRunFiles(run.undoBaseFiles),
|
|
688
711
|
undoTrackedChanges: normalizeRunTrackedChanges(run.undoTrackedChanges),
|
|
689
712
|
undoExpectedFiles: normalizeRunFiles(run.undoExpectedFiles),
|
|
713
|
+
...(normalizeRecoveryRetention(run.recoveryRetention) && !run.forkSnapshot
|
|
714
|
+
? { recoveryRetention: normalizeRecoveryRetention(run.recoveryRetention) } : {}),
|
|
690
715
|
undoStatus: sanitizeAssistantVisibleText(run.undoStatus),
|
|
716
|
+
...(run.undoOwnerProtocol === 1 ? { undoOwnerProtocol: 1 } : {}),
|
|
691
717
|
nativeRequestId: sanitizeAssistantVisibleText(run.nativeRequestId),
|
|
692
718
|
codexThreadId: sanitizeAssistantVisibleText(run.codexThreadId), codexTurnId: sanitizeAssistantVisibleText(run.codexTurnId),
|
|
693
719
|
forkSnapshot: run.forkSnapshot === true,
|
|
@@ -712,6 +738,9 @@
|
|
|
712
738
|
if (Array.isArray(run.trackedChangeCaptures) && run.trackedChangeCaptures.length && !run.forkSnapshot) {
|
|
713
739
|
normalized.trackedChangeCaptures = sanitizeAssistantVisibleValue(run.trackedChangeCaptures);
|
|
714
740
|
}
|
|
741
|
+
const directories = DirectoryCleanupProof.normalize(run.pendingDirectoryCleanup);
|
|
742
|
+
if (directories && directories.runId === normalized.id && directories.projectId === normalized.runProjectId
|
|
743
|
+
&& !run.forkSnapshot) normalized.pendingDirectoryCleanup = directories;
|
|
715
744
|
applyTrackedChangeStatus(normalized, run.trackedChangeStatus);
|
|
716
745
|
Object.assign(normalized, pickWritebackRecovery(run));
|
|
717
746
|
|
|
@@ -724,6 +753,7 @@
|
|
|
724
753
|
// output yields the same result.
|
|
725
754
|
function applyTrackedChangeStatus(run, rawStatus) {
|
|
726
755
|
const hasRefs = run.undoTrackedChanges.length > 0;
|
|
756
|
+
const hasFileUndo = (run.undoOperations || []).some(UndoOperations.isFileUndoOperation);
|
|
727
757
|
const hasRawStatus = rawStatus !== undefined && rawStatus !== null && rawStatus !== '';
|
|
728
758
|
|
|
729
759
|
// Step 1 — value recovery. Keep a stable value; recover any other present
|
|
@@ -740,12 +770,11 @@
|
|
|
740
770
|
}
|
|
741
771
|
|
|
742
772
|
// Step 1 — reload reconciliation. A non-terminal status (`pending`) with no
|
|
743
|
-
// refs
|
|
744
|
-
//
|
|
745
|
-
// the run returns to the legacy-undo world. A terminal status with no refs
|
|
773
|
+
// refs can result from an old record or a storage-budget omission. Drop
|
|
774
|
+
// pending and let actual legacy Undo material decide the action. A terminal status with no refs
|
|
746
775
|
// is kept — step 3 already empties terminal payloads and the label stays
|
|
747
776
|
// meaningful.
|
|
748
|
-
if (!hasRefs && status === 'pending') {
|
|
777
|
+
if (!hasRefs && !hasFileUndo && status === 'pending') {
|
|
749
778
|
status = undefined;
|
|
750
779
|
}
|
|
751
780
|
|
|
@@ -762,7 +791,7 @@
|
|
|
762
791
|
|
|
763
792
|
if (status !== undefined) {
|
|
764
793
|
run.trackedChangeStatus = status;
|
|
765
|
-
}
|
|
794
|
+
} else delete run.trackedChangeStatus;
|
|
766
795
|
}
|
|
767
796
|
|
|
768
797
|
// Welcome-panel + write-guard: the run lifecycle now
|
|
@@ -1034,6 +1063,17 @@
|
|
|
1034
1063
|
return result;
|
|
1035
1064
|
}
|
|
1036
1065
|
|
|
1066
|
+
function normalizeCodexLocalSkillEnabled(value) {
|
|
1067
|
+
const result = {};
|
|
1068
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return result;
|
|
1069
|
+
for (const [id, enabled] of Object.entries(value)) {
|
|
1070
|
+
if (/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(id) && !id.includes('..')
|
|
1071
|
+
&& !['__proto__', 'prototype', 'constructor'].includes(id) && typeof enabled === 'boolean') result[id] = enabled;
|
|
1072
|
+
}
|
|
1073
|
+
if (Object.keys(result).length > 200) throw new Error('Too many skill preferences.');
|
|
1074
|
+
return result;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1037
1077
|
function normalizeProjectPrefKey(value) {
|
|
1038
1078
|
const key = typeof value === 'string' ? value.trim() : '';
|
|
1039
1079
|
if (!key) {
|
|
@@ -1105,6 +1145,7 @@
|
|
|
1105
1145
|
loadCodexLocalSkills: source.loadCodexLocalSkills !== false,
|
|
1106
1146
|
loadCodexOverleafSkills: source.loadCodexOverleafSkills !== false,
|
|
1107
1147
|
codexOverleafSkillEnabled: normalizeCodexOverleafSkillEnabled(source.codexOverleafSkillEnabled),
|
|
1148
|
+
codexLocalSkillEnabled: normalizeCodexLocalSkillEnabled(source.codexLocalSkillEnabled),
|
|
1108
1149
|
theme: ['dark', 'light', 'auto'].includes(source.theme) ? source.theme : 'dark',
|
|
1109
1150
|
panelWidth: normalizePanelWidth(source.panelWidth),
|
|
1110
1151
|
task: summarizeTextForStorage(active?.task || source.task || '', 'task'),
|
|
@@ -1283,7 +1324,13 @@
|
|
|
1283
1324
|
undoBaseFiles: undoPayload.undoBaseFiles,
|
|
1284
1325
|
undoTrackedChanges: undoPayload.undoTrackedChanges,
|
|
1285
1326
|
undoExpectedFiles: undoPayload.undoExpectedFiles,
|
|
1327
|
+
...(!run.forkSnapshot && (run.pendingDirectoryCleanup || run.recoveryRetention?.directoryCleanup === true || (run.undoStatus !== 'applied' && !['accepted', 'rejected'].includes(run.trackedChangeStatus)))
|
|
1328
|
+
&& (run.pendingDirectoryCleanup || run.recoveryRetention?.state === 'omitted' || ['appliedOperations', 'undoOperations', 'undoTrackedChanges', 'undoExpectedFiles']
|
|
1329
|
+
.some(key => Array.isArray(run[key]) && run[key].length))
|
|
1330
|
+
? { recoveryRetention: normalizeRecoveryRetention(run.recoveryRetention)
|
|
1331
|
+
|| { state: 'omitted', reason: 'fallback', bytes: 0, ...(run.pendingDirectoryCleanup ? { directoryCleanup: true } : {}) } } : {}),
|
|
1286
1332
|
undoStatus: summarizeTextForStorage(run.undoStatus, 'undo status'),
|
|
1333
|
+
...(run.undoOwnerProtocol === 1 ? { undoOwnerProtocol: 1 } : {}),
|
|
1287
1334
|
nativeRequestId: normalizeTextField(run.nativeRequestId, 160),
|
|
1288
1335
|
codexThreadId: normalizeTextField(run.codexThreadId, 160), codexTurnId: normalizeTextField(run.codexTurnId, 160),
|
|
1289
1336
|
forkSnapshot: run.forkSnapshot === true,
|
|
@@ -1291,6 +1338,11 @@
|
|
|
1291
1338
|
nativeEventSeq: Number.isFinite(Number(run.nativeEventSeq)) ? Number(run.nativeEventSeq) : 0,
|
|
1292
1339
|
queueItemId: normalizeTextField(run.queueItemId, 160)
|
|
1293
1340
|
};
|
|
1341
|
+
if (compact.recoveryRetention?.coreRetained === true && run.undoStatus !== 'applied'
|
|
1342
|
+
&& !TERMINAL_TRACKED_CHANGE_STATUS.has(run.trackedChangeStatus)
|
|
1343
|
+
&& ['appliedOperations', 'undoOperations', 'undoTrackedChanges', 'undoExpectedFiles'].some(key => run[key]?.length)) {
|
|
1344
|
+
delete compact.recoveryRetention.coreRetained;
|
|
1345
|
+
}
|
|
1294
1346
|
if (run.executionSnapshot && typeof run.executionSnapshot === 'object') {
|
|
1295
1347
|
compact.executionSnapshot = sanitizeAssistantVisibleValue(run.executionSnapshot);
|
|
1296
1348
|
}
|
|
@@ -1577,21 +1629,22 @@
|
|
|
1577
1629
|
if (typeof value !== 'string' || !value) {
|
|
1578
1630
|
return '';
|
|
1579
1631
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1632
|
+
// Conversation text is user/model content, not a credential field. Keep
|
|
1633
|
+
// examples and quoted values intact; local-reference display rules remain.
|
|
1634
|
+
if (!mightContainLocalReferenceText(value)) {
|
|
1635
|
+
return value;
|
|
1583
1636
|
}
|
|
1584
1637
|
if (LineReferences?.sanitizeLocalReferences) {
|
|
1585
1638
|
try {
|
|
1586
|
-
return LineReferences.sanitizeLocalReferences(
|
|
1639
|
+
return LineReferences.sanitizeLocalReferences(value, {
|
|
1587
1640
|
projectFiles: [],
|
|
1588
1641
|
context: 'persist'
|
|
1589
1642
|
});
|
|
1590
1643
|
} catch (_error) {
|
|
1591
|
-
return fallbackSanitizeLocalReferences(
|
|
1644
|
+
return fallbackSanitizeLocalReferences(value);
|
|
1592
1645
|
}
|
|
1593
1646
|
}
|
|
1594
|
-
return fallbackSanitizeLocalReferences(
|
|
1647
|
+
return fallbackSanitizeLocalReferences(value);
|
|
1595
1648
|
}
|
|
1596
1649
|
|
|
1597
1650
|
function mightContainLocalReferenceText(value) {
|
|
@@ -1619,18 +1672,6 @@
|
|
|
1619
1672
|
});
|
|
1620
1673
|
}
|
|
1621
1674
|
|
|
1622
|
-
function redactSecretLikeText(value) {
|
|
1623
|
-
if (typeof value !== 'string') {
|
|
1624
|
-
return '';
|
|
1625
|
-
}
|
|
1626
|
-
let redacted = value;
|
|
1627
|
-
for (const pattern of SECRET_REDACTION_PATTERNS) {
|
|
1628
|
-
pattern.lastIndex = 0;
|
|
1629
|
-
redacted = redacted.replace(pattern, REDACTED_SECRET);
|
|
1630
|
-
}
|
|
1631
|
-
return redacted;
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
1675
|
function containsSecretLikeText(value) {
|
|
1635
1676
|
if (typeof value === 'string') {
|
|
1636
1677
|
return SECRET_REDACTION_PATTERNS.some(pattern => {
|
|
@@ -1703,6 +1744,8 @@
|
|
|
1703
1744
|
}
|
|
1704
1745
|
|
|
1705
1746
|
return {
|
|
1747
|
+
normalizeRecoveryRetention,
|
|
1748
|
+
pruneRunRecoveryScope,
|
|
1706
1749
|
pickWritebackRecovery,
|
|
1707
1750
|
DEFAULT_PANEL_STATE,
|
|
1708
1751
|
createSession,
|
|
@@ -1720,7 +1763,9 @@
|
|
|
1720
1763
|
normalizeRunStatus,
|
|
1721
1764
|
recoverRecordedRunFailure,
|
|
1722
1765
|
recoverSettledRunningRun,
|
|
1766
|
+
normalizeCodexLocalSkillEnabled,
|
|
1723
1767
|
normalizeProjectReferenceFiles,
|
|
1768
|
+
normalizeComposerAttachmentsForPersistence,
|
|
1724
1769
|
normalizeSelectionContext: SelectionContext.normalize,
|
|
1725
1770
|
prepareStateForStorage,
|
|
1726
1771
|
estimateJsonBytes,
|
|
@@ -157,6 +157,9 @@
|
|
|
157
157
|
canAccept,
|
|
158
158
|
canUndo,
|
|
159
159
|
canRetry: Boolean(primaryFailure?.retryable),
|
|
160
|
+
requiresWriteReview: Boolean(facts && (facts.documentEffect === 'possibly-changed'
|
|
161
|
+
|| facts.evidence?.settled === 'needs-review'
|
|
162
|
+
|| facts.failures.some(failure => DefaultFailureReasons.isUnconfirmedWriteFailure?.(failure)))),
|
|
160
163
|
terminalState: failureTerminalState || '',
|
|
161
164
|
actions: { accept: canAccept, undo: canUndo }
|
|
162
165
|
};
|
|
@@ -209,6 +212,10 @@
|
|
|
209
212
|
file: safePath(item.file),
|
|
210
213
|
operationType: text(item.operationType).slice(0, 80),
|
|
211
214
|
changedDocument: item.changedDocument === true,
|
|
215
|
+
...(item.mayHaveMutated === true ? { mayHaveMutated: true } : {}),
|
|
216
|
+
...(item.evidence?.originalCode === 'native_untracked_undo_pending_changes'
|
|
217
|
+
&& item.changedDocument !== true && item.mayHaveMutated !== true && item.evidence.writeStarted !== true
|
|
218
|
+
? { evidence: { originalCode: 'native_untracked_undo_pending_changes' } } : {}),
|
|
212
219
|
terminalState: normalizeTerminalState(item.terminalState)
|
|
213
220
|
}));
|
|
214
221
|
}
|
|
@@ -287,8 +294,9 @@
|
|
|
287
294
|
}
|
|
288
295
|
|
|
289
296
|
function selectPrimaryFailure(failures) {
|
|
290
|
-
|
|
291
|
-
|
|
297
|
+
const select = DefaultFailureReasons?.selectPrimaryWritebackFailure || DefaultFailureReasons?.selectPrimaryFailure;
|
|
298
|
+
return select instanceof Function
|
|
299
|
+
? select(failures)
|
|
292
300
|
: failures[0] || null;
|
|
293
301
|
}
|
|
294
302
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(function (root, factory) {
|
|
2
|
-
if (typeof module === 'object' && module.exports) module.exports = factory();
|
|
3
|
-
else root.CodexOverleafModuleRegistry.define('SharedSessionBridge', [], factory);
|
|
4
|
-
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
2
|
+
if (typeof module === 'object' && module.exports) module.exports = factory(require('./sharedSessionTransfer'));
|
|
3
|
+
else root.CodexOverleafModuleRegistry.define('SharedSessionBridge', ['SharedSessionTransfer'], factory);
|
|
4
|
+
})(typeof globalThis !== 'undefined' ? globalThis : this, function (Transfer) {
|
|
5
5
|
'use strict';
|
|
6
6
|
const MESSAGE = 'codex-overleaf/shared-sessions-v1';
|
|
7
7
|
const LOCK_PORT = 'codex-overleaf/shared-session-lock-v1';
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
}
|
|
35
35
|
function assertScope(value) { capture(value.projectId, value.accountScopeId); }
|
|
36
36
|
const cacheKey = (value, id) => value.accountScopeId + ':' + id;
|
|
37
|
-
const lockKey = (kind, value) => kind === 'preferences' ? 'preferences' : 'state:' + value.accountScopeId;
|
|
37
|
+
const lockKey = (kind, value) => kind === 'review' ? 'review:' + JSON.stringify([value.accountScopeId, value.projectId, value.runId]) : kind === 'preferences' ? 'preferences' : 'state:' + value.accountScopeId;
|
|
38
38
|
async function request(method, value, args = {}) {
|
|
39
39
|
assertScope(value);
|
|
40
40
|
const lock = heldLocks.get(lockKey('state', value));
|
|
@@ -51,23 +51,24 @@
|
|
|
51
51
|
|
|
52
52
|
// Live ports own the locks. Worker/page termination releases them without
|
|
53
53
|
// allowing a stale client to silently fall back to an origin-local lock.
|
|
54
|
-
async function acquire(kind, value, work) {
|
|
54
|
+
async function acquire(kind, value, work, onLost) {
|
|
55
55
|
assertScope(value);
|
|
56
56
|
const key = lockKey(kind, value), port = chromeApi.runtime.connect({ name: LOCK_PORT });
|
|
57
57
|
let timer, heartbeat, released = false, lock = null, rejectGrant;
|
|
58
58
|
const granted = new Promise((resolve, reject) => {
|
|
59
59
|
rejectGrant = reject;
|
|
60
60
|
port.onMessage.addListener(message => {
|
|
61
|
+
if (message?.type === 'busy') { reject(failure('review_busy', 'Another page is reviewing this run. Wait for it to finish.')); return; }
|
|
61
62
|
if (message?.type !== 'granted' || lock || released) return;
|
|
62
63
|
clearTimeout(timer);
|
|
63
|
-
lock = { token: message.token, lost: false };
|
|
64
|
+
lock = { token: message.token, deadlineAt: message.deadlineAt, lost: false };
|
|
64
65
|
heldLocks.set(key, lock);
|
|
65
66
|
resolve();
|
|
66
67
|
});
|
|
67
68
|
port.onDisconnect.addListener(() => {
|
|
68
69
|
// Read lastError to consume the runtime's disconnected-port warning.
|
|
69
70
|
void chromeApi.runtime.lastError;
|
|
70
|
-
if (lock) lock.lost = true;
|
|
71
|
+
if (lock) { lock.lost = true; if (!released) onLost?.(lock.token); }
|
|
71
72
|
if (!released) reject(failure('storage_lock_lost', 'The shared history lock disconnected.'));
|
|
72
73
|
});
|
|
73
74
|
timer = environment.setTimeout(() => reject(failure('storage_lock_timeout',
|
|
@@ -84,12 +85,27 @@
|
|
|
84
85
|
port.postMessage({ type: 'acquire', kind, scope: value });
|
|
85
86
|
await granted;
|
|
86
87
|
assertScope(value);
|
|
87
|
-
const
|
|
88
|
+
const assertOwner = () => { assertScope(value); if (lock.lost) throw failure('storage_lock_lost', 'The shared review owner disconnected.'); };
|
|
89
|
+
assertOwner.token = lock.token;
|
|
90
|
+
assertOwner.markDispatched = async () => {
|
|
91
|
+
assertOwner();
|
|
92
|
+
const lease = await request('review-dispatched', value, { runId: value.runId, reviewToken: lock.token });
|
|
93
|
+
assertOwner(); assertOwner.deadlineAt = lease.deadlineAt; return lease.deadlineAt;
|
|
94
|
+
};
|
|
95
|
+
const result = await work(assertOwner);
|
|
88
96
|
assertScope(value);
|
|
89
97
|
if (lock.lost) throw failure('storage_lock_lost', 'The shared history lock was lost before completion.');
|
|
90
98
|
return result;
|
|
91
99
|
} finally {
|
|
92
100
|
released = true;
|
|
101
|
+
if (kind === 'review' && lock && !lock.lost) {
|
|
102
|
+
await new Promise(resolve => {
|
|
103
|
+
const done = message => { if (message?.type === 'released') { port.onMessage.removeListener(done); environment.clearTimeout(releaseTimer); resolve(); } };
|
|
104
|
+
const releaseTimer = environment.setTimeout(resolve, 2000);
|
|
105
|
+
port.onMessage.addListener(done);
|
|
106
|
+
try { port.postMessage({ type: 'release-review', token: lock.token }); } catch (_) { resolve(); }
|
|
107
|
+
});
|
|
108
|
+
}
|
|
93
109
|
environment.clearTimeout(timer);
|
|
94
110
|
environment.clearInterval(heartbeat);
|
|
95
111
|
if (heldLocks.get(key) === lock) heldLocks.delete(key);
|
|
@@ -179,7 +195,8 @@
|
|
|
179
195
|
record: clean(record),
|
|
180
196
|
base: record[BASE] || baselines.get(cacheKey(value, record.id)) || null
|
|
181
197
|
}));
|
|
182
|
-
const
|
|
198
|
+
const transfer = await Transfer.encode(entries);
|
|
199
|
+
const written = await request(transfer.method, value, { ...transfer.payload, reviewRunIds: options.reviewRunIds || [] });
|
|
183
200
|
// Keep the caller's submitted view as its merge baseline. A merged
|
|
184
201
|
// remote change has not necessarily been applied to the visible UI.
|
|
185
202
|
for (const entry of entries) baselines.set(cacheKey(value, entry.record.id), clean(entry.record));
|
|
@@ -192,8 +209,8 @@
|
|
|
192
209
|
const record = await request('get', value, { id });
|
|
193
210
|
return tag(record, value, !heldLocks.has(lockKey('state', value)));
|
|
194
211
|
}
|
|
195
|
-
async function erase(method, projectId = '', id) {
|
|
196
|
-
const value = capture(projectId);
|
|
212
|
+
async function erase(method, projectId = '', id, accountScopeId) {
|
|
213
|
+
const value = capture(projectId, accountScopeId);
|
|
197
214
|
return withWrite(value, () => request(method, value, { id }));
|
|
198
215
|
}
|
|
199
216
|
function decorate(api) {
|
|
@@ -225,8 +242,9 @@
|
|
|
225
242
|
store === 'sessions' ? (await put([record]))[0] : api.putRecord(store, record));
|
|
226
243
|
route('putRecords', (store, records, options) =>
|
|
227
244
|
store === 'sessions' ? put(records, options) : api.putRecords(store, records));
|
|
228
|
-
route('deleteRecord', (store, id) =>
|
|
229
|
-
store === 'sessions' ? erase('delete', '', id
|
|
245
|
+
route('deleteRecord', (store, id, expectedScope) =>
|
|
246
|
+
store === 'sessions' ? erase('delete', expectedScope?.projectId || '', id, expectedScope?.accountScopeId)
|
|
247
|
+
: api.deleteRecord(store, id));
|
|
230
248
|
route('deleteByIndex', async (store, index, value) => {
|
|
231
249
|
if (store !== 'sessions') return api.deleteByIndex(store, index, value);
|
|
232
250
|
if (index === 'projectId') return erase('clear-project', value);
|
|
@@ -243,7 +261,7 @@
|
|
|
243
261
|
for (const record of await api.getAllSessions()) {
|
|
244
262
|
if (record.accountScopeId === value.accountScopeId) await api.deleteRecord('sessions', record.id);
|
|
245
263
|
}
|
|
246
|
-
|
|
264
|
+
await api.clearAuxiliaryStores();
|
|
247
265
|
baselines.clear();
|
|
248
266
|
});
|
|
249
267
|
route('listRecentProjectsAcrossAccount', async options => {
|
|
@@ -253,6 +271,11 @@
|
|
|
253
271
|
});
|
|
254
272
|
Object.assign(wrapped, {
|
|
255
273
|
sharedSessionsEnabled: enabled,
|
|
274
|
+
withSharedReviewLock: async (input, work) => {
|
|
275
|
+
const value = { ...capture(input.projectId, input.accountScopeId), runId: input.runId };
|
|
276
|
+
return acquire('review', value, work, input.onLost);
|
|
277
|
+
},
|
|
278
|
+
hasSharedReviewOwner: input => request('review-owner', capture(input.projectId, input.accountScopeId), { runId: input.runId }),
|
|
256
279
|
withSharedLock: withLock,
|
|
257
280
|
readSharedProjectSnapshot: projectId => list(projectId, false),
|
|
258
281
|
adoptSharedSessionBaseline: adopt,
|