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.
Files changed (189) hide show
  1. package/README.md +155 -392
  2. package/README.zh-CN.md +154 -393
  3. package/extension/bootstrap/background.js +52 -9
  4. package/extension/bootstrap/manifest.template.json +1 -1
  5. package/extension/bootstrap/popup.html +1 -0
  6. package/extension/bootstrap/popupFallback.js +55 -0
  7. package/extension/bootstrap/updateStatus.js +1 -0
  8. package/extension/src/background.js +283 -55
  9. package/extension/src/backgroundBootstrapMigration.js +181 -0
  10. package/extension/src/backgroundSharedSessions.js +129 -16
  11. package/extension/src/backgroundUpdateCoordinator.js +242 -29
  12. package/extension/src/backgroundUpdateSafety.js +173 -0
  13. package/extension/src/content/activeTurnControl.js +171 -8
  14. package/extension/src/content/applyResultFormatters.js +46 -73
  15. package/extension/src/content/assetTransferBroker.js +72 -14
  16. package/extension/src/content/composerAttachments.js +104 -47
  17. package/extension/src/content/composerPanel.js +110 -12
  18. package/extension/src/content/contentRuntime.js +1555 -926
  19. package/extension/src/content/contextTray.js +8 -2
  20. package/extension/src/content/contextUsageView.js +267 -0
  21. package/extension/src/content/diagnosticsController.js +122 -96
  22. package/extension/src/content/diagnosticsExport.js +19 -5
  23. package/extension/src/content/diagnosticsPanel.js +48 -0
  24. package/extension/src/content/directoryCleanupRecovery.js +54 -0
  25. package/extension/src/content/generated/content.bundle.js +11077 -3412
  26. package/extension/src/content/generated/content.bundle.meta.json +14 -3
  27. package/extension/src/content/globalPreferencesController.js +1 -1
  28. package/extension/src/content/legacyGlobalRegistry.js +10 -0
  29. package/extension/src/content/localSkillsPanel.js +104 -14
  30. package/extension/src/content/markdownDomRenderer.js +5 -3
  31. package/extension/src/content/markdownText.js +47 -11
  32. package/extension/src/content/modelPicker.js +8 -4
  33. package/extension/src/content/nativeCompatibilityController.js +74 -30
  34. package/extension/src/content/otWarmMirror.js +5 -6
  35. package/extension/src/content/otWarmMirrorController.js +17 -20
  36. package/extension/src/content/pageBridgeClient.js +17 -4
  37. package/extension/src/content/panelMaintenance.js +46 -14
  38. package/extension/src/content/panelRenderer.js +57 -27
  39. package/extension/src/content/pendingInputView.js +1 -1
  40. package/extension/src/content/projectProviderSelection.js +13 -4
  41. package/extension/src/content/projectSessionCleanup.js +109 -62
  42. package/extension/src/content/projectSettingsCoordinator.js +67 -6
  43. package/extension/src/content/providerSettingsCoordinator.js +46 -8
  44. package/extension/src/content/providerSettingsDialog.js +73 -14
  45. package/extension/src/content/recentProjects.js +15 -8
  46. package/extension/src/content/runActivitySummary.js +160 -18
  47. package/extension/src/content/runCompletionMeta.js +532 -0
  48. package/extension/src/content/runController.js +39 -15
  49. package/extension/src/content/runFailureNotice.js +29 -13
  50. package/extension/src/content/runGuidanceController.js +72 -27
  51. package/extension/src/content/runGuidanceView.js +59 -10
  52. package/extension/src/content/runPresence.js +18 -8
  53. package/extension/src/content/runQueueScheduler.js +157 -47
  54. package/extension/src/content/runRecoveryActions.js +147 -0
  55. package/extension/src/content/runResultActions.js +28 -143
  56. package/extension/src/content/runReviewController.js +633 -0
  57. package/extension/src/content/runScrollLayout.js +21 -2
  58. package/extension/src/content/runTimelineView.js +367 -175
  59. package/extension/src/content/scopedPersistencePanelState.js +134 -20
  60. package/extension/src/content/selectionContextView.js +1 -1
  61. package/extension/src/content/sensitivePreflight.js +153 -0
  62. package/extension/src/content/sessionForkController.js +80 -17
  63. package/extension/src/content/sessionManager.js +50 -4
  64. package/extension/src/content/sessionMenuView.js +54 -18
  65. package/extension/src/content/sessionPersistence.js +25 -5
  66. package/extension/src/content/settingsPanel.js +22 -5
  67. package/extension/src/content/settingsWorkbench.js +132 -89
  68. package/extension/src/content/sharedSessionViewSync.js +49 -11
  69. package/extension/src/content/subagentActivityView.js +23 -7
  70. package/extension/src/content/updateIdle.js +4 -1
  71. package/extension/src/content/updateNotice.js +118 -12
  72. package/extension/src/content/updateSafetyReceiver.js +58 -0
  73. package/extension/src/content/writebackController.js +53 -4
  74. package/extension/src/content/writebackOrchestrator.js +116 -94
  75. package/extension/src/content/writingStyleSettings.js +35 -11
  76. package/extension/src/page/binaryAssetUploader.js +136 -14
  77. package/extension/src/page/compileBridge.js +193 -180
  78. package/extension/src/page/fileMover.js +256 -0
  79. package/extension/src/page/overleafCapabilities.js +4 -1
  80. package/extension/src/page/ownedDirectoryCleanup.js +94 -0
  81. package/extension/src/page/referenceProjects.js +1 -0
  82. package/extension/src/page/reviewContext.js +113 -0
  83. package/extension/src/page/saveState.js +6 -4
  84. package/extension/src/page/snapshotRouter.js +84 -39
  85. package/extension/src/page/textCoordinates.js +17 -1
  86. package/extension/src/page/textFileCreator.js +114 -26
  87. package/extension/src/page/trackedChangeCapture.js +12 -2
  88. package/extension/src/page/trackedChangeOwnership.js +19 -1
  89. package/extension/src/page/trackedChangeReplay.js +41 -21
  90. package/extension/src/page/trackedChangesLifecycle.js +217 -199
  91. package/extension/src/page/treeOperations.js +7 -10
  92. package/extension/src/page/updateSafetyProbe.js +41 -0
  93. package/extension/src/page/writebackReceiptJournal.js +2 -0
  94. package/extension/src/page/writebackRouter.js +103 -155
  95. package/extension/src/pageBridge.js +126 -69
  96. package/extension/src/popup.js +62 -10
  97. package/extension/src/shared/agentTranscript.js +373 -17
  98. package/extension/src/shared/auditRecords.js +4 -0
  99. package/extension/src/shared/compatibility.js +22 -6
  100. package/extension/src/shared/compileAdapter.js +129 -66
  101. package/extension/src/shared/composerAttachmentDraft.js +156 -0
  102. package/extension/src/shared/contextUsage.js +125 -0
  103. package/extension/src/shared/directoryCleanupProof.js +43 -0
  104. package/extension/src/shared/failureReasons.js +349 -4
  105. package/extension/src/shared/globalPreferences.js +30 -13
  106. package/extension/src/shared/governanceRules.js +4 -37
  107. package/extension/src/shared/i18n.js +590 -24
  108. package/extension/src/shared/lineReferences.js +38 -31
  109. package/extension/src/shared/managedUpdateProjection.js +2 -2
  110. package/extension/src/shared/nativeRequestIdentity.js +1 -0
  111. package/extension/src/shared/pageRpcContract.js +5 -4
  112. package/extension/src/shared/panelIcons.js +39 -0
  113. package/extension/src/shared/projectFiles.js +21 -44
  114. package/extension/src/shared/providerProfiles.js +5 -3
  115. package/extension/src/shared/reviewing.js +130 -1
  116. package/extension/src/shared/runActivityModel.js +70 -4
  117. package/extension/src/shared/runExecutionSnapshot.js +13 -0
  118. package/extension/src/shared/runInputQueue.js +48 -5
  119. package/extension/src/shared/selectionContext.js +12 -3
  120. package/extension/src/shared/sessionState.js +132 -28
  121. package/extension/src/shared/sessionTitle.js +14 -1
  122. package/extension/src/shared/settlementFacts.js +10 -2
  123. package/extension/src/shared/sharedSessionBridge.js +118 -27
  124. package/extension/src/shared/sharedSessionTransfer.js +140 -0
  125. package/extension/src/shared/staleGuard.js +166 -52
  126. package/extension/src/shared/storageDb.js +90 -26
  127. package/extension/src/shared/storageMigration.js +78 -112
  128. package/extension/src/shared/storageRunActions.js +267 -30
  129. package/extension/src/shared/subagentActivityModel.js +1 -1
  130. package/extension/src/shared/undoOperations.js +253 -32
  131. package/extension/src/shared/updateConsent.js +6 -4
  132. package/extension/src/shared/updateRuntimeIdentity.js +17 -3
  133. package/extension/src/shared/writebackIntent.js +16 -0
  134. package/extension/src/shared/writebackOperationEvidence.js +4 -15
  135. package/extension/src/shared/writebackSettlement.js +58 -40
  136. package/extension/styles/panel.css +1123 -493
  137. package/native-host/src/anthropicBridgeRequest.js +4 -2
  138. package/native-host/src/anthropicBridgeResponse.js +6 -2
  139. package/native-host/src/anthropicMessagesBridge.js +24 -16
  140. package/native-host/src/bootstrapMigration.js +296 -0
  141. package/native-host/src/bootstrapMigrationContract.js +101 -0
  142. package/native-host/src/bootstrapUpdate.js +269 -0
  143. package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
  144. package/native-host/src/chatBridgeRequest.js +60 -6
  145. package/native-host/src/chatBridgeResponse.js +20 -1
  146. package/native-host/src/chatCompletionsBridge.js +48 -15
  147. package/native-host/src/codexConfigPaths.js +106 -0
  148. package/native-host/src/codexHome.js +66 -73
  149. package/native-host/src/codexHomeScope.js +124 -0
  150. package/native-host/src/codexInheritedAuth.js +90 -0
  151. package/native-host/src/codexLocalSkills.js +301 -0
  152. package/native-host/src/codexPromptAssembly.js +114 -127
  153. package/native-host/src/codexProviderTest.js +24 -26
  154. package/native-host/src/codexSessionRunner.js +234 -198
  155. package/native-host/src/codexSessionTiming.js +18 -8
  156. package/native-host/src/codexSkillIsolation.js +170 -0
  157. package/native-host/src/codexThreadFork.js +19 -3
  158. package/native-host/src/index.js +19 -7
  159. package/native-host/src/managedInstall.js +110 -35
  160. package/native-host/src/managedInstallRecovery.js +140 -0
  161. package/native-host/src/managedRuntimeEvidence.js +57 -0
  162. package/native-host/src/mirrorWorkspace.js +92 -22
  163. package/native-host/src/nativeDoctor.js +15 -0
  164. package/native-host/src/nativeHelperLifecycle.js +21 -0
  165. package/native-host/src/nativeHostRegistration.js +33 -0
  166. package/native-host/src/nativeRunLifecycle.js +71 -0
  167. package/native-host/src/processStopBarrier.js +42 -7
  168. package/native-host/src/projectPathPlatform.js +30 -0
  169. package/native-host/src/providerContextError.js +20 -0
  170. package/native-host/src/providerHttp.js +80 -0
  171. package/native-host/src/providerProfile.js +4 -2
  172. package/native-host/src/providerReasoning.js +2 -7
  173. package/native-host/src/providerRuntime.js +1 -0
  174. package/native-host/src/providerStore.js +72 -14
  175. package/native-host/src/responsesPassthroughBridge.js +266 -52
  176. package/native-host/src/runtimeInstaller.js +21 -1
  177. package/native-host/src/selectionScope.js +36 -8
  178. package/native-host/src/subagentAdmission.js +26 -0
  179. package/native-host/src/subagentBroker.js +79 -66
  180. package/native-host/src/subagentTelemetry.js +19 -10
  181. package/native-host/src/subagentWorkspacePath.js +5 -2
  182. package/native-host/src/taskRunnerRuntime.js +92 -57
  183. package/native-host/src/textPatch.js +473 -377
  184. package/native-host/src/tomlStatements.js +140 -0
  185. package/native-host/src/updateManager.js +409 -46
  186. package/native-host/src/writingStyleRuntime.js +57 -29
  187. package/native-host/src/writingStyleStore.js +73 -0
  188. package/package.json +5 -8
  189. package/scripts/install-managed.mjs +1 -0
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ globalThis.__CODEX_OVERLEAF_BOOTSTRAP_REVISION__ = '3.1';
4
+
3
5
  const CODEX_OVERLEAF_HOST = 'com.codex.overleaf';
