codex-overleaf-link 2.3.5 → 2.3.6

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 (33) hide show
  1. package/README.md +31 -24
  2. package/extension/bootstrap/manifest.template.json +1 -1
  3. package/extension/src/background.js +4 -0
  4. package/extension/src/backgroundUpdateCoordinator.js +88 -4
  5. package/extension/src/content/contentRuntime.js +24 -7
  6. package/extension/src/content/diagnosticsController.js +13 -3
  7. package/extension/src/content/diagnosticsPanel.js +1 -1
  8. package/extension/src/content/generated/content.bundle.js +848 -245
  9. package/extension/src/content/generated/content.bundle.meta.json +6 -3
  10. package/extension/src/content/legacyGlobalRegistry.js +2 -0
  11. package/extension/src/content/otWarmMirror.js +95 -65
  12. package/extension/src/content/otWarmMirrorController.js +102 -1
  13. package/extension/src/content/panelMaintenance.js +26 -15
  14. package/extension/src/content/providerSettingsCoordinator.js +1 -0
  15. package/extension/src/content/runFailureNotice.js +104 -0
  16. package/extension/src/content/runScrollLayout.js +124 -0
  17. package/extension/src/content/runTimelineView.js +36 -10
  18. package/extension/src/content/settingsPanel.js +28 -11
  19. package/extension/src/content/updateNotice.js +24 -4
  20. package/extension/src/page/overleafRealtimeObserver.js +116 -24
  21. package/extension/src/shared/compatibility.js +1 -1
  22. package/extension/src/shared/i18n.js +77 -37
  23. package/extension/src/shared/managedUpdateProjection.js +1 -1
  24. package/extension/src/shared/otText.js +0 -1
  25. package/extension/src/shared/sessionState.js +17 -21
  26. package/extension/src/shared/sessionTitle.js +120 -0
  27. package/extension/src/shared/updateRuntimeIdentity.js +32 -0
  28. package/extension/styles/panel.css +73 -14
  29. package/native-host/src/mirrorWorkspace.js +20 -1
  30. package/native-host/src/releaseProxy.js +177 -0
  31. package/native-host/src/releaseTransport.js +154 -0
  32. package/native-host/src/updateManager.js +40 -39
  33. package/package.json +1 -1
@@ -3895,7 +3895,7 @@ ${block}`;
3895
3895
  return sha256Hex(utf8Bytes(value));
3896
3896
  }
3897
3897
  function normalizePath(value) {
3898
- return String(value || "").replace(/\s+/g, " ").replace(/\\/g, "/").trim().replace(/^\/+/, "");
3898
+ return String(value || "").replace(/\\/g, "/").trim().replace(/^\/+/, "");
3899
3899
  }
3900
3900
  function normalizeText(value) {
3901
3901
  return String(value ?? "");
@@ -4114,20 +4114,31 @@ ${block}`;
4114
4114
  diagnosticsPageSubtitle: "Current file, write access, track changes",
4115
4115
  diagnosticsSnapshotTitle: "Check Project Read",
4116
4116
  diagnosticsSnapshotSubtitle: "Full project, assets, read source",
4117
- diagnosticsOtTitle: "Check Experimental OT Mirror",
4117
+ diagnosticsOtTitle: "Check OT Mirror",
4118
4118
  diagnosticsOtSubtitle: "Status, fresh files, fallback",
4119
4119
  diagnosticsExportTitle: "Export Diagnostics",
4120
4120
  diagnosticsExportSubtitle: "Redacted audit and environment bundle",
4121
4121
  diagnosticsExportDone: "Diagnostics bundle exported.",
4122
- diagnosticsOtSummaryEnabled: "Experimental OT is enabled. Codex will use the OT-warmed mirror only when matching files are fresh; otherwise it falls back to the normal project read path.",
4123
- diagnosticsOtSummaryDisabled: "Experimental OT is disabled, so Codex is using the normal project read path.",
4124
- diagnosticsOtNextStep: "If you expected OT warm reads, turn on OT and wait for the status to show Live before relying on it.",
4125
- experimentalOtMenuTitle: "Experimental OT Mirror",
4126
- experimentalOtMenuSubtitle: "Experimental \u2014 speeds up reading the file you are editing; Codex falls back to normal reading whenever unsure.",
4127
- experimentalOtConfirmTitle: "Experimental OT Mirror",
4128
- experimentalOtConfirmMessage: "Experimental: tracks the current Overleaf editor and warms the local mirror so Codex can read recent focused-file edits faster. Codex uses it only when file scope is clear and the mirror is fresh; otherwise it falls back to normal project reading.",
4122
+ diagnosticsOtSummaryEnabled: "OT Mirror is enabled. Codex will use the OT-warmed mirror only when matching files are fresh; otherwise it falls back to the normal project read path.",
4123
+ diagnosticsOtSummaryDisabled: "OT Mirror is disabled, so Codex is using the normal project read path.",
4124
+ diagnosticsOtNextStep: "Observer status describes warming availability. File scope and freshness are checked again before each run.",
4125
+ experimentalOtMenuTitle: "OT Mirror",
4126
+ otSettingsTitle: "Project cache",
4127
+ contextLoadingTitle: "Context loading",
4128
+ runFeedbackFailedTitle: "Needs attention",
4129
+ runFeedbackPartialTitle: "Partially completed",
4130
+ runFeedbackUnconfirmedTitle: "Write status needs review",
4131
+ runFeedbackGeneric: "Open the run details for the reported cause and the next step.",
4132
+ runFeedbackUnconfirmed: "Some changes may already be in Overleaf. Check the document before retrying.",
4133
+ runFeedbackUnconfirmedResult: "Not fully confirmed. Review Overleaf before retrying.",
4134
+ runFeedbackReviewFile: "Review {file} in Overleaf",
4135
+ runFeedbackReviewDetails: "Review run details",
4136
+ runFeedbackDetailsUnavailable: "Detailed steps are unavailable for this older run.",
4137
+ experimentalOtMenuSubtitle: "Warms recent edits to the active text file locally. File scope and freshness are checked before reuse.",
4138
+ experimentalOtConfirmTitle: "Enable OT Mirror?",
4139
+ experimentalOtConfirmMessage: "Observes the active text editor and warms its local mirror. This is read-only with respect to Overleaf and does not upload assets. Each run checks file scope and freshness before reuse; normal project reading remains the fallback.",
4129
4140
  experimentalOtConfirmEnable: "Turn on",
4130
- experimentalOtEnabledToast: "Experimental OT Mirror is on. Use @file for the cleanest warm-mirror test.",
4141
+ experimentalOtEnabledToast: "OT Mirror requested for this project. Its status shows whether warming is available.",
4131
4142
  diagnosticsSnapshotLoading: "Checking whether the extension can read the full Overleaf project.",
4132
4143
  diagnosticsSnapshotErrorSummary: "Overleaf may still be loading, or the page API did not return project files yet.",
4133
4144
  diagnosticsNativeLoading: "Checking whether local Codex, Native Host, and LaTeX tools are available.",
@@ -4400,18 +4411,27 @@ ${block}`;
4400
4411
  requireReviewingTitle: "When enabled, Codex checks or switches Overleaf Reviewing/Track Changes before writing. Deletes still require confirmation.",
4401
4412
  autoCompile: "Compile",
4402
4413
  autoCompileTitle: "After Codex writes, click Overleaf Recompile and record the compile result for this task. Ask mode will not trigger it.",
4403
- experimentalOtWarmMirror: "Experimental OT warm mirror",
4414
+ experimentalOtWarmMirror: "OT warm mirror",
4404
4415
  experimentalOtWarmMirrorShort: "OT",
4405
- experimentalOtWarmMirrorTitle: "Experimental read-only OT mirror warming. If unavailable, stale, or inconsistent, Codex falls back to the normal project read path.",
4416
+ experimentalOtWarmMirrorTitle: "Read-only local text warming. File scope and freshness are checked before reuse; normal project reading remains the fallback.",
4406
4417
  otStatus: "OT status",
4407
- otFreshFiles: "OT fresh files",
4408
- otFallback: "Fallback",
4418
+ otFreshFiles: "Files with recent OT evidence",
4419
+ otFallback: "Read fallback",
4409
4420
  otStatusOff: "Off",
4410
- otStatusStarting: "Start",
4411
- otStatusObserving: "Live",
4412
- otStatusUnavailable: "N/A",
4413
- otStatusStale: "Stale",
4414
- otStatusInconsistent: "Check",
4421
+ otStatusStarting: "Connecting",
4422
+ otStatusObserving: "Observing current editor",
4423
+ otStatusUnavailable: "Unavailable",
4424
+ otStatusStale: "Warming paused; awaiting verification",
4425
+ otStatusInconsistent: "Needs verification",
4426
+ otFailureBridge: "The page connection needs to be restored. Reload the extension and Overleaf before retrying.",
4427
+ otFailureObserver: "The editor observer is unavailable. The next run will try normal project reading.",
4428
+ otFailureEditor: "The active editor could not be read. Warming is paused; the next run will try normal project reading.",
4429
+ otFailureFileLimit: "This file exceeds the 1 MiB warming limit. The next run will try normal project reading.",
4430
+ otFailureQueueLimit: "The mirror queue reached its limit. Warming is paused; the next run will try normal project reading.",
4431
+ otFailureExpired: "The observation is too old to reuse. The next run will try normal project reading.",
4432
+ otFailureMirror: "The mirror update was not fully confirmed. The next run will try normal project reading.",
4433
+ otFailureGeneric: "Mirror warming could not continue. The next run will try normal project reading.",
4434
+ otFailureNextStep: "Resolve the reported cause, then enable OT again. If the page connection is unavailable, reload the extension and Overleaf first.",
4415
4435
  modelSourceFallback: "fallback",
4416
4436
  modelSourceDiscovered: "discovered",
4417
4437
  modelSourceFailed: "failed",
@@ -4634,20 +4654,31 @@ ${block}`;
4634
4654
  diagnosticsPageSubtitle: "\u5F53\u524D\u6587\u4EF6\u3001\u5199\u5165\u80FD\u529B\u3001\u7559\u75D5\u72B6\u6001",
4635
4655
  diagnosticsSnapshotTitle: "\u68C0\u67E5\u9879\u76EE\u8BFB\u53D6",
4636
4656
  diagnosticsSnapshotSubtitle: "\u5B8C\u6574\u9879\u76EE\u3001\u8D44\u6E90\u6587\u4EF6\u3001\u8BFB\u53D6\u6765\u6E90",
4637
- diagnosticsOtTitle: "\u68C0\u67E5\u5B9E\u9A8C\u6027 OT Mirror",
4657
+ diagnosticsOtTitle: "\u68C0\u67E5 OT Mirror",
4638
4658
  diagnosticsOtSubtitle: "\u72B6\u6001\u3001\u65B0\u9C9C\u6587\u4EF6\u3001\u56DE\u9000\u8DEF\u5F84",
4639
4659
  diagnosticsExportTitle: "\u5BFC\u51FA\u8BCA\u65AD\u4FE1\u606F",
4640
4660
  diagnosticsExportSubtitle: "\u5DF2\u8131\u654F\u7684\u5BA1\u8BA1\u548C\u73AF\u5883\u4FE1\u606F\u5305",
4641
4661
  diagnosticsExportDone: "\u8BCA\u65AD\u4FE1\u606F\u5DF2\u5BFC\u51FA\u3002",
4642
- diagnosticsOtSummaryEnabled: "\u5B9E\u9A8C\u6027 OT \u5DF2\u5F00\u542F\u3002\u53EA\u6709\u5339\u914D\u6587\u4EF6\u662F\u65B0\u9C9C\u72B6\u6001\u65F6\uFF0CCodex \u624D\u4F1A\u4F7F\u7528 OT \u9884\u70ED mirror\uFF1B\u5426\u5219\u4F1A\u56DE\u9000\u5230\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u8DEF\u5F84\u3002",
4643
- diagnosticsOtSummaryDisabled: "\u5B9E\u9A8C\u6027 OT \u5DF2\u5173\u95ED\uFF0CCodex \u4F1A\u4F7F\u7528\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u8DEF\u5F84\u3002",
4644
- diagnosticsOtNextStep: "\u5982\u679C\u4F60\u5E0C\u671B\u4F7F\u7528 OT \u9884\u70ED\u8BFB\u53D6\uFF0C\u8BF7\u5F00\u542F OT\uFF0C\u5E76\u7B49\u72B6\u6001\u663E\u793A\u4E3A\u201C\u5B9E\u65F6\u201D\u540E\u518D\u4F9D\u8D56\u5B83\u3002",
4645
- experimentalOtMenuTitle: "\u5B9E\u9A8C\u6027 OT Mirror",
4646
- experimentalOtMenuSubtitle: "\u5B9E\u9A8C\u6027\u2014\u2014\u52A0\u5FEB\u8BFB\u53D6\u4F60\u6B63\u5728\u7F16\u8F91\u7684\u6587\u4EF6\uFF1B\u62FF\u4E0D\u51C6\u65F6\u81EA\u52A8\u56DE\u9000\u5230\u666E\u901A\u8BFB\u53D6\u3002",
4647
- experimentalOtConfirmTitle: "\u5B9E\u9A8C\u6027 OT Mirror",
4648
- experimentalOtConfirmMessage: "\u5B9E\u9A8C\u6027\uFF1A\u5B9E\u65F6\u8DDF\u8E2A\u5F53\u524D Overleaf \u7F16\u8F91\u5668\uFF0C\u628A\u6539\u52A8\u9884\u70ED\u5230\u672C\u5730 mirror\uFF0C\u8BA9 Codex \u66F4\u5FEB\u8BFB\u5230\u6700\u8FD1\u7684\u5F53\u524D\u6587\u4EF6\u6539\u52A8\u3002\u53EA\u6709\u6587\u4EF6\u8303\u56F4\u660E\u786E\u4E14 mirror \u65B0\u9C9C\u65F6\u624D\u4F1A\u4F7F\u7528\uFF1B\u5426\u5219\u81EA\u52A8\u56DE\u9000\u5230\u666E\u901A\u9879\u76EE\u8BFB\u53D6\u3002",
4662
+ diagnosticsOtSummaryEnabled: "OT Mirror \u5DF2\u5F00\u542F\u3002\u53EA\u6709\u5339\u914D\u6587\u4EF6\u662F\u65B0\u9C9C\u72B6\u6001\u65F6\uFF0CCodex \u624D\u4F1A\u4F7F\u7528 OT \u9884\u70ED\u955C\u50CF\uFF1B\u5426\u5219\u4F1A\u56DE\u9000\u5230\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u8DEF\u5F84\u3002",
4663
+ diagnosticsOtSummaryDisabled: "OT Mirror \u5DF2\u5173\u95ED\uFF0CCodex \u4F1A\u4F7F\u7528\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u8DEF\u5F84\u3002",
4664
+ diagnosticsOtNextStep: "\u89C2\u6D4B\u72B6\u6001\u8BF4\u660E\u9884\u70ED\u662F\u5426\u53EF\u7528\uFF1B\u6BCF\u6B21\u4EFB\u52A1\u5F00\u59CB\u524D\u4ECD\u4F1A\u91CD\u65B0\u6821\u9A8C\u6587\u4EF6\u8303\u56F4\u548C\u65B0\u9C9C\u5EA6\u3002",
4665
+ experimentalOtMenuTitle: "OT Mirror",
4666
+ otSettingsTitle: "\u9879\u76EE\u7F13\u5B58",
4667
+ contextLoadingTitle: "\u4E0A\u4E0B\u6587\u52A0\u8F7D",
4668
+ runFeedbackFailedTitle: "\u9700\u8981\u5904\u7406",
4669
+ runFeedbackPartialTitle: "\u90E8\u5206\u5B8C\u6210",
4670
+ runFeedbackUnconfirmedTitle: "\u5199\u5165\u72B6\u6001\u5F85\u786E\u8BA4",
4671
+ runFeedbackGeneric: "\u53EF\u5728\u672C\u8F6E\u8BE6\u60C5\u4E2D\u67E5\u770B\u5177\u4F53\u539F\u56E0\u548C\u540E\u7EED\u5904\u7406\u65B9\u5F0F\u3002",
4672
+ runFeedbackUnconfirmed: "\u90E8\u5206\u6539\u52A8\u53EF\u80FD\u5DF2\u7ECF\u5199\u5165 Overleaf\uFF0C\u91CD\u8BD5\u524D\u8BF7\u5148\u68C0\u67E5\u6587\u6863\u3002",
4673
+ runFeedbackUnconfirmedResult: "\u7ED3\u679C\u5C1A\u672A\u5B8C\u5168\u786E\u8BA4\uFF0C\u8BF7\u68C0\u67E5 Overleaf \u540E\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002",
4674
+ runFeedbackReviewFile: "\u5728 Overleaf \u68C0\u67E5 {file}",
4675
+ runFeedbackReviewDetails: "\u67E5\u770B\u8FD0\u884C\u6B65\u9AA4",
4676
+ runFeedbackDetailsUnavailable: "\u8FD9\u6761\u5386\u53F2\u8BB0\u5F55\u6CA1\u6709\u53EF\u5C55\u5F00\u7684\u8BE6\u7EC6\u6B65\u9AA4\u3002",
4677
+ experimentalOtMenuSubtitle: "\u5728\u672C\u5730\u9884\u70ED\u5F53\u524D\u6587\u672C\u6587\u4EF6\u7684\u6700\u8FD1\u6539\u52A8\uFF0C\u590D\u7528\u524D\u91CD\u65B0\u6821\u9A8C\u6587\u4EF6\u8303\u56F4\u548C\u65B0\u9C9C\u5EA6\u3002",
4678
+ experimentalOtConfirmTitle: "\u5F00\u542F OT Mirror\uFF1F",
4679
+ experimentalOtConfirmMessage: "\u89C2\u6D4B\u5F53\u524D\u6587\u672C\u7F16\u8F91\u5668\u5E76\u9884\u70ED\u672C\u5730\u955C\u50CF\u3002\u6B64\u529F\u80FD\u4E0D\u4F1A\u5199\u56DE Overleaf\uFF0C\u4E5F\u4E0D\u8D1F\u8D23\u4E0A\u4F20\u8D44\u4EA7\u3002\u6BCF\u6B21\u4EFB\u52A1\u590D\u7528\u524D\u90FD\u4F1A\u6821\u9A8C\u6587\u4EF6\u8303\u56F4\u548C\u65B0\u9C9C\u5EA6\uFF0C\u4E0D\u6EE1\u8DB3\u6761\u4EF6\u65F6\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4649
4680
  experimentalOtConfirmEnable: "\u5F00\u542F",
4650
- experimentalOtEnabledToast: "\u5B9E\u9A8C\u6027 OT Mirror \u5DF2\u5F00\u542F\u3002\u4F7F\u7528 @file \u53EF\u4EE5\u6700\u6E05\u695A\u5730\u6D4B\u8BD5 warm mirror\u3002",
4681
+ experimentalOtEnabledToast: "\u5DF2\u4E3A\u5F53\u524D\u9879\u76EE\u8BF7\u6C42\u5F00\u542F OT Mirror\uFF0C\u53EF\u7528\u60C5\u51B5\u89C1\u72B6\u6001\u63D0\u793A\u3002",
4651
4682
  diagnosticsSnapshotLoading: "\u786E\u8BA4\u63D2\u4EF6\u80FD\u5426\u8BFB\u53D6\u5B8C\u6574 Overleaf \u9879\u76EE\u3002",
4652
4683
  diagnosticsSnapshotErrorSummary: "\u8FD9\u901A\u5E38\u662F Overleaf \u9875\u9762\u8FD8\u6CA1\u52A0\u8F7D\u5B8C\u6210\uFF0C\u6216\u8005\u5F53\u524D\u9875\u9762\u63A5\u53E3\u6682\u65F6\u6CA1\u6709\u8FD4\u56DE\u9879\u76EE\u6587\u4EF6\u3002",
