codex-overleaf-link 2.2.1 → 2.3.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.
Files changed (79) hide show
  1. package/README.md +25 -23
  2. package/extension/bootstrap/manifest.template.json +1 -1
  3. package/extension/runtime-manifest.json +5 -71
  4. package/extension/src/background.js +67 -63
  5. package/extension/src/backgroundUpdateCoordinator.js +128 -66
  6. package/extension/src/content/applyResultFormatters.js +2 -3
  7. package/extension/src/content/composerPanel.js +0 -2
  8. package/extension/src/content/contentRuntime.js +757 -1558
  9. package/extension/src/content/contextTray.js +4 -6
  10. package/extension/src/content/diagnosticsController.js +1 -2
  11. package/extension/src/content/diffReviewPanel.js +14 -13
  12. package/extension/src/content/generated/content.bundle.js +41605 -0
  13. package/extension/src/content/generated/content.bundle.meta.json +103 -0
  14. package/extension/src/content/legacyGlobalRegistry.js +129 -0
  15. package/extension/src/content/markdownText.js +17 -17
  16. package/extension/src/content/mathText.js +155 -9
  17. package/extension/src/content/modelPicker.js +1 -1
  18. package/extension/src/content/modelPickerSupport.js +10 -5
  19. package/extension/src/content/moduleRegistryKernel.js +125 -0
  20. package/extension/src/content/nativeCompatibilityController.js +313 -0
  21. package/extension/src/content/otWarmMirror.js +8 -6
  22. package/extension/src/content/pageBridgeClient.js +224 -0
  23. package/extension/src/content/panelMaintenance.js +8 -3
  24. package/extension/src/content/postNavigationSettlementPersistence.js +100 -0
  25. package/extension/src/content/projectProviderSelection.js +4 -12
  26. package/extension/src/content/projectSessionCleanup.js +3 -3
  27. package/extension/src/content/providerSettingsCoordinator.js +59 -26
  28. package/extension/src/content/providerSettingsDialog.js +30 -18
  29. package/extension/src/content/recentProjects.js +15 -23
  30. package/extension/src/content/runGuidanceController.js +1 -1
  31. package/extension/src/content/runQueueScheduler.js +129 -29
  32. package/extension/src/content/runSettlementPersistence.js +51 -0
  33. package/extension/src/content/runTimelineView.js +17 -8
  34. package/extension/src/content/scopedPersistenceCoordinator.js +100 -0
  35. package/extension/src/content/scopedPersistenceDetachedCommit.js +47 -0
  36. package/extension/src/content/scopedPersistencePanelState.js +111 -0
  37. package/extension/src/content/sessionManager.js +15 -12
  38. package/extension/src/content/sessionPersistence.js +67 -8
  39. package/extension/src/content/updateNotice.js +10 -4
  40. package/extension/src/content/writebackOrchestrator.js +89 -68
  41. package/extension/src/contentScript.js +5 -1
  42. package/extension/src/page/trackedChangesLifecycle.js +16 -5
  43. package/extension/src/page/writebackRouter.js +6 -2
  44. package/extension/src/pageBridge.js +47 -98
  45. package/extension/src/shared/agentTranscript.js +18 -8
  46. package/extension/src/shared/compatibility.js +1 -1
  47. package/extension/src/shared/governanceRules.js +1 -1
  48. package/extension/src/shared/i18n.js +2 -4
  49. package/extension/src/shared/managedUpdateProjection.js +337 -0
  50. package/extension/src/shared/nativeRequestIdentity.js +60 -0
  51. package/extension/src/shared/otText.js +0 -19
  52. package/extension/src/shared/pageRpcContract.js +136 -0
  53. package/extension/src/shared/runExecutionSnapshot.js +187 -0
  54. package/extension/src/shared/runExecutionSnapshotCodec.js +171 -0
  55. package/extension/src/shared/runInputQueue.js +81 -34
  56. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +79 -0
  57. package/extension/src/shared/scopedPersistenceQueuePolicy.js +200 -0
  58. package/extension/src/shared/scopedPersistenceReceipt.js +60 -0
  59. package/extension/src/shared/scopedPersistenceTransaction.js +241 -0
  60. package/extension/src/shared/sessionState.js +110 -59
  61. package/extension/src/shared/settlementFacts.js +351 -0
  62. package/extension/src/shared/storageDb.js +25 -10
  63. package/extension/src/shared/storageMigration.js +275 -61
  64. package/extension/src/shared/storageSessionClaims.js +60 -0
  65. package/extension/src/shared/updateConsent.js +4 -0
  66. package/extension/src/shared/updateRevocationIntent.js +109 -0
  67. package/extension/src/shared/writebackEvidenceProjection.js +150 -0
  68. package/extension/src/shared/writebackOperationEvidence.js +153 -0
  69. package/extension/src/shared/writebackSettlement.js +727 -0
  70. package/extension/styles/panel.css +18 -8
  71. package/native-host/src/codexPromptAssembly.js +1 -1
  72. package/native-host/src/codexRuntimeIdentity.js +1 -1
  73. package/native-host/src/codexSessionRunner.js +7 -13
  74. package/native-host/src/index.js +3 -69
  75. package/native-host/src/managedInstall.js +50 -8
  76. package/native-host/src/nativeTransportEnvelope.js +148 -0
  77. package/native-host/src/taskRunnerRuntime.js +14 -84
  78. package/native-host/src/updateManager.js +36 -1
  79. package/package.json +13 -5