4
6
  const RUNTIME_SCRIPT_ID = 'codex-overleaf-managed-runtime';
5
7
  const UPDATE_STATE_KEY = 'codex-overleaf-managed-update-state-v1';
@@ -75,7 +77,7 @@ chrome.alarms.onAlarm.addListener(alarm => {
75
77
  }
76
78
  });
77
79
 
78
- initializeBootstrap().catch(async error => {
80
+ globalThis.__CODEX_OVERLEAF_BOOTSTRAP_READY__ = initializeBootstrap().catch(async error => {
79
81
  await setUpdateState({ state: 'failed', code: safeCode(error), message: safeMessage(error) });
80
82
  });
81
83
 
@@ -91,6 +93,8 @@ async function initializeBootstrap() {
91
93
  return;
92
94
  }
93
95
 
96
+ const migration = await globalThis.CodexOverleafBootstrapMigration?.ready?.();
97
+ if (migration?.continueInitialization === false) return;
94
98
  const nativeStatus = await requestInternal({ method: 'update.status', params: {} }).catch(() => null);
95
99
  const transaction = nativeStatus?.ok ? nativeStatus.result?.transaction : null;
96
100
  if (transaction?.state === 'awaiting_health') {
@@ -381,12 +385,12 @@ async function confirmPendingUpdate(transaction) {
381
385
  const targetVersion = transaction.targetVersion;
382
386
  const runtimeHealthy = await verifyPendingRuntimeHealth(targetVersion);
383
387
  if (!runtimeHealthy) {
384
- await rollbackBrokenRuntime(new Error('Updated Overleaf content runtime did not report the target version.'));
388
+ await rollbackBrokenRuntime(new Error('Updated Overleaf content runtime did not report the target version.'), transaction);
385
389
  return;
386
390
  }
387
391
  const ping = await requestInternal({ method: 'bridge.ping', params: {} }).catch(() => null);
388
392
  if (!ping?.ok || ping.result?.version !== targetVersion) {
389
- await rollbackBrokenRuntime(new Error('Updated native host did not report the target version.'));
393
+ await rollbackBrokenRuntime(new Error('Updated native host did not report the target version.'), transaction);
390
394
  return;
391
395
  }
392
396
  const native = ping.result || {};
@@ -399,19 +403,20 @@ async function confirmPendingUpdate(transaction) {
399
403
  native.protocolVersion < protocolRange.min ||
400
404
  native.protocolVersion > protocolRange.max ||
401
405
  missingCapabilities.length) {
402
- await rollbackBrokenRuntime(new Error('Updated native host did not pass protocol and capability health checks.'));
406
+ await rollbackBrokenRuntime(new Error('Updated native host did not pass protocol and capability health checks.'), transaction);
403
407
  return;
404
408
  }
405
409
  const confirmed = await requestInternal({
406
410
  method: 'update.confirm',
407
411
  params: {
408
412
  transactionId: transaction.id,
413
+ bootstrapRevision: String(globalThis.__CODEX_OVERLEAF_BOOTSTRAP_REVISION__ || ''),
409
414
  extensionVersion: chrome.runtime.getManifest().version,
410
415
  nativeVersion: ping.result.version
411
416
  }
412
417
  });
413
418
  if (!confirmed?.ok) {
414
- await rollbackBrokenRuntime(nativeError(confirmed));
419
+ await rollbackBrokenRuntime(nativeError(confirmed), transaction);
415
420
  return;
416
421
  }
417
422
  await setUpdateState({
@@ -451,20 +456,56 @@ async function verifyPendingRuntimeHealth(targetVersion) {
451
456
  return remaining.size === 0;
452
457
  }
453
458
 
454
- async function rollbackBrokenRuntime(error) {
459
+ async function rollbackBrokenRuntime(error, transaction) {
455
460
  await setUpdateState({ state: 'rolling_back', code: safeCode(error), message: safeMessage(error) });
461
+ let pending = transaction;
462
+ let readback;
463
+ if (!pending) {
464
+ readback = await requestInternal({ method: 'update.status', params: {} }).catch(() => null);
465
+ pending = readback?.ok ? readback.result?.transaction : null;
466
+ }
467
+ // A status recovery may have completed an interrupted apply before this
468
+ // loader obtained its transaction. The same source-byte proof is required.
469
+ if (isRollbackReadback(readback, pending)) {
470
+ await setUpdateState({ state: 'rolled_back', code: safeCode(error), currentVersion: pending.sourceVersion, transactionId: pending.id });
471
+ chrome.runtime.reload();
472
+ return;
473
+ }
474
+ if (!pending?.id || !pending.sourceVersion || !['applying', 'bootstrap_pending', 'awaiting_health', 'committed'].includes(pending.state)) {
475
+ await setUpdateState({ state: 'failed', code: safeCode(error), message: safeMessage(error) });
476
+ return;
477
+ }
456
478
  const rolledBack = await requestInternal({
457
479
  method: 'update.rollback',
458
- params: { reasonCode: safeCode(error) }
480
+ params: { reasonCode: safeCode(error), transactionId: pending.id, expectedState: pending.state }
459
481
  }).catch(() => null);
460
- if (rolledBack?.ok) {
461
- await setUpdateState({ state: 'rolled_back', code: safeCode(error), currentVersion: rolledBack.result.version });
482
+ if (rolledBack?.ok && rolledBack.result?.transactionId === pending.id
483
+ && rolledBack.result?.state === 'rolled_back' && rolledBack.result?.version === pending.sourceVersion) {
484
+ readback = await requestInternal({ method: 'update.status', params: {} }).catch(() => null);
485
+ }
486
+ if (rolledBack?.result?.restoredPair && isRollbackReadback(readback, pending, rolledBack.result.restoredPair)) {
487
+ await setUpdateState({ state: 'rolled_back', code: safeCode(error), currentVersion: pending.sourceVersion, transactionId: pending.id });
462
488
  chrome.runtime.reload();
463
489
  return;
464
490
  }
465
491
  await setUpdateState({ state: 'failed', code: safeCode(error), message: safeMessage(error) });
466
492
  }
467
493
 
494
+ function isRollbackReadback(response, transaction, expectedPair) {
495
+ const status = response?.ok ? response.result : null;
496
+ const pair = status?.restoredPair;
497
+ return Boolean(transaction?.id && status?.transaction?.id === transaction.id
498
+ && status.transaction.state === 'rolled_back' && status.activeVersion === transaction.sourceVersion
499
+ && status.installedAligned === true && pair?.extensionVersion === transaction.sourceVersion
500
+ && pair?.nativeVersion === transaction.sourceVersion
501
+ && /^[0-9a-f]{64}$/.test(pair.extensionSha256 || '') && /^[0-9a-f]{64}$/.test(pair.nativeSha256 || '')
502
+ && (!(transaction.bootstrapRevision || status.transaction.bootstrapRevision || expectedPair?.bootstrapSha256)
503
+ || (/^[0-9a-f]{64}$/.test(pair.bootstrapSha256 || '')
504
+ && (!expectedPair || pair.bootstrapSha256 === expectedPair.bootstrapSha256)))
505
+ && (!expectedPair || ['extensionVersion', 'nativeVersion', 'extensionSha256', 'nativeSha256']
506
+ .every(key => pair[key] === expectedPair[key])));
507
+ }
508
+
468
509
  async function reloadPendingOverleafTabs() {
469
510
  const tabIds = await getPendingOverleafTabIds();
470
511
  await chrome.storage.local.remove(UPDATE_RELOAD_TABS_KEY);
@@ -485,6 +526,8 @@ async function postponeUpdate() {
485
526
  }
486
527
 
487
528
  async function requestInternal(payload) {
529
+ if (payload?.method === 'update.status') payload = { ...payload,
530
+ params: { ...payload.params, bootstrapRevision: String(globalThis.__CODEX_OVERLEAF_BOOTSTRAP_REVISION__ || '') } };
488
531
  if (globalThis.CodexOverleafNativeBridge?.requestInternal) {
489
532
  return globalThis.CodexOverleafNativeBridge.requestInternal({
490
533
  id: crypto.randomUUID(),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Codex Overleaf Link",
4
- "version": "2.5.0",
4
+ "version": "2.6.0",
5
5
  "description": "Connect the active Overleaf project to a local Codex bridge.",
6
6
  "icons": {
7
7
  "16": "assets/icons/icon16.png",
@@ -13,6 +13,7 @@
13
13
  <main id="popup-shell" data-bootstrap-shell>
14
14
  <p class="popup-note">Codex Overleaf Link could not load its runtime. Rerun the installer, then reload the extension.</p>
15
15
  </main>
16
+ <script src="popupFallback.js"></script>
16
17
  <script src="../runtime/src/shared/compatibility.js"></script>
17
18
  <script src="../runtime/src/popup.js"></script>
18
19
  <script src="updateStatus.js"></script>
@@ -0,0 +1,55 @@
1
+ (function localizePopupFallback() {
2
+ 'use strict';
3
+
4
+ const preferenceKeys = ['codexOverleafGlobalPrefsV1', 'codexOverleafPrefs'];
5
+ let revision = 0;
6
+ let recoveryReloaded = false;
7
+
8
+ async function refreshFallback() {
9
+ const requestRevision = ++revision;
10
+ let preferences = {};
11
+ try {
12
+ const stored = await chrome.storage.local.get(preferenceKeys);
13
+ preferences = stored.codexOverleafGlobalPrefsV1?.values || stored.codexOverleafPrefs || {};
14
+ } catch (_) { /* A missing language preference uses the product default. */ }
15
+ if (requestRevision !== revision) return;
16
+ const shell = document.querySelector('[data-bootstrap-shell]');
17
+ const message = shell?.querySelector('p');
18
+ // The healthy runtime replaces this shell. Late preference reads must
19
+ // never change the runtime's content or its current language.
20
+ if (!message) return;
21
+ const chinese = preferences.locale === 'zh';
22
+ document.documentElement.lang = chinese ? 'zh-CN' : 'en';
23
+ message.textContent = chinese
24
+ ? 'Codex Overleaf Link 无法加载运行组件。请重新运行安装程序,再重新加载扩展。'
25
+ : 'Codex Overleaf Link could not load its runtime. Rerun the installer, then reload the extension.';
26
+ }
27
+
28
+ chrome.storage.onChanged.addListener((changes, area) => {
29
+ if (area === 'local' && preferenceKeys.some(key => changes[key])) refreshFallback();
30
+ });
31
+ refreshFallback();
32
+
33
+ // This independent extension page can still start when the worker/runtime
34
+ // cannot. Native decides whether a persisted migration needs recovery; the
35
+ // popup never guesses a transaction or sends an unbound rollback request.
36
+ document.addEventListener?.('DOMContentLoaded', () => {
37
+ setTimeout(() => {
38
+ if (!document.querySelector('[data-bootstrap-shell]') || !chrome.runtime?.sendNativeMessage) return;
39
+ chrome.runtime.sendNativeMessage('com.codex.overleaf', {
40
+ id: crypto.randomUUID(), method: 'update.status', params: { bootstrapRecovery: true }
41
+ }, response => {
42
+ if (chrome.runtime.lastError || recoveryReloaded || !document.querySelector('[data-bootstrap-shell]')) return;
43
+ const status = response?.ok ? response.result : null;
44
+ const transaction = status?.transaction;
45
+ const pair = status?.restoredPair;
46
+ if (!transaction?.id || transaction.state !== 'rolled_back' || !transaction.sourceVersion
47
+ || status.activeVersion !== transaction.sourceVersion || status.installedAligned !== true
48
+ || pair?.extensionVersion !== transaction.sourceVersion || pair?.nativeVersion !== transaction.sourceVersion
49
+ || !['extensionSha256', 'nativeSha256', 'bootstrapSha256'].every(key => /^[0-9a-f]{64}$/.test(pair[key] || ''))) return;
50
+ recoveryReloaded = true;
51
+ chrome.runtime.reload();
52
+ });
53
+ }, 250);
54
+ }, { once: true });
55
+ })();
@@ -17,6 +17,7 @@
17
17
  tab_not_idle: 'An Overleaf tab is still busy.',
18
18
  native_project_locked: 'The native host still holds a project lock.',
19
19
  native_run_active: 'The native host is still processing a Codex run.',
20
+ native_process_stop_unconfirmed: 'A previous Codex process has not yet confirmed its exit.',
20
21
  native_gate_unavailable: 'The native host could not report whether it is idle.',
21
22
  native_not_idle: 'The native host is still busy.',
22
23
  busy: 'An update safety check is still busy.'