4653
4684
  diagnosticsNativeLoading: "\u786E\u8BA4\u672C\u673A Codex\u3001Native Host \u548C LaTeX \u5DE5\u5177\u662F\u5426\u53EF\u7528\u3002",
@@ -4920,18 +4951,27 @@ ${block}`;
4920
4951
  requireReviewingTitle: "\u5F00\u542F\u540E\uFF0C\u5199\u5165\u524D\u4F1A\u786E\u8BA4\u5E76\u5C1D\u8BD5\u5207\u5230 Overleaf Reviewing/Track Changes\uFF1B\u5220\u9664\u4ECD\u9700\u786E\u8BA4\u3002",
4921
4952
  autoCompile: "\u7F16\u8BD1",
4922
4953
  autoCompileTitle: "Codex \u5199\u5165\u540E\u81EA\u52A8\u70B9\u51FB Overleaf Recompile\uFF0C\u5E76\u628A\u7F16\u8BD1\u7ED3\u679C\u8BB0\u5F55\u5230\u672C\u8F6E\u4EFB\u52A1\u3002\u53EA\u95EE\u4E0D\u6539\u65F6\u4E0D\u4F1A\u89E6\u53D1\u3002",
4923
- experimentalOtWarmMirror: "\u5B9E\u9A8C\u6027 OT \u9884\u70ED\u955C\u50CF",
4954
+ experimentalOtWarmMirror: "OT \u9884\u70ED\u955C\u50CF",
4924
4955
  experimentalOtWarmMirrorShort: "OT",
4925
- experimentalOtWarmMirrorTitle: "\u5B9E\u9A8C\u6027\u53EA\u8BFB OT \u955C\u50CF\u9884\u70ED\uFF1B\u4E0D\u53EF\u7528\u3001\u8FC7\u671F\u6216\u4E0D\u4E00\u81F4\u65F6\u4F1A\u56DE\u9000\u5230\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4956
+ experimentalOtWarmMirrorTitle: "\u53EA\u8BFB\u672C\u5730\u6587\u672C\u9884\u70ED\uFF1B\u590D\u7528\u524D\u6821\u9A8C\u6587\u4EF6\u8303\u56F4\u548C\u65B0\u9C9C\u5EA6\uFF0C\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u4F5C\u4E3A\u56DE\u9000\u8DEF\u5F84\u3002",
4926
4957
  otStatus: "OT \u72B6\u6001",
4927
- otFreshFiles: "OT \u65B0\u9C9C\u6587\u4EF6",
4928
- otFallback: "\u56DE\u9000",
4929
- otStatusOff: "\u5173",
4930
- otStatusStarting: "\u542F\u52A8",
4931
- otStatusObserving: "\u5B9E\u65F6",
4932
- otStatusUnavailable: "\u4E0D\u53EF\u7528",
4933
- otStatusStale: "\u8FC7\u671F",
4934
- otStatusInconsistent: "\u9700\u68C0\u67E5",
4958
+ otFreshFiles: "\u8FD1\u671F\u6709 OT \u6821\u9A8C\u8BC1\u636E\u7684\u6587\u4EF6",
4959
+ otFallback: "\u8BFB\u53D6\u56DE\u9000",
4960
+ otStatusOff: "\u672A\u5F00\u542F",
4961
+ otStatusStarting: "\u6B63\u5728\u8FDE\u63A5",
4962
+ otStatusObserving: "\u6B63\u5728\u89C2\u6D4B\u5F53\u524D\u7F16\u8F91\u5668",
4963
+ otStatusUnavailable: "\u6682\u4E0D\u53EF\u7528",
4964
+ otStatusStale: "\u9884\u70ED\u6682\u7F13\uFF0C\u7B49\u5F85\u91CD\u65B0\u6821\u9A8C",
4965
+ otStatusInconsistent: "\u9700\u91CD\u65B0\u6821\u9A8C",
4966
+ otFailureBridge: "\u9875\u9762\u8FDE\u63A5\u9700\u8981\u6062\u590D\uFF0C\u8BF7\u5148\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55\u5E76\u5237\u65B0 Overleaf\uFF0C\u518D\u91CD\u8BD5\u3002",
4967
+ otFailureObserver: "\u7F16\u8F91\u5668\u89C2\u5BDF\u5668\u6682\u4E0D\u53EF\u7528\uFF0C\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4968
+ otFailureEditor: "\u5F53\u524D\u7F16\u8F91\u5668\u5185\u5BB9\u5C1A\u4E0D\u53EF\u8BFB\uFF0C\u9884\u70ED\u5DF2\u6682\u505C\uFF1B\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4969
+ otFailureFileLimit: "\u6587\u4EF6\u8D85\u8FC7 1 MiB \u9884\u70ED\u4E0A\u9650\uFF0C\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4970
+ otFailureQueueLimit: "\u955C\u50CF\u961F\u5217\u8FBE\u5230\u5BB9\u91CF\u4E0A\u9650\uFF0C\u9884\u70ED\u5DF2\u6682\u505C\uFF1B\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4971
+ otFailureExpired: "\u89C2\u6D4B\u8BB0\u5F55\u5DF2\u8FC7\u671F\uFF0C\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4972
+ otFailureMirror: "\u955C\u50CF\u66F4\u65B0\u5C1A\u672A\u5B8C\u6574\u786E\u8BA4\uFF0C\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4973
+ otFailureGeneric: "\u955C\u50CF\u9884\u70ED\u672A\u80FD\u7EE7\u7EED\uFF0C\u4E0B\u6B21\u4EFB\u52A1\u5C06\u5C1D\u8BD5\u5E38\u89C4\u9879\u76EE\u8BFB\u53D6\u3002",
4974
+ otFailureNextStep: "\u5904\u7406\u6240\u663E\u793A\u7684\u539F\u56E0\u540E\u91CD\u65B0\u5F00\u542F OT\uFF1B\u82E5\u9875\u9762\u8FDE\u63A5\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5148\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55\u5E76\u5237\u65B0 Overleaf\u3002",
4935
4975
  modelSourceFallback: "\u5907\u7528\u5217\u8868",
4936
4976
  modelSourceDiscovered: "\u5DF2\u53D1\u73B0",
4937
4977
  modelSourceFailed: "\u83B7\u53D6\u5931\u8D25",
@@ -8108,6 +8148,106 @@ ${block}`;
8108
8148
  });
8109
8149
  }).call(globalThis, void 0, void 0, void 0);
8110
8150
  (function runClassicContentModule27(module, exports, require2) {
8151
+ (function initSessionTitle(root, factory) {
8152
+ if (typeof module === "object" && module.exports) {
8153
+ module.exports = factory();
8154
+ } else {
8155
+ root.CodexOverleafModuleRegistry.define("SessionTitle", [], factory);
8156
+ }
8157
+ })(typeof globalThis !== "undefined" ? globalThis : window, function sessionTitleFactory() {
8158
+ "use strict";
8159
+ const INPUT_LIMIT = 12e3;
8160
+ const STORAGE_LIMIT = 80;
8161
+ const segmenter = typeof Intl !== "undefined" && typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
8162
+ const FILE_TOKEN = /@file:(?:"([^"]+)"|'([^']+)'|([^\s]+))/g;
8163
+ function derive(runs, task, options2 = {}) {
8164
+ let fallback = "";
8165
+ for (const run of Array.isArray(runs) ? runs : []) {
8166
+ const candidate = fromPrompt(run?.task, options2);
8167
+ fallback || (fallback = candidate);
8168
+ if (candidate && !isGeneric(candidate)) return candidate;
8169
+ }
8170
+ const draft = fromPrompt(task, options2);
8171
+ return draft && !isGeneric(draft) ? draft : fallback || draft;
8172
+ }
8173
+ function fromPrompt(value, { sanitize = (text) => text, maxChars = 24 } = {}) {
8174
+ if (typeof value !== "string" || !value.trim()) return "";
8175
+ const source = String(sanitize(value.slice(0, INPUT_LIMIT)) || "");
8176
+ let fence = null;
8177
+ let fallback = "";
8178
+ for (const rawLine of source.split(/\r?\n/)) {
8179
+ const line = rawLine.trim();
8180
+ const marker = /^(`{3,}|~{3,})(.*)$/.exec(line);
8181
+ if (marker) {
8182
+ if (!fence) {
8183
+ fence = marker[1];
8184
+ const language = marker[2].trim().match(/^[A-Za-z0-9_+-]{1,24}\b/)?.[0] || "code";
8185
+ fallback || (fallback = `${language} snippet`);
8186
+ } else if (marker[1][0] === fence[0] && marker[1].length >= fence.length && !marker[2].trim()) {
8187
+ fence = null;
8188
+ }
8189
+ continue;
8190
+ }
8191
+ if (fence || !line || /^>/.test(line)) continue;
8192
+ const withoutContext = line.replace(FILE_TOKEN, " ").replace(/@(context|compile-log)\b/g, " ").trim();
8193
+ const cleaned = cleanLine(line);
8194
+ if (!withoutContext || /^https?:\/\/\S+$/i.test(line)) {
8195
+ fallback || (fallback = cleaned);
8196
+ continue;
8197
+ }
8198
+ for (const sentence of cleaned.split(/[\u3002\uff01\uff1f]+/u)) {
8199
+ const candidate = sentence.trim().replace(/[,;:\uff0c\uff1b\uff1a]+$/u, "").trim();
8200
+ if (!/[\p{L}\p{N}]/u.test(candidate) || isScaffolding(candidate)) continue;
8201
+ fallback || (fallback = candidate);
8202
+ if (!isGeneric(candidate)) return shorten(candidate, maxChars);
8203
+ }
8204
+ }
8205
+ return shorten(fallback, maxChars);
8206
+ }
8207
+ function cleanLine(value) {
8208
+ return value.replace(/^#{1,6}\s+/, "").replace(/^(?:[-*+]\s+|\d+\.\s+|\d+[)\u3001]\s*)/, "").replace(FILE_TOKEN, (_match, quoted, singleQuoted, bare) => String(quoted || singleQuoted || bare || "").replace(/\\/g, "/").split("/").pop()).replace(/@(context|compile-log)\b/g, " ").replace(/!?\[([^\]]*)\]\([^\n)]*\)/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/https?:\/\/\S+/gi, (address) => {
8209
+ try {
8210
+ return new URL(address).hostname;
8211
+ } catch (_error) {
8212
+ return "";
8213
+ }
8214
+ }).replace(/\[(?:REDACTED_SECRET|local path(?::\d+)?)\]/gi, " ").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "").replace(/\s+/g, " ").trim().replace(/^(?:\u8bf7(?:\u4f60)?\u5e2e\u6211|\u8bf7\u4f60|\u5e2e\u6211|\u9ebb\u70e6\u4f60(?:\u5e2e\u6211)?|\u9ebb\u70e6\u5e2e\u6211|please\s+)\s*/i, "");
8215
+ }
8216
+ function isScaffolding(value) {
8217
+ return /^(?:my request(?: for [^:]+)?|request|task|context|files(?: mentioned by [^:]+)?|attachments|\u6211\u7684\u8bf7\u6c42|\u9700\u6c42|\u4efb\u52a1|\u4e0a\u4e0b\u6587|\u9644\u4ef6|\u6587\u4ef6)$/i.test(value);
8218
+ }
8219
+ function isGeneric(value) {
8220
+ const text = String(value || "").trim().replace(/[\s.!?\u3002\uff1f\uff01\u2026]+$/u, "");
8221
+ if (!text || Array.from(text).length < 2) return true;
8222
+ return /^(?:ok(?:ay)?|yes|no|go|done|continue|proceed|thanks?|thank you|hello|hi|test|new task|untitled task|\u597d(?:\u7684)?|\u53ef\u4ee5|\u7ee7\u7eed|\u786e\u8ba4|\u786e\u5b9a|\u6536\u5230|\u8c22\u8c22|\u6d4b\u8bd5|\u6267\u884c|\u662f\u7684|\u4f60\u597d)$/i.test(text) || /^[A-Za-z0-9_+-]{1,24} snippet$/i.test(text) || /^[^\s]+\.(?:tex|bib|md|txt|pdf|svg|png|jpe?g|webp)(?::\d+)?$/i.test(text) || /^(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}$/i.test(text);
8223
+ }
8224
+ function shorten(value, maxChars) {
8225
+ const title = String(value || "").trim();
8226
+ if (!title) return "";
8227
+ const chars = Number.isFinite(maxChars) && maxChars > 0 ? Math.min(40, Math.floor(maxChars)) : 24;
8228
+ const maxUnits = chars * 2;
8229
+ const glyphs = segmenter ? Array.from(segmenter.segment(title), (item) => item.segment) : Array.from(title);
8230
+ const width = (glyph) => /[^\u0000-\u00ff]/u.test(glyph) ? 2 : 1;
8231
+ if (title.length <= STORAGE_LIMIT && glyphs.reduce((total, glyph) => total + width(glyph), 0) <= maxUnits) return title;
8232
+ let prefix = "";
8233
+ let units = 0;
8234
+ let index = 0;
8235
+ for (; index < glyphs.length; index++) {
8236
+ const glyph = glyphs[index];
8237
+ if (units + width(glyph) > maxUnits - 2 || prefix.length + glyph.length > STORAGE_LIMIT - 1) break;
8238
+ prefix += glyph;
8239
+ units += width(glyph);
8240
+ }
8241
+ const boundary = prefix.lastIndexOf(" ");
8242
+ if (/[A-Za-z0-9]$/.test(prefix) && /^[A-Za-z0-9]/.test(glyphs[index] || "") && boundary >= prefix.length * 0.6) {
8243
+ prefix = prefix.slice(0, boundary);
8244
+ }
8245
+ return prefix.trimEnd().replace(/[,;:\uff0c\uff1b\uff1a]+$/u, "") + "\u2026";
8246
+ }
8247
+ return Object.freeze({ derive, fromPrompt, isGeneric });
8248
+ });
8249
+ }).call(globalThis, void 0, void 0, void 0);
8250
+ (function runClassicContentModule28(module, exports, require2) {
8111
8251
  (function initSessionState(root, factory) {
8112
8252
  if (typeof module === "object" && module.exports) {
8113
8253
  module.exports = factory(
@@ -8115,16 +8255,17 @@ ${block}`;
8115
8255
  require2("./settlementFacts"),
8116
8256
  require2("./runInputQueue"),
8117
8257
  require2("./lineReferences"),
8118
- require2("./pathRedaction")
8258
+ require2("./pathRedaction"),
8259
+ require2("./sessionTitle")
8119
8260
  );
8120
8261
  } else {
8121
8262
  root.CodexOverleafModuleRegistry.define(
8122
8263
  "SessionState",
8123
- ["I18n", "SettlementFacts", "RunInputQueue", "LineReferences", "PathRedaction"],
8264
+ ["I18n", "SettlementFacts", "RunInputQueue", "LineReferences", "PathRedaction", "SessionTitle"],
8124
8265
  factory
8125
8266
  );
8126
8267
  }
8127
- })(typeof globalThis !== "undefined" ? globalThis : window, function sessionStateFactory(i18n, SettlementFacts, RunInputQueue, LineReferences, PathRedaction) {
8268
+ })(typeof globalThis !== "undefined" ? globalThis : window, function sessionStateFactory(i18n, SettlementFacts, RunInputQueue, LineReferences, PathRedaction, SessionTitle) {
8128
8269
  "use strict";
8129
8270
  const DEFAULT_PANEL_STATE = {
8130
8271
  mode: "ask",
@@ -8446,6 +8587,9 @@ ${block}`;
8446
8587
  if (session.titleSource === "manual" && patch.titleSource !== "manual" && Object.prototype.hasOwnProperty.call(patch, "title")) {
8447
8588
  next.title = session.title;
8448
8589
  next.titleSource = "manual";
8590
+ } else if (session.titleSource === "auto" && patch.titleSource !== "manual" && typeof patch.title === "string" && patch.title.trim() && session.runs?.length && SessionTitle.isGeneric(sanitizeAutoTitle(patch.title)) && !SessionTitle.isGeneric(sanitizeAutoTitle(session.title))) {
8591
+ next.title = session.title;
8592
+ next.titleSource = "auto";
8449
8593
  }
8450
8594
  return normalizeSession({
8451
8595
  ...next
@@ -8507,12 +8651,7 @@ ${block}`;
8507
8651
  }, sessions[0]);
8508
8652
  }
8509
8653
  function deriveSessionTitle(runs, task) {
8510
- const taskTitle = sanitizeAutoTitle(task);
8511
- if (taskTitle) {
8512
- return taskTitle;
8513
- }
8514
- const firstRunTask = Array.isArray(runs) && runs.length ? runs[0]?.task : "";
8515
- return sanitizeAutoTitle(firstRunTask);
8654
+ return SessionTitle.derive(runs, task, { sanitize: sanitizeAssistantVisibleText, maxChars: SESSION_AUTO_TITLE_CHARS });
8516
8655
  }
8517
8656
  function renameSession(state, sessionId, rawTitle, options2 = {}) {
8518
8657
  const sessions = Array.isArray(state?.sessions) ? state.sessions : [];
@@ -8542,14 +8681,13 @@ ${block}`;
8542
8681
  if (titleSource === "manual") {
8543
8682
  return normalizeTextField(rawTitle === LEGACY_DEFAULT_SESSION_TITLE ? "" : rawTitle, STORAGE_DEFAULT_LIMITS.sessionTitleChars);
8544
8683
  }
8545
- return sanitizeAutoTitle(rawTitle === LEGACY_DEFAULT_SESSION_TITLE ? "" : rawTitle) || derivedTitle || "";
8684
+ const current = sanitizeAutoTitle(rawTitle === LEGACY_DEFAULT_SESSION_TITLE ? "" : rawTitle);
8685
+ if (!current || SessionTitle.isGeneric(current)) return derivedTitle || current || "";
8686
+ if (current.endsWith("\u2026") && derivedTitle.startsWith(current.slice(0, -1))) return derivedTitle;
8687
+ return current;
8546
8688
  }
8547
8689
  function sanitizeAutoTitle(value) {
8548
- const title = sanitizeAssistantVisibleText(value).replace(/@file:[^\s]+/g, " ").replace(/@(context|compile-log)\b/g, " ").replace(/\s+/g, " ").trim();
8549
- if (!title) {
8550
- return "";
8551
- }
8552
- return title.length > SESSION_AUTO_TITLE_CHARS ? `${title.slice(0, SESSION_AUTO_TITLE_CHARS - 1)}\u2026` : title;
8690
+ return SessionTitle.fromPrompt(value, { sanitize: sanitizeAssistantVisibleText, maxChars: SESSION_AUTO_TITLE_CHARS });
8553
8691
  }
8554
8692
  function isDisplayableSession(session) {
8555
8693
  if (!session?.id) {
@@ -9426,7 +9564,7 @@ ${block}`;
9426
9564
  };
9427
9565
  });
9428
9566
  }).call(globalThis, void 0, void 0, void 0);