@@ -0,0 +1,125 @@
1
+ (function initCodexOverleafModuleRegistry(root, factory) {
2
+ 'use strict';
3
+
4
+ const api = factory(root);
5
+ if (typeof module === 'object' && module.exports) {
6
+ module.exports = api;
7
+ }
8
+ if (root) {
9
+ root.CodexOverleafModuleRegistry = api;
10
+ }
11
+ })(typeof window !== 'undefined' ? window : globalThis, function moduleRegistryFactory(root) {
12
+ 'use strict';
13
+
14
+ const definitions = new Map();
15
+ const instances = new Map();
16
+
17
+ function define(name, dependencies, factory) {
18
+ name = normalizeName(name);
19
+ if (definitions.has(name) || instances.has(name)) {
20
+ throw new Error(`Codex Overleaf module is already defined: ${name}`);
21
+ }
22
+ if (!Array.isArray(dependencies) || typeof factory !== 'function') {
23
+ throw new TypeError(`Codex Overleaf module ${name} has an invalid definition.`);
24
+ }
25
+ definitions.set(name, {
26
+ dependencies: dependencies.map(normalizeName),
27
+ factory
28
+ });
29
+ Object.defineProperty(root, `CodexOverleaf${name}`, {
30
+ configurable: true,
31
+ enumerable: false,
32
+ get() {
33
+ return resolve(name);
34
+ }
35
+ });
36
+ }
37
+
38
+ function resolve(name, stack = []) {
39
+ name = normalizeName(name);
40
+ if (instances.has(name)) {
41
+ return instances.get(name);
42
+ }
43
+ const definition = definitions.get(name);
44
+ if (!definition) {
45
+ const legacyValue = readLegacyValue(name);
46
+ if (legacyValue) {
47
+ return legacyValue;
48
+ }
49
+ throw moduleError('content_dependency_missing', `Codex Overleaf module is not defined: ${name}`, {
50
+ moduleName: name,
51
+ resolutionStack: stack
52
+ });
53
+ }
54
+ if (stack.includes(name)) {
55
+ const cycle = [...stack.slice(stack.indexOf(name)), name];
56
+ throw moduleError('content_dependency_cycle', `Codex Overleaf module dependency cycle: ${cycle.join(' -> ')}`, {
57
+ cycle
58
+ });
59
+ }
60
+ const nextStack = [...stack, name];
61
+ const args = definition.dependencies.map(dependency => resolve(dependency, nextStack));
62
+ const value = definition.factory(...args);
63
+ if (!value) {
64
+ throw moduleError('content_dependency_invalid_export', `Codex Overleaf module returned no export: ${name}`, {
65
+ moduleName: name
66
+ });
67
+ }
68
+ instances.set(name, value);
69
+ definitions.delete(name);
70
+ Object.defineProperty(root, `CodexOverleaf${name}`, {
71
+ configurable: true,
72
+ enumerable: false,
73
+ value,
74
+ writable: false
75
+ });
76
+ return value;
77
+ }
78
+
79
+ function resolveAll(names) {
80
+ const resolved = {};
81
+ const failures = [];
82
+ for (const name of names || []) {
83
+ try {
84
+ resolved[name] = resolve(name);
85
+ } catch (error) {
86
+ failures.push(error);
87
+ }
88
+ }
89
+ if (failures.length) {
90
+ const error = moduleError(
91
+ 'content_dependency_resolution_failed',
92
+ failures.map(item => item.message).join('; '),
93
+ { failures }
94
+ );
95
+ throw error;
96
+ }
97
+ return resolved;
98
+ }
99
+
100
+ function readLegacyValue(name) {
101
+ const descriptor = Object.getOwnPropertyDescriptor(root, `CodexOverleaf${name}`);
102
+ if (!descriptor || typeof descriptor.get === 'function') {
103
+ return null;
104
+ }
105
+ return descriptor.value || null;
106
+ }
107
+
108
+ function normalizeName(value) {
109
+ const name = String(value || '').trim();
110
+ if (!/^[A-Z][A-Za-z0-9_$]*$/.test(name)) {
111
+ throw new TypeError(`Invalid Codex Overleaf module name: ${name || '(empty)'}`);
112
+ }
113
+ return name;
114
+ }
115
+
116
+ function moduleError(code, message, detail) {
117
+ return Object.assign(new Error(message), { code, detail });
118
+ }
119
+
120
+ return Object.freeze({
121
+ define,
122
+ resolve,
123
+ resolveAll
124
+ });
125
+ });
@@ -0,0 +1,313 @@
1
+ (function initCodexOverleafNativeCompatibilityController(root, factory) {
2
+ const api = factory();
3
+ if (typeof module === 'object' && module.exports) module.exports = api;
4
+ if (root) root.CodexOverleafNativeCompatibilityController = api;
5
+ })(typeof window !== 'undefined' ? window : globalThis, function nativeCompatibilityControllerFactory() {
6
+ 'use strict';
7
+
8
+ function create(options = {}) {
9
+ const Compatibility = options.compatibility;
10
+ const nativeChannel = options.nativeChannel;
11
+ const gatedMethods = options.gatedMethods || new Set();
12
+ const tx = options.tx;
13
+ const tr = options.tr;
14
+
15
+ function sendNative(payload) {
16
+ return dispatch(payload, 'sendNative');
17
+ }
18
+
19
+ function sendBackgroundNative(payload) {
20
+ return dispatch(payload, 'sendBackgroundNative');
21
+ }
22
+
23
+ async function dispatch(payload, channelMethod) {
24
+ const compatibilityGate = await ensureForMethod(payload?.method);
25
+ if (!compatibilityGate.ok) return compatibilityGate.response;
26
+ if (gatedMethods.has(payload?.method)) options.throwIfCancellationRequested?.();
27
+ return nativeChannel[channelMethod](
28
+ attachEvidence(payload, compatibilityGate.compatibility)
29
+ );
30
+ }
31
+
32
+ async function ensureForMethod(method) {
33
+ const metadata = options.getExtensionCompatibilityMetadata?.() || {};
34
+ const params = Compatibility?.buildBridgePingParams
35
+ ? Compatibility.buildBridgePingParams(metadata)
36
+ : {};
37
+ const response = await nativeChannel.sendBackgroundNative({
38
+ method: 'bridge.ping',
39
+ params
40
+ });
41
+ const compatibility = Compatibility?.evaluateNativeCompatibility
42
+ ? Compatibility.evaluateNativeCompatibility(response, metadata)
43
+ : options.fallbackNativeCompatibility(response);
44
+ const allowed = !gatedMethods.has(method) ||
45
+ (Compatibility?.isNativeMethodAllowed
46
+ ? Compatibility.isNativeMethodAllowed(method, compatibility)
47
+ : compatibility.status === 'ok');
48
+ if (allowed) return { ok: true, compatibility };
49
+
50
+ const message = formatBlockedMessage(method, compatibility);
51
+ const installCommand = options.installCommand;
52
+ const error = {
53
+ code: 'native_update_required',
54
+ message,
55
+ status: compatibility.status || 'unknown_native',
56
+ classification: options.getNativeCompatibilityClassification(compatibility),
57
+ installCommand: compatibility.installCommand || installCommand,
58
+ updateCommand: compatibility.updateCommand || compatibility.installCommand || installCommand,
59
+ currentNativeVersion: compatibility.currentNativeVersion
60
+ || compatibility.nativeVersion
61
+ || compatibility.native?.version
62
+ || '',
63
+ requiredVersion: compatibility.requiredVersion || Compatibility?.BUILD_TARGET_VERSION || '',
64
+ releaseUrl: compatibility.releaseUrl || ''
65
+ };
66
+ notifyBlocked(error, compatibility);
67
+ return { ok: false, compatibility, response: { ok: false, error } };
68
+ }
69
+
70
+ function attachEvidence(payload = {}, compatibility) {
71
+ if (!compatibility || !gatedMethods.has(payload?.method)) return payload;
72
+ return {
73
+ ...payload,
74
+ params: {
75
+ ...(payload.params || {}),
76
+ nativeCompatibility: compatibility
77
+ }
78
+ };
79
+ }
80
+
81
+ function notifyBlocked(error, compatibility = {}) {
82
+ const message = error?.message || String(error || '');
83
+ if (options.getCurrentRunView?.()) {
84
+ options.appendRunEvent?.({ title: message, status: 'failed' });
85
+ showUpdateGuidance(compatibility);
86
+ return;
87
+ }
88
+ showUpdateGuidance(compatibility);
89
+ options.showPluginToast?.(message, { status: 'failed', sticky: true });
90
+ }
91
+
92
+ async function refreshBadge() {
93
+ const renderer = options.getPanelRendererInstance?.();
94
+ if (!renderer?.headerEl || !Compatibility?.evaluateNativeCompatibility) return;
95
+ try {
96
+ const metadata = options.getExtensionCompatibilityMetadata?.() || {};
97
+ const params = Compatibility.buildBridgePingParams
98
+ ? Compatibility.buildBridgePingParams(metadata)
99
+ : {};
100
+ const response = await sendBackgroundNative({ method: 'bridge.ping', params });
101
+ const compatibility = Compatibility.evaluateNativeCompatibility(response, metadata);
102
+ const classification = options.getNativeCompatibilityClassification(compatibility);
103
+ if (classification === 'compatible') {
104
+ options.setBadge?.(renderer.headerEl, { type: 'none' });
105
+ options.setDiagnosticsHealth?.('ok');
106
+ try {
107
+ options.localStorage?.setItem('codexOverleafNativeEverOk', 'true');
108
+ } catch (_storageError) {}
109
+ return;
110
+ }
111
+ options.setDiagnosticsHealth?.(classification === 'update-available' ? 'warn' : 'fail');
112
+ options.setBadge?.(renderer.headerEl, {
113
+ type: 'update',
114
+ tooltip: tx('Native host update available', 'Native host 可更新'),
115
+ onClick: () => showUpdateGuidance(compatibility)
116
+ });
117
+ if (!compatibility?.native?.version) maybePromptFirstRunSetup();
118
+ } catch (_error) {
119
+ options.setDiagnosticsHealth?.('fail');
120
+ options.setBadge?.(renderer.headerEl, {
121
+ type: 'update',
122
+ tooltip: tx(
123
+ 'Native host is not responding — click for setup steps',
124
+ 'Native host 未响应——点击查看安装步骤'
125
+ ),
126
+ onClick: () => showUpdateGuidance(options.fallbackNativeCompatibility({ ok: false }))
127
+ });
128
+ maybePromptFirstRunSetup();
129
+ }
130
+ }
131
+
132
+ function maybePromptFirstRunSetup() {
133
+ const storage = options.localStorage;
134
+ try {
135
+ if (!storage || storage.getItem('codexOverleafSetupPromptShown') === 'true') return;
136
+ if (storage.getItem('codexOverleafNativeEverOk') === 'true') return;
137
+ storage.setItem('codexOverleafSetupPromptShown', 'true');
138
+ } catch (_storageError) {
139
+ return;
140
+ }
141
+ showUpdateGuidance(options.fallbackNativeCompatibility({ ok: false }));
142
+ }
143
+
144
+ function showUpdateGuidance(compatibility = {}) {
145
+ let panel = options.getPanel?.();
146
+ if (!panel) {
147
+ options.ensurePanelOpen?.();
148
+ panel = options.getPanel?.();
149
+ }
150
+ if (!panel) return;
151
+ panel.querySelector('[data-native-update-guidance]')?.remove();
152
+ const native = compatibility.native || {};
153
+ const extensionVersion = compatibility.extensionVersion || Compatibility?.BUILD_TARGET_VERSION || '';
154
+ const nativeVersion = compatibility.currentNativeVersion
155
+ || compatibility.nativeVersion
156
+ || native.version
157
+ || tx('missing', '未安装');
158
+ const command = compatibility.updateCommand
159
+ || compatibility.installCommand
160
+ || options.installCommand;
161
+ const releaseUrl = compatibility.releaseUrl || '';
162
+ const overlay = options.document.createElement('div');
163
+ overlay.className = 'codex-plugin-confirm';
164
+ overlay.dataset.nativeUpdateGuidance = 'true';
165
+ overlay.setAttribute('role', 'dialog');
166
+ overlay.setAttribute('aria-modal', 'true');
167
+ const nativeMissing = !native.version;
168
+ overlay.setAttribute(
169
+ 'aria-label',
170
+ nativeMissing
171
+ ? tx('Set up the native host', '安装 Native host')
172
+ : tx('Native host update available', 'Native host 可更新')
173
+ );
174
+ const card = options.document.createElement('section');
175
+ card.className = 'codex-plugin-confirm-card';
176
+ const title = options.document.createElement('div');
177
+ title.className = 'codex-plugin-confirm-title';
178
+ title.textContent = nativeMissing
179
+ ? tx('One step left: install the native host', '还差一步:安装 Native host')
180
+ : tx('Native host update available', 'Native host 可更新');
181
+ const body = options.document.createElement('div');
182
+ body.className = 'codex-plugin-confirm-body';
183
+ body.textContent = [
184
+ nativeMissing
185
+ ? tx(
186
+ `Extension v${extensionVersion} is ready; Codex still needs its local bridge to read and edit this project.`,
187
+ `扩展 v${extensionVersion} 已就绪;Codex 还需要本地桥接程序才能读写这个项目。`
188
+ )
189
+ : tx(
190
+ `Extension v${extensionVersion} / Native v${nativeVersion}`,
191
+ `扩展 v${extensionVersion} / Native v${nativeVersion}`
192
+ ),
193
+ tx(
194
+ 'Run the platform-specific command below, reload the extension, then refresh Overleaf.',
195
+ '运行下面的平台命令,重新加载扩展,然后刷新 Overleaf。'
196
+ )
197
+ ].join('\n\n');
198
+ const commandCode = options.document.createElement('code');
199
+ commandCode.textContent = command;
200
+ Object.assign(commandCode.style, {
201
+ display: 'block',
202
+ whiteSpace: 'pre-wrap',
203
+ marginTop: '0.75rem'
204
+ });
205
+ body.append(commandCode);
206
+ if (releaseUrl) {
207
+ const link = options.document.createElement('a');
208
+ link.href = releaseUrl;
209
+ link.target = '_blank';
210
+ link.rel = 'noopener noreferrer';
211
+ link.textContent = tx('Open GitHub Release', '打开 GitHub Release');
212
+ Object.assign(link.style, { display: 'block', marginTop: '0.75rem' });
213
+ body.append(link);
214
+ }
215
+ const actions = options.document.createElement('div');
216
+ actions.className = 'codex-plugin-confirm-actions';
217
+ const copy = options.document.createElement('button');
218
+ copy.type = 'button';
219
+ copy.className = 'codex-plugin-confirm-confirm';
220
+ copy.textContent = tx('Copy command', '复制命令');
221
+ copy.addEventListener('click', async () => {
222
+ await options.navigator.clipboard.writeText(command);
223
+ copy.textContent = tx('Copied', '已复制');
224
+ });
225
+ const close = options.document.createElement('button');
226
+ close.type = 'button';
227
+ close.className = 'codex-plugin-confirm-cancel';
228
+ close.textContent = tx('Close', '关闭');
229
+ close.addEventListener('click', () => overlay.remove());
230
+ actions.append(close, copy);
231
+ card.append(title, body, actions);
232
+ overlay.append(card);
233
+ overlay.addEventListener('click', event => {
234
+ if (event.target === overlay) overlay.remove();
235
+ });
236
+ panel.append(overlay);
237
+ copy.focus();
238
+ }
239
+
240
+ function scheduleFirstUseOnboardingTip() {
241
+ options.setTimeout(() => {
242
+ maybeShowFirstUseOnboardingTip().catch(() => {});
243
+ }, 250);
244
+ }
245
+
246
+ async function maybeShowFirstUseOnboardingTip() {
247
+ const panel = options.getPanel?.();
248
+ if (!panel || (options.getState?.()?.sessions || []).length > 0) return;
249
+ const key = options.onboardingTipStorageKey;
250
+ const stored = await options.chromeApi.storage.local.get([key]);
251
+ if (stored?.[key]) return;
252
+ const modeSelect = panel.querySelector('[data-mode]');
253
+ if (!modeSelect) return;
254
+ const tip = options.document.createElement('div');
255
+ tip.className = 'codex-onboarding-tip';
256
+ tip.dataset.onboardingTip = 'true';
257
+ tip.setAttribute('role', 'status');
258
+ tip.textContent = tx(
259
+ 'Tip: Start with Ask mode to explore safely. Switch to Auto only when you want Codex to edit files.',
260
+ '提示:先用 Ask 模式安全探索;只有需要 Codex 修改文件时才切换到 Auto。'
261
+ );
262
+ Object.assign(tip.style, {
263
+ position: 'absolute',
264
+ zIndex: '2147483647',
265
+ maxWidth: '280px'
266
+ });
267
+ panel.append(tip);
268
+ const panelRect = panel.getBoundingClientRect();
269
+ const modeRect = modeSelect.getBoundingClientRect();
270
+ tip.style.left = `${Math.max(12, modeRect.left - panelRect.left)}px`;
271
+ tip.style.bottom = `${Math.max(72, panelRect.bottom - modeRect.top + 8)}px`;
272
+ const dismiss = () => {
273
+ tip.remove();
274
+ options.chromeApi.storage.local.set({ [key]: true }).catch?.(() => {});
275
+ panel.removeEventListener('click', dismiss, true);
276
+ panel.removeEventListener('keydown', dismiss, true);
277
+ };
278
+ panel.addEventListener('click', dismiss, true);
279
+ panel.addEventListener('keydown', dismiss, true);
280
+ options.setTimeout(dismiss, 8000);
281
+ }
282
+
283
+ function formatBlockedMessage(method, compatibility = {}) {
284
+ const params = { method: method || 'native request' };
285
+ switch (compatibility.status || 'unknown_native') {
286
+ case 'native_too_old':
287
+ return tr('nativeCompatibilityBlockedNativeTooOld', params);
288
+ case 'extension_too_old':
289
+ return tr('nativeCompatibilityBlockedExtensionTooOld', params);
290
+ case 'protocol_unsupported':
291
+ return tr('nativeCompatibilityBlockedProtocol', params);
292
+ case 'native_unhealthy':
293
+ return tr('nativeCompatibilityBlockedUnhealthy', params);
294
+ case 'native_missing':
295
+ return tr('nativeCompatibilityBlockedMissing', params);
296
+ default:
297
+ return tr('nativeCompatibilityBlockedGeneric', params);
298
+ }
299
+ }
300
+
301
+ return Object.freeze({
302
+ attachEvidence,
303
+ ensureForMethod,
304
+ refreshBadge,
305
+ scheduleFirstUseOnboardingTip,
306
+ sendBackgroundNative,
307
+ sendNative,
308
+ showUpdateGuidance
309
+ });
310
+ }
311
+
312
+ return Object.freeze({ create });
313
+ });
@@ -1,10 +1,6 @@
1
1
  (function initCodexOverleafOtWarmMirror() {
2
2
  'use strict';
3
3
 
4
- const otWarmMirrorController = window.CodexOverleafOtWarmMirrorController;
5
- const runController = window.CodexOverleafRunController;
6
- const mirrorHealth = window.CodexOverleafMirrorHealth;
7
-
8
4
  // Experimental OT warm-mirror glue carved out of contentRuntime.js (v1.4.9
9
5
  // structural-debt phase 5): the per-project enable toggle flow, the
10
6
  // poll/flush timers and patch queue, mirror prefetch, warm-start
@@ -15,6 +11,12 @@
15
11
  // runtime reads it through the exported accessors and clears it on project
16
12
  // navigation via clearMirrorPrefetchTimer()/releaseOtWarmMirrorProject().
17
13
  function create(deps = {}) {
14
+ const {
15
+ otWarmMirrorController,
16
+ runController,
17
+ mirrorHealth,
18
+ projectFiles
19
+ } = deps;
18
20
  const {
19
21
  tr,
20
22
  tx,
@@ -853,7 +855,7 @@
853
855
  project,
854
856
  snapshotWarnings,
855
857
  focusFiles,
856
- isUsableProjectFileContent: window.CodexOverleafProjectFiles.isUsableProjectFileContent
858
+ isUsableProjectFileContent: projectFiles.isUsableProjectFileContent
857
859
  });
858
860
  if (snapshotWarnings.blocking.length && !focusedPartialSnapshot) {
859
861
  for (const warning of snapshotWarnings.blocking) {
@@ -866,7 +868,7 @@
866
868
  applyResults: [],
867
869
  nextStep: tr('warmMirrorStaleBlockedNextStep')
868
870
  });
869
- finishRunView(tr('warmMirrorStaleBlockedTitle'), 'failed');
871
+ await finishRunView(tr('warmMirrorStaleBlockedTitle'), 'failed');
870
872
  return { ok: false };
871
873
  }
872
874
  if (focusedPartialSnapshot) {