9429
- (function runClassicContentModule28(module, exports, require2) {
9567
+ (function runClassicContentModule29(module, exports, require2) {
9430
9568
  (function initStorageKeys(root, factory) {
9431
9569
  if (typeof module === "object" && module.exports) {
9432
9570
  module.exports = factory();
@@ -9454,7 +9592,7 @@ ${block}`;
9454
9592
  };
9455
9593
  });
9456
9594
  }).call(globalThis, void 0, void 0, void 0);
9457
- (function runClassicContentModule29(module, exports, require2) {
9595
+ (function runClassicContentModule30(module, exports, require2) {
9458
9596
  (function initStaleGuard(root, factory) {
9459
9597
  if (typeof module === "object" && module.exports) {
9460
9598
  module.exports = factory();
@@ -9605,7 +9743,7 @@ ${block}`;
9605
9743
  };
9606
9744
  });
9607
9745
  }).call(globalThis, void 0, void 0, void 0);
9608
- (function runClassicContentModule30(module, exports, require2) {
9746
+ (function runClassicContentModule31(module, exports, require2) {
9609
9747
  (function initStorageRunActions(root, factory) {
9610
9748
  if (typeof module === "object" && module.exports) {
9611
9749
  module.exports = factory();
@@ -9734,7 +9872,7 @@ ${block}`;
9734
9872
  };
9735
9873
  });
9736
9874
  }).call(globalThis, void 0, void 0, void 0);
9737
- (function runClassicContentModule31(module, exports, require2) {
9875
+ (function runClassicContentModule32(module, exports, require2) {
9738
9876
  (function initStorageSessionClaims(root, factory) {
9739
9877
  var api = factory();
9740
9878
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -9800,7 +9938,7 @@ ${block}`;
9800
9938
  return Object.freeze({ createSessionClaimer });
9801
9939
  });
9802
9940
  }).call(globalThis, void 0, void 0, void 0);
9803
- (function runClassicContentModule32(module, exports, require2) {
9941
+ (function runClassicContentModule33(module, exports, require2) {
9804
9942
  (function initStorageDb(root, factory) {
9805
9943
  if (typeof module === "object" && module.exports) {
9806
9944
  module.exports = factory(
@@ -11025,7 +11163,7 @@ ${block}`;
11025
11163
  };
11026
11164
  });
11027
11165
  }).call(globalThis, void 0, void 0, void 0);
11028
- (function runClassicContentModule33(module, exports, require2) {
11166
+ (function runClassicContentModule34(module, exports, require2) {
11029
11167
  (function initStorageMigration(root, factory) {
11030
11168
  if (typeof module === "object" && module.exports) {
11031
11169
  module.exports = factory(require2("./storageDb"));
@@ -11480,7 +11618,7 @@ ${block}`;
11480
11618
  };
11481
11619
  });
11482
11620
  }).call(globalThis, void 0, void 0, void 0);
11483
- (function runClassicContentModule34(module, exports, require2) {
11621
+ (function runClassicContentModule35(module, exports, require2) {
11484
11622
  (function initCompileAdapter(root, factory) {
11485
11623
  if (typeof module === "object" && module.exports) {
11486
11624
  module.exports = factory();
@@ -11623,7 +11761,7 @@ ${block}`;
11623
11761
  };
11624
11762
  });
11625
11763
  }).call(globalThis, void 0, void 0, void 0);
11626
- (function runClassicContentModule35(module, exports, require2) {
11764
+ (function runClassicContentModule36(module, exports, require2) {
11627
11765
  (function initCodexOverleafCompatibility(root, factory) {
11628
11766
  if (typeof module === "object" && module.exports) {
11629
11767
  module.exports = factory();
@@ -11637,7 +11775,7 @@ ${block}`;
11637
11775
  const MIN_NATIVE_VERSION = "1.0.0";
11638
11776
  const MIN_COMPATIBLE_NATIVE_VERSION = "1.0.0";
11639
11777
  const MIN_COMPATIBLE_EXTENSION_VERSION = "1.0.0";
11640
- const BUILD_TARGET_VERSION = "2.3.5";
11778
+ const BUILD_TARGET_VERSION = "2.3.6";
11641
11779
  const DEFAULT_CHROME_EXTENSION_ID = "illdpneeeopfffmiepaejglgmhpmdhdc";
11642
11780
  const REQUIRED_CAPABILITIES = Object.freeze([
11643
11781
  "bridgePing",
@@ -11933,7 +12071,7 @@ ${block}`;
11933
12071
  };
11934
12072
  });
11935
12073
  }).call(globalThis, void 0, void 0, void 0);
11936
- (function runClassicContentModule36(module, exports, require2) {
12074
+ (function runClassicContentModule37(module, exports, require2) {
11937
12075
  (function(root, factory) {
11938
12076
  var api = factory();
11939
12077
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -12064,7 +12202,7 @@ ${block}`;
12064
12202
  });
12065
12203
  });
12066
12204
  }).call(globalThis, void 0, void 0, void 0);
12067
- (function runClassicContentModule37(module, exports, require2) {
12205
+ (function runClassicContentModule38(module, exports, require2) {
12068
12206
  (function initCodexOverleafManagedUpdateProjection(root) {
12069
12207
  "use strict";
12070
12208
  const PHASE_ALIASES = Object.freeze({
@@ -12090,7 +12228,7 @@ ${block}`;
12090
12228
  "deferred"
12091
12229
  ]);
12092
12230
  const PHASE_TIMEOUTS = Object.freeze({
12093
- checking: 30 * 1e3,
12231
+ checking: 60 * 1e3,
12094
12232
  downloading: 2 * 60 * 1e3,
12095
12233
  applying: 90 * 1e3,
12096
12234
  awaiting_health: 2 * 60 * 1e3,
@@ -12370,7 +12508,7 @@ ${block}`;
12370
12508
  });
12371
12509
  })(typeof window !== "undefined" ? window : globalThis);
12372
12510
  }).call(globalThis, void 0, void 0, void 0);
12373
- (function runClassicContentModule38(module, exports, require2) {
12511
+ (function runClassicContentModule39(module, exports, require2) {
12374
12512
  (function initGovernanceRules(root, factory) {
12375
12513
  if (typeof module === "object" && module.exports) {
12376
12514
  let projectFiles = null;
@@ -12587,7 +12725,7 @@ ${block}`;
12587
12725
  };
12588
12726
  });
12589
12727
  }).call(globalThis, void 0, void 0, void 0);
12590
- (function runClassicContentModule39(module, exports, require2) {
12728
+ (function runClassicContentModule40(module, exports, require2) {
12591
12729
  (function initSensitiveScan(root, factory) {
12592
12730
  if (typeof module === "object" && module.exports) {
12593
12731
  module.exports = factory();
@@ -12697,7 +12835,7 @@ ${block}`;
12697
12835
  };
12698
12836
  });
12699
12837
  }).call(globalThis, void 0, void 0, void 0);
12700
- (function runClassicContentModule40(module, exports, require2) {
12838
+ (function runClassicContentModule41(module, exports, require2) {
12701
12839
  (function initAuditRecords(root, factory) {
12702
12840
  if (typeof module === "object" && module.exports) {
12703
12841
  module.exports = factory();
@@ -13223,7 +13361,7 @@ ${block}`;
13223
13361
  };
13224
13362
  });
13225
13363
  }).call(globalThis, void 0, void 0, void 0);
13226
- (function runClassicContentModule41(module, exports, require2) {
13364
+ (function runClassicContentModule42(module, exports, require2) {
13227
13365
  (function initCodexOverleafNativeChannel(root, factory) {
13228
13366
  if (typeof module === "object" && module.exports) {
13229
13367
  module.exports = factory();
@@ -13302,7 +13440,7 @@ ${block}`;
13302
13440
  };
13303
13441
  });
13304
13442
  }).call(globalThis, void 0, void 0, void 0);
13305
- (function runClassicContentModule42(module, exports, require2) {
13443
+ (function runClassicContentModule43(module, exports, require2) {
13306
13444
  (function initCodexOverleafPageBridgeClient(root, factory) {
13307
13445
  const api = factory();
13308
13446
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -13505,7 +13643,7 @@ ${block}`;
13505
13643
  });
13506
13644
  });
13507
13645
  }).call(globalThis, void 0, void 0, void 0);
13508
- (function runClassicContentModule43(module, exports, require2) {
13646
+ (function runClassicContentModule44(module, exports, require2) {
13509
13647
  (function initCodexOverleafNativeCompatibilityController(root, factory) {
13510
13648
  const api = factory();
13511
13649
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -13784,7 +13922,7 @@ ${block}`;
13784
13922
  return Object.freeze({ create });
13785
13923
  });
13786
13924
  }).call(globalThis, void 0, void 0, void 0);
13787
- (function runClassicContentModule44(module, exports, require2) {
13925
+ (function runClassicContentModule45(module, exports, require2) {
13788
13926
  (function initCodexOverleafWritebackController(root, factory) {
13789
13927
  if (typeof module === "object" && module.exports) {
13790
13928
  module.exports = factory();
@@ -14049,7 +14187,7 @@ ${block}`;
14049
14187
  };
14050
14188
  });
14051
14189
  }).call(globalThis, void 0, void 0, void 0);
14052
- (function runClassicContentModule45(module, exports, require2) {
14190
+ (function runClassicContentModule46(module, exports, require2) {
14053
14191
  (function initCodexOverleafAssetTransferBroker(root, factory) {
14054
14192
  const api = factory();
14055
14193
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -14211,7 +14349,7 @@ ${block}`;
14211
14349
  return { create, mergeApplyResults };
14212
14350
  });
14213
14351
  }).call(globalThis, void 0, void 0, void 0);
14214
- (function runClassicContentModule46(module, exports, require2) {
14352
+ (function runClassicContentModule47(module, exports, require2) {
14215
14353
  (function initCodexOverleafReviewHunks(root, factory) {
14216
14354
  if (typeof module === "object" && module.exports) {
14217
14355
  module.exports = factory();
@@ -14430,7 +14568,7 @@ ${block}`;
14430
14568
  };
14431
14569
  });
14432
14570
  }).call(globalThis, void 0, void 0, void 0);
14433
- (function runClassicContentModule47(module, exports, require2) {
14571
+ (function runClassicContentModule48(module, exports, require2) {
14434
14572
  (function initCodexOverleafDiffReviewPanel(root, factory) {
14435
14573
  if (typeof module === "object" && module.exports) {
14436
14574
  module.exports = factory(require2("./reviewHunks"));
@@ -15157,7 +15295,7 @@ ${block}`;
15157
15295
  };
15158
15296
  });
15159
15297
  }).call(globalThis, void 0, void 0, void 0);
15160
- (function runClassicContentModule48(module, exports, require2) {
15298
+ (function runClassicContentModule49(module, exports, require2) {
15161
15299
  (function initCodexOverleafContextTray(root, factory) {
15162
15300
  if (typeof module === "object" && module.exports) {
15163
15301
  module.exports = factory(require2("../shared/projectFiles"));
@@ -15905,7 +16043,7 @@ ${block}`;
15905
16043
  };
15906
16044
  });
15907
16045
  }).call(globalThis, void 0, void 0, void 0);
15908
- (function runClassicContentModule49(module, exports, require2) {
16046
+ (function runClassicContentModule50(module, exports, require2) {
15909
16047
  (function initCodexOverleafLocalSkillsPanel(root, factory) {
15910
16048
  if (typeof module === "object" && module.exports) {
15911
16049
  module.exports = factory();
@@ -16136,7 +16274,7 @@ ${block}`;
16136
16274
  };
16137
16275
  });
16138
16276
  }).call(globalThis, void 0, void 0, void 0);
16139
- (function runClassicContentModule50(module, exports, require2) {
16277
+ (function runClassicContentModule51(module, exports, require2) {
16140
16278
  (function initCodexOverleafRunController(root, factory) {
16141
16279
  if (typeof module === "object" && module.exports) {
16142
16280
  module.exports = factory();
@@ -16366,7 +16504,7 @@ ${block}`;
16366
16504
  };
16367
16505
  });
16368
16506
  }).call(globalThis, void 0, void 0, void 0);
16369
- (function runClassicContentModule51(module, exports, require2) {
16507
+ (function runClassicContentModule52(module, exports, require2) {
16370
16508
  (function initCodexOverleafMirrorHealth(root, factory) {
16371
16509
  if (typeof module === "object" && module.exports) {
16372
16510
  module.exports = factory();
@@ -16450,7 +16588,7 @@ ${block}`;
16450
16588
  };
16451
16589
  });
16452
16590
  }).call(globalThis, void 0, void 0, void 0);
16453
- (function runClassicContentModule52(module, exports, require2) {
16591
+ (function runClassicContentModule53(module, exports, require2) {
16454
16592
  (function initCodexOverleafOtWarmMirrorController(root, factory) {
16455
16593
  if (typeof module === "object" && module.exports) {
16456
16594
  module.exports = factory();
@@ -16462,6 +16600,12 @@ ${block}`;
16462
16600
  const OT_POLL_INTERVAL_MS = 1e3;
16463
16601
  const OT_PATCH_DEBOUNCE_MS = 500;
16464
16602
  const OT_MAX_PATCH_BATCH = 25;
16603
+ const OT_FRESHNESS_MAX_AGE_MS = 3e4;
16604
+ const OT_MAX_FILE_BYTES = 1024 * 1024;
16605
+ const OT_MAX_PENDING_EVENTS = 64;
16606
+ const OT_MAX_PENDING_BYTES = 4 * 1024 * 1024;
16607
+ const OT_MAX_BATCH_BYTES = 2 * 1024 * 1024;
16608
+ const encoder = typeof TextEncoder === "function" ? new TextEncoder() : null;
16465
16609
  const PAUSE_STATES = /* @__PURE__ */ new Set(["running", "writing", "undoing", "compiling"]);
16466
16610
  function buildPatchFilesRequest({ projectId, events, nativeCompatibility } = {}) {
16467
16611
  const files = [];
@@ -16513,13 +16657,14 @@ ${block}`;
16513
16657
  }
16514
16658
  return { pause: false };
16515
16659
  }
16516
- function canUseOtWarmStart({ enabled, focusFiles, mirrorStatus } = {}) {
16660
+ function canUseOtWarmStart({ enabled, focusFiles, mirrorStatus, now = Date.now() } = {}) {
16517
16661
  if (!enabled) {
16518
16662
  return { ok: false, reason: "disabled" };
16519
16663
  }
16520
16664
  if (!mirrorStatus || mirrorStatus.exists !== true) {
16521
16665
  return { ok: false, reason: "mirror_missing" };
16522
16666
  }
16667
+ if (mirrorStatus.dirty === true) return { ok: false, reason: "mirror_dirty" };
16523
16668
  const normalizedFocusFiles = normalizePaths(focusFiles);
16524
16669
  if (!normalizedFocusFiles.length) {
16525
16670
  return { ok: false, reason: "no_focus_files" };
@@ -16529,6 +16674,8 @@ ${block}`;
16529
16674
  if (file?.state !== "fresh") {
16530
16675
  continue;
16531
16676
  }
16677
+ const age = now - Date.parse(file.observedAt ?? file.lastPatchAt ?? "");
16678
+ if (!Number.isFinite(age) || age < 0 || age > OT_FRESHNESS_MAX_AGE_MS) continue;
16532
16679
  const filePath = normalizePath(file.path);
16533
16680
  if (filePath) {
16534
16681
  freshFiles.add(filePath);
@@ -16544,6 +16691,88 @@ ${block}`;
16544
16691
  }
16545
16692
  return { ok: false, reason: "missing_ot_fresh_focus" };
16546
16693
  }
16694
+ function textBytes(value) {
16695
+ const text = String(value || "");
16696
+ return encoder ? encoder.encode(text).byteLength : text.length * 3;
16697
+ }
16698
+ function patchBytes(event) {
16699
+ return textBytes(event.nextContent) + textBytes(event.path) + 512;
16700
+ }
16701
+ function queuePatchEvents(queue, events, now = Date.now()) {
16702
+ if (!Array.isArray(events) || events.length > OT_MAX_PENDING_EVENTS) return { ok: false, reason: "ot_queue_limit" };
16703
+ const next = Array.isArray(queue) ? queue.slice() : [];
16704
+ let bytes = next.reduce((sum, event) => sum + patchBytes(event), 0);
16705
+ if (next.length > OT_MAX_PENDING_EVENTS || bytes > OT_MAX_PENDING_BYTES) return { ok: false, reason: "ot_queue_limit" };
16706
+ for (const input of events) {
16707
+ const path = normalizePath(input?.path);
16708
+ const time = typeof input?.observedAt === "number" ? input.observedAt : Date.parse(input?.observedAt || "");
16709
+ if (!isSafeRelativePath(path) || path.length > 1024 || typeof input?.nextContent !== "string" || typeof input.baseHash !== "string" || !input.baseHash || input.baseHash.length > 128) {
16710
+ return { ok: false, reason: "ot_event_invalid" };
16711
+ }
16712
+ if (!Number.isFinite(time) || now - time < 0 || now - time > OT_FRESHNESS_MAX_AGE_MS) return { ok: false, reason: "ot_event_expired" };
16713
+ if (textBytes(input.nextContent) > OT_MAX_FILE_BYTES) return { ok: false, reason: "ot_file_limit" };
16714
+ const event = {
16715
+ path,
16716
+ baseHash: input.baseHash,
16717
+ nextContent: input.nextContent,
16718
+ nextHash: typeof input.nextHash === "string" && input.nextHash.length <= 128 ? input.nextHash : "",
16719
+ observedAt: new Date(time).toISOString()
16720
+ };
16721
+ if (isPrimitiveMetadata(input.observedVersion) && String(input.observedVersion).length <= 128) event.observedVersion = input.observedVersion;
16722
+ const tail = next[next.length - 1];
16723
+ if (tail?.path === path && tail.nextHash && tail.nextHash === event.baseHash) {
16724
+ event.baseHash = tail.baseHash;
16725
+ bytes -= patchBytes(next.pop());
16726
+ }
16727
+ if (event.nextHash !== event.baseHash) {
16728
+ next.push(event);
16729
+ bytes += patchBytes(event);
16730
+ }
16731
+ if (next.length > OT_MAX_PENDING_EVENTS || bytes > OT_MAX_PENDING_BYTES) return { ok: false, reason: "ot_queue_limit" };
16732
+ }
16733
+ return { ok: true, queue: next, bytes };
16734
+ }
16735
+ function takePatchBatch(queue) {
16736
+ let bytes = 0;
16737
+ let count = 0;
16738
+ while (count < Math.min(queue.length, OT_MAX_PATCH_BATCH)) {
16739
+ const size = patchBytes(queue[count]);
16740
+ if (bytes + size > OT_MAX_BATCH_BYTES) break;
16741
+ bytes += size;
16742
+ count += 1;
16743
+ }
16744
+ return queue.splice(0, count);
16745
+ }
16746
+ function validatePatchReceipt(events, result = {}, now = Date.now()) {
16747
+ if (Array.isArray(result.skippedFiles) && result.skippedFiles.length || Number(result.skippedCount || 0) > 0) {
16748
+ return { ok: false, reason: "mirror_patch_skipped" };
16749
+ }
16750
+ if (!events.length || Number(result.appliedCount) !== events.length || !Array.isArray(result.appliedFiles) || result.appliedFiles.length !== events.length || !result.appliedFiles.every((file, index) => normalizePath(file?.path) === events[index].path && (!events[index].nextHash || file.hash === events[index].nextHash))) {
16751
+ return { ok: false, reason: "mirror_patch_invalid_result" };
16752
+ }
16753
+ if (events.some((event) => {
16754
+ const time = Date.parse(event.observedAt);
16755
+ return !Number.isFinite(time) || time > now || now - time > OT_FRESHNESS_MAX_AGE_MS;
16756
+ })) return { ok: false, reason: "ot_event_expired" };
16757
+ return { ok: true };
16758
+ }
16759
+ function normalizeFailureCode(value, fallback = "ot_error") {
16760
+ const code = typeof value === "string" ? value : value?.code;
16761
+ if (/^[a-z][a-z0-9_]{0,79}$/.test(code || "")) return code;
16762
+ if (/page bridge|capability|bridge timed out/i.test(String(code || ""))) return "ot_bridge_unavailable";
16763
+ return fallback;
16764
+ }
16765
+ function getFailureMessageKey(value) {
16766
+ const code = normalizeFailureCode(value);
16767
+ if (/bridge|ot_status|ot_events/.test(code)) return "otFailureBridge";
16768
+ if (/missing_ot_text|observer_create|observer_unavailable/.test(code)) return "otFailureObserver";
16769
+ if (code === "ot_file_limit") return "otFailureFileLimit";
16770
+ if (code === "ot_queue_limit") return "otFailureQueueLimit";
16771
+ if (code === "ot_event_expired") return "otFailureExpired";
16772
+ if (/editor|active_path|document/.test(code)) return "otFailureEditor";
16773
+ if (/mirror|hash|baseline/.test(code)) return "otFailureMirror";
16774
+ return "otFailureGeneric";
16775
+ }
16547
16776
  function normalizePath(value) {
16548
16777
  return String(value ?? "").trim().replace(/^@file:/i, "").trim().replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\/+/, "");
16549
16778
  }
@@ -16595,6 +16824,16 @@ ${block}`;
16595
16824
  OT_POLL_INTERVAL_MS,
16596
16825
  OT_PATCH_DEBOUNCE_MS,
16597
16826
  OT_MAX_PATCH_BATCH,
16827
+ OT_FRESHNESS_MAX_AGE_MS,
16828
+ OT_MAX_FILE_BYTES,
16829
+ OT_MAX_PENDING_EVENTS,
16830
+ OT_MAX_PENDING_BYTES,
16831
+ OT_MAX_BATCH_BYTES,
16832
+ queuePatchEvents,
16833
+ takePatchBatch,
16834
+ validatePatchReceipt,
16835
+ normalizeFailureCode,
16836
+ getFailureMessageKey,
16598
16837
  buildPatchFilesRequest,
16599
16838
  canUseOtWarmStart,
16600
16839
  normalizePath,
@@ -16603,7 +16842,7 @@ ${block}`;
16603
16842
  };
16604
16843
  });
16605
16844
  }).call(globalThis, void 0, void 0, void 0);
16606
- (function runClassicContentModule53(module, exports, require2) {
16845
+ (function runClassicContentModule54(module, exports, require2) {
16607
16846
  (function initComposerAttachments(global) {
16608
16847
  "use strict";
16609
16848
  function createComposerAttachmentController(options2 = {}) {
@@ -17063,7 +17302,7 @@ ${block}`;
17063
17302
  };
17064
17303
  })(window);
17065
17304
  }).call(globalThis, void 0, void 0, void 0);
17066
- (function runClassicContentModule54(module, exports, require2) {
17305
+ (function runClassicContentModule55(module, exports, require2) {
17067
17306
  (function initCodexOverleafPanelRenderer() {
17068
17307
  "use strict";
17069
17308
  const ROOT_CLASS = "codex-overleaf-panel-mounted";
@@ -17464,7 +17703,7 @@ ${block}`;
17464
17703
  };
17465
17704
  })();
17466
17705
  }).call(globalThis, void 0, void 0, void 0);
17467
- (function runClassicContentModule55(module, exports, require2) {
17706
+ (function runClassicContentModule56(module, exports, require2) {
17468
17707
  (function initCodexOverleafSessionPanel() {
17469
17708
  "use strict";
17470
17709
  function create(options2 = {}) {
@@ -17700,7 +17939,7 @@ ${block}`;
17700
17939
  };
17701
17940
  })();
17702
17941
  }).call(globalThis, void 0, void 0, void 0);
17703
- (function runClassicContentModule56(module, exports, require2) {
17942
+ (function runClassicContentModule57(module, exports, require2) {
17704
17943
  (function initCodexOverleafSettingsPanel() {
17705
17944
  "use strict";
17706
17945
  function codexIcon(name) {
@@ -17794,18 +18033,18 @@ ${block}`;
17794
18033
  </details>
17795
18034
  <details class="codex-set-group" data-set-group="experimental">
17796
18035
  <summary class="codex-set-group-head">
17797
- <span class="codex-set-group-title">${codexSetIcon("flask")}<span data-i18n="experimentalTitle">Experimental</span></span>
18036
+ <span class="codex-set-group-title">${codexSetIcon("database")}<span data-i18n="otSettingsTitle">Project cache</span></span>
17798
18037
  <span class="codex-set-saved" data-set-saved hidden>\u2713 <span data-i18n="settingsSaved">Saved</span></span>
17799
18038
  </summary>
17800
18039
  <div class="codex-set-card">
17801
18040
  <label class="codex-project-settings-row codex-project-settings-row--switch">
17802
18041
  <span class="codex-project-settings-row-label">
17803
- <span data-i18n="experimentalOtMenuTitle">Experimental OT Mirror</span>
17804
- <small class="codex-set-row-sub" data-i18n="experimentalOtMenuSubtitle">Experimental \u2014 speeds up reading the file you are editing; Codex falls back to normal reading whenever unsure.</small>
18042
+ <span data-i18n="experimentalOtMenuTitle">OT Mirror</span>
18043
+ <small class="codex-set-row-sub" data-i18n="experimentalOtMenuSubtitle">Warms recent edits to the active text file locally. File scope and freshness are checked before reuse.</small>
17805
18044
  </span>
17806
18045
  <input type="checkbox" class="codex-switch" data-experimental-ot>
17807
18046
  </label>
17808
- <p class="codex-set-row-help" data-experimental-ot-menu-status></p>
18047
+ <p class="codex-set-row-help" data-experimental-ot-menu-status aria-live="polite"></p>
17809
18048
  </div>
17810
18049
  </details>
17811
18050
  </div>
@@ -17858,17 +18097,25 @@ ${block}`;
17858
18097
  <button type="button" class="codex-set-btn" data-provider-settings-open data-i18n="providerSettingsConfigure">Configure</button>
17859
18098
  </div>
17860
18099
  </details>
18100
+ <details class="codex-set-group" data-set-group="context-loading" open>
18101
+ <summary class="codex-set-group-head">
18102
+ <span class="codex-set-group-title">${codexSetIcon("database")}<span data-i18n="contextLoadingTitle">Context loading</span></span>
18103
+ <span class="codex-set-saved" data-set-saved hidden>\u2713 <span data-i18n="settingsSaved">Saved</span></span>
18104
+ </summary>
18105
+ <div class="codex-set-card">
18106
+ <label class="codex-project-settings-row codex-project-settings-row--switch">
18107
+ <span class="codex-project-settings-row-label" data-i18n="preloadProjectContextTitle">Preload project context</span>
18108
+ <input type="checkbox" class="codex-switch" data-preload-project-context>
18109
+ </label>
18110
+ <p class="codex-set-row-help" data-i18n="preloadProjectContextDescription">Fetch the exact project file list in the background after an Overleaf project becomes idle.</p>
18111
+ </div>
18112
+ </details>
17861
18113
  <details class="codex-set-group" data-set-group="updates" open>
17862
18114
  <summary class="codex-set-group-head">
17863
18115
  <span class="codex-set-group-title">${codexSetIcon("software")}<span data-i18n="softwareUpdatesTitle">Software updates</span></span>
17864
18116
  </summary>
17865
18117
  <div class="codex-set-card" data-update-settings>
17866
18118
  <div class="codex-set-row">
17867
- <label class="codex-project-settings-row codex-project-settings-row--switch">
17868
- <span class="codex-project-settings-row-label" data-i18n="preloadProjectContextTitle">Preload project context</span>
17869
- <input type="checkbox" class="codex-switch" data-preload-project-context>
17870
- </label>
17871
- <p class="codex-set-row-help" data-i18n="preloadProjectContextDescription">Fetch the exact project file list in the background after an Overleaf project becomes idle.</p>
17872
18119
  <p class="codex-set-row-help" data-update-settings-summary data-i18n="softwareUpdatesHelp">Automatically checks signed stable releases for the Extension and Native Host.</p>
17873
18120
  <p class="codex-set-note" data-update-settings-state aria-live="polite" hidden></p>
17874
18121
  <button type="button" class="codex-set-btn" data-check-updates data-i18n="checkForUpdates">Check for updates</button>
@@ -17933,6 +18180,9 @@ ${block}`;
17933
18180
  instance.callbacks.onHistoryOpen?.();
17934
18181
  }
17935
18182
  });
18183
+ container.querySelector("[data-storage-card]")?.addEventListener("toggle", (event) => {
18184
+ if (event.target.open) instance.callbacks.onStorageOpen?.();
18185
+ });
17936
18186
  container.querySelector("[data-history-filter]")?.addEventListener("input", () => instance.callbacks.onHistoryFilter?.());
17937
18187
  container.querySelector("[data-experimental-ot]")?.addEventListener("click", (event) => instance.callbacks.onOtToggleClick?.(event));
17938
18188
  const customInstructionsInput = container.querySelector("[data-custom-instructions-input]");
@@ -17943,7 +18193,12 @@ ${block}`;
17943
18193
  for (const selector of ["[data-governance-readonly-patterns]", "[data-governance-writable-patterns]", "[data-sensitive-check-enabled]", "[data-sensitive-confirm-allowed]", "[data-preload-project-context]", "[data-load-codex-local-skills]", "[data-load-codex-overleaf-skills]", "[data-theme-select]", "[data-language-select]"]) {
17944
18194
  const element = container.querySelector(selector);
17945
18195
  element?.addEventListener?.("change", (event) => {
17946
- Promise.resolve(instance.callbacks.onInputChange?.(event)).then(() => flashSaved(instance, event)).catch(() => {
18196
+ Promise.resolve(instance.callbacks.onInputChange?.(event)).then(() => {
18197
+ flashSaved(instance, event);
18198
+ if (selector === "[data-language-select]" && container.querySelector("[data-storage-card]")?.open) {
18199
+ instance.callbacks.onStorageOpen?.();
18200
+ }
18201
+ }).catch(() => {
17947
18202
  });
17948
18203
  });
17949
18204
  element?.addEventListener?.("input", (event) => {
@@ -17958,6 +18213,9 @@ ${block}`;
17958
18213
  }
17959
18214
  setupGroupPersistence(instance);
17960
18215
  return {
18216
+ get container() {
18217
+ return instance.container;
18218
+ },
17961
18219
  show: () => show(instance),
17962
18220
  hide: () => hide(instance),
17963
18221
  loadState: (state) => loadState(instance, state),
@@ -18218,7 +18476,7 @@ ${block}`;
18218
18476
  };
18219
18477
  })();
18220
18478
  }).call(globalThis, void 0, void 0, void 0);
18221
- (function runClassicContentModule57(module, exports, require2) {
18479
+ (function runClassicContentModule58(module, exports, require2) {
18222
18480
  (function initCodexOverleafProviderSettingsDialog() {
18223
18481
  "use strict";
18224
18482
  const CODEX_BLOSSOM_PATH = "M13.798 23.976a5.7 5.7 0 0 1-2.26-.456 6.1 6.1 0 0 1-1.903-1.27 5.7 5.7 0 0 1-1.88.311 5.75 5.75 0 0 1-2.95-.79 6.2 6.2 0 0 1-2.188-2.159q-.81-1.366-.809-3.045 0-.695.19-1.51a6.4 6.4 0 0 1-1.475-2.038A5.95 5.95 0 0 1 0 10.573Q0 9.278.547 8.08q.547-1.2 1.523-2.062a5.5 5.5 0 0 1 2.307-1.223A5.7 5.7 0 0 1 5.472 2.35 6.1 6.1 0 0 1 7.565.623 5.8 5.8 0 0 1 10.206 0q1.19 0 2.26.456a6.1 6.1 0 0 1 1.903 1.27 5.7 5.7 0 0 1 1.88-.311q1.594 0 2.95.79a6 6 0 0 1 2.165 2.159q.832 1.366.832 3.045 0 .695-.19 1.51a6.3 6.3 0 0 1 1.475 2.062q.523 1.15.523 2.422a5.9 5.9 0 0 1-.547 2.493q-.547 1.2-1.546 2.086a5.4 5.4 0 0 1-2.284 1.199 5.56 5.56 0 0 1-1.118 2.445 5.9 5.9 0 0 1-2.07 1.727 5.8 5.8 0 0 1-2.64.623m-5.876-2.997q1.19 0 2.07-.504l4.472-2.589a.53.53 0 0 0 .238-.455v-2.062L8.945 18.7a.96.96 0 0 1-1.047 0l-4.496-2.613a.7.7 0 0 1-.024.168v.287q0 1.224.571 2.254a4.24 4.24 0 0 0 1.642 1.583q1.047.6 2.331.599m.238-3.908a.6.6 0 0 0 .262.072q.118 0 .238-.072l1.784-1.031-5.734-3.357q-.522-.312-.523-.935V6.545a4.3 4.3 0 0 0-1.903 1.63 4.25 4.25 0 0 0-.714 2.398q0 1.176.595 2.254.594 1.08 1.546 1.63zm5.638 5.323q1.26 0 2.284-.576a4.3 4.3 0 0 0 1.618-1.582q.595-1.008.595-2.254v-5.179a.47.47 0 0 0-.238-.431l-1.808-1.055v6.689q0 .624-.524.935l-4.496 2.613a4.3 4.3 0 0 0 2.57.84m.904-8.776v-3.26l-2.688-1.535-2.712 1.535v3.26l2.712 1.535zM7.756 5.97q0-.623.523-.935l4.496-2.613a4.3 4.3 0 0 0-2.569-.84q-1.26 0-2.284.576A4.3 4.3 0 0 0 6.304 3.74q-.57 1.008-.57 2.254v5.155q0 .287.237.455l1.785 1.055zM19.84 17.43a4.16 4.16 0 0 0 1.88-1.63 4.33 4.33 0 0 0 .713-2.397q0-1.176-.595-2.254-.594-1.08-1.546-1.63l-4.449-2.59q-.143-.096-.261-.072a.46.46 0 0 0-.238.072L13.56 7.936l5.758 3.38a.9.9 0 0 1 .38.384q.143.216.143.528zM15.059 5.25q.524-.335 1.047 0l4.52 2.662V7.48q0-1.15-.57-2.181A4.14 4.14 0 0 0 18.46 3.62q-1.023-.623-2.379-.623-1.19 0-2.07.503L9.54 6.09a.53.53 0 0 0-.238.455v2.062z";
@@ -19152,7 +19410,7 @@ ${block}`;
19152
19410
  window.CodexOverleafProviderSettingsDialog = { create, getFooterActionState };
19153
19411
  })();
19154
19412
  }).call(globalThis, void 0, void 0, void 0);
19155
- (function runClassicContentModule58(module, exports, require2) {
19413
+ (function runClassicContentModule59(module, exports, require2) {
19156
19414
  (function initCodexOverleafProjectProviderSelection() {
19157
19415
  "use strict";
19158
19416
  function create(deps = {}) {
@@ -19209,7 +19467,7 @@ ${block}`;
19209
19467
  window.CodexOverleafProjectProviderSelection = { create };
19210
19468
  })();
19211
19469
  }).call(globalThis, void 0, void 0, void 0);
19212
- (function runClassicContentModule59(module, exports, require2) {
19470
+ (function runClassicContentModule60(module, exports, require2) {
19213
19471
  (function initCodexOverleafProviderSettingsCoordinator() {
19214
19472
  "use strict";
19215
19473
  function create(options2 = {}) {
@@ -19273,6 +19531,7 @@ ${block}`;
19273
19531
  return {
19274
19532
  open: () => open(instance),
19275
19533
  refreshSummary: () => refreshSummary(instance),
19534
+ renderSummary: () => updateSettingsSummary(instance),
19276
19535
  ensureLoaded: () => ensureLoaded(instance),
19277
19536
  getRunSelection: (providerId) => instance.loaded ? Profiles.buildRunSelection(instance.catalog, providerId || instance.getSelectedProviderId()) : null,
19278
19537
  getProviderSnapshot: (providerId) => getProviderSnapshot(instance, providerId),
@@ -19819,7 +20078,7 @@ ${block}`;
19819
20078
  window.CodexOverleafProviderSettingsCoordinator = { create };
19820
20079
  })();
19821
20080
  }).call(globalThis, void 0, void 0, void 0);
19822
- (function runClassicContentModule60(module, exports, require2) {
20081
+ (function runClassicContentModule61(module, exports, require2) {
19823
20082
  (function initCodexOverleafSessionPersistence(root, factory) {
19824
20083
  if (typeof module === "object" && module.exports) {
19825
20084
  module.exports = factory(require2("../shared/storageMigration"));
@@ -19913,7 +20172,7 @@ ${block}`;
19913
20172
  };
19914
20173
  });
19915
20174
  }).call(globalThis, void 0, void 0, void 0);
19916
- (function runClassicContentModule61(module, exports, require2) {
20175
+ (function runClassicContentModule62(module, exports, require2) {
19917
20176
  (function(root, factory) {
19918
20177
  var api = factory();
19919
20178
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -20017,7 +20276,7 @@ ${block}`;
20017
20276
  return Object.freeze({ persistPanelState });
20018
20277
  });
20019
20278
  }).call(globalThis, void 0, void 0, void 0);
20020
- (function runClassicContentModule62(module, exports, require2) {
20279
+ (function runClassicContentModule63(module, exports, require2) {
20021
20280
  (function(root, factory) {
20022
20281
  var api = factory();
20023
20282
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -20062,7 +20321,7 @@ ${block}`;
20062
20321
  return Object.freeze({ create });
20063
20322
  });
20064
20323
  }).call(globalThis, void 0, void 0, void 0);
20065
- (function runClassicContentModule63(module, exports, require2) {
20324
+ (function runClassicContentModule64(module, exports, require2) {
20066
20325
  (function(root, factory) {
20067
20326
  if (typeof module === "object" && module.exports) {
20068
20327
  module.exports = factory(
@@ -20157,7 +20416,7 @@ ${block}`;
20157
20416
  });
20158
20417
  });
20159
20418
  }).call(globalThis, void 0, void 0, void 0);
20160
- (function runClassicContentModule64(module, exports, require2) {
20419
+ (function runClassicContentModule65(module, exports, require2) {
20161
20420
  (function initCodexOverleafDiagnosticsPanel() {
20162
20421
  "use strict";
20163
20422
  function create(options2 = {}) {
@@ -20196,7 +20455,7 @@ ${block}`;
20196
20455
  <small data-i18n="diagnosticsSnapshotSubtitle">Full project, assets, read source</small>
20197
20456
  </button>
20198
20457
  <button type="button" data-diagnostics-ot>
20199
- <span data-i18n="diagnosticsOtTitle">Check Experimental OT Mirror</span>
20458
+ <span data-i18n="diagnosticsOtTitle">Check OT Mirror</span>
20200
20459
  <small data-i18n="diagnosticsOtSubtitle">Status, fresh files, fallback</small>
20201
20460
  </button>
20202
20461
  <button type="button" data-diagnostics-export>
@@ -20585,7 +20844,7 @@ ${block}`;
20585
20844
  };
20586
20845
  })();
20587
20846
  }).call(globalThis, void 0, void 0, void 0);
20588
- (function runClassicContentModule65(module, exports, require2) {
20847
+ (function runClassicContentModule66(module, exports, require2) {
20589
20848
  (function initCodexOverleafRunQueueScheduler(root, factory) {
20590
20849
  if (typeof module === "object" && module.exports) {
20591
20850
  module.exports = factory(require2("../shared/runInputQueue"));
@@ -20913,7 +21172,7 @@ ${block}`;
20913
21172
  return { create, createCoordinator };
20914
21173
  });
20915
21174
  }).call(globalThis, void 0, void 0, void 0);
20916
- (function runClassicContentModule66(module, exports, require2) {
21175
+ (function runClassicContentModule67(module, exports, require2) {
20917
21176
  (function initCodexOverleafActiveTurnControl(root, factory) {
20918
21177
  if (typeof module === "object" && module.exports) {
20919
21178
  module.exports = factory();
@@ -21082,7 +21341,7 @@ ${block}`;
21082
21341
  return { create };
21083
21342
  });
21084
21343
  }).call(globalThis, void 0, void 0, void 0);
21085
- (function runClassicContentModule67(module, exports, require2) {
21344
+ (function runClassicContentModule68(module, exports, require2) {
21086
21345
  (function initCodexOverleafPendingInputView(root, factory) {
21087
21346
  if (typeof module === "object" && module.exports) {
21088
21347
  module.exports = factory();
@@ -21184,7 +21443,7 @@ ${block}`;
21184
21443
  return { create };
21185
21444
  });
21186
21445
  }).call(globalThis, void 0, void 0, void 0);
21187
- (function runClassicContentModule68(module, exports, require2) {
21446
+ (function runClassicContentModule69(module, exports, require2) {
21188
21447
  (function initCodexOverleafComposerPanel() {
21189
21448
  "use strict";
21190
21449
  function create(options2 = {}) {
@@ -21443,7 +21702,7 @@ ${block}`;
21443
21702
  };
21444
21703
  })();
21445
21704
  }).call(globalThis, void 0, void 0, void 0);
21446
- (function runClassicContentModule69(module, exports, require2) {
21705
+ (function runClassicContentModule70(module, exports, require2) {
21447
21706
  (function initCodexOverleafTheme(root, factory) {
21448
21707
  if (typeof module === "object" && module.exports) {
21449
21708
  module.exports = factory();
@@ -21514,7 +21773,7 @@ ${block}`;
21514
21773
  };
21515
21774
  });
21516
21775
  }).call(globalThis, void 0, void 0, void 0);
21517
- (function runClassicContentModule70(module, exports, require2) {
21776
+ (function runClassicContentModule71(module, exports, require2) {
21518
21777
  !(function(e, t) {
21519
21778
  "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.katex = t() : e.katex = t();
21520
21779
  })("undefined" != typeof self ? self : this, function() {
@@ -24934,7 +25193,7 @@ ${block}`;
24934
25193
  })();
24935
25194
  });
24936
25195
  }).call(globalThis, void 0, void 0, void 0);
24937
- (function runClassicContentModule71(module, exports, require2) {
25196
+ (function runClassicContentModule72(module, exports, require2) {
24938
25197
  !(function(t, e) {
24939
25198
  "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).markdownit = e();
24940
25199
  })(this, function() {
@@ -27006,7 +27265,7 @@ ${block}`;
27006
27265
  }, Ke;
27007
27266
  });
27008
27267
  }).call(globalThis, void 0, void 0, void 0);
27009
- (function runClassicContentModule72(module, exports, require2) {
27268
+ (function runClassicContentModule73(module, exports, require2) {
27010
27269
  (function initCodexOverleafMathText(root) {
27011
27270
  "use strict";
27012
27271
  const DELIMITERS = Object.freeze([
@@ -27391,7 +27650,7 @@ ${block}`;
27391
27650
  }
27392
27651
  })(typeof window !== "undefined" ? window : globalThis);
27393
27652
  }).call(globalThis, void 0, void 0, void 0);
27394
- (function runClassicContentModule73(module, exports, require2) {
27653
+ (function runClassicContentModule74(module, exports, require2) {
27395
27654
  (function initCodexOverleafMarkdownDomRenderer(root, factory) {
27396
27655
  const api = factory();
27397
27656
  if (typeof module === "object" && module.exports) {
@@ -27879,7 +28138,7 @@ ${block}`;
27879
28138
  };
27880
28139
  });
27881
28140
  }).call(globalThis, void 0, void 0, void 0);
27882
- (function runClassicContentModule74(module, exports, require2) {
28141
+ (function runClassicContentModule75(module, exports, require2) {
27883
28142
  (function initCodexOverleafMarkdownText() {
27884
28143
  "use strict";
27885
28144
  function create(deps = {}) {
@@ -28506,7 +28765,7 @@ ${block}`;
28506
28765
  window.CodexOverleafMarkdownText = { create };
28507
28766
  })();
28508
28767
  }).call(globalThis, void 0, void 0, void 0);
28509
- (function runClassicContentModule75(module, exports, require2) {
28768
+ (function runClassicContentModule76(module, exports, require2) {
28510
28769
  (function initCodexOverleafDiagnosticsController() {
28511
28770
  "use strict";
28512
28771
  function create(deps = {}) {
@@ -28823,6 +29082,16 @@ ${block}`;
28823
29082
  nextStep: "",
28824
29083
  technical: ""
28825
29084
  };
29085
+ const mirrorState = getOtWarmMirrorState?.() || {};
29086
+ if (mirrorState.failureActive && mirrorState.lastFailure) {
29087
+ const failure = mirrorState.lastFailure;
29088
+ disabledResult.status = "warning";
29089
+ disabledResult.summary = tr(otWarmMirrorController.getFailureMessageKey(failure.code));
29090
+ disabledResult.nextStep = tr("otFailureNextStep");
29091
+ disabledResult.technical = `lastErrorCode: ${failure.code}
29092
+ phase: ${failure.phase}
29093
+ failedAt: ${new Date(failure.at).toISOString()}`;
29094
+ }
28826
29095
  if (options2.collectOnly) {
28827
29096
  return disabledResult;
28828
29097
  }
@@ -28877,6 +29146,7 @@ ${block}`;
28877
29146
  const queuedEventCount = normalizeOtDiagnosticsCount(otStatus?.queuedEventCount);
28878
29147
  const lastEventAt = formatOtDiagnosticValue(otStatus?.lastEventAt, tr("noneValue"));
28879
29148
  const warmMirrorState = getOtWarmMirrorState() || {};
29149
+ const failureActive = warmMirrorState.failureActive === true;
28880
29150
  const lastOtPatchAt = formatOtDiagnosticValue(mirrorStatus?.lastOtPatchAt || warmMirrorState.lastPatchAt, tr("noneValue"));
28881
29151
  const lastOtErrorCode = formatOtDiagnosticValue(mirrorStatus?.lastOtErrorCode || warmMirrorState.lastErrorCode, tr("noneValue"));
28882
29152
  const lastErrorCode = formatOtDiagnosticValue(otStatus?.lastErrorCode || otStatus?.reason || otStatus?.error, tr("noneValue"));
@@ -28888,12 +29158,12 @@ ${block}`;
28888
29158
  const bridgeFailed = otStatus?.ok === false;
28889
29159
  const focusFiles = getActiveFocusFiles();
28890
29160
  const otWarmStart = otWarmMirrorController?.canUseOtWarmStart?.({ enabled, focusFiles, mirrorStatus }) || { ok: false };
28891
- const fallback = !enabled || statusValue !== "observing" || bridgeFailed || otWarmStart?.ok !== true;
29161
+ const fallback = !enabled || failureActive || statusValue !== "observing" || bridgeFailed || otWarmStart?.ok !== true;
28892
29162
  return {
28893
29163
  title: tr("diagnosticsOtTitle"),
28894
29164
  subtitle: tr("diagnosticsOtSubtitle"),
28895
29165
  status: enabled && !fallback && !bridgeFailed ? "completed" : enabled || bridgeFailed ? "warning" : "completed",
28896
- summary: tr(enabled ? "diagnosticsOtSummaryEnabled" : "diagnosticsOtSummaryDisabled"),
29166
+ summary: tr(failureActive ? otWarmMirrorController.getFailureMessageKey(warmMirrorState.lastErrorCode) : enabled ? "diagnosticsOtSummaryEnabled" : "diagnosticsOtSummaryDisabled"),
28897
29167
  bullets: [
28898
29168
  `${tr("otStatus")}: ${formatOtStatusLabel(statusValue)}`,
28899
29169
  `${tr("otFreshFiles")}: ${otFreshFileCount}`,
@@ -29075,7 +29345,7 @@ ${block}`;
29075
29345
  window.CodexOverleafDiagnosticsController = { create };
29076
29346
  })();
29077
29347
  }).call(globalThis, void 0, void 0, void 0);
29078
- (function runClassicContentModule76(module, exports, require2) {
29348
+ (function runClassicContentModule77(module, exports, require2) {
29079
29349
  (function initCodexOverleafRunGuidanceView() {
29080
29350
  "use strict";
29081
29351
  const LEGACY_GUIDANCE_TITLES = /* @__PURE__ */ new Set([
@@ -29115,7 +29385,7 @@ ${block}`;
29115
29385
  };
29116
29386
  })();
29117
29387
  }).call(globalThis, void 0, void 0, void 0);
29118
- (function runClassicContentModule77(module, exports, require2) {
29388
+ (function runClassicContentModule78(module, exports, require2) {
29119
29389
  (function initCodexOverleafRunGuidanceController() {
29120
29390
  "use strict";
29121
29391
  function create(deps = {}) {
@@ -29178,7 +29448,7 @@ ${block}`;
29178
29448
  window.CodexOverleafRunGuidanceController = { create };
29179
29449
  })();
29180
29450
  }).call(globalThis, void 0, void 0, void 0);
29181
- (function runClassicContentModule78(module, exports, require2) {
29451
+ (function runClassicContentModule79(module, exports, require2) {
29182
29452
  (function initCodexOverleafRunResultActions(root, factory) {
29183
29453
  const api = factory();
29184
29454
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -29283,13 +29553,224 @@ ${block}`;
29283
29553
  return Object.freeze({ create });
29284
29554
  });
29285
29555
  }).call(globalThis, void 0, void 0, void 0);
29286
- (function runClassicContentModule79(module, exports, require2) {
29556
+ (function runClassicContentModule80(module, exports, require2) {
29557
+ (function initRunScrollLayout(root, factory) {
29558
+ if (typeof module === "object" && module.exports) {
29559
+ module.exports = factory();
29560
+ } else {
29561
+ root.CodexOverleafModuleRegistry.define("RunScrollLayout", [], factory);
29562
+ }
29563
+ })(typeof window !== "undefined" ? window : globalThis, function runScrollLayoutFactory() {
29564
+ "use strict";
29565
+ const READING_ANCHORS = ".run-final-answer p, .run-final-answer li, .run-final-answer pre, .run-final-answer h1, .run-final-answer h2, .run-final-answer h3, .run-stream p, .run-stream li, .run-stream pre, [data-run-task], [data-run-status]";
29566
+ function create({ getScroller, onLayoutChange, isFollowing = () => true, window: host = globalThis } = {}) {
29567
+ let current = null;
29568
+ let resizeObserver = null;
29569
+ let mutationObserver = null;
29570
+ let anchor = null;
29571
+ let extent = "";
29572
+ function measure() {
29573
+ return current ? `${current.scrollHeight}:${current.clientHeight}` : "";
29574
+ }
29575
+ function captureAnchor(force = false) {
29576
+ if (!current || isFollowing()) {
29577
+ anchor = null;
29578
+ return;
29579
+ }
29580
+ if (!force && extent !== measure()) return;
29581
+ const bounds = current.getBoundingClientRect?.();
29582
+ if (!bounds) return;
29583
+ const nodes = current.querySelectorAll?.(READING_ANCHORS) || [];
29584
+ anchor = null;
29585
+ for (const node of nodes) {
29586
+ const rect = node.getBoundingClientRect();
29587
+ if (rect.height > 0 && rect.bottom > bounds.top && rect.top < bounds.bottom) {
29588
+ anchor = { node, offset: rect.top - bounds.top };
29589
+ break;
29590
+ }
29591
+ }
29592
+ }
29593
+ function restoreAnchor() {
29594
+ if (isFollowing() || !anchor || !current.contains?.(anchor.node)) return;
29595
+ const rect = anchor.node.getBoundingClientRect();
29596
+ if (!rect.height) return;
29597
+ const delta = rect.top - current.getBoundingClientRect().top - anchor.offset;
29598
+ if (Math.abs(delta) > 0.5) current.scrollTop += delta;
29599
+ }
29600
+ function snapshot() {
29601
+ captureAnchor();
29602
+ const run = anchor?.node.closest?.("[data-run-id]");
29603
+ return {
29604
+ scrollTop: current?.scrollTop || 0,
29605
+ runId: run?.dataset?.runId || "",
29606
+ index: run ? Array.from(run.querySelectorAll(READING_ANCHORS)).indexOf(anchor.node) : -1,
29607
+ offset: anchor?.offset || 0
29608
+ };
29609
+ }
29610
+ function restore(reading) {
29611
+ if (!current || !reading) return;
29612
+ current.scrollTop = reading.scrollTop;
29613
+ const run = Array.from(current.querySelectorAll?.("[data-run-id]") || []).find((node2) => node2.dataset.runId === reading.runId);
29614
+ const node = run?.querySelectorAll(READING_ANCHORS)[reading.index];
29615
+ anchor = node ? { node, offset: reading.offset } : null;
29616
+ restoreAnchor();
29617
+ extent = measure();
29618
+ captureAnchor(true);
29619
+ }
29620
+ function dispose() {
29621
+ resizeObserver?.disconnect();
29622
+ mutationObserver?.disconnect();
29623
+ resizeObserver = null;
29624
+ mutationObserver = null;
29625
+ current = null;
29626
+ anchor = null;
29627
+ extent = "";
29628
+ }
29629
+ function notify() {
29630
+ if (!current) return;
29631
+ const active = getScroller();
29632
+ if (active !== current) {
29633
+ bind(active);
29634
+ return;
29635
+ }
29636
+ restoreAnchor();
29637
+ extent = measure();
29638
+ onLayoutChange(current);
29639
+ captureAnchor(true);
29640
+ }
29641
+ function bind(scroller) {
29642
+ if (scroller === current) return;
29643
+ dispose();
29644
+ if (!scroller || typeof host.ResizeObserver !== "function") return;
29645
+ current = scroller;
29646
+ extent = measure();
29647
+ captureAnchor(true);
29648
+ resizeObserver = new host.ResizeObserver(notify);
29649
+ resizeObserver.observe(scroller);
29650
+ for (const child of scroller.children || []) resizeObserver.observe(child);
29651
+ if (typeof host.MutationObserver === "function") {
29652
+ mutationObserver = new host.MutationObserver((records) => {
29653
+ if (current !== scroller) return;
29654
+ for (const record of records) {
29655
+ for (const node of record.removedNodes) {
29656
+ if (node.nodeType === 1) resizeObserver.unobserve(node);
29657
+ }
29658
+ for (const node of record.addedNodes) {
29659
+ if (node.nodeType === 1) resizeObserver.observe(node);
29660
+ }
29661
+ }
29662
+ notify();
29663
+ });
29664
+ mutationObserver.observe(scroller, { childList: true });
29665
+ }
29666
+ }
29667
+ return Object.freeze({ bind, dispose, captureAnchor, snapshot, restore });
29668
+ }
29669
+ return Object.freeze({ create });
29670
+ });
29671
+ }).call(globalThis, void 0, void 0, void 0);
29672
+ (function runClassicContentModule81(module, exports, require2) {
29673
+ (function initRunFailureNotice(root, factory) {
29674
+ if (typeof module === "object" && module.exports) {
29675
+ module.exports = factory();
29676
+ } else {
29677
+ root.CodexOverleafModuleRegistry.define("RunFailureNotice", [], factory);
29678
+ }
29679
+ })(typeof window !== "undefined" ? window : globalThis, function runFailureNoticeFactory() {
29680
+ "use strict";
29681
+ const REVIEW_CODES = /* @__PURE__ */ new Set(["write_timeout", "partial_write_needs_review"]);
29682
+ const CANCEL_CODES = /* @__PURE__ */ new Set(["cancelled", "user_cancelled", "codex_cancelled"]);
29683
+ function create({
29684
+ tr,
29685
+ projectRunSettlement,
29686
+ sanitizeText = (value) => value,
29687
+ document: documentRef = globalThis.document
29688
+ } = {}) {
29689
+ const notices = /* @__PURE__ */ new WeakMap();
29690
+ function append(report, event = {}, run = {}) {
29691
+ const projection = typeof projectRunSettlement === "function" && run ? projectRunSettlement(run) : null;
29692
+ const failure = projection?.primaryFailure || event.failure;
29693
+ if (report.dataset.status === "cancelled" || CANCEL_CODES.has(failure?.code)) return;
29694
+ const facts = run?.settlement || run?.settlementFacts || {};
29695
+ const unconfirmed = REVIEW_CODES.has(failure?.code) || facts.documentEffect === "possibly-changed" || facts.evidence?.applied === "unknown" && facts.evidence?.settled === "needs-review";
29696
+ const partial = facts.evidence?.applied === "partial" || run?.partialWriteback === true;
29697
+ if (!failure && !unconfirmed && !partial && report.dataset.status !== "failed") return;
29698
+ const notice = documentRef.createElement("aside");
29699
+ notice.className = "run-feedback";
29700
+ notice.dataset.tone = unconfirmed || partial || failure?.terminalState === "degraded" || failure?.terminalState === "needs_review" ? "warning" : "error";
29701
+ notice.setAttribute("role", "note");
29702
+ const heading = documentRef.createElement("strong");
29703
+ heading.className = "run-feedback__title";
29704
+ heading.textContent = tr(unconfirmed ? "runFeedbackUnconfirmedTitle" : partial ? "runFeedbackPartialTitle" : "runFeedbackFailedTitle");
29705
+ const message = documentRef.createElement("p");
29706
+ const detail = typeof failure?.userMessage === "string" ? failure.userMessage : "";
29707
+ const file = safeProjectPath(failure?.file);
29708
+ message.textContent = sanitizeText([file, detail].filter(Boolean).join(": ").slice(0, 1e3)) || tr("runFeedbackGeneric");
29709
+ notice.append(heading, message);
29710
+ if (unconfirmed) {
29711
+ const warning = documentRef.createElement("p");
29712
+ warning.textContent = tr("runFeedbackUnconfirmed");
29713
+ notice.append(warning);
29714
+ }
29715
+ notices.set(report, { notice, unconfirmed, failure, file });
29716
+ report.append(notice);
29717
+ }
29718
+ function formatMetaValue(report, row) {
29719
+ if (!notices.get(report)?.unconfirmed) return row.value;
29720
+ const key = String(row.key || "").toLowerCase().replace(/[^a-z]/g, "");
29721
+ const label = String(row.label || "").trim().toLowerCase();
29722
+ if (key === "writeresult" || key === "next" || ["write result", "next", "\u5199\u5165\u7ED3\u679C", "\u4E0B\u4E00\u6B65"].includes(label)) {
29723
+ return tr("runFeedbackUnconfirmedResult");
29724
+ }
29725
+ return row.value;
29726
+ }
29727
+ function prepareRecovery(report, { openFile } = {}) {
29728
+ const info = notices.get(report);
29729
+ const target = info?.notice || report;
29730
+ if (!info?.unconfirmed) return { target, handled: false };
29731
+ const canOpen = Boolean(info.file && typeof openFile === "function");
29732
+ const button = documentRef.createElement("button");
29733
+ button.type = "button";
29734
+ button.className = "run-final-answer__recovery-action";
29735
+ button.dataset.recoveryFor = info.failure?.code || "write_unconfirmed";
29736
+ button.textContent = tr(canOpen ? "runFeedbackReviewFile" : "runFeedbackReviewDetails", { file: info.file });
29737
+ button.addEventListener("click", (event) => {
29738
+ event.stopPropagation();
29739
+ if (canOpen) {
29740
+ openFile(info.file);
29741
+ return;
29742
+ }
29743
+ const process = report.closest?.("[data-run-id]")?.querySelector?.("[data-run-process]");
29744
+ if (process) {
29745
+ process.open = true;
29746
+ process.scrollIntoView?.({ block: "nearest" });
29747
+ } else {
29748
+ button.disabled = true;
29749
+ button.title = tr("runFeedbackDetailsUnavailable");
29750
+ }
29751
+ });
29752
+ target.append(button);
29753
+ return { target, handled: true };
29754
+ }
29755
+ return Object.freeze({ append, formatMetaValue, prepareRecovery });
29756
+ }
29757
+ function safeProjectPath(value) {
29758
+ if (typeof value !== "string") return "";
29759
+ const path = value.replace(/\\/g, "/");
29760
+ return path && !path.startsWith("/") && !/^[A-Za-z]:/.test(path) && !path.split("/").includes("..") ? path.slice(0, 300) : "";
29761
+ }
29762
+ return Object.freeze({ create });
29763
+ });
29764
+ }).call(globalThis, void 0, void 0, void 0);
29765
+ (function runClassicContentModule82(module, exports, require2) {
29287
29766
  (function initCodexOverleafRunTimelineView() {
29288
29767
  "use strict";
29289
29768
  function create(deps = {}) {
29290
29769
  const {
29291
29770
  RunGuidanceView,
29292
29771
  RunResultActions,
29772
+ RunScrollLayout,
29773
+ RunFailureNotice,
29293
29774
  tr,
29294
29775
  tx,
29295
29776
  getLocale,
@@ -29323,17 +29804,25 @@ ${block}`;
29323
29804
  } = deps;
29324
29805
  let logAutoFollow = true;
29325
29806
  let userScrollIntentUntil = 0;
29807
+ let userScrollExtent = "";
29326
29808
  let scrollLogRafId = 0;
29327
29809
  let scrollLogPendingForce = false;
29328
29810
  let jumpToLatestButton = null;
29329
29811
  let unreadSinceDetach = 0;
29330
29812
  let runElapsedTimer = null;
29813
+ const scrollLayout = RunScrollLayout?.create({
29814
+ getScroller: getLogScrollContainer,
29815
+ isFollowing: () => logAutoFollow,
29816
+ onLayoutChange: (scroller) => logAutoFollow ? scrollLogToBottom() : updateJumpToLatestButton(scroller)
29817
+ });
29818
+ const failureNotice = RunFailureNotice?.create({ tr, projectRunSettlement, sanitizeText: sanitizeAssistantVisibleText });
29331
29819
  function resetAutoFollow() {
29332
29820
  logAutoFollow = true;
29333
29821
  userScrollIntentUntil = 0;
29334
29822
  }
29335
29823
  function bindLogAutoFollow() {
29336
29824
  const scroller = getLogScrollContainer();
29825
+ scrollLayout?.bind(scroller);
29337
29826
  if (!scroller || scroller.dataset.autoFollowBound === "true") {
29338
29827
  return;
29339
29828
  }
@@ -29343,15 +29832,14 @@ ${block}`;
29343
29832
  scroller.addEventListener("pointerdown", markUserScrollIntent, { passive: true });
29344
29833
  scroller.addEventListener("keydown", (event) => {
29345
29834
  if (["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(event.key)) {
29346
- markUserScrollIntent();
29835
+ markUserScrollIntent(event);
29347
29836
  }
29348
29837
  });
29349
29838
  scroller.addEventListener("scroll", () => {
29350
- if (Date.now() <= userScrollIntentUntil) {
29839
+ if (Date.now() <= userScrollIntentUntil && userScrollExtent === `${scroller.scrollHeight}:${scroller.clientHeight}`) {
29351
29840
  logAutoFollow = isLogNearBottom(scroller);
29352
- } else if (isLogNearBottom(scroller)) {
29353
- logAutoFollow = true;
29354
29841
  }
29842
+ scrollLayout?.captureAnchor();
29355
29843
  updateJumpToLatestButton(scroller);
29356
29844
  }, { passive: true });
29357
29845
  }
@@ -29382,6 +29870,7 @@ ${block}`;
29382
29870
  if (!el) {
29383
29871
  return;
29384
29872
  }
29873
+ if (el.dataset) el.dataset.logAutoFollow = logAutoFollow ? "true" : "false";
29385
29874
  const button = ensureJumpToLatestButton();
29386
29875
  if (!button) {
29387
29876
  return;
@@ -29404,8 +29893,16 @@ ${block}`;
29404
29893
  function getLogScrollContainer() {
29405
29894
  return getPanel()?.querySelector("[data-log]") || getPanel()?.querySelector("[data-main]");
29406
29895
  }
29407
- function markUserScrollIntent() {
29896
+ function markUserScrollIntent(event) {
29897
+ const scroller = getLogScrollContainer();
29898
+ if (!scroller || event?.type === "pointerdown" && event.target !== scroller) return;
29899
+ if (event?.target?.closest?.('input, textarea, select, [contenteditable="true"]')) return;
29408
29900
  userScrollIntentUntil = Date.now() + 1200;
29901
+ userScrollExtent = `${scroller.scrollHeight}:${scroller.clientHeight}`;
29902
+ if (event?.type === "wheel" && event.deltaY < 0 || ["ArrowUp", "PageUp", "Home"].includes(event?.key)) {
29903
+ logAutoFollow = false;
29904
+ scrollLogPendingForce = false;
29905
+ }
29409
29906
  }
29410
29907
  function isLogNearBottom(log) {
29411
29908
  if (!log) {
@@ -29424,7 +29921,7 @@ ${block}`;
29424
29921
  userScrollIntentUntil = 0;
29425
29922
  unreadSinceDetach = 0;
29426
29923
  scrollLogPendingForce = true;
29427
- } else if (!(logAutoFollow || isLogNearBottom(scroller))) {
29924
+ } else if (!logAutoFollow) {
29428
29925
  updateJumpToLatestButton(scroller);
29429
29926
  return;
29430
29927
  }
@@ -29433,7 +29930,7 @@ ${block}`;
29433
29930
  if (!el) {
29434
29931
  return;
29435
29932
  }
29436
- if (scrollLogPendingForce || logAutoFollow || isLogNearBottom(el)) {
29933
+ if (scrollLogPendingForce || logAutoFollow) {
29437
29934
  setLogScrollPosition(el);
29438
29935
  }
29439
29936
  scrollLogPendingForce = false;
@@ -29509,11 +30006,12 @@ ${block}`;
29509
30006
  }
29510
30007
  return tr("processed", { elapsed });
29511
30008
  }
29512
- function renderRunHistory() {
30009
+ function renderRunHistory(options2 = {}) {
29513
30010
  const log = getPanel()?.querySelector("[data-log]");
29514
30011
  if (!log) {
29515
30012
  return;
29516
30013
  }
30014
+ const reading = options2.preserveScroll === true && !logAutoFollow ? scrollLayout?.snapshot() || { scrollTop: log.scrollTop } : null;
29517
30015
  log.replaceChildren();
29518
30016
  if (!getState().runs?.length) {
29519
30017
  const empty = document.createElement("div");
@@ -29542,7 +30040,11 @@ ${block}`;
29542
30040
  for (const run of runs) {
29543
30041
  log.append(renderRunCard(run));
29544
30042
  }
29545
- scrollLogToBottom({ force: true });
30043
+ if (reading) {
30044
+ log.scrollTop = reading.scrollTop;
30045
+ scrollLayout?.restore(reading);
30046
+ updateJumpToLatestButton(log);
30047
+ } else scrollLogToBottom({ force: true });
29546
30048
  }
29547
30049
  function renderRunCard(run) {
29548
30050
  const root = document.createElement("section");
@@ -29817,7 +30319,7 @@ ${block}`;
29817
30319
  if (row.key) dt.dataset.metaKey = row.key;
29818
30320
  const dd = document.createElement("dd");
29819
30321
  dd.className = "run-final-answer__meta-value";
29820
- dd.textContent = row.value;
30322
+ dd.textContent = failureNotice?.formatMetaValue(report, row) ?? row.value;
29821
30323
  metaBlock.append(dt, dd);
29822
30324
  }
29823
30325
  if (metaBlock.children.length) {
@@ -29890,6 +30392,7 @@ ${lines}`
29890
30392
  decorateCompletionReport(main, { tx });
29891
30393
  report.append(main);
29892
30394
  }
30395
+ failureNotice?.append(report, event, run);
29893
30396
  appendCompletionMetaBlock(report, structured.meta);
29894
30397
  appendCompileFix(report);
29895
30398
  appendRejectedRedo(report);
@@ -29905,6 +30408,7 @@ ${lines}`
29905
30408
  report.append(body);
29906
30409
  appendCompileFix(report);
29907
30410
  appendRejectedRedo(report);
30411
+ failureNotice?.append(report, event, run);
29908
30412
  appendCompletionMetaBlock(report, split.meta);
29909
30413
  appendRecoveryActionForFailure(report, event, run);
29910
30414
  return report;
@@ -29958,6 +30462,9 @@ ${conclusion}` : `${label} ${conclusion}`;
29958
30462
  return button;
29959
30463
  }
29960
30464
  function appendRecoveryActionForFailure(report, event, run) {
30465
+ const recovery = failureNotice?.prepareRecovery(report, { openFile: openProjectFileForFailure });
30466
+ if (recovery?.handled) return;
30467
+ report = recovery?.target || report;
29961
30468
  const failureCode = event?.failure?.code || "";
29962
30469
  if (RETRYABLE_FAILURE_CODES.has(failureCode) && typeof refillComposerForRetry === "function") {
29963
30470
  const retry = buildRecoveryButton(
@@ -30255,7 +30762,7 @@ ${conclusion}` : `${label} ${conclusion}`;
30255
30762
  window.CodexOverleafRunTimelineView = { create };
30256
30763
  })();
30257
30764
  }).call(globalThis, void 0, void 0, void 0);
30258
- (function runClassicContentModule80(module, exports, require2) {
30765
+ (function runClassicContentModule83(module, exports, require2) {
30259
30766
  (function initCodexOverleafProjectSettingsCoordinator() {
30260
30767
  "use strict";
30261
30768
  function create(deps = {}) {
@@ -30584,7 +31091,7 @@ ${conclusion}` : `${label} ${conclusion}`;
30584
31091
  window.CodexOverleafProjectSettingsCoordinator = { create };
30585
31092
  })();
30586
31093
  }).call(globalThis, void 0, void 0, void 0);
30587
- (function runClassicContentModule81(module, exports, require2) {
31094
+ (function runClassicContentModule84(module, exports, require2) {
30588
31095
  (function initCodexOverleafSessionMenuView() {
30589
31096
  "use strict";
30590
31097
  function create(deps = {}) {
@@ -30789,7 +31296,7 @@ ${conclusion}` : `${label} ${conclusion}`;
30789
31296
  window.CodexOverleafSessionMenuView = { create };
30790
31297
  })();
30791
31298
  }).call(globalThis, void 0, void 0, void 0);
30792
- (function runClassicContentModule82(module, exports, require2) {
31299
+ (function runClassicContentModule85(module, exports, require2) {
30793
31300
  (function initCodexOverleafSessionManager() {
30794
31301
  "use strict";
30795
31302
  function create(deps = {}) {
@@ -31048,7 +31555,7 @@ ${conclusion}` : `${label} ${conclusion}`;
31048
31555
  window.CodexOverleafSessionManager = { create };
31049
31556
  })();
31050
31557
  }).call(globalThis, void 0, void 0, void 0);
31051
- (function runClassicContentModule83(module, exports, require2) {
31558
+ (function runClassicContentModule86(module, exports, require2) {
31052
31559
  (function initCodexOverleafSessionForkController(root, factory) {
31053
31560
  const api = factory();
31054
31561
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -31177,7 +31684,7 @@ ${conclusion}` : `${label} ${conclusion}`;
31177
31684
  return { copyRunSnapshot, create };
31178
31685
  });
31179
31686
  }).call(globalThis, void 0, void 0, void 0);
31180
- (function runClassicContentModule84(module, exports, require2) {
31687
+ (function runClassicContentModule87(module, exports, require2) {
31181
31688
  (function initCodexOverleafApplyResultFormatters() {
31182
31689
  "use strict";
31183
31690
  function create(deps = {}) {
@@ -31497,7 +32004,7 @@ ${conclusion}` : `${label} ${conclusion}`;
31497
32004
  window.CodexOverleafApplyResultFormatters = { create };
31498
32005
  })();
31499
32006
  }).call(globalThis, void 0, void 0, void 0);
31500
- (function runClassicContentModule85(module, exports, require2) {
32007
+ (function runClassicContentModule88(module, exports, require2) {
31501
32008
  (function initCodexOverleafModelPickerSupport(root, factory) {
31502
32009
  if (typeof module === "object" && module.exports) {
31503
32010
  module.exports = factory(require2("../shared/models"));
@@ -31598,7 +32105,7 @@ ${conclusion}` : `${label} ${conclusion}`;
31598
32105
  return api;
31599
32106
  });
31600
32107
  }).call(globalThis, void 0, void 0, void 0);
31601
- (function runClassicContentModule86(module, exports, require2) {
32108
+ (function runClassicContentModule89(module, exports, require2) {
31602
32109
  (function initCodexOverleafModelPicker() {
31603
32110
  "use strict";
31604
32111
  function create(deps = {}) {
@@ -32076,7 +32583,7 @@ ${conclusion}` : `${label} ${conclusion}`;
32076
32583
  window.CodexOverleafModelPicker = { create };
32077
32584
  })();
32078
32585
  }).call(globalThis, void 0, void 0, void 0);
32079
- (function runClassicContentModule87(module, exports, require2) {
32586
+ (function runClassicContentModule90(module, exports, require2) {
32080
32587
  (function initCodexOverleafProjectSessionCleanup() {
32081
32588
  "use strict";
32082
32589
  const FRESH_RUNNING_WINDOW_MS = 30 * 60 * 1e3;
@@ -32176,7 +32683,7 @@ ${conclusion}` : `${label} ${conclusion}`;
32176
32683
  window.CodexOverleafProjectSessionCleanup = { create };
32177
32684
  })();
32178
32685
  }).call(globalThis, void 0, void 0, void 0);
32179
- (function runClassicContentModule88(module, exports, require2) {
32686
+ (function runClassicContentModule91(module, exports, require2) {
32180
32687
  (function initCodexOverleafRecentProjects() {
32181
32688
  "use strict";
32182
32689
  function create(deps = {}) {
@@ -33102,7 +33609,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33102
33609
  window.CodexOverleafRecentProjects = { create };
33103
33610
  })();
33104
33611
  }).call(globalThis, void 0, void 0, void 0);
33105
- (function runClassicContentModule89(module, exports, require2) {
33612
+ (function runClassicContentModule92(module, exports, require2) {
33106
33613
  (function initCodexOverleafOtWarmMirror() {
33107
33614
  "use strict";
33108
33615
  function create(deps = {}) {
@@ -33144,6 +33651,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33144
33651
  RUN_SNAPSHOT_ZIP_TIMEOUT_MS
33145
33652
  } = deps;
33146
33653
  let currentOtStatus = "off";
33654
+ let otTogglePending = false;
33147
33655
  let otSyncRequestId = 0;
33148
33656
  let otWarmMirrorProjectId = "";
33149
33657
  let lastExperimentalOtProjectId = "";
@@ -33155,7 +33663,10 @@ ${conclusion}` : `${label} ${conclusion}`;
33155
33663
  patchQueue: [],
33156
33664
  lastStatus: "off",
33157
33665
  lastPatchAt: 0,
33158
- lastErrorCode: ""
33666
+ lastErrorCode: "",
33667
+ failureActive: false,
33668
+ lastFailure: null,
33669
+ suspended: false
33159
33670
  };
33160
33671
  let mirrorPrefetchState = {
33161
33672
  inFlight: null,
@@ -33237,7 +33748,10 @@ ${conclusion}` : `${label} ${conclusion}`;
33237
33748
  async function handleExperimentalOtToggleClick(event) {
33238
33749
  const clicked = event?.currentTarget || event?.target;
33239
33750
  const targetEnabled = clicked && typeof clicked.checked === "boolean" ? clicked.checked : void 0;
33751
+ const projectId = getCurrentProjectId();
33240
33752
  event.preventDefault();
33753
+ await new Promise((resolve) => window.setTimeout(resolve, 0));
33754
+ if (projectId !== getCurrentProjectId()) return;
33241
33755
  await toggleExperimentalOtCheckbox(targetEnabled);
33242
33756
  }
33243
33757
  async function handleExperimentalOtToggleKeydown(event) {
@@ -33249,28 +33763,35 @@ ${conclusion}` : `${label} ${conclusion}`;
33249
33763
  }
33250
33764
  async function toggleExperimentalOtCheckbox(targetEnabled) {
33251
33765
  const checkbox = getPanel()?.querySelector("[data-experimental-ot]");
33252
- if (!checkbox) {
33766
+ if (!checkbox || otTogglePending) {
33253
33767
  return;
33254
33768
  }
33255
- const nextEnabled = typeof targetEnabled === "boolean" ? targetEnabled : !checkbox.checked;
33256
- if (nextEnabled) {
33257
- closeDiagnosticsMenu();
33258
- const approved = await showPluginConfirm({
33259
- title: tr("experimentalOtConfirmTitle"),
33260
- message: tr("experimentalOtConfirmMessage"),
33261
- confirmLabel: tr("experimentalOtConfirmEnable"),
33262
- cancelLabel: tr("confirmDefaultCancel")
33263
- });
33264
- if (!approved) {
33265
- return;
33769
+ const projectId = getCurrentProjectId();
33770
+ otTogglePending = true;
33771
+ try {
33772
+ const nextEnabled = typeof targetEnabled === "boolean" ? targetEnabled : !checkbox.checked;
33773
+ if (nextEnabled) {
33774
+ closeDiagnosticsMenu();
33775
+ const approved = await showPluginConfirm({
33776
+ title: tr("experimentalOtConfirmTitle"),
33777
+ message: tr("experimentalOtConfirmMessage"),
33778
+ confirmLabel: tr("experimentalOtConfirmEnable"),
33779
+ cancelLabel: tr("confirmDefaultCancel")
33780
+ });
33781
+ if (!approved) {
33782
+ return;
33783
+ }
33784
+ } else {
33785
+ closeDiagnosticsMenu();
33266
33786
  }
33267
- } else {
33268
- closeDiagnosticsMenu();
33269
- }
33270
- checkbox.checked = nextEnabled;
33271
- handleExperimentalOtToggleChange({ currentTarget: checkbox });
33272
- if (nextEnabled) {
33273
- showPluginToast(tr("experimentalOtEnabledToast"), { status: "info" });
33787
+ if (projectId !== getCurrentProjectId() || checkbox !== getPanel()?.querySelector("[data-experimental-ot]")) return;
33788
+ checkbox.checked = nextEnabled;
33789
+ handleExperimentalOtToggleChange({ currentTarget: checkbox });
33790
+ if (nextEnabled) {
33791
+ showPluginToast(tr("experimentalOtEnabledToast"), { status: "info" });
33792
+ }
33793
+ } finally {
33794
+ otTogglePending = false;
33274
33795
  }
33275
33796
  }
33276
33797
  function handleExperimentalOtToggleChange(event) {
@@ -33279,6 +33800,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33279
33800
  return;
33280
33801
  }
33281
33802
  const projectId = getCurrentProjectId();
33803
+ otWarmMirrorState.failureActive = false;
33282
33804
  lastExperimentalOtProjectId = projectId;
33283
33805
  setExperimentalOtEnabledForProject(projectId, checkbox.checked);
33284
33806
  updateExperimentalOtToggleControl(checkbox.checked);
@@ -33295,7 +33817,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33295
33817
  updateOtStatusDisplay(checkbox.checked ? currentOtStatus === "off" ? "starting" : currentOtStatus : "off");
33296
33818
  syncOtWarmMirrorController().catch((error) => {
33297
33819
  updateOtStatusDisplay("unavailable");
33298
- appendPlainLog(tx(`Experimental OT warm mirror unavailable: ${error.message}`, `\u5B9E\u9A8C\u6027 OT \u9884\u70ED\u955C\u50CF\u4E0D\u53EF\u7528\uFF1A${error.message}`));
33820
+ appendPlainLog(tx(`OT warm mirror unavailable: ${error.message}`, `OT \u9884\u70ED\u955C\u50CF\u4E0D\u53EF\u7528\uFF1A${error.message}`));
33299
33821
  });
33300
33822
  saveStateSoon();
33301
33823
  }
@@ -33313,6 +33835,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33313
33835
  otWarmMirrorProjectId = projectId;
33314
33836
  ensureOtWarmMirrorStateProject(projectId);
33315
33837
  if (enabled) {
33838
+ otWarmMirrorState.suspended = false;
33316
33839
  const pause = otWarmMirrorController?.shouldPauseOtWarmMirror?.({ running: Boolean(getCurrentRunView()) }) || { pause: false };
33317
33840
  if (pause.pause) {
33318
33841
  clearOtEventPolling({ clearPatchQueue: true });
@@ -33324,7 +33847,12 @@ ${conclusion}` : `${label} ${conclusion}`;
33324
33847
  } else {
33325
33848
  clearOtEventPolling({ clearPatchQueue: true });
33326
33849
  }
33327
- const response = enabled ? await callPageBridge("startOtObserver", { projectId }) : await callPageBridge("stopOtObserver", {});
33850
+ let response;
33851
+ try {
33852
+ response = enabled ? await callPageBridge("startOtObserver", { projectId }) : await callPageBridge("stopOtObserver", {});
33853
+ } catch (error) {
33854
+ response = { ok: false, error: otWarmMirrorController.normalizeFailureCode(error?.code || error?.message, "ot_bridge_unavailable") };
33855
+ }
33328
33856
  if (!isCurrentOtSync(requestId, projectId) || getCurrentProjectId() !== projectId) {
33329
33857
  if (enabled) {
33330
33858
  await handleStaleOtStartResponse(projectId, requestId);
@@ -33341,7 +33869,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33341
33869
  }
33342
33870
  const status = readOtBridgeStatus(response);
33343
33871
  if (!isSuccessfulOtBridgeResponse(response) || status === "unavailable") {
33344
- handleFailedOtStart(projectId, requestId);
33872
+ await handleFailedOtStart(projectId, requestId, response);
33345
33873
  return response;
33346
33874
  }
33347
33875
  const pauseAfterStart = otWarmMirrorController?.shouldPauseOtWarmMirror?.({ running: Boolean(getCurrentRunView()) }) || { pause: false };
@@ -33349,6 +33877,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33349
33877
  await pauseOtWarmMirror(pauseAfterStart.reason || "paused");
33350
33878
  return response;
33351
33879
  }
33880
+ otWarmMirrorState.failureActive = false;
33352
33881
  updateOtStatusDisplay(status);
33353
33882
  scheduleOtEventPolling(projectId, { immediate: true });
33354
33883
  return response;
@@ -33369,11 +33898,13 @@ ${conclusion}` : `${label} ${conclusion}`;
33369
33898
  await syncOtWarmMirrorController();
33370
33899
  }
33371
33900
  }
33372
- function handleFailedOtStart(projectId, requestId) {
33901
+ async function handleFailedOtStart(projectId, requestId, response) {
33373
33902
  if (!isCurrentOtSync(requestId, projectId) || getCurrentProjectId() !== projectId) {
33374
33903
  return;
33375
33904
  }
33376
33905
  clearOtEventPolling({ clearPatchQueue: true });
33906
+ recordOtFailure(readOtBridgeErrorCode(response, "ot_start_failed"), "start");
33907
+ otWarmMirrorState.suspended = true;
33377
33908
  setExperimentalOtEnabledForProject(projectId, false);
33378
33909
  const experimentalOtCheckbox = getPanel()?.querySelector("[data-experimental-ot]");
33379
33910
  if (experimentalOtCheckbox) {
@@ -33381,12 +33912,16 @@ ${conclusion}` : `${label} ${conclusion}`;
33381
33912
  }
33382
33913
  updateOtStatusDisplay("unavailable");
33383
33914
  saveStateSoon();
33915
+ try {
33916
+ await callPageBridge("stopOtObserver", { projectId });
33917
+ } catch (_error) {
33918
+ }
33384
33919
  }
33385
33920
  function readOtBridgeStatus(response) {
33386
33921
  if (!response || response.ok === false) {
33387
33922
  return "unavailable";
33388
33923
  }
33389
- return response.getState() || response.status || response.result?.getState() || response.result?.status || "unavailable";
33924
+ return response.state || response.status || response.result?.state || response.result?.status || "unavailable";
33390
33925
  }
33391
33926
  function ensureOtWarmMirrorStateProject(projectId) {
33392
33927
  if (!projectId || otWarmMirrorState.projectId === projectId) {
@@ -33396,6 +33931,9 @@ ${conclusion}` : `${label} ${conclusion}`;
33396
33931
  otWarmMirrorState.projectId = projectId;
33397
33932
  otWarmMirrorState.lastPatchAt = 0;
33398
33933
  otWarmMirrorState.lastErrorCode = "";
33934
+ otWarmMirrorState.failureActive = false;
33935
+ otWarmMirrorState.lastFailure = null;
33936
+ otWarmMirrorState.suspended = false;
33399
33937
  otWarmMirrorState.lastStatus = currentOtStatus;
33400
33938
  }
33401
33939
  function clearOtEventPolling(options2 = {}) {
@@ -33429,7 +33967,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33429
33967
  }, delayMs);
33430
33968
  }
33431
33969
  function canPollOtWarmMirror(projectId) {
33432
- return Boolean(projectId && otWarmMirrorController?.shouldPauseOtWarmMirror && otWarmMirrorController?.buildPatchFilesRequest && isExperimentalOtEnabledForProject(projectId) && otWarmMirrorProjectId === projectId && getCurrentProjectId() === projectId);
33970
+ return Boolean(projectId && otWarmMirrorController?.shouldPauseOtWarmMirror && otWarmMirrorController?.buildPatchFilesRequest && isExperimentalOtEnabledForProject(projectId) && otWarmMirrorProjectId === projectId && getCurrentProjectId() === projectId && !otWarmMirrorState.suspended);
33433
33971
  }
33434
33972
  async function pollOtEvents(projectId = otWarmMirrorState.projectId || getCurrentProjectId()) {
33435
33973
  if (!canPollOtWarmMirror(projectId)) {
@@ -33449,11 +33987,12 @@ ${conclusion}` : `${label} ${conclusion}`;
33449
33987
  return { ok: false, skipped: true, reason: "project_changed" };
33450
33988
  }
33451
33989
  if (!isSuccessfulOtBridgeResponse(statusResponse)) {
33452
- otWarmMirrorState.lastErrorCode = readOtBridgeErrorCode(statusResponse, "get_ot_status_failed");
33990
+ recordOtFailure(readOtBridgeErrorCode(statusResponse, "get_ot_status_failed"), "observe");
33453
33991
  updateOtStatusDisplay("unavailable");
33454
33992
  return statusResponse;
33455
33993
  }
33456
33994
  const status = readOtBridgeStatus(statusResponse);
33995
+ if (["unavailable", "inconsistent"].includes(status)) recordOtFailure(readOtBridgeErrorCode(statusResponse, "ot_observer_unavailable"), "observe");
33457
33996
  if (status) {
33458
33997
  updateOtStatusDisplay(status);
33459
33998
  }
@@ -33462,7 +34001,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33462
34001
  return { ok: false, skipped: true, reason: "project_changed" };
33463
34002
  }
33464
34003
  if (!isSuccessfulOtBridgeResponse(drainResponse)) {
33465
- otWarmMirrorState.lastErrorCode = readOtBridgeErrorCode(drainResponse, "drain_ot_events_failed");
34004
+ recordOtFailure(readOtBridgeErrorCode(drainResponse, "drain_ot_events_failed"), "observe");
33466
34005
  updateOtStatusDisplay("unavailable");
33467
34006
  return drainResponse;
33468
34007
  }
@@ -33472,7 +34011,8 @@ ${conclusion}` : `${label} ${conclusion}`;
33472
34011
  }
33473
34012
  return drainResponse;
33474
34013
  } catch (error) {
33475
- otWarmMirrorState.lastErrorCode = error?.code || error?.message || "ot_poll_failed";
34014
+ if (!canPollOtWarmMirror(projectId)) return { ok: false, skipped: true, reason: "project_changed" };
34015
+ recordOtFailure(error?.code || error?.message || "ot_poll_failed", "observe");
33476
34016
  updateOtStatusDisplay("unavailable");
33477
34017
  return { ok: false, error };
33478
34018
  } finally {
@@ -33497,12 +34037,28 @@ ${conclusion}` : `${label} ${conclusion}`;
33497
34037
  const value = response?.lastErrorCode || response?.reason || response?.error?.code || response?.error || fallback;
33498
34038
  return typeof value === "string" ? value : fallback;
33499
34039
  }
34040
+ function recordOtFailure(code, phase) {
34041
+ code = otWarmMirrorController.normalizeFailureCode(code);
34042
+ otWarmMirrorState.lastErrorCode = code;
34043
+ otWarmMirrorState.failureActive = true;
34044
+ otWarmMirrorState.lastFailure = { code, phase, at: Date.now() };
34045
+ }
33500
34046
  function queueOtPatchEvents(events, projectId = getCurrentProjectId()) {
33501
34047
  if (!Array.isArray(events) || !events.length || !canPollOtWarmMirror(projectId)) {
33502
34048
  return;
33503
34049
  }
33504
34050
  ensureOtWarmMirrorStateProject(projectId);
33505
- otWarmMirrorState.patchQueue.push(...events);
34051
+ const queued = otWarmMirrorController.queuePatchEvents(otWarmMirrorState.patchQueue, events);
34052
+ if (!queued.ok) {
34053
+ recordOtFailure(queued.reason, "queue");
34054
+ clearOtEventPolling({ clearPatchQueue: true });
34055
+ otWarmMirrorState.suspended = true;
34056
+ updateOtStatusDisplay("inconsistent");
34057
+ void callPageBridge("stopOtObserver", { projectId }).catch(() => {
34058
+ });
34059
+ return;
34060
+ }
34061
+ otWarmMirrorState.patchQueue = queued.queue;
33506
34062
  scheduleOtPatchFlush(projectId);
33507
34063
  }
33508
34064
  function scheduleOtPatchFlush(projectId = otWarmMirrorState.projectId || getCurrentProjectId(), options2 = {}) {
@@ -33536,11 +34092,18 @@ ${conclusion}` : `${label} ${conclusion}`;
33536
34092
  clearOtEventPolling({ clearPatchQueue: false });
33537
34093
  return { ok: false, skipped: true, reason: pause.reason || "paused" };
33538
34094
  }
33539
- const maxBatch = Math.max(1, Number(otWarmMirrorController?.OT_MAX_PATCH_BATCH) || 25);
33540
- const batch = otWarmMirrorState.patchQueue.splice(0, maxBatch);
34095
+ let batch = otWarmMirrorController.takePatchBatch(otWarmMirrorState.patchQueue);
33541
34096
  if (!batch.length) {
33542
34097
  return { ok: true, skipped: true, reason: "empty_batch" };
33543
34098
  }
34099
+ const fresh = otWarmMirrorController.queuePatchEvents([], batch);
34100
+ if (!fresh.ok) {
34101
+ recordOtFailure(fresh.reason, "queue");
34102
+ clearOtEventPolling({ clearPatchQueue: true });
34103
+ updateOtStatusDisplay("inconsistent");
34104
+ return { ok: false, skipped: true, reason: fresh.reason };
34105
+ }
34106
+ batch = fresh.queue;
33544
34107
  otWarmMirrorState.flushing = true;
33545
34108
  try {
33546
34109
  const request = {
@@ -33554,40 +34117,35 @@ ${conclusion}` : `${label} ${conclusion}`;
33554
34117
  return { ok: false, skipped: true, reason: "project_changed" };
33555
34118
  }
33556
34119
  const response = await sendBackgroundNative(request);
34120
+ if (!canPollOtWarmMirror(projectId)) return { ok: false, skipped: true, reason: "project_changed" };
33557
34121
  if (!response?.ok) {
33558
- otWarmMirrorState.lastErrorCode = response?.error?.code || response?.error?.message || "mirror_patch_failed";
33559
- updateOtStatusDisplay("inconsistent");
33560
- return response;
33561
- }
33562
- const result = response.result || {};
33563
- const skippedFiles = Array.isArray(result?.skippedFiles) ? result.skippedFiles : [];
33564
- const skippedCount = Number.isFinite(Number(result?.skippedCount)) ? Number(result.skippedCount) : skippedFiles.length;
33565
- if (skippedFiles.length || skippedCount > 0) {
33566
- otWarmMirrorState.lastErrorCode = "mirror_patch_skipped";
34122
+ recordOtFailure(response?.error?.code || "mirror_patch_failed", "flush");
33567
34123
  updateOtStatusDisplay("inconsistent");
33568
34124
  return response;
33569
34125
  }
33570
- const appliedFiles = Array.isArray(result?.appliedFiles) ? result.appliedFiles : null;
33571
- const appliedCount = Number.isFinite(Number(result?.appliedCount)) ? Number(result.appliedCount) : NaN;
33572
- if (!appliedFiles || !Number.isFinite(appliedCount) || appliedCount <= 0 || appliedFiles.length !== appliedCount) {
33573
- otWarmMirrorState.lastErrorCode = "mirror_patch_invalid_result";
34126
+ const receipt = otWarmMirrorController.validatePatchReceipt(batch, response.result);
34127
+ if (!receipt.ok) {
34128
+ recordOtFailure(receipt.reason, "flush");
33574
34129
  updateOtStatusDisplay("inconsistent");
33575
34130
  return response;
33576
34131
  }
33577
34132
  otWarmMirrorState.lastPatchAt = Date.now();
33578
34133
  otWarmMirrorState.lastErrorCode = "";
33579
- if (canPollOtWarmMirror(projectId)) {
34134
+ otWarmMirrorState.failureActive = false;
34135
+ if (canPollOtWarmMirror(projectId) && !getCurrentRunView()) {
33580
34136
  updateOtStatusDisplay("observing");
33581
34137
  }
33582
34138
  return response;
33583
34139
  } catch (error) {
33584
- otWarmMirrorState.lastErrorCode = error?.code || error?.message || "mirror_patch_failed";
34140
+ if (!canPollOtWarmMirror(projectId)) return { ok: false, skipped: true, reason: "project_changed" };
34141
+ recordOtFailure(error?.code || "mirror_patch_failed", "flush");
33585
34142
  updateOtStatusDisplay("inconsistent");
33586
34143
  return { ok: false, error };
33587
34144
  } finally {
33588
34145
  otWarmMirrorState.flushing = false;
33589
- if (otWarmMirrorState.patchQueue.length && canPollOtWarmMirror(projectId) && !getCurrentRunView()) {
33590
- scheduleOtPatchFlush(projectId, { immediate: true });
34146
+ const nextProjectId = otWarmMirrorState.projectId;
34147
+ if (otWarmMirrorState.patchQueue.length && canPollOtWarmMirror(nextProjectId) && !getCurrentRunView()) {
34148
+ scheduleOtPatchFlush(nextProjectId, { immediate: true });
33591
34149
  }
33592
34150
  }
33593
34151
  }
@@ -33627,12 +34185,12 @@ ${conclusion}` : `${label} ${conclusion}`;
33627
34185
  }
33628
34186
  }
33629
34187
  function updateOtStatusDisplay(status = currentOtStatus) {
33630
- const normalized = normalizeOtStatus(status);
34188
+ const normalized = otWarmMirrorState.failureActive && status === "observing" ? "inconsistent" : normalizeOtStatus(status);
33631
34189
  currentOtStatus = normalized;
33632
34190
  otWarmMirrorState.lastStatus = normalized;
33633
34191
  const statusElement = getPanel()?.querySelector("[data-ot-status]");
33634
34192
  if (statusElement) {
33635
- const label = formatOtStatusLabel(normalized);
34193
+ const label = formatOtStatusLabel(normalized) + (otWarmMirrorState.failureActive ? ": " + tr(otWarmMirrorController.getFailureMessageKey(otWarmMirrorState.lastErrorCode)) : "");
33636
34194
  statusElement.textContent = formatOtToggleStatusText(label);
33637
34195
  statusElement.dataset.otStatus = normalized;
33638
34196
  statusElement.title = formatOtToggleStatusText(label);
@@ -33780,37 +34338,23 @@ ${conclusion}` : `${label} ${conclusion}`;
33780
34338
  return health.reusable === true;
33781
34339
  }
33782
34340
  async function resolveWarmRunStart(taskContext = {}) {
34341
+ const projectId = getCurrentProjectId();
33783
34342
  const focusFiles = taskContext.focusFiles || [];
33784
34343
  const mode = taskContext.mode || getState()?.mode;
33785
34344
  const mirrorStatus = await getMirrorFreshness();
34345
+ if (getCurrentProjectId() !== projectId) return { useExistingMirror: false, reason: "project_changed" };
33786
34346
  const otWarmStart = otWarmMirrorController.canUseOtWarmStart({
33787
- enabled: isExperimentalOtEnabled(),
34347
+ enabled: isExperimentalOtEnabled() && !otWarmMirrorState.failureActive,
33788
34348
  focusFiles,
33789
34349
  mirrorStatus
33790
34350
  });
33791
- if (otWarmStart.ok) {
33792
- return {
33793
- useExistingMirror: true,
33794
- warmStart: true,
33795
- otWarmStart: true,
33796
- reason: "ot_focus_fresh",
33797
- mirrorStatus,
33798
- focusFiles: otWarmStart.focusFiles,
33799
- project: {
33800
- capabilities: {
33801
- fullProjectSnapshot: false,
33802
- method: "ot-warm-mirror"
33803
- },
33804
- files: []
33805
- }
33806
- };
33807
- }
33808
- if (!mirrorStatus?.exists || !isMirrorReusable(mirrorStatus)) {
34351
+ if (!mirrorStatus?.exists || !otWarmStart.ok && !isMirrorReusable(mirrorStatus)) {
33809
34352
  return { useExistingMirror: false, reason: "mirror_not_fresh", mirrorStatus };
33810
34353
  }
33811
34354
  let overlayProject = null;
33812
34355
  try {
33813
34356
  overlayProject = await callPageBridge("getProjectSnapshot", {
34357
+ projectId,
33814
34358
  force: true,
33815
34359
  maxAgeMs: 0,
33816
34360
  preferLightweight: true,
@@ -33824,6 +34368,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33824
34368
  } catch (error) {
33825
34369
  return { useExistingMirror: false, reason: "overlay_probe_failed", mirrorStatus };
33826
34370
  }
34371
+ if (getCurrentProjectId() !== projectId) return { useExistingMirror: false, reason: "project_changed" };
33827
34372
  const fileOverlays = buildSnapshotFileOverlays(overlayProject, focusFiles);
33828
34373
  if (!fileOverlays.length) {
33829
34374
  return { useExistingMirror: false, reason: "missing_current_overlay", mirrorStatus };
@@ -33837,7 +34382,9 @@ ${conclusion}` : `${label} ${conclusion}`;
33837
34382
  return {
33838
34383
  useExistingMirror: true,
33839
34384
  warmStart: true,
33840
- reason: mode === "ask" ? "warm_whole_project_ask" : "warm_whole_project",
34385
+ otWarmStart: otWarmStart.ok,
34386
+ focusFiles,
34387
+ reason: otWarmStart.ok ? "ot_focus_fresh" : mode === "ask" ? "warm_whole_project_ask" : "warm_whole_project",
33841
34388
  mirrorStatus,
33842
34389
  fileOverlays,
33843
34390
  project: overlayProject
@@ -33922,7 +34469,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33922
34469
  return syncOtWarmMirrorController();
33923
34470
  }).catch((error) => {
33924
34471
  updateOtStatusDisplay("unavailable");
33925
- appendPlainLog(tx(`Experimental OT warm mirror unavailable: ${error.message}`, `\u5B9E\u9A8C\u6027 OT \u9884\u70ED\u955C\u50CF\u4E0D\u53EF\u7528\uFF1A${error.message}`));
34472
+ appendPlainLog(tx(`OT warm mirror unavailable: ${error.message}`, `OT \u9884\u70ED\u955C\u50CF\u4E0D\u53EF\u7528\uFF1A${error.message}`));
33926
34473
  });
33927
34474
  }
33928
34475
  return {
@@ -33957,7 +34504,7 @@ ${conclusion}` : `${label} ${conclusion}`;
33957
34504
  window.CodexOverleafOtWarmMirror = { create };
33958
34505
  })();
33959
34506
  }).call(globalThis, void 0, void 0, void 0);
33960
- (function runClassicContentModule90(module, exports, require2) {
34507
+ (function runClassicContentModule93(module, exports, require2) {
33961
34508
  (function initCodexOverleafWritebackOrchestrator() {
33962
34509
  "use strict";
33963
34510
  let tr;
@@ -34713,7 +35260,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
34713
35260
  window.CodexOverleafWritebackOrchestrator = { create };
34714
35261
  })();
34715
35262
  }).call(globalThis, void 0, void 0, void 0);
34716
- (function runClassicContentModule91(module, exports, require2) {
35263
+ (function runClassicContentModule94(module, exports, require2) {
34717
35264
  (function initCodexOverleafRunSettlementPersistence(root, factory) {
34718
35265
  const api = factory();
34719
35266
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -34756,7 +35303,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
34756
35303
  return Object.freeze({ create });
34757
35304
  });
34758
35305
  }).call(globalThis, void 0, void 0, void 0);
34759
- (function runClassicContentModule92(module, exports, require2) {
35306
+ (function runClassicContentModule95(module, exports, require2) {
34760
35307
  (function initPostNavigationSettlementPersistence(root, factory) {
34761
35308
  const api = factory();
34762
35309
  if (typeof module === "object" && module.exports) module.exports = api;
@@ -34848,7 +35395,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
34848
35395
  return Object.freeze({ persist, persistRequired });
34849
35396
  });
34850
35397
  }).call(globalThis, void 0, void 0, void 0);
34851
- (function runClassicContentModule93(module, exports, require2) {
35398
+ (function runClassicContentModule96(module, exports, require2) {
34852
35399
  (function initCodexOverleafPanelMaintenance() {
34853
35400
  "use strict";
34854
35401
  function create(deps = {}) {
@@ -34951,30 +35498,43 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
34951
35498
  list.append(row);
34952
35499
  }
34953
35500
  }
35501
+ let storageUsageRequestId = 0;
34954
35502
  function refreshStorageUsageSummary() {
34955
35503
  const node = getSettingsPanelInstance()?.container?.querySelector("[data-storage-usage]");
34956
35504
  if (!node) {
34957
35505
  return;
34958
35506
  }
34959
- const sessionCount = Array.isArray(getState()?.sessions) ? getState().sessions.length : 0;
34960
- const runCount = Array.isArray(getState()?.runs) ? getState().runs.length : 0;
35507
+ const requestId = ++storageUsageRequestId;
35508
+ const projectId = getCurrentProjectId?.();
35509
+ const isCurrent = () => requestId === storageUsageRequestId && projectId === getCurrentProjectId?.() && getSettingsPanelInstance()?.container?.querySelector("[data-storage-usage]") === node;
35510
+ const current = getState();
35511
+ const sessionCount = Array.isArray(current?.sessions) ? current.sessions.length : 0;
35512
+ const runCount = Array.isArray(current?.runs) ? current.runs.length : 0;
34961
35513
  const counts = tx(
34962
- `${sessionCount} session(s) \xB7 ${runCount} recent run(s) kept`,
34963
- `${sessionCount} \u4E2A\u4F1A\u8BDD \xB7 \u4FDD\u7559\u6700\u8FD1 ${runCount} \u8F6E\u8FD0\u884C`
35514
+ `${sessionCount} loaded session(s) in this project \xB7 ${runCount} run(s) in the active session`,
35515
+ `\u5F53\u524D\u9879\u76EE\u5DF2\u52A0\u8F7D ${sessionCount} \u4E2A\u4F1A\u8BDD \xB7 \u5F53\u524D\u4F1A\u8BDD ${runCount} \u8F6E\u8FD0\u884C`
34964
35516
  );
35517
+ node.removeAttribute?.("data-i18n");
34965
35518
  node.textContent = counts;
34966
- const estimate = navigator.storage?.estimate?.();
34967
- if (estimate?.then) {
34968
- estimate.then((info) => {
34969
- const usage = Number(info?.usage);
34970
- if (Number.isFinite(usage) && usage >= 0) {
34971
- const mb = usage / (1024 * 1024);
34972
- const size = mb >= 1 ? `${mb.toFixed(1)} MB` : `${Math.max(1, Math.round(usage / 1024))} KB`;
34973
- node.textContent = tx(`${counts} \xB7 ~${size} used on this site`, `${counts} \xB7 \u672C\u7AD9\u70B9\u7EA6\u5360\u7528 ${size}`);
34974
- }
34975
- }).catch(() => {
34976
- });
34977
- }
35519
+ const unavailable = () => {
35520
+ if (isCurrent()) node.textContent = tx(`${counts} \xB7 Site storage estimate unavailable`, `${counts} \xB7 \u672C\u7AD9\u70B9\u5BB9\u91CF\u6682\u65E0\u6CD5\u4F30\u7B97`);
35521
+ };
35522
+ let timer;
35523
+ const estimate = Promise.resolve().then(() => navigator.storage?.estimate?.());
35524
+ const deadline = new Promise((resolve) => {
35525
+ timer = setTimeout(() => resolve(null), 2e3);
35526
+ });
35527
+ return Promise.race([estimate, deadline]).then((info) => {
35528
+ if (!isCurrent()) return;
35529
+ const usage = info?.usage;
35530
+ if (!Number.isFinite(usage) || usage < 0) {
35531
+ unavailable();
35532
+ return;
35533
+ }
35534
+ const mb = usage / (1024 * 1024);
35535
+ const size = usage === 0 ? "0 KB" : mb >= 1 ? `${mb.toFixed(1)} MB` : `${Math.max(1, Math.round(usage / 1024))} KB`;
35536
+ node.textContent = tx(`${counts} \xB7 Site total ~${size}`, `${counts} \xB7 \u672C\u7AD9\u70B9\u603B\u5360\u7528\u7EA6 ${size}`);
35537
+ }).catch(unavailable).finally(() => clearTimeout(timer));
34978
35538
  }
34979
35539
  async function clearAllHistoryWithConfirm() {
34980
35540
  if (getCurrentRunView()) {
@@ -35166,7 +35726,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35166
35726
  window.CodexOverleafPanelMaintenance = { create };
35167
35727
  })();
35168
35728
  }).call(globalThis, void 0, void 0, void 0);
35169
- (function runClassicContentModule94(module, exports, require2) {
35729
+ (function runClassicContentModule97(module, exports, require2) {
35170
35730
  (function initCodexOverleafUpdateIdle(root) {
35171
35731
  "use strict";
35172
35732
  function create(options2 = {}) {
@@ -35234,7 +35794,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35234
35794
  root.CodexOverleafUpdateIdle = Object.freeze({ create });
35235
35795
  })(typeof window !== "undefined" ? window : globalThis);
35236
35796
  }).call(globalThis, void 0, void 0, void 0);
35237
- (function runClassicContentModule95(module, exports, require2) {
35797
+ (function runClassicContentModule98(module, exports, require2) {
35238
35798
  (function initCodexOverleafUpdateNotice(root, factory) {
35239
35799
  if (typeof module === "object" && module.exports) {
35240
35800
  module.exports = factory(require2("../shared/managedUpdateProjection"));
@@ -35322,7 +35882,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35322
35882
  install: "codex-overleaf/consent-update-install",
35323
35883
  retry: "codex-overleaf/consent-update-check",
35324
35884
  later: "codex-overleaf/consent-update-later",
35325
- dismiss: "codex-overleaf/consent-update-dismiss"
35885
+ dismiss: "codex-overleaf/consent-update-dismiss",
35886
+ reload: "codex-overleaf/consent-update-reload"
35326
35887
  }[action]);
35327
35888
  } catch (error) {
35328
35889
  currentView = await reconcileAfterActionError(error, {
@@ -35435,7 +35996,10 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35435
35996
  const stateName = currentView?.state?.state || "idle";
35436
35997
  let requestedAction = "check";
35437
35998
  try {
35438
- if (stateName === "update_available") {
35999
+ if (["reload_required", "reload_tabs_required"].includes(stateName)) {
36000
+ requestedAction = "reload";
36001
+ currentView = await request("codex-overleaf/consent-update-reload");
36002
+ } else if (stateName === "update_available") {
35439
36003
  requestedAction = "install";
35440
36004
  currentView = await request("codex-overleaf/consent-update-install");
35441
36005
  } else if (["failed", "rolled_back"].includes(stateName)) {
@@ -35494,7 +36058,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35494
36058
  command.textContent = manualUpdateCommand(state);
35495
36059
  body.append(recovery, command);
35496
36060
  }
35497
- if (!["update_available", "failed", "rolled_back"].includes(state.state)) {
36061
+ if (!["update_available", "failed", "rolled_back", "reload_required", "reload_tabs_required"].includes(state.state)) {
35498
36062
  const bar = document.createElement("div");
35499
36063
  bar.className = "codex-update-notice-progress" + (progress.determinate ? "" : " is-indeterminate");
35500
36064
  bar.setAttribute("role", "progressbar");
@@ -35540,7 +36104,11 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35540
36104
  );
35541
36105
  let statusText = "";
35542
36106
  let buttonText = tx("Check for updates", "\u68C0\u67E5\u66F4\u65B0");
35543
- if (stateName === "checking") {
36107
+ if (["reload_required", "reload_tabs_required"].includes(stateName)) {
36108
+ summaryText = tx(`Installed v${latestVersion}; running extension v${currentVersion}.`, `\u5DF2\u5B89\u88C5 v${latestVersion}\uFF1B\u6269\u5C55\u5F53\u524D\u8FD0\u884C v${currentVersion}\u3002`);
36109
+ statusText = getCopy(state).detail;
36110
+ buttonText = stateName === "reload_required" ? tx("Reload extension", "\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55") : tx("Refresh Overleaf tabs", "\u5237\u65B0 Overleaf \u6807\u7B7E\u9875");
36111
+ } else if (stateName === "checking") {
35544
36112
  statusText = tx("Checking the latest stable release\u2026", "\u6B63\u5728\u68C0\u67E5\u6700\u65B0\u7A33\u5B9A\u7248\u672C\u2026");
35545
36113
  buttonText = tx("Checking\u2026", "\u68C0\u67E5\u4E2D\u2026");
35546
36114
  } else if (stateName === "update_available") {
@@ -35565,6 +36133,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35565
36133
  }
35566
36134
  function visibleActions(state) {
35567
36135
  if (actionInFlight) return [];
36136
+ if (["reload_required", "reload_tabs_required"].includes(state)) {
36137
+ return [{ id: "reload", label: state === "reload_required" ? tx("Reload extension", "\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55") : tx("Refresh Overleaf tabs", "\u5237\u65B0 Overleaf \u6807\u7B7E\u9875"), primary: true }];
36138
+ }
35568
36139
  if (state === "update_available") {
35569
36140
  return [
35570
36141
  { id: "later", label: tx("Later", "\u7A0D\u540E"), primary: false },
@@ -35589,6 +36160,16 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35589
36160
  const target = state.latestVersion ? "v" + state.latestVersion : "";
35590
36161
  const blocker = blockersCopy(state.blockers?.length ? state.blockers : [state.blocker]);
35591
36162
  return {
36163
+ reload_required: {
36164
+ eyebrow: tx("Installed, awaiting reload", "\u5DF2\u5B89\u88C5\uFF0C\u7B49\u5F85\u52A0\u8F7D"),
36165
+ title: target,
36166
+ detail: state.message || tx("The new files are installed. Reload the extension when Overleaf is saved and idle.", "\u65B0\u7248\u6587\u4EF6\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5728 Overleaf \u4FDD\u5B58\u5E76\u7A7A\u95F2\u540E\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55\u3002")
36167
+ },
36168
+ reload_tabs_required: {
36169
+ eyebrow: tx("Updated runtime is ready", "\u65B0\u7248\u8FD0\u884C\u7EC4\u4EF6\u5DF2\u5C31\u7EEA"),
36170
+ title: target,
36171
+ detail: state.message || tx("Refresh the saved, idle Overleaf tabs to load the updated panel.", "\u5237\u65B0\u5DF2\u4FDD\u5B58\u4E14\u7A7A\u95F2\u7684 Overleaf \u6807\u7B7E\u9875\u4EE5\u52A0\u8F7D\u65B0\u7248\u9762\u677F\u3002")
36172
+ },
35592
36173
  update_available: {
35593
36174
  eyebrow: tx("Update available", "\u53D1\u73B0\u65B0\u7248\u672C"),
35594
36175
  title: target,
@@ -35678,7 +36259,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
35678
36259
  return Object.freeze({ mount });
35679
36260
  });
35680
36261
  }).call(globalThis, void 0, void 0, void 0);
35681
- (function runClassicContentModule96(module, exports, require2) {
36262
+ (function runClassicContentModule99(module, exports, require2) {
35682
36263
  (function initCodexOverleafContentRuntime(root) {
35683
36264
  "use strict";
35684
36265
  function init(dependencies2) {
@@ -36072,6 +36653,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
36072
36653
  const runTimelineView = Modules.RunTimelineView.create({
36073
36654
  RunGuidanceView: Modules.RunGuidanceView,
36074
36655
  RunResultActions: runResultActions,
36656
+ RunScrollLayout: Modules.RunScrollLayout,
36657
+ RunFailureNotice: Modules.RunFailureNotice,
36075
36658
  tr,
36076
36659
  tx,
36077
36660
  getLocale,
@@ -36473,6 +37056,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
36473
37056
  }
36474
37057
  });
36475
37058
  let panel = null;
37059
+ let probeStatusSnapshot = null;
36476
37060
  let panelRendererInstance = null;
36477
37061
  let sessionPanelInstance = null;
36478
37062
  let settingsPanelInstance = null;
@@ -36646,7 +37230,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
36646
37230
  });
36647
37231
  syncOtWarmMirrorController().catch((error) => {
36648
37232
  updateOtStatusDisplay("unavailable");
36649
- appendPlainLog(tx(`Failed to sync experimental OT warm mirror: ${error.message}`, `\u540C\u6B65\u5B9E\u9A8C\u6027 OT \u9884\u70ED\u955C\u50CF\u5931\u8D25\uFF1A${error.message}`));
37233
+ appendPlainLog(tx(`Failed to sync OT warm mirror: ${error.message}`, `\u540C\u6B65 OT \u9884\u70ED\u955C\u50CF\u5931\u8D25\uFF1A${error.message}`));
36650
37234
  });
36651
37235
  await refreshProbe({ quiet: true });
36652
37236
  }
@@ -36869,6 +37453,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
36869
37453
  onProvidersOpen: () => providerSettingsCoordinator.open(),
36870
37454
  onClearAllHistory: () => clearAllHistoryWithConfirm(),
36871
37455
  onHistoryOpen: () => renderAuditHistoryPanel(),
37456
+ onStorageOpen: () => refreshStorageUsageSummary(),
36872
37457
  onHistoryFilter: () => applyAuditHistoryFilter(),
36873
37458
  // Experimental OT mirror: a single visible switch whose click is
36874
37459
  // intercepted so the confirm-before-enable flow still runs.
@@ -37095,6 +37680,17 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
37095
37680
  updateModelDisplay();
37096
37681
  renderSessionList();
37097
37682
  renderContextSelection();
37683
+ const probeStatus = panel.querySelector("[data-probe-status]");
37684
+ if (probeStatus?.dataset.refreshing === "true") probeStatus.textContent = tr("refreshProbeLoading");
37685
+ else if (probeStatus && probeStatusSnapshot?.projectId === getCurrentProjectId()) {
37686
+ const { failed, probe, userInitiated } = probeStatusSnapshot;
37687
+ const text = failed ? tr("refreshProbeFailed") : formatProbeStatusBar(probe);
37688
+ probeStatus.textContent = userInitiated && !failed ? tr("refreshProbeDone", { status: text }) : text;
37689
+ if (!failed) updateExistingProbeNotice(probe);
37690
+ }
37691
+ updateSkillsEntrySummary();
37692
+ providerSettingsCoordinator.renderSummary();
37693
+ if (settingsPanelInstance?.container?.querySelector("[data-storage-card]")?.open) refreshStorageUsageSummary();
37098
37694
  }
37099
37695
  function setElementTitleAndAria(selector, title, ariaLabel) {
37100
37696
  const element = panel?.querySelector(selector);
@@ -37817,7 +38413,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
37817
38413
  }
37818
38414
  }
37819
38415
  await saveState();
37820
- applyStateToPanel();
38416
+ applyStateToPanel({ preserveScroll: true });
37821
38417
  } catch (persistenceError) {
37822
38418
  appendRunEvent({
37823
38419
  title: tx("Codex result was generated, but saving local session history failed.", "Codex \u7ED3\u679C\u5DF2\u751F\u6210\uFF0C\u4F46\u4FDD\u5B58\u672C\u5730\u4F1A\u8BDD\u8BB0\u5F55\u5931\u8D25\u3002"),
@@ -39948,6 +40544,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
39948
40544
  return { safe, skipped };
39949
40545
  }
39950
40546
  async function refreshProbe(options2 = {}) {
40547
+ const projectId = getCurrentProjectId();
39951
40548
  const userInitiated = options2.userInitiated === true;
39952
40549
  if (userInitiated) {
39953
40550
  setRefreshProbeLoading(true);
@@ -39962,6 +40559,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
39962
40559
  const probe = await callPageBridge("probe", {
39963
40560
  manualOverride: state?.requireReviewing === false
39964
40561
  });
40562
+ if (projectId !== getCurrentProjectId()) return null;
40563
+ probeStatusSnapshot = { projectId, probe, userInitiated };
39965
40564
  const status = panel?.querySelector("[data-probe-status]");
39966
40565
  if (status) {
39967
40566
  status.textContent = userInitiated ? tr("refreshProbeDone", { status: formatProbeStatusBar(probe) }) : formatProbeStatusBar(probe);
@@ -39978,6 +40577,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
39978
40577
  if (!userInitiated) {
39979
40578
  throw error;
39980
40579
  }
40580
+ if (projectId !== getCurrentProjectId()) return null;
40581
+ probeStatusSnapshot = { projectId, failed: true };
39981
40582
  const status = panel?.querySelector("[data-probe-status]");
39982
40583
  if (status) {
39983
40584
  status.textContent = tr("refreshProbeFailed");
@@ -40864,7 +41465,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
40864
41465
  state = updateActiveSession(state, { task: "" });
40865
41466
  saveStateSoon();
40866
41467
  }
40867
- function applyStateToPanel() {
41468
+ function applyStateToPanel(options2 = {}) {
40868
41469
  applyPanelTheme(getThemePreference());
40869
41470
  if ((state.providerId || "builtin") === "builtin" && !modelSelectHasOption(state.model)) {
40870
41471
  renderModelOptions(getModelCatalog().FALLBACK_MODELS, state.model);
@@ -40898,7 +41499,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
40898
41499
  syncModeControls();
40899
41500
  applySessionLabel();
40900
41501
  renderSessionList();
40901
- renderRunHistory();
41502
+ renderRunHistory(options2);
40902
41503
  renderContextSelection();
40903
41504
  renderContextSummary();
40904
41505
  if (!composerAttachmentsRestoredOnce && Array.isArray(state.composerAttachments) && state.composerAttachments.length && !composerAttachmentController.getAttachmentsForRun?.().length && typeof composerAttachmentController.restorePersistedAttachments === "function") {
@@ -42502,7 +43103,7 @@ Reason: ${item.reason || "No reason provided"}`),
42502
43103
  root.CodexOverleafContentRuntime = { init };
42503
43104
  })(typeof window !== "undefined" ? window : globalThis);
42504
43105
  }).call(globalThis, void 0, void 0, void 0);
42505
- (function runClassicContentModule97(module, exports, require2) {
43106
+ (function runClassicContentModule100(module, exports, require2) {
42506
43107
  (function initCodexOverleafLegacyGlobalRegistry(root, factory) {
42507
43108
  "use strict";
42508
43109
  const api = factory();
@@ -42560,6 +43161,8 @@ Reason: ${item.reason || "No reason provided"}`),
42560
43161
  "RunInputQueue",
42561
43162
  "RunQueueScheduler",
42562
43163
  "RunResultActions",
43164
+ "RunScrollLayout",
43165
+ "RunFailureNotice",
42563
43166
  "RunSettlementPersistence",
42564
43167
  "RunTimelineView",
42565
43168
  "ScopedPersistenceCoordinator",