codex-overleaf-link 2.6.0 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/README.zh-CN.md +9 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/background.js +70 -0
- package/extension/src/content/composerAttachments.js +35 -8
- package/extension/src/content/contentRuntime.js +200 -51
- package/extension/src/content/diagnosticsController.js +77 -34
- package/extension/src/content/diagnosticsExport.js +1 -1
- package/extension/src/content/diagnosticsPanel.js +129 -42
- package/extension/src/content/generated/content.bundle.js +1283 -331
- package/extension/src/content/generated/content.bundle.meta.json +3 -3
- package/extension/src/content/localSkillsPanel.js +4 -2
- package/extension/src/content/markdownText.js +11 -9
- package/extension/src/content/modelPicker.js +28 -19
- package/extension/src/content/nativeCompatibilityController.js +23 -9
- package/extension/src/content/pageBridgeClient.js +5 -5
- package/extension/src/content/panelMaintenance.js +4 -0
- package/extension/src/content/panelRenderer.js +4 -1
- package/extension/src/content/providerSettingsDialog.js +26 -18
- package/extension/src/content/recentProjects.js +26 -16
- package/extension/src/content/runQueueScheduler.js +19 -9
- package/extension/src/content/runResultActions.js +51 -4
- package/extension/src/content/runReviewController.js +9 -3
- package/extension/src/content/scopedPersistencePanelState.js +34 -25
- package/extension/src/content/selectionContextView.js +30 -3
- package/extension/src/content/sharedSessionViewSync.js +9 -1
- package/extension/src/content/writebackOrchestrator.js +266 -50
- package/extension/src/content/writingStyleSettings.js +70 -17
- package/extension/src/page/overleafEditor.js +12 -3
- package/extension/src/page/overleafProjectSnapshot.js +56 -3
- package/extension/src/page/snapshotRouter.js +75 -66
- package/extension/src/page/treeOperations.js +200 -19
- package/extension/src/page/writebackRouter.js +152 -40
- package/extension/src/pageBridge.js +17 -7
- package/extension/src/shared/agentTranscript.js +23 -2
- package/extension/src/shared/auditRecords.js +1 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/composerAttachmentDraft.js +22 -7
- package/extension/src/shared/failureReasons.js +15 -0
- package/extension/src/shared/i18n.js +16 -0
- package/extension/src/shared/pageRpcContract.js +1 -1
- package/extension/src/shared/projectFiles.js +2 -1
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +34 -0
- package/extension/src/shared/staleGuard.js +58 -0
- package/extension/src/shared/storageMigration.js +104 -1
- package/extension/styles/panel.css +191 -63
- package/native-host/src/codexSessionRunner.js +1 -0
- package/native-host/src/debugLog.js +27 -3
- package/native-host/src/index.js +42 -11
- package/native-host/src/localSkills.js +1 -1
- package/native-host/src/mirrorWorkspace.js +47 -3
- package/native-host/src/nativeEnvironment.js +27 -5
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/skills/reviewer-response/SKILL.md +65 -0
- package/native-host/src/taskRunnerRuntime.js +11 -3
- package/native-host/src/updateManager.js +24 -6
- package/native-host/src/writingStyleRuntime.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
if (typeof document !== 'undefined' && document.documentElement) document.documentElement.setAttribute('data-codex-overleaf-source-digest', "
|
|
1
|
+
if (typeof document !== 'undefined' && document.documentElement) document.documentElement.setAttribute('data-codex-overleaf-source-digest', "91739cf894fed56c2880986120922d3b54bb423ab2d116705385da1d0fe518be");
|
|
2
2
|
(() => {
|
|
3
3
|
// extension/entries/content-entry.mjs
|
|
4
4
|
(function runClassicContentModule(module, exports, require2) {
|
|
@@ -913,6 +913,13 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
913
913
|
fallbackUserMessage: "The file changed while Codex was working.",
|
|
914
914
|
fallbackNextAction: "Review the current file, then rerun the task."
|
|
915
915
|
},
|
|
916
|
+
document_identity_mismatch: {
|
|
917
|
+
stage: "preflight",
|
|
918
|
+
severity: "blocked",
|
|
919
|
+
defaultRetryable: true,
|
|
920
|
+
fallbackUserMessage: "Codex could not confirm that the editor content belongs to the target file, so it was not used.",
|
|
921
|
+
fallbackNextAction: "Wait for the target file to open and settle, then retry. Reload Overleaf if this continues."
|
|
922
|
+
},
|
|
916
923
|
patch_anchor_not_found: {
|
|
917
924
|
stage: "preflight",
|
|
918
925
|
severity: "blocked",
|
|
@@ -1213,6 +1220,13 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
1213
1220
|
fallbackUserMessage: "Native host request failed.",
|
|
1214
1221
|
fallbackNextAction: "Open diagnostics and retry."
|
|
1215
1222
|
},
|
|
1223
|
+
native_request_timeout: {
|
|
1224
|
+
stage: "native",
|
|
1225
|
+
severity: "error",
|
|
1226
|
+
defaultRetryable: true,
|
|
1227
|
+
fallbackUserMessage: "The local service did not respond.",
|
|
1228
|
+
fallbackNextAction: "Retry, or open Diagnostics to check the local connection."
|
|
1229
|
+
},
|
|
1216
1230
|
native_protocol_incompatible: {
|
|
1217
1231
|
stage: "native",
|
|
1218
1232
|
severity: "blocked",
|
|
@@ -1311,6 +1325,13 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
1311
1325
|
fallbackUserMessage: "The provider rate limit was reached.",
|
|
1312
1326
|
fallbackNextAction: "Wait for the rate-limit window to recover and retry."
|
|
1313
1327
|
},
|
|
1328
|
+
provider_quota_exceeded: {
|
|
1329
|
+
stage: "codex",
|
|
1330
|
+
severity: "error",
|
|
1331
|
+
defaultRetryable: true,
|
|
1332
|
+
fallbackUserMessage: "The model provider quota or billing limit was reached.",
|
|
1333
|
+
fallbackNextAction: "Check the provider account and plan, or switch model or provider before retrying."
|
|
1334
|
+
},
|
|
1314
1335
|
provider_connection_timeout: {
|
|
1315
1336
|
stage: "codex",
|
|
1316
1337
|
severity: "error",
|
|
@@ -2038,6 +2059,9 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2038
2059
|
"timeout": {
|
|
2039
2060
|
"message": "timed out"
|
|
2040
2061
|
},
|
|
2062
|
+
"native_request_timeout": {
|
|
2063
|
+
"code": "native_request_timeout"
|
|
2064
|
+
},
|
|
2041
2065
|
"output_limit": {
|
|
2042
2066
|
"message": "output limit exceeded"
|
|
2043
2067
|
},
|
|
@@ -2054,7 +2078,7 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2054
2078
|
"message": "unsupported_parameter reasoning.summary"
|
|
2055
2079
|
},
|
|
2056
2080
|
"storage_quota": {
|
|
2057
|
-
"message": "quota"
|
|
2081
|
+
"message": "storage quota"
|
|
2058
2082
|
},
|
|
2059
2083
|
"checkpoint": {
|
|
2060
2084
|
"message": "checkpoint"
|
|
@@ -2092,6 +2116,9 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2092
2116
|
"provider_rate_limited": {
|
|
2093
2117
|
"message": "provider_rate_limited"
|
|
2094
2118
|
},
|
|
2119
|
+
"provider_quota_exceeded": {
|
|
2120
|
+
"message": "provider_quota_exceeded"
|
|
2121
|
+
},
|
|
2095
2122
|
"provider_connection_timeout": {
|
|
2096
2123
|
"message": "provider_connection_timeout"
|
|
2097
2124
|
},
|
|
@@ -2660,6 +2687,14 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2660
2687
|
nextEn: "Switch between Responses and Chat Completions, or test again with Auto detection.",
|
|
2661
2688
|
code: "provider_protocol_incompatible"
|
|
2662
2689
|
},
|
|
2690
|
+
{
|
|
2691
|
+
pattern: /provider_quota_exceeded|insufficient_quota|exceeded your current quota|(?:billing|usage|spend(?:ing)?|credit)[_ -]?(?:hard[_ -]?)?limit[_ -]?(?:reached|exceeded)|(?:billing|plan).{0,40}(?:quota|limit|exhausted)|(?:quota|credits?).{0,40}(?:billing|plan|exhausted|insufficient)/i,
|
|
2692
|
+
conclusionZh: "\u6A21\u578B\u670D\u52A1\u7684\u914D\u989D\u6216\u8D26\u5355\u9650\u989D\u5DF2\u8FBE\u5230\u3002",
|
|
2693
|
+
conclusionEn: "The model provider quota or billing limit was reached.",
|
|
2694
|
+
nextZh: "\u8BF7\u68C0\u67E5\u6A21\u578B\u670D\u52A1\u8D26\u6237\u548C\u5957\u9910\uFF0C\u6216\u5207\u6362\u6A21\u578B\u6216\u6A21\u578B\u670D\u52A1\u540E\u91CD\u8BD5\u3002",
|
|
2695
|
+
nextEn: "Check the provider account and plan, or switch model or provider before retrying.",
|
|
2696
|
+
code: "provider_quota_exceeded"
|
|
2697
|
+
},
|
|
2663
2698
|
{
|
|
2664
2699
|
pattern: /provider_rate_limited|rate limit was reached/i,
|
|
2665
2700
|
conclusionZh: "\u8FD9\u8F6E\u6CA1\u6709\u5B8C\u6210\uFF1A\u7B2C\u4E09\u65B9\u6A21\u578B\u670D\u52A1\u89E6\u53D1\u4E86\u9650\u6D41\u3002",
|
|
@@ -2738,6 +2773,13 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2738
2773
|
function translateRawErrorCopy(message, context = {}) {
|
|
2739
2774
|
const locale = normalizeLocale(context);
|
|
2740
2775
|
const text = String(message || "");
|
|
2776
|
+
if (context.code === "native_request_timeout" || /native_request_timeout/i.test(text)) {
|
|
2777
|
+
return {
|
|
2778
|
+
conclusion: textFor(locale, "\u672C\u673A\u670D\u52A1\u6CA1\u6709\u54CD\u5E94\u3002", "The local service did not respond."),
|
|
2779
|
+
nextStep: textFor(locale, "\u8BF7\u91CD\u8BD5\uFF0C\u6216\u6253\u5F00\u300C\u8BCA\u65AD\u300D\u68C0\u67E5\u672C\u673A\u8FDE\u63A5\u3002", "Retry, or open Diagnostics to check the local connection."),
|
|
2780
|
+
failureCode: "native_request_timeout"
|
|
2781
|
+
};
|
|
2782
|
+
}
|
|
2741
2783
|
if (context.code === "codex_local_skill_unavailable" || /(?:The )?selected local Codex skill is unavailable/i.test(text)) {
|
|
2742
2784
|
return {
|
|
2743
2785
|
conclusion: textFor(locale, "\u6240\u9009 Codex \u672C\u5730\u6280\u80FD\u4E0D\u53EF\u7528\u6216\u5DF2\u5173\u95ED\uFF0C\u672C\u8F6E\u6CA1\u6709\u542F\u52A8\u3002", "The selected local Codex skill is unavailable or disabled. This run did not start."),
|
|
@@ -2835,7 +2877,7 @@ if (typeof document !== 'undefined' && document.documentElement) document.docume
|
|
|
2835
2877
|
failureCode: "native_protocol_incompatible"
|
|
2836
2878
|
};
|
|
2837
2879
|
}
|
|
2838
|
-
if (/
|
|
2880
|
+
if (/kQuotaBytes|QUOTA_BYTES|QuotaExceededError|storage quota/i.test(text)) {
|
|
2839
2881
|
return {
|
|
2840
2882
|
conclusion: textFor(locale, "Codex \u7ED3\u679C\u5DF2\u7ECF\u751F\u6210\uFF0C\u4F46\u672C\u5730\u4F1A\u8BDD\u8BB0\u5F55\u8D85\u51FA Chrome \u5B58\u50A8\u914D\u989D\u3002", "Codex produced a result, but local session history exceeded Chrome storage quota."),
|
|
2841
2883
|
nextStep: textFor(locale, "\u8BF7\u5220\u9664\u4E00\u4E9B\u65E7 session\uFF0C\u6216\u5237\u65B0\u6269\u5C55\u540E\u91CD\u8BD5\uFF1B\u8FD9\u4E0D\u662F\u8BBA\u6587\u5206\u6790\u672C\u8EAB\u5931\u8D25\u3002", "Delete older sessions or reload the extension and retry. The paper analysis itself did not fail."),
|
|
@@ -4228,10 +4270,11 @@ ${block}`;
|
|
|
4228
4270
|
continue;
|
|
4229
4271
|
}
|
|
4230
4272
|
seen.add(normalized);
|
|
4231
|
-
result.push(normalized);
|
|
4232
4273
|
if (result.length >= limit) {
|
|
4274
|
+
result.truncated = true;
|
|
4233
4275
|
break;
|
|
4234
4276
|
}
|
|
4277
|
+
result.push(normalized);
|
|
4235
4278
|
}
|
|
4236
4279
|
return result;
|
|
4237
4280
|
}
|
|
@@ -4835,6 +4878,46 @@ ${block}`;
|
|
|
4835
4878
|
}
|
|
4836
4879
|
})(typeof globalThis !== "undefined" ? globalThis : window, function staleGuardFactory() {
|
|
4837
4880
|
"use strict";
|
|
4881
|
+
const DOCUMENT_PROVENANCE_OTHER_MIN = 0.9;
|
|
4882
|
+
const DOCUMENT_PROVENANCE_CLAIMED_MAX = 0.5;
|
|
4883
|
+
const DOCUMENT_PROVENANCE_EDGE_LIMIT = 64 * 1024;
|
|
4884
|
+
function assessDocumentProvenance(input = {}) {
|
|
4885
|
+
const { path, projectId, documentIdentity } = input || {};
|
|
4886
|
+
if (documentIdentity !== void 0) {
|
|
4887
|
+
const valid = documentIdentity && typeof documentIdentity === "object" && !Array.isArray(documentIdentity) && documentIdentity.version === 1 && documentIdentity.source === "cm-ranges-v1" && typeof projectId === "string" && projectId.length > 0 && documentIdentity.projectId === projectId && typeof path === "string" && path.length > 0 && documentIdentity.path === path && typeof documentIdentity.documentId === "string" && typeof documentIdentity.targetDocumentId === "string" && /^[a-f0-9]{24}$/.test(documentIdentity.documentId) && /^[a-f0-9]{24}$/.test(documentIdentity.targetDocumentId) && documentIdentity.documentId === documentIdentity.targetDocumentId;
|
|
4888
|
+
return valid ? { ok: true, identityState: "match" } : { ok: false, code: "document_identity_mismatch", identityState: "mismatch" };
|
|
4889
|
+
}
|
|
4890
|
+
try {
|
|
4891
|
+
const { path: path2, text, references } = input || {};
|
|
4892
|
+
if (typeof text !== "string" || !references) return { ok: true, identityState: "fallback" };
|
|
4893
|
+
const entries = references instanceof Map ? references : Object.entries(references);
|
|
4894
|
+
const claimed = references instanceof Map ? references.get(path2) : Object.prototype.hasOwnProperty.call(references, path2) ? references[path2] : void 0;
|
|
4895
|
+
if (text === claimed) return { ok: true, identityState: "fallback" };
|
|
4896
|
+
let matchedPath, bestScore = -1;
|
|
4897
|
+
for (const [otherPath, reference] of entries) {
|
|
4898
|
+
if (otherPath === path2 || typeof reference !== "string") continue;
|
|
4899
|
+
if (text === reference) return { ok: false, code: "document_identity_mismatch", identityState: "fallback", matchedPath: otherPath };
|
|
4900
|
+
const score = documentSimilarity(text, reference);
|
|
4901
|
+
if (score > bestScore) {
|
|
4902
|
+
bestScore = score;
|
|
4903
|
+
matchedPath = otherPath;
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4906
|
+
if (bestScore >= DOCUMENT_PROVENANCE_OTHER_MIN && (typeof claimed !== "string" || documentSimilarity(text, claimed) < DOCUMENT_PROVENANCE_CLAIMED_MAX)) {
|
|
4907
|
+
return { ok: false, code: "document_identity_mismatch", identityState: "fallback", matchedPath };
|
|
4908
|
+
}
|
|
4909
|
+
} catch (_error) {
|
|
4910
|
+
}
|
|
4911
|
+
return { ok: true, identityState: "fallback" };
|
|
4912
|
+
}
|
|
4913
|
+
function documentSimilarity(left, right) {
|
|
4914
|
+
const length = Math.min(left.length, right.length);
|
|
4915
|
+
let prefix = 0, suffix = 0;
|
|
4916
|
+
while (prefix < Math.min(length, DOCUMENT_PROVENANCE_EDGE_LIMIT) && left[prefix] === right[prefix]) prefix++;
|
|
4917
|
+
while (suffix < Math.min(length - prefix, DOCUMENT_PROVENANCE_EDGE_LIMIT) && left[left.length - suffix - 1] === right[right.length - suffix - 1]) suffix++;
|
|
4918
|
+
const denominator = Math.min(Math.max(left.length, right.length), 2 * DOCUMENT_PROVENANCE_EDGE_LIMIT);
|
|
4919
|
+
return denominator ? (prefix + suffix) / denominator : 1;
|
|
4920
|
+
}
|
|
4838
4921
|
function buildBaseFileLookup(files) {
|
|
4839
4922
|
if (!Array.isArray(files) || files.length === 0) {
|
|
4840
4923
|
return null;
|
|
@@ -5053,6 +5136,7 @@ ${block}`;
|
|
|
5053
5136
|
return String(value || "").replace(/\s+/g, " ").replace(/\\/g, "/").trim().replace(/^\/+/, "");
|
|
5054
5137
|
}
|
|
5055
5138
|
return {
|
|
5139
|
+
assessDocumentProvenance,
|
|
5056
5140
|
buildBaseFileLookup,
|
|
5057
5141
|
checkOperationFreshness,
|
|
5058
5142
|
prepareOperationPatches,
|
|
@@ -6446,6 +6530,8 @@ ${block}`;
|
|
|
6446
6530
|
failureReason_provider_request_rejected_next: "Review the model ID, reasoning controls, tool support, and request overrides.",
|
|
6447
6531
|
failureReason_provider_rate_limited_user: "The provider rate limit was reached.",
|
|
6448
6532
|
failureReason_provider_rate_limited_next: "Wait for the rate-limit window to recover and retry.",
|
|
6533
|
+
failureReason_provider_quota_exceeded_user: "The model provider quota or billing limit was reached.",
|
|
6534
|
+
failureReason_provider_quota_exceeded_next: "Check the provider account and plan, or switch model or provider before retrying.",
|
|
6449
6535
|
failureReason_provider_connection_timeout_user: "The provider connection timed out.",
|
|
6450
6536
|
failureReason_provider_connection_timeout_next: "Check the endpoint and network, then retry.",
|
|
6451
6537
|
failureReason_provider_dns_failed_user: "The provider hostname could not be resolved.",
|
|
@@ -6934,6 +7020,7 @@ ${block}`;
|
|
|
6934
7020
|
queuedInputResume: "Resume",
|
|
6935
7021
|
queuedInputRemove: "Remove",
|
|
6936
7022
|
queuedInputAttachmentsUnsupported: "Queued follow-ups currently support text and @context. Remove binary attachments before queuing.",
|
|
7023
|
+
attachmentsLoading: "Attachments are still loading",
|
|
6937
7024
|
queuedInputError_empty_input: "Enter a follow-up first.",
|
|
6938
7025
|
queuedInputError_input_too_long: "This follow-up is too long to queue.",
|
|
6939
7026
|
queuedInputError_queue_full: "The follow-up queue is full.",
|
|
@@ -7054,6 +7141,8 @@ ${block}`;
|
|
|
7054
7141
|
failureReason_accept_replay_failed_next: "Inspect the file in Overleaf, then retry.",
|
|
7055
7142
|
failureReason_native_request_failed_user: "The request to the local Codex bridge failed.",
|
|
7056
7143
|
failureReason_native_request_failed_next: "Open Diagnostics to check the bridge, then retry.",
|
|
7144
|
+
failureReason_native_request_timeout_user: "The local service did not respond.",
|
|
7145
|
+
failureReason_native_request_timeout_next: "Retry, or open Diagnostics to check the local connection.",
|
|
7057
7146
|
failureReason_panel_reload_interrupted_user: "This run was interrupted by a page refresh.",
|
|
7058
7147
|
failureReason_panel_reload_interrupted_next: "Edit and resend the task to continue.",
|
|
7059
7148
|
failureReason_sensitive_content_blocked_user: "Sensitive content was found before sending, so Codex did not receive this request.",
|
|
@@ -7080,6 +7169,8 @@ ${block}`;
|
|
|
7080
7169
|
failureReason_target_editor_not_ready_next: "Wait for Overleaf to finish loading, then retry.",
|
|
7081
7170
|
failureReason_stale_source_changed_user: "{file} changed while Codex was working, so Codex did not overwrite it.",
|
|
7082
7171
|
failureReason_stale_source_changed_next: "Review the current file, then rerun the task.",
|
|
7172
|
+
failureReason_document_identity_mismatch_user: "Codex could not confirm that the editor content belongs to the target file, so it was not used.",
|
|
7173
|
+
failureReason_document_identity_mismatch_next: "Wait for the target file to open and settle, then retry. Reload Overleaf if this continues.",
|
|
7083
7174
|
failureReason_patch_anchor_not_found_user: "The edit anchor for {file} no longer matches current Overleaf content.",
|
|
7084
7175
|
failureReason_patch_anchor_not_found_next: "Rerun the task against the current document.",
|
|
7085
7176
|
failureReason_write_observed_mismatch_user: "Codex attempted to write {file}, but the content read back from Overleaf did not match the approved change.",
|
|
@@ -7146,6 +7237,7 @@ ${block}`;
|
|
|
7146
7237
|
recentProjects_previewUnavailableHint: "Saved conversation could not be loaded.",
|
|
7147
7238
|
recentProjects_conversationGone: "This conversation is no longer available. Choose another conversation from the refreshed list.",
|
|
7148
7239
|
recentProjects_continueFailed: "Could not open the conversation. Please try again.",
|
|
7240
|
+
recentProjects_renameFailed: "Could not rename the conversation. Your title is still available to edit or copy.",
|
|
7149
7241
|
recentProjects_welcome_subtitle: "Conversations saved in this browser",
|
|
7150
7242
|
recentProjects_empty: "No conversations saved in this browser yet. Open an Overleaf project and start a Codex conversation.",
|
|
7151
7243
|
recentProjects_sessions_empty: "No saved conversations in this project",
|
|
@@ -7330,6 +7422,8 @@ ${block}`;
|
|
|
7330
7422
|
failureReason_provider_request_rejected_next: "\u8BF7\u68C0\u67E5\u6A21\u578B\u6807\u8BC6\u3001\u63A8\u7406\u8BBE\u7F6E\u3001\u5DE5\u5177\u652F\u6301\u53CA\u81EA\u5B9A\u4E49\u8BF7\u6C42\u53C2\u6570\u3002",
|
|
7331
7423
|
failureReason_provider_rate_limited_user: "\u6A21\u578B\u670D\u52A1\u5DF2\u8FBE\u5230\u8BF7\u6C42\u9891\u7387\u9650\u5236\u3002",
|
|
7332
7424
|
failureReason_provider_rate_limited_next: "\u8BF7\u7B49\u5F85\u9650\u6D41\u7A97\u53E3\u6062\u590D\u540E\u91CD\u8BD5\u3002",
|
|
7425
|
+
failureReason_provider_quota_exceeded_user: "\u6A21\u578B\u670D\u52A1\u7684\u914D\u989D\u6216\u8D26\u5355\u9650\u989D\u5DF2\u8FBE\u5230\u3002",
|
|
7426
|
+
failureReason_provider_quota_exceeded_next: "\u8BF7\u68C0\u67E5\u6A21\u578B\u670D\u52A1\u8D26\u6237\u548C\u5957\u9910\uFF0C\u6216\u5207\u6362\u6A21\u578B\u6216\u6A21\u578B\u670D\u52A1\u540E\u91CD\u8BD5\u3002",
|
|
7333
7427
|
failureReason_provider_connection_timeout_user: "\u6A21\u578B\u670D\u52A1\u8FDE\u63A5\u8D85\u65F6\u3002",
|
|
7334
7428
|
failureReason_provider_connection_timeout_next: "\u8BF7\u68C0\u67E5\u670D\u52A1\u7AEF\u70B9\u548C\u7F51\u7EDC\uFF0C\u7136\u540E\u91CD\u8BD5\u3002",
|
|
7335
7429
|
failureReason_provider_dns_failed_user: "\u65E0\u6CD5\u89E3\u6790\u6A21\u578B\u670D\u52A1\u7684\u4E3B\u673A\u540D\u3002",
|
|
@@ -7818,6 +7912,7 @@ ${block}`;
|
|
|
7818
7912
|
queuedInputResume: "\u7EE7\u7EED",
|
|
7819
7913
|
queuedInputRemove: "\u5220\u9664",
|
|
7820
7914
|
queuedInputAttachmentsUnsupported: "\u5F53\u524D\u6392\u961F\u6D88\u606F\u652F\u6301\u6587\u672C\u548C @context\uFF1B\u8BF7\u5148\u79FB\u9664\u4E8C\u8FDB\u5236\u9644\u4EF6\u3002",
|
|
7915
|
+
attachmentsLoading: "\u9644\u4EF6\u8BFB\u53D6\u4E2D",
|
|
7821
7916
|
queuedInputError_empty_input: "\u8BF7\u5148\u8F93\u5165\u540E\u7EED\u4EFB\u52A1\u3002",
|
|
7822
7917
|
queuedInputError_input_too_long: "\u8FD9\u6761\u540E\u7EED\u4EFB\u52A1\u592A\u957F\uFF0C\u65E0\u6CD5\u6392\u961F\u3002",
|
|
7823
7918
|
queuedInputError_queue_full: "\u540E\u7EED\u4EFB\u52A1\u961F\u5217\u5DF2\u6EE1\u3002",
|
|
@@ -7937,6 +8032,8 @@ ${block}`;
|
|
|
7937
8032
|
failureReason_accept_replay_failed_next: "\u8BF7\u5728 Overleaf \u4E2D\u68C0\u67E5\u8BE5\u6587\u4EF6\u540E\u91CD\u8BD5\u3002",
|
|
7938
8033
|
failureReason_native_request_failed_user: "\u5411\u672C\u5730 Codex bridge \u7684\u8BF7\u6C42\u5931\u8D25\u3002",
|
|
7939
8034
|
failureReason_native_request_failed_next: "\u6253\u5F00\u300C\u8BCA\u65AD\u300D\u68C0\u67E5 bridge \u540E\u91CD\u8BD5\u3002",
|
|
8035
|
+
failureReason_native_request_timeout_user: "\u672C\u673A\u670D\u52A1\u6CA1\u6709\u54CD\u5E94\u3002",
|
|
8036
|
+
failureReason_native_request_timeout_next: "\u8BF7\u91CD\u8BD5\uFF0C\u6216\u6253\u5F00\u300C\u8BCA\u65AD\u300D\u68C0\u67E5\u672C\u673A\u8FDE\u63A5\u3002",
|
|
7940
8037
|
failureReason_panel_reload_interrupted_user: "\u9875\u9762\u5237\u65B0\u5BFC\u81F4\u672C\u8F6E\u4E2D\u65AD\u3002",
|
|
7941
8038
|
failureReason_panel_reload_interrupted_next: "\u53EF\u7F16\u8F91\u540E\u91CD\u53D1\u4EFB\u52A1\u4EE5\u7EE7\u7EED\u3002",
|
|
7942
8039
|
failureReason_sensitive_content_blocked_user: "\u53D1\u9001\u524D\u53D1\u73B0\u654F\u611F\u5185\u5BB9\uFF0CCodex \u6CA1\u6709\u6536\u5230\u8FD9\u6B21\u8BF7\u6C42\u3002",
|
|
@@ -7963,6 +8060,8 @@ ${block}`;
|
|
|
7963
8060
|
failureReason_target_editor_not_ready_next: "\u8BF7\u7B49 Overleaf \u52A0\u8F7D\u5B8C\u6210\u540E\u518D\u91CD\u8BD5\u3002",
|
|
7964
8061
|
failureReason_stale_source_changed_user: "{file} \u5728\u4EFB\u52A1\u6267\u884C\u671F\u95F4\u88AB\u4FEE\u6539\u8FC7\uFF0CCodex \u6CA1\u6709\u8986\u76D6\u5B83\u3002",
|
|
7965
8062
|
failureReason_stale_source_changed_next: "\u8BF7\u5148\u67E5\u770B\u5F53\u524D\u6587\u4EF6\u5185\u5BB9\uFF0C\u518D\u91CD\u65B0\u8FD0\u884C\u672C\u8F6E\u4EFB\u52A1\u3002",
|
|
8063
|
+
failureReason_document_identity_mismatch_user: "Codex \u65E0\u6CD5\u786E\u8BA4\u7F16\u8F91\u5668\u5185\u5BB9\u5C5E\u4E8E\u76EE\u6807\u6587\u4EF6\uFF0C\u56E0\u6B64\u6CA1\u6709\u4F7F\u7528\u8FD9\u4E9B\u5185\u5BB9\u3002",
|
|
8064
|
+
failureReason_document_identity_mismatch_next: "\u8BF7\u7B49\u76EE\u6807\u6587\u4EF6\u6253\u5F00\u5E76\u7A33\u5B9A\u540E\u91CD\u8BD5\uFF1B\u5982\u679C\u95EE\u9898\u6301\u7EED\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D Overleaf\u3002",
|
|
7966
8065
|
failureReason_patch_anchor_not_found_user: "{file} \u7684\u4FEE\u6539\u951A\u70B9\u5DF2\u7ECF\u65E0\u6CD5\u548C\u5F53\u524D Overleaf \u5185\u5BB9\u5BF9\u9F50\u3002",
|
|
7967
8066
|
failureReason_patch_anchor_not_found_next: "\u8BF7\u57FA\u4E8E\u5F53\u524D\u6587\u6863\u91CD\u65B0\u8FD0\u884C\u4EFB\u52A1\u3002",
|
|
7968
8067
|
failureReason_write_observed_mismatch_user: "Codex \u5C1D\u8BD5\u5199\u5165 {file}\uFF0C\u4F46\u5199\u5165\u540E\u4ECE Overleaf \u8BFB\u56DE\u7684\u5185\u5BB9\u4E0E\u6279\u51C6\u7684\u6539\u52A8\u4E0D\u4E00\u81F4\u3002",
|
|
@@ -8029,6 +8128,7 @@ ${block}`;
|
|
|
8029
8128
|
recentProjects_previewUnavailableHint: "\u5DF2\u4FDD\u5B58\u7684\u5BF9\u8BDD\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u3002",
|
|
8030
8129
|
recentProjects_conversationGone: "\u8BE5\u5BF9\u8BDD\u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u4ECE\u66F4\u65B0\u540E\u7684\u5217\u8868\u4E2D\u9009\u62E9\u5176\u4ED6\u5BF9\u8BDD\u3002",
|
|
8031
8130
|
recentProjects_continueFailed: "\u6682\u65F6\u65E0\u6CD5\u6253\u5F00\u5BF9\u8BDD\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
8131
|
+
recentProjects_renameFailed: "\u6682\u65F6\u65E0\u6CD5\u91CD\u547D\u540D\u5BF9\u8BDD\uFF0C\u8F93\u5165\u7684\u6807\u9898\u4ECD\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u7F16\u8F91\u6216\u590D\u5236\u3002",
|
|
8032
8132
|
recentProjects_welcome_subtitle: "\u5F53\u524D\u6D4F\u89C8\u5668\u4FDD\u5B58\u7684\u5BF9\u8BDD",
|
|
8033
8133
|
recentProjects_empty: "\u5F53\u524D\u6D4F\u89C8\u5668\u8FD8\u6CA1\u6709\u4FDD\u5B58\u7684\u5BF9\u8BDD\u3002\u6253\u5F00\u4E00\u4E2A Overleaf \u9879\u76EE\uFF0C\u4E0E Codex \u5F00\u59CB\u5BF9\u8BDD\u5373\u53EF\u3002",
|
|
8034
8134
|
recentProjects_sessions_empty: "\u8BE5\u9879\u76EE\u8FD8\u6CA1\u6709\u4FDD\u5B58\u7684\u5BF9\u8BDD",
|
|
@@ -9943,7 +10043,18 @@ ${block}`;
|
|
|
9943
10043
|
const sameScope = (a, b) => a.accountScopeId === b.accountScopeId && a.projectId === b.projectId && a.generation === b.generation;
|
|
9944
10044
|
function applySnapshot(options, sessions) {
|
|
9945
10045
|
const previous = options.getState(), scope = options.getScope();
|
|
9946
|
-
const
|
|
10046
|
+
const input = sessions.length ? { ...previous, sessions } : {
|
|
10047
|
+
...previous,
|
|
10048
|
+
session: null,
|
|
10049
|
+
sessions: [],
|
|
10050
|
+
runs: [],
|
|
10051
|
+
activeSessionId: "",
|
|
10052
|
+
task: "",
|
|
10053
|
+
focusFiles: [],
|
|
10054
|
+
selectionContext: null,
|
|
10055
|
+
composerAttachments: []
|
|
10056
|
+
};
|
|
10057
|
+
const next = options.normalize(input, { restoreRunningRuns: false });
|
|
9947
10058
|
const unchangedSnapshot = JSON.stringify(next);
|
|
9948
10059
|
options.setState(next);
|
|
9949
10060
|
try {
|
|
@@ -10029,6 +10140,10 @@ ${block}`;
|
|
|
10029
10140
|
}
|
|
10030
10141
|
const unsubscribe = Bridge.subscribe((change) => {
|
|
10031
10142
|
const scope = getScope();
|
|
10143
|
+
if (options.isDashboard?.()) {
|
|
10144
|
+
if (scope.accountScopeId && change.accountScopeId === scope.accountScopeId) options.refreshDashboard?.();
|
|
10145
|
+
return;
|
|
10146
|
+
}
|
|
10032
10147
|
if (!change.projectId || change.projectId === scope.projectId) {
|
|
10033
10148
|
retryCount = 0;
|
|
10034
10149
|
pending = true;
|
|
@@ -10072,6 +10187,7 @@ ${block}`;
|
|
|
10072
10187
|
})(typeof globalThis !== "undefined" ? globalThis : this, function(QueuePolicy, SharedSessions) {
|
|
10073
10188
|
"use strict";
|
|
10074
10189
|
var META_PREFIX = "codex-overleaf-scoped-persistence-v1:";
|
|
10190
|
+
var MIRROR_FENCE_PREFIX = "codex-overleaf-mirror-reuse-fence-v1:";
|
|
10075
10191
|
var fallbackMeta = /* @__PURE__ */ new Map();
|
|
10076
10192
|
var cleanPart = QueuePolicy.cleanPart;
|
|
10077
10193
|
var normalizeMeta = QueuePolicy.normalizeMeta;
|
|
@@ -10127,7 +10243,35 @@ ${block}`;
|
|
|
10127
10243
|
}
|
|
10128
10244
|
};
|
|
10129
10245
|
}
|
|
10246
|
+
async function getMirrorReuseFences(scope, chromeApi) {
|
|
10247
|
+
chromeApi = chromeApi || (typeof chrome !== "undefined" ? chrome : null);
|
|
10248
|
+
if (!normalizeScope(scope).projectId || !chromeApi?.storage?.local) throw new Error("Mirror fence storage is unavailable.");
|
|
10249
|
+
var prefix = MIRROR_FENCE_PREFIX + scopeKey(scope).slice(META_PREFIX.length) + ":";
|
|
10250
|
+
var stored = await chromeApi.storage.local.get(null);
|
|
10251
|
+
return Object.keys(stored || {}).filter((key) => key.startsWith(prefix)).map((key) => {
|
|
10252
|
+
var generation = key.slice(prefix.length);
|
|
10253
|
+
if (!/^[a-zA-Z0-9_-]{1,160}$/.test(generation) || stored[key]?.v !== 1 || stored[key].generation !== generation) {
|
|
10254
|
+
throw new Error("Mirror fence storage contains an unreadable generation.");
|
|
10255
|
+
}
|
|
10256
|
+
return generation;
|
|
10257
|
+
}).sort();
|
|
10258
|
+
}
|
|
10259
|
+
async function setMirrorReuseFence(scope, generation, chromeApi) {
|
|
10260
|
+
chromeApi = chromeApi || (typeof chrome !== "undefined" ? chrome : null);
|
|
10261
|
+
if (!normalizeScope(scope).projectId || !chromeApi?.storage?.local || !/^[a-zA-Z0-9_-]{1,160}$/.test(generation)) throw new Error("Mirror fence storage is unavailable.");
|
|
10262
|
+
var key = MIRROR_FENCE_PREFIX + scopeKey(scope).slice(META_PREFIX.length) + ":" + generation;
|
|
10263
|
+
await chromeApi.storage.local.set({ [key]: { v: 1, generation } });
|
|
10264
|
+
}
|
|
10265
|
+
async function clearMirrorReuseFences(scope, generations, chromeApi) {
|
|
10266
|
+
chromeApi = chromeApi || (typeof chrome !== "undefined" ? chrome : null);
|
|
10267
|
+
if (!normalizeScope(scope).projectId || !chromeApi?.storage?.local || !Array.isArray(generations) || generations.some((generation) => !/^[a-zA-Z0-9_-]{1,160}$/.test(generation))) throw new Error("Mirror fence storage is unavailable.");
|
|
10268
|
+
var prefix = MIRROR_FENCE_PREFIX + scopeKey(scope).slice(META_PREFIX.length) + ":";
|
|
10269
|
+
await chromeApi.storage.local.remove(generations.map((generation) => prefix + generation));
|
|
10270
|
+
}
|
|
10130
10271
|
return Object.freeze({
|
|
10272
|
+
getMirrorReuseFences,
|
|
10273
|
+
setMirrorReuseFence,
|
|
10274
|
+
clearMirrorReuseFences,
|
|
10131
10275
|
createBrowserAdapter,
|
|
10132
10276
|
normalizeScope,
|
|
10133
10277
|
scopeKey
|
|
@@ -14405,6 +14549,10 @@ ${block}`;
|
|
|
14405
14549
|
"use strict";
|
|
14406
14550
|
const EPOCH_KEY = "composer-attachment-draft:clear-epoch";
|
|
14407
14551
|
const normalize = (value) => SessionState.normalizeComposerAttachmentsForPersistence(value);
|
|
14552
|
+
function normalizeOmitted(value) {
|
|
14553
|
+
const names = (Array.isArray(value?.names) ? value.names : []).filter((name) => typeof name === "string").map((name) => name.replace(/\0/g, "").trim().slice(0, 180)).filter(Boolean).slice(0, 8);
|
|
14554
|
+
return { count: names.length, names };
|
|
14555
|
+
}
|
|
14408
14556
|
const scopeKey = (scope) => JSON.stringify([scope?.accountScopeId || "", scope?.projectId || ""]);
|
|
14409
14557
|
function checkedScope(scope) {
|
|
14410
14558
|
const accountScopeId = String(scope?.accountScopeId || "").trim();
|
|
@@ -14438,21 +14586,23 @@ ${block}`;
|
|
|
14438
14586
|
throw failure("account_scope_unavailable");
|
|
14439
14587
|
}
|
|
14440
14588
|
const revision = Number(previous?.revision) || 0;
|
|
14441
|
-
result = { epoch, clearedAt, revision, attachments: normalize(previous?.attachments) };
|
|
14589
|
+
result = { epoch, clearedAt, revision, attachments: normalize(previous?.attachments), omittedAttachments: normalizeOmitted(previous?.omittedAttachments) };
|
|
14442
14590
|
if (!value) return;
|
|
14443
14591
|
const attachments = normalize(value.attachments);
|
|
14592
|
+
const omittedAttachments = normalizeOmitted(value.omittedAttachments);
|
|
14593
|
+
const hasDraft = attachments.length || omittedAttachments.count;
|
|
14444
14594
|
if (value.epoch !== epoch) {
|
|
14445
|
-
if (!
|
|
14595
|
+
if (!hasDraft) return;
|
|
14446
14596
|
throw failure("composer_draft_cleared");
|
|
14447
14597
|
}
|
|
14448
14598
|
if (value.revision !== revision) {
|
|
14449
|
-
if (JSON.stringify(attachments) === JSON.stringify(result.attachments)) return;
|
|
14599
|
+
if (JSON.stringify(attachments) === JSON.stringify(result.attachments) && JSON.stringify(omittedAttachments) === JSON.stringify(result.omittedAttachments)) return;
|
|
14450
14600
|
throw failure("composer_draft_conflict");
|
|
14451
14601
|
}
|
|
14452
|
-
if (
|
|
14602
|
+
if (hasDraft && value.unbased && clearedAt && value.changedAt <= clearedAt) {
|
|
14453
14603
|
throw failure("composer_draft_cleared");
|
|
14454
14604
|
}
|
|
14455
|
-
result = { epoch, clearedAt, revision: revision + 1, attachments };
|
|
14605
|
+
result = { epoch, clearedAt, revision: revision + 1, attachments, omittedAttachments };
|
|
14456
14606
|
store.put({ id, type: "composer-attachment-draft", ...scope, ...result });
|
|
14457
14607
|
} catch (caught) {
|
|
14458
14608
|
error = caught;
|
|
@@ -14522,7 +14672,11 @@ ${block}`;
|
|
|
14522
14672
|
function hydrate(attachments) {
|
|
14523
14673
|
syncScope();
|
|
14524
14674
|
if (hydrated) return;
|
|
14525
|
-
if (!changedVersion && !options.getAttachments().length)
|
|
14675
|
+
if (!changedVersion && !options.getAttachments().length) {
|
|
14676
|
+
options.restore(normalize(attachments));
|
|
14677
|
+
const omitted = normalizeOmitted(base?.omittedAttachments);
|
|
14678
|
+
if (omitted.count) options.onRestoreOmittedAttachments?.(omitted);
|
|
14679
|
+
}
|
|
14526
14680
|
hydrated = true;
|
|
14527
14681
|
publish();
|
|
14528
14682
|
}
|
|
@@ -14547,10 +14701,11 @@ ${block}`;
|
|
|
14547
14701
|
if (captured !== generation || scopeKey(options.getScope()) !== key || changedVersion === savedVersion) return;
|
|
14548
14702
|
const version = changedVersion;
|
|
14549
14703
|
const attachments = normalize(options.getAttachments());
|
|
14704
|
+
const omittedAttachments = normalizeOmitted({ names: options.getOmittedAttachmentNames?.() });
|
|
14550
14705
|
const unbased = dirtyUnbased, changedAt = dirtySince;
|
|
14551
14706
|
if (!base) await load(scope);
|
|
14552
14707
|
if (captured !== generation || scopeKey(options.getScope()) !== key) return;
|
|
14553
|
-
const written = await options.write(checkedScope(scope), { ...base, attachments, unbased, changedAt });
|
|
14708
|
+
const written = await options.write(checkedScope(scope), { ...base, attachments, omittedAttachments, unbased, changedAt });
|
|
14554
14709
|
if (captured !== generation) return;
|
|
14555
14710
|
base = written;
|
|
14556
14711
|
savedVersion = version;
|
|
@@ -15851,6 +16006,95 @@ ${block}`;
|
|
|
15851
16006
|
"selectedLocalSkillIdsByProject"
|
|
15852
16007
|
];
|
|
15853
16008
|
var projectPreferenceLockTails = {};
|
|
16009
|
+
var projectPreferenceBaselines = /* @__PURE__ */ new Map();
|
|
16010
|
+
var projectPreferenceIntents = /* @__PURE__ */ new Map();
|
|
16011
|
+
var projectPreferenceBaselineVersions = /* @__PURE__ */ new WeakMap();
|
|
16012
|
+
function getProjectPreferenceBaseline(accountScopeId, projectId) {
|
|
16013
|
+
var key = buildScopedProjectPreferenceKey(accountScopeId, projectId);
|
|
16014
|
+
var baseline = copyPreferenceValue(projectPreferenceBaselines.get(key));
|
|
16015
|
+
var intents = projectPreferenceIntents.get(key);
|
|
16016
|
+
if (baseline && intents) projectPreferenceBaselineVersions.set(baseline, {
|
|
16017
|
+
owner: intents,
|
|
16018
|
+
versions: Object.assign({}, intents.acknowledged)
|
|
16019
|
+
});
|
|
16020
|
+
return baseline;
|
|
16021
|
+
}
|
|
16022
|
+
function adoptProjectPreferenceBaseline(prefs, accountScopeId, projectId) {
|
|
16023
|
+
var key = buildScopedProjectPreferenceKey(accountScopeId, projectId);
|
|
16024
|
+
if (key) {
|
|
16025
|
+
projectPreferenceBaselines.set(key, copyPreferenceValue(prefs));
|
|
16026
|
+
projectPreferenceIntents.set(key, { revision: 0, fields: {}, acknowledged: {} });
|
|
16027
|
+
}
|
|
16028
|
+
}
|
|
16029
|
+
function captureProjectPreferenceWrite(input) {
|
|
16030
|
+
var projectId = input.projectId;
|
|
16031
|
+
var key = buildScopedProjectPreferenceKey(input.accountScopeId, projectId);
|
|
16032
|
+
if (!key) return null;
|
|
16033
|
+
var intents = projectPreferenceIntents.get(key);
|
|
16034
|
+
if (!intents) {
|
|
16035
|
+
intents = { revision: 0, fields: {}, acknowledged: {} };
|
|
16036
|
+
projectPreferenceIntents.set(key, intents);
|
|
16037
|
+
}
|
|
16038
|
+
function values(prefs) {
|
|
16039
|
+
return {
|
|
16040
|
+
experimentalOtByProject: input.normalizeExperimentalOtByProject(prefs.experimentalOtByProject)[projectId] === true,
|
|
16041
|
+
reviewingAvailabilityByProject: prefs.reviewingAvailabilityByProject?.[projectId],
|
|
16042
|
+
governanceRulesByProject: input.normalizeGovernanceRulesByProject({
|
|
16043
|
+
[projectId]: prefs.governanceRulesByProject?.[projectId] || {}
|
|
16044
|
+
})[projectId],
|
|
16045
|
+
customInstructionsByProject: input.normalizeCustomInstructionsByProject({
|
|
16046
|
+
[projectId]: prefs.customInstructionsByProject?.[projectId] || ""
|
|
16047
|
+
})[projectId]
|
|
16048
|
+
};
|
|
16049
|
+
}
|
|
16050
|
+
var baseline = input.baseline || getProjectPreferenceBaseline(input.accountScopeId, projectId);
|
|
16051
|
+
var captured = projectPreferenceBaselineVersions.get(baseline);
|
|
16052
|
+
var versions = captured?.owner === intents ? captured.versions : {};
|
|
16053
|
+
var previous = values(baseline || {});
|
|
16054
|
+
var current = values(input.state);
|
|
16055
|
+
var token = { key, owner: intents, projectId, fields: {}, versions: {}, written: [] };
|
|
16056
|
+
for (var name of Object.keys(current)) {
|
|
16057
|
+
var latest = intents.fields[name];
|
|
16058
|
+
var reference = latest && latest.revision > (versions[name] || 0) ? latest.value : previous[name];
|
|
16059
|
+
if (JSON.stringify(current[name]) !== JSON.stringify(reference)) {
|
|
16060
|
+
latest = { revision: ++intents.revision, value: copyPreferenceValue(current[name]), dirty: true };
|
|
16061
|
+
intents.fields[name] = latest;
|
|
16062
|
+
}
|
|
16063
|
+
token.fields[name] = latest && JSON.stringify(current[name]) === JSON.stringify(latest.value) ? latest : null;
|
|
16064
|
+
token.versions[name] = latest?.revision || 0;
|
|
16065
|
+
}
|
|
16066
|
+
return token;
|
|
16067
|
+
}
|
|
16068
|
+
function projectPreferencePatch(token, accountScopeId, projectId) {
|
|
16069
|
+
if (token.key !== buildScopedProjectPreferenceKey(accountScopeId, projectId)) {
|
|
16070
|
+
throw Object.assign(new Error("Scoped project preferences require account and project identity."), {
|
|
16071
|
+
code: "account_scope_unavailable"
|
|
16072
|
+
});
|
|
16073
|
+
}
|
|
16074
|
+
var current = projectPreferenceIntents.get(token.key) === token.owner;
|
|
16075
|
+
var patch = {};
|
|
16076
|
+
token.written = [];
|
|
16077
|
+
for (var name of Object.keys(token.fields)) {
|
|
16078
|
+
var intent = token.fields[name];
|
|
16079
|
+
var changed = current && intent?.dirty && token.owner.fields[name] === intent;
|
|
16080
|
+
patch[name] = changed ? { [token.projectId]: copyPreferenceValue(intent.value) } : {};
|
|
16081
|
+
if (changed) token.written.push(name);
|
|
16082
|
+
}
|
|
16083
|
+
return patch;
|
|
16084
|
+
}
|
|
16085
|
+
function completeProjectPreferenceWrite(token, prefs) {
|
|
16086
|
+
if (projectPreferenceIntents.get(token.key) !== token.owner) return [];
|
|
16087
|
+
for (var name of token.written) {
|
|
16088
|
+
var intent = token.fields[name];
|
|
16089
|
+
intent.dirty = false;
|
|
16090
|
+
token.owner.acknowledged[name] = Math.max(token.owner.acknowledged[name] || 0, intent.revision);
|
|
16091
|
+
}
|
|
16092
|
+
projectPreferenceBaselines.set(token.key, copyPreferenceValue(prefs));
|
|
16093
|
+
return Object.keys(token.fields).filter(function(name2) {
|
|
16094
|
+
var latest = token.owner.fields[name2];
|
|
16095
|
+
return (latest?.revision || 0) === token.versions[name2] && !latest?.dirty;
|
|
16096
|
+
});
|
|
16097
|
+
}
|
|
15854
16098
|
function buildScopedProjectPreferenceKey(accountScopeId, projectId) {
|
|
15855
16099
|
var account = compactScopePart(accountScopeId);
|
|
15856
16100
|
var project = compactScopePart(projectId);
|
|
@@ -15984,6 +16228,7 @@ ${block}`;
|
|
|
15984
16228
|
var visible = await StorageDb.claimSessionsForAccount(projectId, account, deleted);
|
|
15985
16229
|
function result(currentPrefs, sessions2, migrated) {
|
|
15986
16230
|
var wanted = currentPrefs.activeSessionByProject?.[projectId] || "";
|
|
16231
|
+
adoptProjectPreferenceBaseline(currentPrefs, account, projectId);
|
|
15987
16232
|
return {
|
|
15988
16233
|
prefs: currentPrefs,
|
|
15989
16234
|
sessions: sessions2,
|
|
@@ -16071,7 +16316,9 @@ ${block}`;
|
|
|
16071
16316
|
return chrome.storage.local.get([PREFS_KEY]).then(function(stored) {
|
|
16072
16317
|
var claimed = claimLegacyProjectPreferences(stored[PREFS_KEY] || {}, account, project);
|
|
16073
16318
|
var next = mergeScopedProjectPreferences(claimed.prefs, prefs, account, project);
|
|
16074
|
-
return chrome.storage.local.set({ [PREFS_KEY]: next })
|
|
16319
|
+
return chrome.storage.local.set({ [PREFS_KEY]: next }).then(function() {
|
|
16320
|
+
return buildProjectPreferenceView(next, account, project);
|
|
16321
|
+
});
|
|
16075
16322
|
});
|
|
16076
16323
|
});
|
|
16077
16324
|
}
|
|
@@ -16255,6 +16502,11 @@ ${block}`;
|
|
|
16255
16502
|
runMigrationIfNeeded,
|
|
16256
16503
|
savePrefs,
|
|
16257
16504
|
loadPrefs,
|
|
16505
|
+
getProjectPreferenceBaseline,
|
|
16506
|
+
adoptProjectPreferenceBaseline,
|
|
16507
|
+
captureProjectPreferenceWrite,
|
|
16508
|
+
projectPreferencePatch,
|
|
16509
|
+
completeProjectPreferenceWrite,
|
|
16258
16510
|
loadSessionTombstones,
|
|
16259
16511
|
addSessionTombstones,
|
|
16260
16512
|
getDeletedSessionIds,
|
|
@@ -16507,7 +16759,7 @@ ${block}`;
|
|
|
16507
16759
|
const MIN_NATIVE_VERSION = "1.0.0";
|
|
16508
16760
|
const MIN_COMPATIBLE_NATIVE_VERSION = "1.0.0";
|
|
16509
16761
|
const MIN_COMPATIBLE_EXTENSION_VERSION = "1.0.0";
|
|
16510
|
-
const BUILD_TARGET_VERSION = "2.6.
|
|
16762
|
+
const BUILD_TARGET_VERSION = "2.6.5";
|
|
16511
16763
|
const DEFAULT_CHROME_EXTENSION_ID = "illdpneeeopfffmiepaejglgmhpmdhdc";
|
|
16512
16764
|
const REQUIRED_CAPABILITIES = Object.freeze([
|
|
16513
16765
|
"bridgePing",
|
|
@@ -16824,7 +17076,7 @@ ${block}`;
|
|
|
16824
17076
|
if (root) root.CodexOverleafPageRpcContract = api;
|
|
16825
17077
|
})(typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : this, function() {
|
|
16826
17078
|
"use strict";
|
|
16827
|
-
var REVISION = "2026-10-
|
|
17079
|
+
var REVISION = "2026-10-29-identity-v54";
|
|
16828
17080
|
var METHODS = freezeCatalog({
|
|
16829
17081
|
initializeCapability: entry("bridge.initialize", "control", "none", "default", false, "none"),
|
|
16830
17082
|
probe: entry("bridge.probe", "read", "none", "default", false, "safe"),
|
|
@@ -17809,6 +18061,7 @@ ${block}`;
|
|
|
17809
18061
|
return removeEmptySummaryFields(result);
|
|
17810
18062
|
}
|
|
17811
18063
|
function summarizeMirror(mirror = {}) {
|
|
18064
|
+
mirror = mirror ?? { status: "unavailable" };
|
|
17812
18065
|
const files = Array.isArray(mirror.files) ? mirror.files : [];
|
|
17813
18066
|
const skippedFiles = Array.isArray(mirror.skippedFiles) ? mirror.skippedFiles : [];
|
|
17814
18067
|
return removeEmptySummaryFields({
|
|
@@ -18258,21 +18511,22 @@ ${block}`;
|
|
|
18258
18511
|
["src/shared/projectFiles.js", "codex-overleaf-project-files-script"],
|
|
18259
18512
|
["src/shared/compatibility.js", "codex-overleaf-compatibility-page-script"],
|
|
18260
18513
|
["src/shared/pageRpcContract.js", "codex-overleaf-page-rpc-contract-script", true],
|
|
18261
|
-
["src/shared/staleGuard.js", "codex-overleaf-stale-guard-script"],
|
|
18514
|
+
["src/shared/staleGuard.js", "codex-overleaf-stale-guard-script", true],
|
|
18515
|
+
["src/shared/otText.js", "codex-overleaf-ot-text-script"],
|
|
18262
18516
|
["src/shared/compileAdapter.js", "codex-overleaf-compile-adapter-script"],
|
|
18263
18517
|
["src/shared/sensitiveScan.js", "codex-overleaf-sensitive-scan-script"],
|
|
18264
18518
|
["src/shared/auditRecords.js", "codex-overleaf-audit-records-script"],
|
|
18265
18519
|
["src/page/saveState.js", "codex-overleaf-save-state-script", true],
|
|
18266
18520
|
["src/page/overleafCapabilities.js", "codex-overleaf-capabilities-script", true],
|
|
18267
18521
|
["src/page/compileBridge.js", "codex-overleaf-compile-bridge-script"],
|
|
18268
|
-
["src/page/overleafEditor.js", "codex-overleaf-editor-script"],
|
|
18269
|
-
["src/page/overleafProjectSnapshot.js", "codex-overleaf-project-snapshot-script"],
|
|
18522
|
+
["src/page/overleafEditor.js", "codex-overleaf-editor-script", true],
|
|
18523
|
+
["src/page/overleafProjectSnapshot.js", "codex-overleaf-project-snapshot-script", true],
|
|
18270
18524
|
["src/page/pageBridgeCapability.js", "codex-overleaf-page-bridge-capability-script"],
|
|
18271
18525
|
["src/page/treeOperations.js", "codex-overleaf-tree-operations-script", true],
|
|
18272
18526
|
["src/page/ownedDirectoryCleanup.js", "codex-overleaf-owned-directory-cleanup-script", true],
|
|
18273
18527
|
["src/page/textFileCreator.js", "codex-overleaf-text-file-creator-script", true],
|
|
18274
18528
|
["src/page/binaryAssetUploader.js", "codex-overleaf-binary-asset-uploader-script", true],
|
|
18275
|
-
["src/page/snapshotRouter.js", "codex-overleaf-snapshot-router-script"],
|
|
18529
|
+
["src/page/snapshotRouter.js", "codex-overleaf-snapshot-router-script", true],
|
|
18276
18530
|
["src/page/referenceProjects.js", "codex-overleaf-reference-projects-script", true],
|
|
18277
18531
|
["src/page/fileMover.js", "codex-overleaf-file-mover-script", true],
|
|
18278
18532
|
["src/page/writeGuard.js", "codex-overleaf-write-guard-script", true],
|
|
@@ -18287,7 +18541,6 @@ ${block}`;
|
|
|
18287
18541
|
["src/pageBridge.js", "codex-overleaf-page-bridge-script", true]
|
|
18288
18542
|
]);
|
|
18289
18543
|
const OPTIONAL_OT_SCRIPTS = Object.freeze([
|
|
18290
|
-
["src/shared/otText.js", "codex-overleaf-ot-text-script"],
|
|
18291
18544
|
["src/page/overleafRealtimeObserver.js", "codex-overleaf-realtime-observer-script"]
|
|
18292
18545
|
]);
|
|
18293
18546
|
function create(options = {}) {
|
|
@@ -18525,7 +18778,8 @@ ${block}`;
|
|
|
18525
18778
|
try {
|
|
18526
18779
|
compatibilityGate = await ensureForMethod(payload?.method, context);
|
|
18527
18780
|
if (!compatibilityGate.ok) return compatibilityGate.response;
|
|
18528
|
-
|
|
18781
|
+
const independentCatalog = payload?.method === "codex.models" || payload?.method === "codex.providers.list";
|
|
18782
|
+
if (gatedMethods.has(payload?.method) && payload.method !== "mirror.invalidate" && !independentCatalog) {
|
|
18529
18783
|
options.throwIfCancellationRequested?.();
|
|
18530
18784
|
}
|
|
18531
18785
|
context.assertCurrent?.();
|
|
@@ -18617,7 +18871,7 @@ ${block}`;
|
|
|
18617
18871
|
options.setDiagnosticsHealth?.(classification === "update-available" ? "warn" : "fail");
|
|
18618
18872
|
options.setBadge?.(renderer.headerEl, {
|
|
18619
18873
|
type: "update",
|
|
18620
|
-
tooltip: tx("Native host update available", "Native host \u53EF\u66F4\u65B0"),
|
|
18874
|
+
tooltip: compatibility.status === "native_unhealthy" ? tx("Codex Unavailable", "Codex \u4E0D\u53EF\u7528") : tx("Native host update available", "Native host \u53EF\u66F4\u65B0"),
|
|
18621
18875
|
onClick: () => showUpdateGuidance(compatibility)
|
|
18622
18876
|
});
|
|
18623
18877
|
if (!compatibility?.native?.version) maybePromptFirstRunSetup();
|
|
@@ -18656,7 +18910,9 @@ ${block}`;
|
|
|
18656
18910
|
const native = compatibility.native || {};
|
|
18657
18911
|
const extensionVersion = compatibility.extensionVersion || Compatibility?.BUILD_TARGET_VERSION || "";
|
|
18658
18912
|
const nativeVersion = compatibility.currentNativeVersion || compatibility.nativeVersion || native.version || tx("missing", "\u672A\u5B89\u88C5");
|
|
18659
|
-
const
|
|
18913
|
+
const codexUnavailable = compatibility.status === "native_unhealthy";
|
|
18914
|
+
const resolvedCommand = resolveInstallCommand(compatibility);
|
|
18915
|
+
const command = codexUnavailable ? "" : resolvedCommand;
|
|
18660
18916
|
const releaseUrl = compatibility.releaseUrl || "";
|
|
18661
18917
|
const overlay = options.document.createElement("div");
|
|
18662
18918
|
overlay.className = "codex-plugin-confirm";
|
|
@@ -18666,7 +18922,7 @@ ${block}`;
|
|
|
18666
18922
|
const nativeMissing = !native.version;
|
|
18667
18923
|
overlay.setAttribute(
|
|
18668
18924
|
"aria-label",
|
|
18669
|
-
nativeMissing ? tx("Set up the native host", "\u5B89\u88C5 Native host") : tx("Native host update available", "Native host \u53EF\u66F4\u65B0")
|
|
18925
|
+
codexUnavailable ? tx("Codex Unavailable", "Codex \u4E0D\u53EF\u7528") : nativeMissing ? tx("Set up the native host", "\u5B89\u88C5 Native host") : tx("Native host update available", "Native host \u53EF\u66F4\u65B0")
|
|
18670
18926
|
);
|
|
18671
18927
|
const card = options.document.createElement("section");
|
|
18672
18928
|
card.className = "codex-plugin-confirm-card";
|
|
@@ -18683,12 +18939,15 @@ ${block}`;
|
|
|
18683
18939
|
brand.textContent = "Codex Overleaf Link";
|
|
18684
18940
|
const title = options.document.createElement("div");
|
|
18685
18941
|
title.className = "codex-plugin-confirm-title";
|
|
18686
|
-
title.textContent = nativeMissing ? tx("One step left: install the native host", "\u8FD8\u5DEE\u4E00\u6B65\uFF1A\u5B89\u88C5 Native host") : tx("Native host update available", "Native host \u53EF\u66F4\u65B0");
|
|
18942
|
+
title.textContent = codexUnavailable ? tx("Codex Unavailable", "Codex \u4E0D\u53EF\u7528") : nativeMissing ? tx("One step left: install the native host", "\u8FD8\u5DEE\u4E00\u6B65\uFF1A\u5B89\u88C5 Native host") : tx("Native host update available", "Native host \u53EF\u66F4\u65B0");
|
|
18687
18943
|
titleWrap.append(brand, title);
|
|
18688
18944
|
head.append(icon, titleWrap);
|
|
18689
18945
|
const body = options.document.createElement("div");
|
|
18690
18946
|
body.className = "codex-plugin-confirm-body";
|
|
18691
|
-
body.textContent = [
|
|
18947
|
+
body.textContent = codexUnavailable ? [
|
|
18948
|
+
tx("The extension reached the native host, but local Codex was not found, so tasks cannot start.", "\u63D2\u4EF6\u5DF2\u7ECF\u8FDE\u4E0A native host\uFF0C\u4F46\u6CA1\u6709\u627E\u5230\u672C\u673A Codex\uFF0C\u6240\u4EE5\u4E0D\u80FD\u542F\u52A8\u4EFB\u52A1\u3002"),
|
|
18949
|
+
tx("Make sure codex works in Terminal, then reload the extension.", "\u8BF7\u786E\u8BA4\u7EC8\u7AEF\u91CC\u53EF\u4EE5\u8FD0\u884C codex\uFF0C\u7136\u540E\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55\u3002")
|
|
18950
|
+
].join("\n\n") : [
|
|
18692
18951
|
nativeMissing ? tx(
|
|
18693
18952
|
`Extension v${extensionVersion} is ready; Codex still needs its local bridge to read and edit this project.`,
|
|
18694
18953
|
`\u6269\u5C55 v${extensionVersion} \u5DF2\u5C31\u7EEA\uFF1BCodex \u8FD8\u9700\u8981\u672C\u5730\u6865\u63A5\u7A0B\u5E8F\u624D\u80FD\u8BFB\u5199\u8FD9\u4E2A\u9879\u76EE\u3002`
|
|
@@ -18704,8 +18963,8 @@ ${block}`;
|
|
|
18704
18963
|
const commandCode = options.document.createElement("code");
|
|
18705
18964
|
commandCode.className = "codex-native-guidance-command";
|
|
18706
18965
|
commandCode.textContent = command;
|
|
18707
|
-
body.append(commandCode);
|
|
18708
|
-
if (releaseUrl) {
|
|
18966
|
+
if (!codexUnavailable) body.append(commandCode);
|
|
18967
|
+
if (!codexUnavailable && releaseUrl) {
|
|
18709
18968
|
const link = options.document.createElement("a");
|
|
18710
18969
|
link.className = "codex-native-guidance-link";
|
|
18711
18970
|
link.href = releaseUrl;
|
|
@@ -18731,7 +18990,8 @@ ${block}`;
|
|
|
18731
18990
|
close.className = "codex-plugin-confirm-cancel";
|
|
18732
18991
|
close.textContent = tx("Close", "\u5173\u95ED");
|
|
18733
18992
|
close.addEventListener("click", () => overlay.remove());
|
|
18734
|
-
actions.append(close
|
|
18993
|
+
actions.append(close);
|
|
18994
|
+
if (!codexUnavailable) actions.append(copy);
|
|
18735
18995
|
card.append(head, body, actions);
|
|
18736
18996
|
overlay.append(card);
|
|
18737
18997
|
overlay.addEventListener("click", (event) => {
|
|
@@ -21929,7 +22189,8 @@ ${block}`;
|
|
|
21929
22189
|
copy.append(text);
|
|
21930
22190
|
const descriptions = {
|
|
21931
22191
|
"annotated-rewrite": tx("Guided editing for document revisions.", "\u7528\u4E8E\u6587\u7A3F\u4FEE\u8BA2\u7684\u7F16\u8F91\u6D41\u7A0B\u3002"),
|
|
21932
|
-
"parallel-subagents": tx("Split independent subtasks across multiple agents.", "\u5C06\u76F8\u4E92\u72EC\u7ACB\u7684\u5B50\u4EFB\u52A1\u5206\u914D\u7ED9\u591A\u4E2A agent\u3002")
|
|
22192
|
+
"parallel-subagents": tx("Split independent subtasks across multiple agents.", "\u5C06\u76F8\u4E92\u72EC\u7ACB\u7684\u5B50\u4EFB\u52A1\u5206\u914D\u7ED9\u591A\u4E2A agent\u3002"),
|
|
22193
|
+
"reviewer-response": tx("Map reviewer comments to evidence, edits and reply drafts.", "\u628A\u5BA1\u7A3F\u610F\u89C1\u5BF9\u5E94\u5230\u8BBA\u6587\u8BC1\u636E\u3001\u4FEE\u6539\u548C\u56DE\u590D\u8349\u7A3F\u3002")
|
|
21933
22194
|
};
|
|
21934
22195
|
const description = !local && descriptions[id] || (typeof skill.description === "string" ? skill.description.replace(/\s+/g, " ").trim() : "");
|
|
21935
22196
|
if (description) {
|
|
@@ -21967,7 +22228,7 @@ ${block}`;
|
|
|
21967
22228
|
row._refreshLocale = () => {
|
|
21968
22229
|
if (sourceLabel) sourceLabel.textContent = sourceText();
|
|
21969
22230
|
toggle.setAttribute("aria-label", accessibleSkillName + ": " + tr("codexOverleafSkillEnableToggle"));
|
|
21970
|
-
const label = !local && id === "annotated-rewrite" ? tx("Guided editing for document revisions.", "\u7528\u4E8E\u6587\u7A3F\u4FEE\u8BA2\u7684\u7F16\u8F91\u6D41\u7A0B\u3002") : !local && id === "parallel-subagents" ? tx("Split independent subtasks across multiple agents.", "\u5C06\u76F8\u4E92\u72EC\u7ACB\u7684\u5B50\u4EFB\u52A1\u5206\u914D\u7ED9\u591A\u4E2A agent\u3002") : "";
|
|
22231
|
+
const label = !local && id === "annotated-rewrite" ? tx("Guided editing for document revisions.", "\u7528\u4E8E\u6587\u7A3F\u4FEE\u8BA2\u7684\u7F16\u8F91\u6D41\u7A0B\u3002") : !local && id === "parallel-subagents" ? tx("Split independent subtasks across multiple agents.", "\u5C06\u76F8\u4E92\u72EC\u7ACB\u7684\u5B50\u4EFB\u52A1\u5206\u914D\u7ED9\u591A\u4E2A agent\u3002") : !local && id === "reviewer-response" ? tx("Map reviewer comments to evidence, edits and reply drafts.", "\u628A\u5BA1\u7A3F\u610F\u89C1\u5BF9\u5E94\u5230\u8BBA\u6587\u8BC1\u636E\u3001\u4FEE\u6539\u548C\u56DE\u590D\u8349\u7A3F\u3002") : "";
|
|
21971
22232
|
const help = copy.querySelector(".codex-local-skill-description");
|
|
21972
22233
|
if (label && help) {
|
|
21973
22234
|
help.textContent = label;
|
|
@@ -22681,6 +22942,11 @@ ${block}`;
|
|
|
22681
22942
|
async function executeUndo(runId) {
|
|
22682
22943
|
let run = findRunRecord(runId);
|
|
22683
22944
|
if (run) Object.assign(run, Modules.UndoOperations.prepareRunUndo(run));
|
|
22945
|
+
const mirrorOwner = {
|
|
22946
|
+
projectId: getRunProjectIdForWriteback(run),
|
|
22947
|
+
runAccountScopeId: run?.runAccountScopeId || getAccountScopeId?.() || "",
|
|
22948
|
+
sessionId: getState().activeSessionId
|
|
22949
|
+
};
|
|
22684
22950
|
const assertCurrent = undoOwner(run);
|
|
22685
22951
|
let assertInputs = checkpointGuard(run, assertCurrent);
|
|
22686
22952
|
if (!getRunUndoCount(run) || run.undoStatus === "applied") {
|
|
@@ -22765,9 +23031,9 @@ ${block}`;
|
|
|
22765
23031
|
// Undo remains bound to its original project, including after navigation.
|
|
22766
23032
|
runProjectId: getRunProjectIdForWriteback(run)
|
|
22767
23033
|
});
|
|
23034
|
+
writebackOrchestrator.invalidateMirrorAfterUndo(runId, mirrorOwner.projectId, result, mirrorOwner);
|
|
22768
23035
|
run = assertInputs();
|
|
22769
23036
|
const undoApplied = isUndoResultEffectivelyApplied(run, result);
|
|
22770
|
-
writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
22771
23037
|
appendUndoReviewingPolicyEvent(runId, result.reviewingPolicy);
|
|
22772
23038
|
appendRunRecordEvent(runId, {
|
|
22773
23039
|
title: tr("undoResult", { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
@@ -22793,6 +23059,11 @@ ${block}`;
|
|
|
22793
23059
|
);
|
|
22794
23060
|
}
|
|
22795
23061
|
async function executeTrackedUndo(runId, run) {
|
|
23062
|
+
const mirrorOwner = {
|
|
23063
|
+
projectId: getRunProjectIdForWriteback(run),
|
|
23064
|
+
runAccountScopeId: run?.runAccountScopeId || getAccountScopeId?.() || "",
|
|
23065
|
+
sessionId: getState().activeSessionId
|
|
23066
|
+
};
|
|
22796
23067
|
const assertCurrent = undoOwner(run);
|
|
22797
23068
|
let assertInputs = checkpointGuard(run, assertCurrent);
|
|
22798
23069
|
const fileUndoOperations = Modules.UndoOperations.getFileUndoOperations(run);
|
|
@@ -22876,8 +23147,8 @@ ${block}`;
|
|
|
22876
23147
|
result: { ok: false, code: "undo_operation_failed", reason: error.message }
|
|
22877
23148
|
})) };
|
|
22878
23149
|
}
|
|
22879
|
-
run = assertInputs();
|
|
22880
23150
|
result = Modules.UndoOperations.mergeFileUndoResult(result, createdResult, fileUndoOperations);
|
|
23151
|
+
run = assertInputs();
|
|
22881
23152
|
}
|
|
22882
23153
|
appendRunRecordEvent(runId, {
|
|
22883
23154
|
title: fileUndoOperations.length ? tr("undoResult", { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }) : trackedUndo ? tr("undoTrackedResult", { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }) : tr("undoNativeResult", { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
@@ -22905,7 +23176,7 @@ ${block}`;
|
|
|
22905
23176
|
}
|
|
22906
23177
|
await applyLegacyUndoSettlement(runId, result.ok === true && !result.skipped?.length ? "applied" : "partial", result);
|
|
22907
23178
|
} finally {
|
|
22908
|
-
if (result) writebackOrchestrator.invalidateMirrorAfterUndo(runId,
|
|
23179
|
+
if (result) writebackOrchestrator.invalidateMirrorAfterUndo(runId, mirrorOwner.projectId, result, mirrorOwner);
|
|
22909
23180
|
}
|
|
22910
23181
|
}
|
|
22911
23182
|
function reviewOwner(run) {
|
|
@@ -23593,7 +23864,7 @@ ${block}`;
|
|
|
23593
23864
|
const maxAttachmentTotalBytes = Number(limits.maxAttachmentTotalBytes) || 32 * 1024 * 1024;
|
|
23594
23865
|
const maxPreviewDataUrlChars = Number(limits.maxPreviewDataUrlChars) || 768 * 1024;
|
|
23595
23866
|
let attachments = [];
|
|
23596
|
-
const pendingAttachmentKeys = /* @__PURE__ */ new
|
|
23867
|
+
const pendingAttachmentKeys = /* @__PURE__ */ new Map();
|
|
23597
23868
|
let pendingAttachmentBytes = 0;
|
|
23598
23869
|
let attachmentGeneration = 0;
|
|
23599
23870
|
let attachmentRevision = 0;
|
|
@@ -23661,8 +23932,15 @@ ${block}`;
|
|
|
23661
23932
|
continue;
|
|
23662
23933
|
}
|
|
23663
23934
|
attachmentRevision += 1;
|
|
23664
|
-
pendingAttachmentKeys.
|
|
23935
|
+
pendingAttachmentKeys.set(dedupeKey, {
|
|
23936
|
+
name: normalizeAttachmentName(file.name),
|
|
23937
|
+
mimeType: String(file.type || ""),
|
|
23938
|
+
size: fileSize,
|
|
23939
|
+
loading: true
|
|
23940
|
+
});
|
|
23665
23941
|
pendingAttachmentBytes += fileSize;
|
|
23942
|
+
renderComposerAttachments();
|
|
23943
|
+
onChange();
|
|
23666
23944
|
try {
|
|
23667
23945
|
const dataUrl = await readFileAsDataUrl(file, tx);
|
|
23668
23946
|
if (generation !== attachmentGeneration) return;
|
|
@@ -23690,6 +23968,8 @@ ${block}`;
|
|
|
23690
23968
|
if (generation === attachmentGeneration) {
|
|
23691
23969
|
pendingAttachmentBytes = Math.max(0, pendingAttachmentBytes - fileSize);
|
|
23692
23970
|
pendingAttachmentKeys.delete(dedupeKey);
|
|
23971
|
+
renderComposerAttachments();
|
|
23972
|
+
onChange();
|
|
23693
23973
|
}
|
|
23694
23974
|
}
|
|
23695
23975
|
}
|
|
@@ -23721,8 +24001,9 @@ ${block}`;
|
|
|
23721
24001
|
if (!strip) {
|
|
23722
24002
|
return;
|
|
23723
24003
|
}
|
|
23724
|
-
|
|
23725
|
-
|
|
24004
|
+
const visibleAttachments = [...attachments, ...pendingAttachmentKeys.values()];
|
|
24005
|
+
strip.hidden = visibleAttachments.length === 0;
|
|
24006
|
+
renderAttachmentPreviewList(visibleAttachments, strip, {
|
|
23726
24007
|
root: getPanel() || document.body,
|
|
23727
24008
|
tr,
|
|
23728
24009
|
tx,
|
|
@@ -23840,6 +24121,14 @@ ${block}`;
|
|
|
23840
24121
|
renderComposerAttachments();
|
|
23841
24122
|
return attachments.length;
|
|
23842
24123
|
}
|
|
24124
|
+
function getOmittedAttachmentNames() {
|
|
24125
|
+
let persistedCount = 0;
|
|
24126
|
+
return attachments.filter((attachment) => {
|
|
24127
|
+
if ((attachment.contentBase64 || "").length > PERSIST_MAX_CONTENT_CHARS || persistedCount >= PERSIST_MAX_COUNT) return true;
|
|
24128
|
+
persistedCount += 1;
|
|
24129
|
+
return false;
|
|
24130
|
+
}).map((attachment) => attachment.name);
|
|
24131
|
+
}
|
|
23843
24132
|
function restoreSubmittedAttachments(value, expectedRevision) {
|
|
23844
24133
|
if (expectedRevision !== attachmentRevision || attachments.length || pendingAttachmentBytes || pendingAttachmentKeys.size) return false;
|
|
23845
24134
|
if (!Array.isArray(value) || value.length > maxAttachments) return false;
|
|
@@ -23858,6 +24147,8 @@ ${block}`;
|
|
|
23858
24147
|
}
|
|
23859
24148
|
return {
|
|
23860
24149
|
serializePersistableAttachments,
|
|
24150
|
+
getOmittedAttachmentNames,
|
|
24151
|
+
hasPendingReads: () => pendingAttachmentKeys.size > 0,
|
|
23861
24152
|
restorePersistedAttachments,
|
|
23862
24153
|
restoreSubmittedAttachments,
|
|
23863
24154
|
getRevision: () => attachmentRevision,
|
|
@@ -23956,6 +24247,10 @@ ${block}`;
|
|
|
23956
24247
|
const card = document.createElement("div");
|
|
23957
24248
|
card.className = "codex-attachment-preview-card";
|
|
23958
24249
|
card.dataset.kind = isImage ? "image" : "file";
|
|
24250
|
+
if (attachment.loading) {
|
|
24251
|
+
card.dataset.loading = "true";
|
|
24252
|
+
card.setAttribute("aria-busy", "true");
|
|
24253
|
+
}
|
|
23959
24254
|
card.title = label + " \xB7 " + formatFileSize(attachment.size);
|
|
23960
24255
|
if (isImage) {
|
|
23961
24256
|
const preview = document.createElement("button");
|
|
@@ -23984,11 +24279,11 @@ ${block}`;
|
|
|
23984
24279
|
if (!isImage) {
|
|
23985
24280
|
const size = document.createElement("span");
|
|
23986
24281
|
size.className = "codex-attachment-preview-size";
|
|
23987
|
-
size.textContent = formatFileSize(attachment.size);
|
|
24282
|
+
size.textContent = attachment.loading ? options.tx ? options.tx("Loading\u2026", "\u8BFB\u53D6\u4E2D\u2026") : "Loading\u2026" : formatFileSize(attachment.size);
|
|
23988
24283
|
meta.append(size);
|
|
23989
24284
|
}
|
|
23990
24285
|
card.append(meta);
|
|
23991
|
-
if (options.removable) {
|
|
24286
|
+
if (options.removable && !attachment.loading) {
|
|
23992
24287
|
const remove = document.createElement("button");
|
|
23993
24288
|
remove.type = "button";
|
|
23994
24289
|
remove.className = "codex-attachment-preview-remove";
|
|
@@ -24308,7 +24603,10 @@ ${block}`;
|
|
|
24308
24603
|
}
|
|
24309
24604
|
return compact;
|
|
24310
24605
|
}
|
|
24311
|
-
function setVisible(
|
|
24606
|
+
function setVisible(target, visible) {
|
|
24607
|
+
const instance = target?._instance;
|
|
24608
|
+
const panelEl = instance?.panelEl || target;
|
|
24609
|
+
if (visible && instance) updateCompactMode(instance);
|
|
24312
24610
|
panelEl?.classList?.toggle("is-open", Boolean(visible));
|
|
24313
24611
|
document.documentElement.classList.toggle(ROOT_CLASS, Boolean(visible));
|
|
24314
24612
|
const launcherEl = panelEl?.ownerDocument?.getElementById?.("codex-overleaf-launcher");
|
|
@@ -26355,18 +26653,7 @@ ${block}`;
|
|
|
26355
26653
|
actions.innerHTML = instance.embedded ? "" : `<button type="button" class="codex-provider-secondary-button" data-provider-action="close">${escapeHtml(tx("Close", "\u5173\u95ED"))}</button>`;
|
|
26356
26654
|
return;
|
|
26357
26655
|
}
|
|
26358
|
-
const
|
|
26359
|
-
const isNew = !provider.id;
|
|
26360
|
-
const destinationChanged = active && getCurrentBaseUrl(instance) !== provider.endpointDisclosureBaseUrl;
|
|
26361
|
-
const actionState = getFooterActionState({
|
|
26362
|
-
isNew,
|
|
26363
|
-
active,
|
|
26364
|
-
dirty: instance.dirty,
|
|
26365
|
-
destinationChanged,
|
|
26366
|
-
canSave: canSaveCurrentDraft(instance),
|
|
26367
|
-
hasProject: instance.callbacks.hasCurrentProject?.() !== false,
|
|
26368
|
-
canActivate: canActivateCurrentProvider(instance)
|
|
26369
|
-
});
|
|
26656
|
+
const actionState = getCurrentFooterActionState(instance);
|
|
26370
26657
|
const saveDisabled = actionState.saveEnabled ? "" : ' disabled aria-disabled="true"';
|
|
26371
26658
|
const useDisabled = actionState.useEnabled ? "" : ' disabled aria-disabled="true"';
|
|
26372
26659
|
actions.innerHTML = `
|
|
@@ -26379,6 +26666,20 @@ ${block}`;
|
|
|
26379
26666
|
${actionState.showUse ? `<button type="button" class="codex-provider-primary-button" data-provider-action="use"${useDisabled}>${escapeHtml(tx("Use for this project", "\u7528\u4E8E\u5F53\u524D\u9879\u76EE"))}</button>` : ""}
|
|
26380
26667
|
`;
|
|
26381
26668
|
}
|
|
26669
|
+
function getCurrentFooterActionState(instance) {
|
|
26670
|
+
const provider = getSelectedProvider(instance);
|
|
26671
|
+
const active = Boolean(provider?.id && provider.id === getCurrentProjectProviderId(instance));
|
|
26672
|
+
return getFooterActionState({
|
|
26673
|
+
isNew: !provider?.id,
|
|
26674
|
+
active,
|
|
26675
|
+
dirty: instance.dirty,
|
|
26676
|
+
destinationChanged: active && getCurrentBaseUrl(instance) !== provider.endpointDisclosureBaseUrl,
|
|
26677
|
+
disclosureAccepted: instance.root.querySelector("[data-provider-disclosure]")?.checked === true,
|
|
26678
|
+
canSave: canSaveCurrentDraft(instance),
|
|
26679
|
+
hasProject: instance.callbacks.hasCurrentProject?.() !== false,
|
|
26680
|
+
canActivate: canActivateCurrentProvider(instance)
|
|
26681
|
+
});
|
|
26682
|
+
}
|
|
26382
26683
|
function getFooterActionState(options = {}) {
|
|
26383
26684
|
const isNew = options.isNew === true;
|
|
26384
26685
|
const active = options.active === true;
|
|
@@ -26386,9 +26687,9 @@ ${block}`;
|
|
|
26386
26687
|
return {
|
|
26387
26688
|
showSave: isNew || dirty,
|
|
26388
26689
|
showSaveAndUse: options.hasProject !== false && (isNew || dirty) && (!active || options.destinationChanged === true),
|
|
26389
|
-
showUse: options.hasProject !== false && !isNew && !active && !dirty,
|
|
26690
|
+
showUse: options.hasProject !== false && !isNew && (!active || options.destinationChanged === true) && !dirty,
|
|
26390
26691
|
saveEnabled: options.canSave === true,
|
|
26391
|
-
useEnabled: options.canActivate === true
|
|
26692
|
+
useEnabled: options.canActivate === true && (!options.destinationChanged || options.disclosureAccepted === true)
|
|
26392
26693
|
};
|
|
26393
26694
|
}
|
|
26394
26695
|
async function handleClick(instance, event) {
|
|
@@ -26574,6 +26875,11 @@ ${block}`;
|
|
|
26574
26875
|
refreshTestState(instance);
|
|
26575
26876
|
return;
|
|
26576
26877
|
}
|
|
26878
|
+
if (event.target.matches("[data-provider-disclosure]")) {
|
|
26879
|
+
renderFooter(instance);
|
|
26880
|
+
applyBusyState(instance);
|
|
26881
|
+
return;
|
|
26882
|
+
}
|
|
26577
26883
|
if (event.target.matches("[data-provider-field]")) {
|
|
26578
26884
|
const field = event.target.dataset.providerField;
|
|
26579
26885
|
if (event.target.dataset.providerField === "apiKey") {
|
|
@@ -26744,8 +27050,7 @@ ${block}`;
|
|
|
26744
27050
|
}
|
|
26745
27051
|
function applyBusyState(instance) {
|
|
26746
27052
|
const busy = Boolean(instance.busy && instance.busy !== "failed");
|
|
26747
|
-
const
|
|
26748
|
-
const canActivate = canActivateCurrentProvider(instance);
|
|
27053
|
+
const actionState = getCurrentFooterActionState(instance);
|
|
26749
27054
|
instance.root.dataset.busy = instance.busy || "";
|
|
26750
27055
|
for (const element of instance.root.querySelectorAll("input, select, textarea, button")) {
|
|
26751
27056
|
if (element.matches("[data-provider-confirm-answer]")) {
|
|
@@ -26755,9 +27060,9 @@ ${block}`;
|
|
|
26755
27060
|
} else if (element.matches('[data-provider-action="cancel-test"]')) {
|
|
26756
27061
|
element.disabled = false;
|
|
26757
27062
|
} else if (element.matches('[data-provider-action="save"], [data-provider-action="save-use"]')) {
|
|
26758
|
-
element.disabled = busy || !
|
|
27063
|
+
element.disabled = busy || !actionState.saveEnabled;
|
|
26759
27064
|
} else if (element.matches('[data-provider-action="use"]')) {
|
|
26760
|
-
element.disabled = busy || !
|
|
27065
|
+
element.disabled = busy || !actionState.useEnabled;
|
|
26761
27066
|
} else {
|
|
26762
27067
|
element.disabled = busy;
|
|
26763
27068
|
}
|
|
@@ -28268,6 +28573,18 @@ ${block}`;
|
|
|
28268
28573
|
});
|
|
28269
28574
|
}
|
|
28270
28575
|
}
|
|
28576
|
+
function projectPreferenceValues(input, prefs, projectId) {
|
|
28577
|
+
return {
|
|
28578
|
+
experimentalOtByProject: input.normalizeExperimentalOtByProject(prefs.experimentalOtByProject)[projectId] === true,
|
|
28579
|
+
reviewingAvailabilityByProject: prefs.reviewingAvailabilityByProject?.[projectId],
|
|
28580
|
+
governanceRulesByProject: input.normalizeGovernanceRulesByProject({
|
|
28581
|
+
[projectId]: prefs.governanceRulesByProject?.[projectId] || {}
|
|
28582
|
+
})[projectId],
|
|
28583
|
+
customInstructionsByProject: input.normalizeCustomInstructionsByProject({
|
|
28584
|
+
[projectId]: prefs.customInstructionsByProject?.[projectId] || ""
|
|
28585
|
+
})[projectId]
|
|
28586
|
+
};
|
|
28587
|
+
}
|
|
28271
28588
|
async function persistPanelState(input) {
|
|
28272
28589
|
var state = cloneSnapshot(input.state || {});
|
|
28273
28590
|
var compactState = cloneSnapshot(input.compactState || {});
|
|
@@ -28293,6 +28610,14 @@ ${block}`;
|
|
|
28293
28610
|
}
|
|
28294
28611
|
var reviewRuns = (input.reviewRunIds || []).map((id) => (state.sessions || []).flatMap((session) => session.runs || []).find((run) => run.id === id));
|
|
28295
28612
|
if (reviewRuns.some((run) => !run)) throw reviewPersistenceError();
|
|
28613
|
+
var preferenceBaseline = input.projectPreferenceBaseline || Migration.getProjectPreferenceBaseline?.(accountScopeId, projectId);
|
|
28614
|
+
var preferenceWrite = input.projectPreferenceWrite || Migration.captureProjectPreferenceWrite?.({
|
|
28615
|
+
...input,
|
|
28616
|
+
state,
|
|
28617
|
+
baseline: preferenceBaseline,
|
|
28618
|
+
accountScopeId,
|
|
28619
|
+
projectId
|
|
28620
|
+
});
|
|
28296
28621
|
var latestPrefs = typeof Migration.loadPrefs === "function" ? await Migration.loadPrefs(accountScopeId, projectId) : {};
|
|
28297
28622
|
var prefs = Object.assign(
|
|
28298
28623
|
{},
|
|
@@ -28304,32 +28629,21 @@ ${block}`;
|
|
|
28304
28629
|
projectId,
|
|
28305
28630
|
compactState.activeSessionId || state.activeSessionId || ""
|
|
28306
28631
|
);
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
);
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
);
|
|
28322
|
-
var normalizedCustomProject = input.normalizeCustomInstructionsByProject({ [projectId]: "" });
|
|
28323
|
-
var customProjectId = Object.keys(normalizedCustomProject)[0] || "";
|
|
28324
|
-
var currentCustom = input.normalizeCustomInstructionsByProject(state.customInstructionsByProject);
|
|
28325
|
-
prefs.customInstructionsByProject = Object.assign(
|
|
28326
|
-
{},
|
|
28327
|
-
latestPrefs && latestPrefs.customInstructionsByProject || {}
|
|
28328
|
-
);
|
|
28329
|
-
if (customProjectId) {
|
|
28330
|
-
prefs.customInstructionsByProject[customProjectId] = Object.prototype.hasOwnProperty.call(currentCustom, customProjectId) ? currentCustom[customProjectId] : "";
|
|
28632
|
+
var currentPreferences = projectPreferenceValues(input, state, projectId);
|
|
28633
|
+
if (preferenceWrite) {
|
|
28634
|
+
Object.assign(prefs, Migration.projectPreferencePatch(preferenceWrite, accountScopeId, projectId));
|
|
28635
|
+
} else {
|
|
28636
|
+
var baselinePreferences = projectPreferenceValues(input, preferenceBaseline || latestPrefs || {}, projectId);
|
|
28637
|
+
for (var name of Object.keys(currentPreferences)) {
|
|
28638
|
+
prefs[name] = JSON.stringify(currentPreferences[name]) === JSON.stringify(baselinePreferences[name]) ? {} : { [projectId]: currentPreferences[name] };
|
|
28639
|
+
}
|
|
28640
|
+
}
|
|
28641
|
+
var savedPrefs = await Migration.savePrefs(prefs, accountScopeId, projectId);
|
|
28642
|
+
if (savedPrefs) {
|
|
28643
|
+
var fields = preferenceWrite ? Migration.completeProjectPreferenceWrite(preferenceWrite, savedPrefs) : Object.keys(currentPreferences);
|
|
28644
|
+
var applied = input.applyProjectPreferences?.(savedPrefs, state, fields);
|
|
28645
|
+
if (!preferenceWrite && applied !== false) Migration.adoptProjectPreferenceBaseline?.(savedPrefs, accountScopeId, projectId);
|
|
28331
28646
|
}
|
|
28332
|
-
await Migration.savePrefs(prefs, accountScopeId, projectId);
|
|
28333
28647
|
var persistenceMeta = input.persistenceContext?.nextMeta || {};
|
|
28334
28648
|
var queueTombstones = persistenceMeta.queueTombstones || {};
|
|
28335
28649
|
var sessionTombstones = persistenceMeta.sessionTombstones || {};
|
|
@@ -28702,11 +29016,18 @@ ${block}`;
|
|
|
28702
29016
|
const details = root.querySelector("[data-diagnostics-result-details]");
|
|
28703
29017
|
const scroll = root.querySelector(".codex-diagnostics-result-scroll");
|
|
28704
29018
|
const open = details?.open, scrollTop = scroll?.scrollTop;
|
|
28705
|
-
const checks = Array.from(root.querySelectorAll(".codex-diagnostics-check"), (node) =>
|
|
29019
|
+
const checks = Array.from(root.querySelectorAll(".codex-diagnostics-check"), (node) => ({
|
|
29020
|
+
open: node.open,
|
|
29021
|
+
technicalOpen: node.querySelector(".codex-diagnostics-technical")?.open
|
|
29022
|
+
}));
|
|
28706
29023
|
showResult(instance, result);
|
|
28707
29024
|
if (details) details.open = open;
|
|
28708
29025
|
root.querySelectorAll(".codex-diagnostics-check").forEach((node, index) => {
|
|
28709
|
-
if (index < checks.length)
|
|
29026
|
+
if (index < checks.length) {
|
|
29027
|
+
node.open = checks[index].open;
|
|
29028
|
+
const technical = node.querySelector(".codex-diagnostics-technical");
|
|
29029
|
+
if (technical) technical.open = checks[index].technicalOpen;
|
|
29030
|
+
}
|
|
28710
29031
|
});
|
|
28711
29032
|
if (scroll) scroll.scrollTop = scrollTop;
|
|
28712
29033
|
}
|
|
@@ -28721,42 +29042,45 @@ ${block}`;
|
|
|
28721
29042
|
root.hidden = false;
|
|
28722
29043
|
root.dataset.status = result.status || "info";
|
|
28723
29044
|
root.setAttribute("aria-label", result.title || t(instance, "diagnosticsResult"));
|
|
28724
|
-
root.querySelector("[data-diagnostics-result-title]")
|
|
29045
|
+
const titleNode = root.querySelector("[data-diagnostics-result-title]");
|
|
29046
|
+
const dot = document.createElement("span");
|
|
29047
|
+
dot.className = "codex-diagnostics-status-dot";
|
|
29048
|
+
dot.setAttribute("aria-hidden", "true");
|
|
29049
|
+
const titleText = document.createElement("span");
|
|
29050
|
+
titleText.className = "codex-diagnostics-result-title-text";
|
|
29051
|
+
titleText.textContent = result.title || t(instance, "diagnosticsResult");
|
|
29052
|
+
titleNode.replaceChildren(dot, titleText);
|
|
28725
29053
|
root.querySelector("[data-diagnostics-result-subtitle]").textContent = result.subtitle || "";
|
|
28726
29054
|
const body = root.querySelector("[data-diagnostics-result-body]");
|
|
28727
29055
|
body.textContent = "";
|
|
28728
|
-
|
|
28729
|
-
|
|
29056
|
+
const facts = Array.isArray(result.facts) ? result.facts.filter((fact) => fact?.label) : [];
|
|
29057
|
+
const notes = [
|
|
29058
|
+
...Array.isArray(result.notes) ? result.notes : [],
|
|
29059
|
+
...Array.isArray(result.bullets) ? result.bullets : []
|
|
29060
|
+
].filter(Boolean);
|
|
29061
|
+
const hasChecks = Array.isArray(result.checks) && result.checks.length > 0;
|
|
29062
|
+
if (result.summary && !(result.status === "completed" && facts.length)) {
|
|
29063
|
+
appendParagraph(body, result.summary, "codex-diagnostics-summary");
|
|
28730
29064
|
}
|
|
28731
|
-
if (
|
|
28732
|
-
renderCheckRows(body, result.checks);
|
|
28733
|
-
} else if (!result.summary) {
|
|
29065
|
+
if (hasChecks) {
|
|
29066
|
+
renderCheckRows(instance, body, result.checks);
|
|
29067
|
+
} else if (!result.summary && !facts.length && !notes.length) {
|
|
28734
29068
|
appendParagraph(body, t(instance, "diagnosticsNoResult"));
|
|
28735
29069
|
}
|
|
28736
|
-
if (
|
|
28737
|
-
|
|
28738
|
-
|
|
28739
|
-
|
|
28740
|
-
|
|
28741
|
-
list.append(li);
|
|
28742
|
-
}
|
|
28743
|
-
body.append(list);
|
|
29070
|
+
if (facts.length) {
|
|
29071
|
+
renderFacts(body, facts);
|
|
29072
|
+
}
|
|
29073
|
+
if (notes.length) {
|
|
29074
|
+
renderNotes(body, notes);
|
|
28744
29075
|
}
|
|
28745
29076
|
if (result.nextStep) {
|
|
28746
|
-
|
|
28747
|
-
next.className = "codex-diagnostics-next-step";
|
|
28748
|
-
next.textContent = `${t(instance, "nextStepPrefix")}${result.nextStep}`;
|
|
28749
|
-
body.append(next);
|
|
29077
|
+
appendNextStep(instance, body, result.nextStep, "p", "codex-diagnostics-next-step");
|
|
28750
29078
|
}
|
|
28751
29079
|
if (result.installCommand) {
|
|
28752
29080
|
renderInstallCommand(instance, body, result.installCommand);
|
|
28753
29081
|
}
|
|
28754
29082
|
const details = root.querySelector("[data-diagnostics-result-details]");
|
|
28755
|
-
|
|
28756
|
-
const technicalText = String(result.technical || "").trim();
|
|
28757
|
-
details.open = false;
|
|
28758
|
-
details.hidden = !technicalText;
|
|
28759
|
-
technical.textContent = technicalText;
|
|
29083
|
+
renderTechnicalDetails(details, result.technical);
|
|
28760
29084
|
closeMenu(instance);
|
|
28761
29085
|
openFloating(instance, root, 400);
|
|
28762
29086
|
if (wasHidden) root.querySelector("[data-diagnostics-result-close]")?.focus({ preventScroll: true });
|
|
@@ -28829,13 +29153,13 @@ ${block}`;
|
|
|
28829
29153
|
function renderInstallCommand(instance, container, command) {
|
|
28830
29154
|
const wrap = document.createElement("div");
|
|
28831
29155
|
wrap.className = "codex-install-command";
|
|
28832
|
-
const
|
|
29156
|
+
const head = document.createElement("div");
|
|
29157
|
+
head.className = "codex-install-command-head";
|
|
29158
|
+
const label = document.createElement("span");
|
|
28833
29159
|
label.className = "codex-install-command-label";
|
|
28834
29160
|
label.textContent = t(instance, "runInTerminal");
|
|
28835
|
-
wrap.append(label);
|
|
28836
29161
|
const code = document.createElement("code");
|
|
28837
29162
|
code.textContent = command;
|
|
28838
|
-
wrap.append(code);
|
|
28839
29163
|
const copyButton = document.createElement("button");
|
|
28840
29164
|
copyButton.type = "button";
|
|
28841
29165
|
copyButton.textContent = t(instance, "copyInstallCommand");
|
|
@@ -28846,21 +29170,82 @@ ${block}`;
|
|
|
28846
29170
|
copyButton.textContent = t(instance, "copyInstallCommand");
|
|
28847
29171
|
}, 1400);
|
|
28848
29172
|
});
|
|
28849
|
-
|
|
29173
|
+
head.append(label, copyButton);
|
|
29174
|
+
wrap.append(head, code);
|
|
28850
29175
|
container.append(wrap);
|
|
28851
29176
|
}
|
|
28852
|
-
function appendParagraph(container, text) {
|
|
29177
|
+
function appendParagraph(container, text, className) {
|
|
28853
29178
|
const paragraph = document.createElement("p");
|
|
29179
|
+
if (className) {
|
|
29180
|
+
paragraph.className = className;
|
|
29181
|
+
}
|
|
28854
29182
|
paragraph.textContent = text;
|
|
28855
29183
|
container.append(paragraph);
|
|
28856
29184
|
}
|
|
29185
|
+
function appendNextStep(instance, container, text, tagName, className) {
|
|
29186
|
+
const next = document.createElement(tagName);
|
|
29187
|
+
next.className = className;
|
|
29188
|
+
const label = document.createElement("span");
|
|
29189
|
+
label.className = "codex-diagnostics-next-label";
|
|
29190
|
+
label.textContent = t(instance, "nextStepPrefix");
|
|
29191
|
+
next.append(label, document.createTextNode(text));
|
|
29192
|
+
container.append(next);
|
|
29193
|
+
}
|
|
29194
|
+
function renderFacts(container, facts) {
|
|
29195
|
+
const list = document.createElement("dl");
|
|
29196
|
+
list.className = "codex-diagnostics-facts";
|
|
29197
|
+
for (const fact of facts) {
|
|
29198
|
+
const term = document.createElement("dt");
|
|
29199
|
+
term.textContent = fact.label;
|
|
29200
|
+
const value = document.createElement("dd");
|
|
29201
|
+
const text = String(fact.value ?? "");
|
|
29202
|
+
if (fact.kind === "path") {
|
|
29203
|
+
value.textContent = shortenPath(text);
|
|
29204
|
+
value.title = text;
|
|
29205
|
+
} else {
|
|
29206
|
+
value.textContent = text;
|
|
29207
|
+
}
|
|
29208
|
+
if (fact.tone) {
|
|
29209
|
+
value.dataset.tone = fact.tone;
|
|
29210
|
+
}
|
|
29211
|
+
list.append(term, value);
|
|
29212
|
+
}
|
|
29213
|
+
container.append(list);
|
|
29214
|
+
}
|
|
29215
|
+
function shortenPath(path) {
|
|
29216
|
+
if (path.length <= 36) {
|
|
29217
|
+
return path;
|
|
29218
|
+
}
|
|
29219
|
+
const parts = path.split("/");
|
|
29220
|
+
if (parts.length < 5) {
|
|
29221
|
+
return path;
|
|
29222
|
+
}
|
|
29223
|
+
const short = `${parts.slice(0, 3).join("/")}/\u2026/${parts[parts.length - 1]}`;
|
|
29224
|
+
return short.length < path.length ? short : path;
|
|
29225
|
+
}
|
|
29226
|
+
function renderNotes(container, notes) {
|
|
29227
|
+
const list = document.createElement("ul");
|
|
29228
|
+
list.className = "codex-diagnostics-notes";
|
|
29229
|
+
for (const note of notes) {
|
|
29230
|
+
const item = document.createElement("li");
|
|
29231
|
+
item.textContent = note;
|
|
29232
|
+
list.append(item);
|
|
29233
|
+
}
|
|
29234
|
+
container.append(list);
|
|
29235
|
+
}
|
|
29236
|
+
function renderTechnicalDetails(details, value) {
|
|
29237
|
+
const text = String(value || "").trim();
|
|
29238
|
+
details.open = false;
|
|
29239
|
+
details.hidden = !text;
|
|
29240
|
+
details.querySelector("pre").textContent = text;
|
|
29241
|
+
}
|
|
28857
29242
|
function healthBucket(status) {
|
|
28858
29243
|
if (status === "completed" || status === "ok") return "ok";
|
|
28859
29244
|
if (status === "warning" || status === "warn") return "warn";
|
|
28860
29245
|
if (status === "failed" || status === "fail") return "fail";
|
|
28861
29246
|
return "info";
|
|
28862
29247
|
}
|
|
28863
|
-
function renderCheckRows(container, checks) {
|
|
29248
|
+
function renderCheckRows(instance, container, checks) {
|
|
28864
29249
|
const list = document.createElement("div");
|
|
28865
29250
|
list.className = "codex-diagnostics-checks";
|
|
28866
29251
|
for (const check of checks) {
|
|
@@ -28870,15 +29255,15 @@ ${block}`;
|
|
|
28870
29255
|
row.dataset.status = healthBucket(check.status);
|
|
28871
29256
|
row.open = row.dataset.status === "warn" || row.dataset.status === "fail";
|
|
28872
29257
|
const heading = document.createElement("summary");
|
|
28873
|
-
const
|
|
28874
|
-
|
|
28875
|
-
|
|
29258
|
+
const dot = document.createElement("span");
|
|
29259
|
+
dot.className = "codex-diagnostics-check-dot";
|
|
29260
|
+
dot.setAttribute("aria-hidden", "true");
|
|
28876
29261
|
const textWrap = document.createElement("div");
|
|
28877
29262
|
textWrap.className = "codex-diagnostics-check-text";
|
|
28878
29263
|
const title = document.createElement("div");
|
|
28879
29264
|
title.className = "codex-diagnostics-check-title";
|
|
28880
29265
|
title.textContent = check.title || "";
|
|
28881
|
-
heading.append(
|
|
29266
|
+
heading.append(dot, title);
|
|
28882
29267
|
if (check.summary) {
|
|
28883
29268
|
const summary = document.createElement("div");
|
|
28884
29269
|
summary.className = "codex-diagnostics-check-summary";
|
|
@@ -28886,10 +29271,19 @@ ${block}`;
|
|
|
28886
29271
|
textWrap.append(summary);
|
|
28887
29272
|
}
|
|
28888
29273
|
if (check.nextStep) {
|
|
28889
|
-
|
|
28890
|
-
|
|
28891
|
-
|
|
28892
|
-
textWrap.
|
|
29274
|
+
appendNextStep(instance, textWrap, check.nextStep, "div", "codex-diagnostics-check-next");
|
|
29275
|
+
}
|
|
29276
|
+
if (check.installCommand) {
|
|
29277
|
+
renderInstallCommand(instance, textWrap, check.installCommand);
|
|
29278
|
+
}
|
|
29279
|
+
if (check.technical) {
|
|
29280
|
+
const details = document.createElement("details");
|
|
29281
|
+
details.className = "codex-diagnostics-technical";
|
|
29282
|
+
const summary = document.createElement("summary");
|
|
29283
|
+
summary.textContent = t(instance, "technicalDetails");
|
|
29284
|
+
details.append(summary, document.createElement("pre"));
|
|
29285
|
+
renderTechnicalDetails(details, check.technical);
|
|
29286
|
+
textWrap.append(details);
|
|
28893
29287
|
}
|
|
28894
29288
|
row.append(heading, textWrap);
|
|
28895
29289
|
list.append(row);
|
|
@@ -29179,37 +29573,46 @@ ${block}`;
|
|
|
29179
29573
|
claimToken: claimedItem?.claimToken
|
|
29180
29574
|
}
|
|
29181
29575
|
});
|
|
29182
|
-
const
|
|
29576
|
+
const latestQueue2 = options.getQueue?.(sessionId) || originalQueue;
|
|
29183
29577
|
options.setQueue?.(
|
|
29184
29578
|
sessionId,
|
|
29185
|
-
dequeue(
|
|
29579
|
+
dequeue(latestQueue2, queueItemId, {
|
|
29186
29580
|
sessionId,
|
|
29187
29581
|
reason: status === "completed" ? "completed" : "continue_queue"
|
|
29188
29582
|
})
|
|
29189
29583
|
);
|
|
29190
|
-
}
|
|
29191
|
-
|
|
29584
|
+
}
|
|
29585
|
+
const canStart = shouldContinue ? options.canStart?.(sessionId) : true;
|
|
29586
|
+
const latestQueue = options.getQueue?.(sessionId) || originalQueue;
|
|
29587
|
+
const inactive = shouldContinue && canStart !== "session_transition" && (canStart === false || options.isRunning?.()) && latestQueue.some((item) => item?.status === "queued");
|
|
29588
|
+
if (!shouldContinue || inactive) {
|
|
29589
|
+
const reason = inactive ? "session_inactive" : status || "run_did_not_complete";
|
|
29590
|
+
const paused = latestQueue.length ? Queue.pauseAll(latestQueue, reason) : latestQueue;
|
|
29192
29591
|
options.setQueue?.(sessionId, paused);
|
|
29193
29592
|
try {
|
|
29194
29593
|
await options.persist?.({
|
|
29195
29594
|
queueMutation: { type: "transition", sessionId }
|
|
29196
29595
|
});
|
|
29197
29596
|
} catch (error) {
|
|
29198
|
-
const
|
|
29597
|
+
const latestQueue2 = options.getQueue?.(sessionId) || paused;
|
|
29199
29598
|
options.setQueue?.(
|
|
29200
29599
|
sessionId,
|
|
29201
|
-
Queue.pauseAll(
|
|
29600
|
+
Queue.pauseAll(latestQueue2, reason)
|
|
29202
29601
|
);
|
|
29203
29602
|
throw error;
|
|
29204
29603
|
}
|
|
29205
29604
|
}
|
|
29206
29605
|
options.onChange?.(sessionId);
|
|
29207
|
-
if (shouldContinue) {
|
|
29606
|
+
if (shouldContinue && !inactive) {
|
|
29208
29607
|
scheduleOne(sessionId);
|
|
29209
29608
|
}
|
|
29210
29609
|
}
|
|
29211
29610
|
function scheduleOne(sessionId) {
|
|
29212
|
-
if (scheduling || options.isRunning?.()
|
|
29611
|
+
if (scheduling || options.isRunning?.()) {
|
|
29612
|
+
return false;
|
|
29613
|
+
}
|
|
29614
|
+
const canStart = options.canStart?.(sessionId);
|
|
29615
|
+
if (canStart === false || canStart === "session_transition") {
|
|
29213
29616
|
return false;
|
|
29214
29617
|
}
|
|
29215
29618
|
const initialQueue = options.getQueue?.(sessionId) || [];
|
|
@@ -29326,7 +29729,7 @@ ${block}`;
|
|
|
29326
29729
|
setQueue: (sessionId, pendingInputs) => options.setQueue?.(sessionId, pendingInputs),
|
|
29327
29730
|
persist: (persistenceOptions) => options.save?.(persistenceOptions),
|
|
29328
29731
|
isRunning: () => Boolean(options.getCurrentRun?.()),
|
|
29329
|
-
canStart: (sessionId) => options.canStart?.(sessionId)
|
|
29732
|
+
canStart: (sessionId) => options.canStart?.(sessionId),
|
|
29330
29733
|
start: (item, sessionId) => startQueuedInput(item, sessionId),
|
|
29331
29734
|
onChange: () => render(),
|
|
29332
29735
|
onDequeued: (item, context) => options.removeGuidance?.(item.id, {
|
|
@@ -29565,7 +29968,8 @@ ${block}`;
|
|
|
29565
29968
|
}
|
|
29566
29969
|
async function startQueuedInput(item, sessionId) {
|
|
29567
29970
|
const assertCanStart = () => {
|
|
29568
|
-
|
|
29971
|
+
const canStart = options.canStart?.(sessionId);
|
|
29972
|
+
if (canStart === false || canStart === "session_transition" || options.getCurrentRun?.()) {
|
|
29569
29973
|
const error = new Error("Queued input cannot start in the current session.");
|
|
29570
29974
|
error.code = "queue_session_not_active";
|
|
29571
29975
|
throw error;
|
|
@@ -30845,6 +31249,33 @@ ${block}`;
|
|
|
30845
31249
|
return null;
|
|
30846
31250
|
}
|
|
30847
31251
|
}
|
|
31252
|
+
async function attachInstruction(action, selected) {
|
|
31253
|
+
const selection = await attach("edit", selected);
|
|
31254
|
+
if (!selection) return;
|
|
31255
|
+
const task = deps.getPanel()?.querySelector("[data-task]");
|
|
31256
|
+
if (!task) return;
|
|
31257
|
+
if (task.value.trim()) {
|
|
31258
|
+
deps.toast?.(tx("Kept your draft. The selection is attached for editing.", "\u5DF2\u4FDD\u7559\u4F60\u7684\u8349\u7A3F\uFF0C\u9009\u533A\u5DF2\u9644\u4E0A\uFF0C\u4EC5\u7F16\u8F91\u6B64\u5904\u3002"));
|
|
31259
|
+
return;
|
|
31260
|
+
}
|
|
31261
|
+
const instructions = {
|
|
31262
|
+
polish: tx(
|
|
31263
|
+
"Polish the selected passage for clarity and flow. Keep the meaning, citations, labels and math unchanged.",
|
|
31264
|
+
"\u6DA6\u8272\u9009\u4E2D\u6BB5\u843D\uFF0C\u8BA9\u8868\u8FBE\u66F4\u6E05\u6670\u6D41\u7545\uFF0C\u4FDD\u6301\u539F\u610F\u4EE5\u53CA\u5F15\u7528\u3001\u6807\u7B7E\u3001\u516C\u5F0F\u4E0D\u53D8\u3002"
|
|
31265
|
+
),
|
|
31266
|
+
shorten: tx(
|
|
31267
|
+
"Shorten the selected passage by about 20%. Keep citations, labels, math and the main claim unchanged.",
|
|
31268
|
+
"\u5C06\u9009\u4E2D\u6BB5\u843D\u7CBE\u7B80\u7EA6 20%\uFF0C\u4FDD\u7559\u5F15\u7528\u3001\u6807\u7B7E\u3001\u516C\u5F0F\u548C\u6838\u5FC3\u8BBA\u70B9\u4E0D\u53D8\u3002"
|
|
31269
|
+
),
|
|
31270
|
+
translate: tx(
|
|
31271
|
+
"Translate the selected passage into English. Keep LaTeX commands, citations, labels and math unchanged.",
|
|
31272
|
+
"\u5C06\u9009\u4E2D\u6BB5\u843D\u7FFB\u8BD1\u6210\u82F1\u6587\uFF0C\u4FDD\u7559 LaTeX \u547D\u4EE4\u3001\u5F15\u7528\u3001\u6807\u7B7E\u548C\u516C\u5F0F\u4E0D\u53D8\u3002"
|
|
31273
|
+
)
|
|
31274
|
+
};
|
|
31275
|
+
task.value = instructions[action];
|
|
31276
|
+
task.setSelectionRange(task.value.length, task.value.length);
|
|
31277
|
+
task.dispatchEvent(new Event("input", { bubbles: true }));
|
|
31278
|
+
}
|
|
30848
31279
|
function editorFor(node) {
|
|
30849
31280
|
const element = node?.nodeType === 1 ? node : node?.parentElement;
|
|
30850
31281
|
const editor = element?.closest?.(".cm-editor");
|
|
@@ -30871,6 +31302,9 @@ ${block}`;
|
|
|
30871
31302
|
toolbar.setAttribute("aria-label", tx("Selected text actions", "\u9009\u533A\u64CD\u4F5C"));
|
|
30872
31303
|
toolbar.querySelector('[data-selection-action="reference"]').textContent = tx("Add to Chat", "\u52A0\u5165\u5BF9\u8BDD");
|
|
30873
31304
|
toolbar.querySelector('[data-selection-action="edit"]').textContent = tx("Edit Selection", "\u4EC5\u7F16\u8F91\u6B64\u5904");
|
|
31305
|
+
toolbar.querySelector('[data-selection-action="polish"]').textContent = tx("Polish", "\u6DA6\u8272");
|
|
31306
|
+
toolbar.querySelector('[data-selection-action="shorten"]').textContent = tx("Shorten", "\u7CBE\u7B80");
|
|
31307
|
+
toolbar.querySelector('[data-selection-action="translate"]').textContent = tx("Translate", "\u7FFB\u8BD1");
|
|
30874
31308
|
}
|
|
30875
31309
|
function ensureToolbar() {
|
|
30876
31310
|
if (toolbar) return;
|
|
@@ -30880,8 +31314,8 @@ ${block}`;
|
|
|
30880
31314
|
toolbar.setAttribute("role", "toolbar");
|
|
30881
31315
|
toolbar.hidden = true;
|
|
30882
31316
|
if (typeof toolbar.showPopover === "function") toolbar.setAttribute("popover", "manual");
|
|
30883
|
-
for (const mode of ["reference", "edit"]) {
|
|
30884
|
-
if (mode === "edit") {
|
|
31317
|
+
for (const mode of ["reference", "edit", "polish", "shorten", "translate"]) {
|
|
31318
|
+
if (mode === "edit" || mode === "polish") {
|
|
30885
31319
|
const divider = document.createElement("span");
|
|
30886
31320
|
divider.className = "codex-selection-action-divider";
|
|
30887
31321
|
divider.setAttribute("aria-hidden", "true");
|
|
@@ -30892,7 +31326,9 @@ ${block}`;
|
|
|
30892
31326
|
button.dataset.selectionAction = mode;
|
|
30893
31327
|
button.addEventListener("click", () => {
|
|
30894
31328
|
const selected = candidate;
|
|
30895
|
-
if (selected)
|
|
31329
|
+
if (!selected) return;
|
|
31330
|
+
if (mode === "reference" || mode === "edit") void attach(mode, selected);
|
|
31331
|
+
else void attachInstruction(mode, selected);
|
|
30896
31332
|
});
|
|
30897
31333
|
toolbar.append(button);
|
|
30898
31334
|
}
|
|
@@ -37519,6 +37955,18 @@ ${block}`;
|
|
|
37519
37955
|
renderText: buildMarkdownInlineNodesWithoutMath
|
|
37520
37956
|
});
|
|
37521
37957
|
}
|
|
37958
|
+
function buildParsedTextNodes(value) {
|
|
37959
|
+
const source = String(value || "");
|
|
37960
|
+
if (!MathText?.buildMathNodes) {
|
|
37961
|
+
return buildLineReferenceInlineNodes(source);
|
|
37962
|
+
}
|
|
37963
|
+
return MathText.buildMathNodes(source, {
|
|
37964
|
+
document,
|
|
37965
|
+
katex: window.katex,
|
|
37966
|
+
macros: getMathMacros(),
|
|
37967
|
+
renderText: buildLineReferenceInlineNodes
|
|
37968
|
+
});
|
|
37969
|
+
}
|
|
37522
37970
|
function buildMarkdownInlineNodesWithoutMath(value) {
|
|
37523
37971
|
const source = String(value || "");
|
|
37524
37972
|
const nodes = [];
|
|
@@ -37911,15 +38359,8 @@ ${block}`;
|
|
|
37911
38359
|
document,
|
|
37912
38360
|
markdownIt: runtimeRoot.markdownit,
|
|
37913
38361
|
mathText: runtimeRoot.CodexOverleafMathText,
|
|
37914
|
-
renderTextNodes:
|
|
37915
|
-
renderLinkNodes:
|
|
37916
|
-
const safeLabel = String(label || "");
|
|
37917
|
-
const target2 = String(href || "").trim();
|
|
37918
|
-
if (!/^https?:\/\//i.test(target2) && !resolveMarkdownLineReference(safeLabel, target2)) return buildMarkdownInlineNodes(safeLabel);
|
|
37919
|
-
return buildMarkdownInlineNodes(
|
|
37920
|
-
`[${safeLabel.replace(/]/g, "\\]")}](${target2.replace(/\)/g, "\\)")})`
|
|
37921
|
-
);
|
|
37922
|
-
},
|
|
38362
|
+
renderTextNodes: buildParsedTextNodes,
|
|
38363
|
+
renderLinkNodes: buildMarkdownLinkNodes,
|
|
37923
38364
|
renderCodeNodes: (text) => buildInlineCodeNodes(text),
|
|
37924
38365
|
sanitizeText: sanitizeAssistantVisibleText,
|
|
37925
38366
|
createMathNode: (segment) => runtimeRoot.CodexOverleafMathText.createMathNode(
|
|
@@ -38199,7 +38640,12 @@ ${block}`;
|
|
|
38199
38640
|
try {
|
|
38200
38641
|
result = await spec.run({ collectOnly: true });
|
|
38201
38642
|
} catch (error) {
|
|
38202
|
-
result = projectableResult(() => ({
|
|
38643
|
+
result = projectableResult(() => ({
|
|
38644
|
+
status: "failed",
|
|
38645
|
+
summary: tr("diagnosticsCheckErrored"),
|
|
38646
|
+
nextStep: tr("runOutcomeNext"),
|
|
38647
|
+
technical: error?.message || String(error)
|
|
38648
|
+
}));
|
|
38203
38649
|
}
|
|
38204
38650
|
const bucket = diagnosticsHealthBucket(result?.status);
|
|
38205
38651
|
if (bucket === "fail") {
|
|
@@ -38214,7 +38660,9 @@ ${block}`;
|
|
|
38214
38660
|
status: result?.status || "info",
|
|
38215
38661
|
title: tr(spec.label),
|
|
38216
38662
|
summary: translated?.summary || translated?.subtitle || "",
|
|
38217
|
-
nextStep: bucket === "ok" ? "" : translated?.nextStep || ""
|
|
38663
|
+
nextStep: bucket === "ok" ? "" : translated?.nextStep || "",
|
|
38664
|
+
installCommand: translated?.installCommand,
|
|
38665
|
+
technical: translated?.technical
|
|
38218
38666
|
};
|
|
38219
38667
|
});
|
|
38220
38668
|
}
|
|
@@ -38296,9 +38744,9 @@ ${block}`;
|
|
|
38296
38744
|
const codexOk = environment.codex?.ok === true;
|
|
38297
38745
|
const latexTools = environment.latex?.available || [];
|
|
38298
38746
|
const latexOk = latexTools.length > 0;
|
|
38299
|
-
const
|
|
38300
|
-
codexOk ?
|
|
38301
|
-
latexOk ?
|
|
38747
|
+
const facts = [
|
|
38748
|
+
codexOk ? environment.codex.path ? { label: "Codex", value: environment.codex.path, kind: "path" } : { label: "Codex", value: tx("Found on PATH", "\u5DF2\u5728 PATH \u4E2D\u627E\u5230") } : { label: "Codex", value: tx("Not found", "\u672A\u627E\u5230"), tone: "fail" },
|
|
38749
|
+
latexOk ? { label: "LaTeX", value: latexTools.join(", ") } : { label: "LaTeX", value: tx("Not found", "\u672A\u627E\u5230"), tone: "warn" }
|
|
38302
38750
|
];
|
|
38303
38751
|
if (codexOk && latexOk) {
|
|
38304
38752
|
return {
|
|
@@ -38306,7 +38754,7 @@ ${block}`;
|
|
|
38306
38754
|
subtitle: tx("Codex and LaTeX are available.", "Codex \u548C LaTeX \u90FD\u53EF\u4EE5\u4F7F\u7528\u3002"),
|
|
38307
38755
|
status: "completed",
|
|
38308
38756
|
summary: tx("Codex is connected and local LaTeX tools are available. Codex can read, edit, and locally check this Overleaf project.", "Codex \u5DF2\u8FDE\u63A5\uFF0C\u672C\u673A LaTeX \u5DE5\u5177\u53EF\u7528\u3002\u4F60\u53EF\u4EE5\u8BA9 Codex \u8BFB\u53D6\u3001\u4FEE\u6539\u5E76\u672C\u5730\u68C0\u67E5 Overleaf \u9879\u76EE\u3002"),
|
|
38309
|
-
|
|
38757
|
+
facts,
|
|
38310
38758
|
technical: JSON.stringify(environment, null, 2)
|
|
38311
38759
|
};
|
|
38312
38760
|
}
|
|
@@ -38315,7 +38763,7 @@ ${block}`;
|
|
|
38315
38763
|
subtitle: codexOk ? tx("Codex is available, but compile tools are incomplete.", "Codex \u53EF\u7528\uFF0C\u4F46\u7F16\u8BD1\u5DE5\u5177\u4E0D\u5B8C\u6574\u3002") : tx("Local Codex was not found.", "\u6CA1\u6709\u627E\u5230\u672C\u673A Codex\u3002"),
|
|
38316
38764
|
status: codexOk ? "warning" : "failed",
|
|
38317
38765
|
summary: codexOk ? tx("Local Codex can run, but LaTeX compile tools were not found. File edits are unaffected, but compile verification is limited.", "\u672C\u673A Codex \u53EF\u4EE5\u8FD0\u884C\uFF0C\u4F46\u6CA1\u6709\u627E\u5230 LaTeX \u7F16\u8BD1\u5DE5\u5177\uFF1B\u4FEE\u6539\u6587\u4EF6\u4E0D\u53D7\u5F71\u54CD\uFF0C\u7F16\u8BD1\u9A8C\u8BC1\u4F1A\u53D7\u9650\u3002") : tx("The extension reached the native host, but local Codex was not found, so tasks cannot start.", "\u63D2\u4EF6\u5DF2\u7ECF\u8FDE\u4E0A native host\uFF0C\u4F46\u6CA1\u6709\u627E\u5230\u672C\u673A Codex\uFF0C\u6240\u4EE5\u4E0D\u80FD\u542F\u52A8\u4EFB\u52A1\u3002"),
|
|
38318
|
-
|
|
38766
|
+
facts,
|
|
38319
38767
|
nextStep: codexOk ? tx("For compile verification, make sure latexmk or pdflatex is available on your Terminal PATH.", "\u5982\u9700\u7F16\u8BD1\u9A8C\u8BC1\uFF0C\u8BF7\u786E\u8BA4 latexmk \u6216 pdflatex \u5728\u7EC8\u7AEF PATH \u4E2D\u53EF\u7528\u3002") : tx("Make sure codex works in Terminal, then reload the extension.", "\u8BF7\u786E\u8BA4\u7EC8\u7AEF\u91CC\u53EF\u4EE5\u8FD0\u884C codex\uFF0C\u7136\u540E\u91CD\u65B0\u52A0\u8F7D\u6269\u5C55\u3002"),
|
|
38320
38768
|
technical: JSON.stringify(environment, null, 2)
|
|
38321
38769
|
};
|
|
@@ -38351,7 +38799,7 @@ ${block}`;
|
|
|
38351
38799
|
subtitle: messages.subtitle,
|
|
38352
38800
|
status: "failed",
|
|
38353
38801
|
summary: messages.summary,
|
|
38354
|
-
|
|
38802
|
+
facts: formatNativeCompatibilityFacts(compatibility, statusValue),
|
|
38355
38803
|
nextStep: messages.nextStep,
|
|
38356
38804
|
installCommand: compatibility.installCommand,
|
|
38357
38805
|
technical: formatNativeCompatibilityTechnicalDetails(compatibility, response)
|
|
@@ -38389,14 +38837,24 @@ ${block}`;
|
|
|
38389
38837
|
};
|
|
38390
38838
|
}
|
|
38391
38839
|
}
|
|
38392
|
-
function
|
|
38840
|
+
function formatNativeCompatibilityFacts(compatibility = {}, statusValue = "") {
|
|
38393
38841
|
const native = compatibility.native || {};
|
|
38394
38842
|
return [
|
|
38395
|
-
|
|
38396
|
-
|
|
38397
|
-
|
|
38398
|
-
|
|
38399
|
-
|
|
38843
|
+
{
|
|
38844
|
+
label: tx("Extension version", "\u6269\u5C55\u7248\u672C"),
|
|
38845
|
+
value: compatibility.extensionVersion || "unknown",
|
|
38846
|
+
tone: statusValue === "extension_too_old" ? "fail" : void 0
|
|
38847
|
+
},
|
|
38848
|
+
{
|
|
38849
|
+
label: tx("Native version", "Native \u7248\u672C"),
|
|
38850
|
+
value: native.version || "unknown",
|
|
38851
|
+
tone: statusValue === "native_too_old" ? "fail" : void 0
|
|
38852
|
+
},
|
|
38853
|
+
{
|
|
38854
|
+
label: tx("Native protocol", "Native \u534F\u8BAE"),
|
|
38855
|
+
value: formatNativeProtocolVersion(native),
|
|
38856
|
+
tone: statusValue === "protocol_unsupported" ? "fail" : void 0
|
|
38857
|
+
}
|
|
38400
38858
|
];
|
|
38401
38859
|
}
|
|
38402
38860
|
function formatNativeProtocolVersion(native = {}) {
|
|
@@ -38457,7 +38915,7 @@ ${block}`;
|
|
|
38457
38915
|
subtitle: tr("diagnosticsOtSubtitle"),
|
|
38458
38916
|
status: "completed",
|
|
38459
38917
|
summary: tr("diagnosticsOtSummaryDisabled"),
|
|
38460
|
-
|
|
38918
|
+
facts: [],
|
|
38461
38919
|
nextStep: "",
|
|
38462
38920
|
technical: ""
|
|
38463
38921
|
};
|
|
@@ -38552,10 +39010,14 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38552
39010
|
subtitle: tr("diagnosticsOtSubtitle"),
|
|
38553
39011
|
status: enabled && !fallback && !bridgeFailed ? "completed" : enabled || bridgeFailed ? "warning" : "completed",
|
|
38554
39012
|
summary: tr(failureActive ? otWarmMirrorController.getFailureMessageKey(warmMirrorState.lastErrorCode) : enabled ? "diagnosticsOtSummaryEnabled" : "diagnosticsOtSummaryDisabled"),
|
|
38555
|
-
|
|
38556
|
-
|
|
38557
|
-
|
|
38558
|
-
|
|
39013
|
+
facts: [
|
|
39014
|
+
{ label: tr("otStatus"), value: formatOtStatusLabel(statusValue) },
|
|
39015
|
+
{ label: tr("otFreshFiles"), value: String(otFreshFileCount) },
|
|
39016
|
+
{
|
|
39017
|
+
label: tr("otFallback"),
|
|
39018
|
+
value: fallback ? tr("yes") : tr("no"),
|
|
39019
|
+
tone: enabled && fallback ? "warn" : void 0
|
|
39020
|
+
}
|
|
38559
39021
|
],
|
|
38560
39022
|
nextStep: fallback ? tr("diagnosticsOtNextStep") : "",
|
|
38561
39023
|
technical: formatOtDiagnosticsTechnicalDetails({
|
|
@@ -38614,10 +39076,23 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38614
39076
|
const reviewingOk = probe?.reviewing?.ok === true;
|
|
38615
39077
|
const writable = probe?.capabilities?.editor?.write !== false;
|
|
38616
39078
|
const readable = probe?.editor?.ok === true;
|
|
38617
|
-
const
|
|
38618
|
-
|
|
38619
|
-
|
|
38620
|
-
|
|
39079
|
+
const reviewingNeeded = mode !== "ask";
|
|
39080
|
+
const facts = [
|
|
39081
|
+
{
|
|
39082
|
+
label: tx("Current file", "\u5F53\u524D\u6587\u4EF6"),
|
|
39083
|
+
value: readable ? tx("Read", "\u5DF2\u8BFB\u53D6") : tx("Not verified", "\u672A\u786E\u8BA4"),
|
|
39084
|
+
tone: readable ? void 0 : "warn"
|
|
39085
|
+
},
|
|
39086
|
+
{
|
|
39087
|
+
label: tx("Write access", "\u5199\u5165"),
|
|
39088
|
+
value: writable ? tx("Checked again before writing", "\u5199\u5165\u524D\u4F1A\u518D\u6B21\u9A8C\u8BC1") : tx("Not writable yet", "\u6682\u4E0D\u53EF\u5199"),
|
|
39089
|
+
tone: writable ? void 0 : "warn"
|
|
39090
|
+
},
|
|
39091
|
+
{
|
|
39092
|
+
label: tx("Track changes", "\u7559\u75D5"),
|
|
39093
|
+
value: reviewingOk ? tx("Verified", "\u5DF2\u786E\u8BA4") : tx("Not verified", "\u672A\u786E\u8BA4"),
|
|
39094
|
+
tone: reviewingOk || !reviewingNeeded ? void 0 : "warn"
|
|
39095
|
+
}
|
|
38621
39096
|
];
|
|
38622
39097
|
if (readable && writable) {
|
|
38623
39098
|
return {
|
|
@@ -38625,7 +39100,7 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38625
39100
|
subtitle: formatProbeStatusBar(probe),
|
|
38626
39101
|
status: reviewingOk || mode === "ask" ? "completed" : "warning",
|
|
38627
39102
|
summary: tx("The current Overleaf file can be read and written. The extension still verifies before writing to avoid overwriting new user or collaborator edits.", "\u5F53\u524D Overleaf \u6587\u4EF6\u53EF\u4EE5\u8BFB\u53D6\u548C\u5199\u5165\u3002\u5199\u5165\u524D\u63D2\u4EF6\u4ECD\u4F1A\u518D\u6B21\u9A8C\u8BC1\uFF0C\u907F\u514D\u8986\u76D6\u7528\u6237\u6216\u534F\u4F5C\u8005\u7684\u65B0\u6539\u52A8\u3002"),
|
|
38628
|
-
|
|
39103
|
+
facts,
|
|
38629
39104
|
nextStep: reviewingOk || mode === "ask" ? "" : tx("If you need tracked writes, turn on Overleaf Reviewing/Track Changes first.", "\u5982\u679C\u9700\u8981\u7559\u75D5\u5199\u5165\uFF0C\u8BF7\u5148\u5728 Overleaf \u5F00\u542F Reviewing/Track Changes\u3002"),
|
|
38630
39105
|
technical: formatPageDiagnosticsTechnicalDetails(probe)
|
|
38631
39106
|
};
|
|
@@ -38635,7 +39110,7 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38635
39110
|
subtitle: formatProbeStatusBar(probe),
|
|
38636
39111
|
status: "warning",
|
|
38637
39112
|
summary: readable ? tx("The extension read the current Overleaf file, but has not verified that the current editor can be written.", "\u63D2\u4EF6\u5DF2\u8BFB\u5230\u5F53\u524D Overleaf \u6587\u4EF6\uFF0C\u4F46\u8FD8\u6CA1\u6709\u786E\u8BA4\u5F53\u524D\u7F16\u8F91\u5668\u53EF\u4EE5\u5199\u5165\u3002") : tx("The extension has not verified that the current editor can be written. Usually this means no .tex file is open yet, or Overleaf is still loading.", "\u63D2\u4EF6\u6CA1\u6709\u786E\u8BA4\u5F53\u524D\u7F16\u8F91\u5668\u53EF\u4EE5\u5199\u5165\u3002\u901A\u5E38\u662F\u8FD8\u6CA1\u70B9\u5F00 .tex \u6587\u4EF6\uFF0C\u6216\u8005 Overleaf \u9875\u9762\u4ECD\u5728\u52A0\u8F7D\u3002"),
|
|
38638
|
-
|
|
39113
|
+
facts,
|
|
38639
39114
|
nextStep: tx("Open the target .tex file from the left Overleaf file tree, wait for the editor to load, then check again.", "\u5728 Overleaf \u5DE6\u4FA7\u6587\u4EF6\u6811\u70B9\u5F00\u8981\u5904\u7406\u7684 .tex \u6587\u4EF6\uFF0C\u7B49\u7F16\u8F91\u5668\u52A0\u8F7D\u5B8C\u6210\u540E\u91CD\u65B0\u68C0\u6D4B\u3002"),
|
|
38640
39115
|
technical: formatPageDiagnosticsTechnicalDetails(probe)
|
|
38641
39116
|
};
|
|
@@ -38648,10 +39123,10 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38648
39123
|
const warnings = getProjectSnapshotWarnings(project);
|
|
38649
39124
|
const warningText = [...warnings.blocking, ...warnings.nonBlocking].map(formatProjectSnapshotWarning);
|
|
38650
39125
|
const source = project?.capabilities?.method || "unknown";
|
|
38651
|
-
const
|
|
38652
|
-
tx(
|
|
38653
|
-
tx(
|
|
38654
|
-
|
|
39126
|
+
const facts = [
|
|
39127
|
+
{ label: tx("Text files", "\u6587\u672C\u6587\u4EF6"), value: tx(String(textCount), `${textCount} \u4E2A`) },
|
|
39128
|
+
{ label: tx("Asset files", "\u8D44\u6E90\u6587\u4EF6"), value: tx(String(binaryCount), `${binaryCount} \u4E2A`) },
|
|
39129
|
+
{ label: tx("Current file", "\u5F53\u524D\u6587\u4EF6"), value: project?.activePath || tx("Not detected", "\u672A\u8BC6\u522B") }
|
|
38655
39130
|
];
|
|
38656
39131
|
if (fullProject && files.length) {
|
|
38657
39132
|
return {
|
|
@@ -38662,7 +39137,8 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38662
39137
|
`The extension read the full Overleaf project: ${textCount} text file(s)${binaryCount ? `, ${binaryCount} asset file(s)` : ""}.`,
|
|
38663
39138
|
`\u63D2\u4EF6\u5DF2\u8BFB\u5230\u5B8C\u6574 Overleaf \u9879\u76EE\uFF1A${textCount} \u4E2A\u6587\u672C\u6587\u4EF6${binaryCount ? `\uFF0C${binaryCount} \u4E2A\u8D44\u6E90\u6587\u4EF6` : ""}\u3002`
|
|
38664
39139
|
),
|
|
38665
|
-
|
|
39140
|
+
facts,
|
|
39141
|
+
notes: warningText,
|
|
38666
39142
|
technical: formatProjectSnapshotLog(project)
|
|
38667
39143
|
};
|
|
38668
39144
|
}
|
|
@@ -38674,7 +39150,8 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38674
39150
|
`The full Overleaf project was not read. Currently read ${textCount} text file(s)${binaryCount ? `, ${binaryCount} asset file(s)` : ""}.`,
|
|
38675
39151
|
`\u6CA1\u6709\u8BFB\u5230\u5B8C\u6574\u7684 Overleaf \u9879\u76EE\u3002\u5F53\u524D\u53EA\u8BFB\u5230 ${textCount} \u4E2A\u6587\u672C\u6587\u4EF6${binaryCount ? `\uFF0C${binaryCount} \u4E2A\u8D44\u6E90\u6587\u4EF6` : ""}\u3002`
|
|
38676
39152
|
) : tx("The full Overleaf project was not read, and no usable file content was available.", "\u6CA1\u6709\u8BFB\u5230\u5B8C\u6574\u7684 Overleaf \u9879\u76EE\uFF0C\u4E5F\u6CA1\u6709\u62FF\u5230\u53EF\u7528\u6587\u4EF6\u5185\u5BB9\u3002"),
|
|
38677
|
-
|
|
39153
|
+
facts,
|
|
39154
|
+
notes: warningText,
|
|
38678
39155
|
nextStep: tx("Reload Overleaf and wait for the left file tree to load, then retry. If you only want one file, use + to add @file context.", "\u5237\u65B0 Overleaf \u9875\u9762\uFF0C\u7B49\u5DE6\u4FA7\u6587\u4EF6\u6811\u52A0\u8F7D\u5B8C\u6210\u540E\u91CD\u8BD5\uFF1B\u5982\u679C\u53EA\u60F3\u5904\u7406\u4E00\u4E2A\u6587\u4EF6\uFF0C\u53EF\u4EE5\u7528 + \u6DFB\u52A0 @file \u4E0A\u4E0B\u6587\u3002"),
|
|
38679
39156
|
technical: formatProjectSnapshotLog(project)
|
|
38680
39157
|
};
|
|
@@ -38886,7 +39363,7 @@ failedAt: ${new Date(failure.at).toISOString()}`;
|
|
|
38886
39363
|
},
|
|
38887
39364
|
platform: nativeDiagnostics.platform,
|
|
38888
39365
|
nativeEnvironment: nativeDiagnostics.nativeEnvironment,
|
|
38889
|
-
mirror,
|
|
39366
|
+
mirror: mirror ?? { status: "unavailable" },
|
|
38890
39367
|
auditLogs,
|
|
38891
39368
|
run: activeRecord?.runProjectId === projectId && matchesAccount(activeRecord, currentRunView?.runAccountScopeId) ? activeRecord : recentRuns[0] || {},
|
|
38892
39369
|
recentRuns,
|
|
@@ -39737,17 +40214,18 @@ ${AgentTranscript.formatFailureBlock(failure, locale, indent)}`;
|
|
|
39737
40214
|
const existing = root.querySelector("[data-run-copy]");
|
|
39738
40215
|
const button = existing.cloneNode(true);
|
|
39739
40216
|
existing.replaceWith(button);
|
|
39740
|
-
const
|
|
39741
|
-
const copyText = String(finalAnswer?.innerText || finalAnswer?.textContent || "").trim();
|
|
40217
|
+
const available = Boolean(readConclusionText(root).trim());
|
|
39742
40218
|
button.hidden = false;
|
|
39743
|
-
button.disabled = !
|
|
40219
|
+
button.disabled = !available;
|
|
39744
40220
|
button.title = tr("copyConclusionTitle");
|
|
39745
40221
|
button.setAttribute("aria-label", button.title);
|
|
39746
40222
|
button.innerHTML = '<svg viewBox="0 0 20 20" aria-hidden="true"><g transform="translate(.75 .75)"><rect x="6.5" y="6.5" width="9" height="9" rx="2"/><path d="M13.5 6.5V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6.5a2 2 0 0 0 2 2h1.5"/></g></svg>';
|
|
39747
|
-
if (!
|
|
40223
|
+
if (!available) return;
|
|
39748
40224
|
button.addEventListener("click", async (event) => {
|
|
39749
40225
|
event.stopPropagation();
|
|
39750
40226
|
try {
|
|
40227
|
+
const copyText = readConclusionText(root);
|
|
40228
|
+
if (!copyText.trim()) return;
|
|
39751
40229
|
await writeClipboardText(copyText);
|
|
39752
40230
|
button.title = tr("copyConclusionDone");
|
|
39753
40231
|
} catch (_error) {
|
|
@@ -39756,6 +40234,47 @@ ${AgentTranscript.formatFailureBlock(failure, locale, indent)}`;
|
|
|
39756
40234
|
button.setAttribute("aria-label", button.title);
|
|
39757
40235
|
});
|
|
39758
40236
|
}
|
|
40237
|
+
function readConclusionText(root) {
|
|
40238
|
+
const answer = root.querySelector(".run-completion-report .run-final-answer");
|
|
40239
|
+
if (!answer) return "";
|
|
40240
|
+
return extractConclusionText(answer).replace(/\u200b/g, "").replace(/[ \t]+$/gm, "").trim();
|
|
40241
|
+
}
|
|
40242
|
+
function extractConclusionText(node) {
|
|
40243
|
+
if (node.nodeType === 3) return String(node.textContent || "").replace(/\s+/g, " ");
|
|
40244
|
+
const tag = node.tagName?.toLowerCase();
|
|
40245
|
+
if (tag === "br") return "\n";
|
|
40246
|
+
if (tag === "pre" || tag === "code") return node.textContent || "";
|
|
40247
|
+
if (node.classList?.contains("run-math")) {
|
|
40248
|
+
const source = node.dataset.mathRendered === "false" ? node.textContent || "" : node.querySelector('annotation[encoding="application/x-tex"]')?.textContent || "";
|
|
40249
|
+
const delimiter = node.dataset.mathDisplay === "block" ? "$$" : "$";
|
|
40250
|
+
return source ? `${delimiter}${source}${delimiter}` : "";
|
|
40251
|
+
}
|
|
40252
|
+
const children = Array.from(node.childNodes || []);
|
|
40253
|
+
if (tag === "ul" || tag === "ol") {
|
|
40254
|
+
const start = Number(node.getAttribute("start") || 1);
|
|
40255
|
+
return children.filter((child) => child.tagName?.toLowerCase() === "li").map((child, index) => `${tag === "ol" ? `${start + index}. ` : "- "}${extractConclusionText(child)}`).join("\n");
|
|
40256
|
+
}
|
|
40257
|
+
if (tag === "table") {
|
|
40258
|
+
return Array.from(node.querySelectorAll("tr"), (row) => Array.from(
|
|
40259
|
+
row.children,
|
|
40260
|
+
(cell) => extractConclusionText(cell)
|
|
40261
|
+
).join(" ")).join("\n");
|
|
40262
|
+
}
|
|
40263
|
+
let text = "";
|
|
40264
|
+
let previousBlock = false;
|
|
40265
|
+
for (const child of children) {
|
|
40266
|
+
const value = extractConclusionText(child);
|
|
40267
|
+
if (!value) continue;
|
|
40268
|
+
const block = /^(p|h[1-6]|blockquote|ul|ol|pre|table|div)$/.test(child.tagName?.toLowerCase()) || child.dataset?.mathDisplay === "block";
|
|
40269
|
+
if (text && (previousBlock || block)) {
|
|
40270
|
+
const newlines = (text.match(/\n*$/)?.[0].length || 0) + (value.match(/^\n*/)?.[0].length || 0);
|
|
40271
|
+
text += "\n".repeat(Math.max(0, 2 - newlines));
|
|
40272
|
+
}
|
|
40273
|
+
text += value;
|
|
40274
|
+
previousBlock = block;
|
|
40275
|
+
}
|
|
40276
|
+
return text;
|
|
40277
|
+
}
|
|
39759
40278
|
async function writeClipboardText(text) {
|
|
39760
40279
|
if (navigatorRef?.clipboard?.writeText) {
|
|
39761
40280
|
await navigatorRef.clipboard.writeText(text);
|
|
@@ -44577,7 +45096,7 @@ ${lines}`
|
|
|
44577
45096
|
normalizeSpeedTiersForSelect,
|
|
44578
45097
|
retainSelectedModel
|
|
44579
45098
|
} = Support;
|
|
44580
|
-
let modelDiscovery = { status: "fallback", source: "fallback", fetchedAt: "" };
|
|
45099
|
+
let modelDiscovery = { status: "fallback", source: "fallback", fetchedAt: "", provisional: true };
|
|
44581
45100
|
let modelLoadGeneration = 0;
|
|
44582
45101
|
function getModelDiscovery() {
|
|
44583
45102
|
return modelDiscovery;
|
|
@@ -44621,22 +45140,18 @@ ${lines}`
|
|
|
44621
45140
|
const modelSelect = getPanel()?.querySelector("[data-model]");
|
|
44622
45141
|
const reasoningSelect = getPanel()?.querySelector("[data-reasoning]");
|
|
44623
45142
|
const speedSelect = getPanel()?.querySelector("[data-speed]");
|
|
44624
|
-
|
|
44625
|
-
|
|
44626
|
-
|
|
44627
|
-
|
|
44628
|
-
|
|
44629
|
-
|
|
44630
|
-
changedInput = modelSelect;
|
|
45143
|
+
const changedInput = choice.dataset.reasoningChoice ? reasoningSelect : choice.dataset.modelChoice ? modelSelect : choice.dataset.speedChoice ? speedSelect : null;
|
|
45144
|
+
const value = choice.dataset.reasoningChoice || choice.dataset.modelChoice || choice.dataset.speedChoice;
|
|
45145
|
+
const option = Array.from(changedInput?.options || []).find((item) => item.value === value);
|
|
45146
|
+
if (!changedInput || changedInput.disabled || !option || option.disabled) return;
|
|
45147
|
+
changedInput.value = value;
|
|
45148
|
+
if (changedInput === modelSelect) {
|
|
44631
45149
|
renderReasoningOptions(getRenderedModelEntries());
|
|
44632
45150
|
renderSpeedOptions(getRenderedModelEntries());
|
|
44633
|
-
} else if (choice.dataset.speedChoice && speedSelect) {
|
|
44634
|
-
speedSelect.value = choice.dataset.speedChoice;
|
|
44635
|
-
changedInput = speedSelect;
|
|
44636
45151
|
}
|
|
44637
45152
|
renderModelConfigChoices();
|
|
44638
45153
|
updateModelDisplay();
|
|
44639
|
-
await persistPanelInputs(
|
|
45154
|
+
await persistPanelInputs({ type: "change", target: changedInput });
|
|
44640
45155
|
}
|
|
44641
45156
|
async function loadModelOptions(providerSelection, options = {}) {
|
|
44642
45157
|
const generation = ++modelLoadGeneration;
|
|
@@ -44668,7 +45183,7 @@ ${lines}`
|
|
|
44668
45183
|
}
|
|
44669
45184
|
const sourceModels = hasDiscoveredModels ? response.result.models : fallbackModels;
|
|
44670
45185
|
const preserveBuiltin = (selection?.providerId || "builtin") === "builtin" && (getState()?.providerId || "builtin") === "builtin";
|
|
44671
|
-
const retainedSelectedModel = retainSelectedModel(sourceModels, currentSelectedModel, { preserveUnavailable: preserveBuiltin });
|
|
45186
|
+
const retainedSelectedModel = retainSelectedModel(sourceModels, currentSelectedModel, { preserveUnavailable: preserveBuiltin }) || (responseProviderId && responseProviderId !== "builtin" ? retainSelectedModel(sourceModels, response.result?.defaultModelId) : "");
|
|
44672
45187
|
const normalized = modelCatalog.normalizeDiscoveredModels({ models: sourceModels, selectedModel: retainedSelectedModel });
|
|
44673
45188
|
if (normalized.usedFallback && response.result?.providerId && response.result.providerId !== "builtin") {
|
|
44674
45189
|
applyUnavailableModelOptions({ code: "provider_model_catalog_invalid", message: "The active provider returned no usable models." });
|
|
@@ -44766,6 +45281,13 @@ ${lines}`
|
|
|
44766
45281
|
return;
|
|
44767
45282
|
}
|
|
44768
45283
|
const selectedId = normalizeModelOptionId(selectedModel);
|
|
45284
|
+
if (options.provisionalSelected === true) {
|
|
45285
|
+
models = [...Array.isArray(models) ? models : []];
|
|
45286
|
+
if (selectedId && !models.some((model) => normalizeModelOptionId(model?.id) === selectedId)) {
|
|
45287
|
+
models.push({ id: selectedId, label: selectedId, unverified: true });
|
|
45288
|
+
}
|
|
45289
|
+
models = Support.preserveSelectedCapabilities(models, selectedId, getState(), true);
|
|
45290
|
+
}
|
|
44769
45291
|
modelSelect.textContent = "";
|
|
44770
45292
|
modelSelect.disabled = false;
|
|
44771
45293
|
let renderedSelected = false;
|
|
@@ -44887,7 +45409,8 @@ ${lines}`
|
|
|
44887
45409
|
list.append(createModelConfigChoice({
|
|
44888
45410
|
value: option.value,
|
|
44889
45411
|
label: formatReasoningEffortLabel(option.value, reasoningSelect.dataset.presentation),
|
|
44890
|
-
datasetName: "reasoningChoice"
|
|
45412
|
+
datasetName: "reasoningChoice",
|
|
45413
|
+
disabled: reasoningSelect.disabled || option.disabled
|
|
44891
45414
|
}));
|
|
44892
45415
|
}
|
|
44893
45416
|
}
|
|
@@ -44903,7 +45426,8 @@ ${lines}`
|
|
|
44903
45426
|
const choice = createModelConfigChoice({
|
|
44904
45427
|
value: option.value,
|
|
44905
45428
|
label: option.textContent || option.value,
|
|
44906
|
-
datasetName: "modelChoice"
|
|
45429
|
+
datasetName: "modelChoice",
|
|
45430
|
+
disabled: modelSelect.disabled || option.disabled
|
|
44907
45431
|
});
|
|
44908
45432
|
choice.title = option.textContent || option.value;
|
|
44909
45433
|
list.append(choice);
|
|
@@ -44920,15 +45444,16 @@ ${lines}`
|
|
|
44920
45444
|
const choice = createModelConfigChoice({
|
|
44921
45445
|
value: option.value,
|
|
44922
45446
|
label: formatSpeedTierLabel(option.value),
|
|
44923
|
-
datasetName: "speedChoice"
|
|
45447
|
+
datasetName: "speedChoice",
|
|
45448
|
+
disabled: speedSelect.disabled || option.disabled
|
|
44924
45449
|
});
|
|
44925
|
-
choice.disabled = speedSelect.disabled && speedSelect.options.length <= 1;
|
|
44926
45450
|
list.append(choice);
|
|
44927
45451
|
}
|
|
44928
45452
|
}
|
|
44929
|
-
function createModelConfigChoice({ value, label, datasetName }) {
|
|
45453
|
+
function createModelConfigChoice({ value, label, datasetName, disabled = false }) {
|
|
44930
45454
|
const button = document.createElement("button");
|
|
44931
45455
|
button.type = "button";
|
|
45456
|
+
button.disabled = disabled;
|
|
44932
45457
|
button.className = "codex-model-config-choice";
|
|
44933
45458
|
button.dataset[datasetName] = value;
|
|
44934
45459
|
button.setAttribute("role", "menuitemradio");
|
|
@@ -45573,10 +46098,10 @@ ${lines}`
|
|
|
45573
46098
|
restoreScrollTop: root ? root.scrollTop : 0
|
|
45574
46099
|
};
|
|
45575
46100
|
}
|
|
45576
|
-
async function refreshDashboardView() {
|
|
46101
|
+
async function refreshDashboardView(options = {}) {
|
|
45577
46102
|
var panelEl = getPanel();
|
|
45578
46103
|
if (panelEl && panelEl.dataset.view === "recent-projects") {
|
|
45579
|
-
await renderRecentProjectsVariant(dashboardViewOptions());
|
|
46104
|
+
await renderRecentProjectsVariant(Object.assign(dashboardViewOptions(), options));
|
|
45580
46105
|
}
|
|
45581
46106
|
}
|
|
45582
46107
|
async function openDashboardConversation(projectId, record, row) {
|
|
@@ -45751,7 +46276,7 @@ ${lines}`
|
|
|
45751
46276
|
var map = prefs.activeSessionByProject && typeof prefs.activeSessionByProject === "object" ? prefs.activeSessionByProject : {};
|
|
45752
46277
|
map[projectId] = record.id;
|
|
45753
46278
|
prefs.activeSessionByProject = map;
|
|
45754
|
-
await Migration.savePrefs(
|
|
46279
|
+
await Migration.savePrefs({ activeSessionByProject: map }, accountScopeId, projectId);
|
|
45755
46280
|
}
|
|
45756
46281
|
} catch (_error) {
|
|
45757
46282
|
}
|
|
@@ -45886,18 +46411,30 @@ ${lines}`
|
|
|
45886
46411
|
input.focus();
|
|
45887
46412
|
input.select();
|
|
45888
46413
|
var settled = false;
|
|
45889
|
-
var finish = function(commit) {
|
|
46414
|
+
var finish = async function(commit) {
|
|
45890
46415
|
if (settled) {
|
|
45891
46416
|
return;
|
|
45892
46417
|
}
|
|
45893
46418
|
settled = true;
|
|
45894
46419
|
var nextRaw = input.value;
|
|
45895
|
-
input.remove();
|
|
45896
|
-
titleEl.hidden = false;
|
|
45897
46420
|
if (!commit || nextRaw.trim() === seed.trim()) {
|
|
46421
|
+
input.remove();
|
|
46422
|
+
titleEl.hidden = false;
|
|
46423
|
+
return;
|
|
46424
|
+
}
|
|
46425
|
+
input.readOnly = true;
|
|
46426
|
+
try {
|
|
46427
|
+
await commitDashboardSessionRename(sessionsEl, projectId, record, nextRaw);
|
|
46428
|
+
} catch (_error) {
|
|
46429
|
+
settled = false;
|
|
46430
|
+
input.readOnly = false;
|
|
46431
|
+
showPluginToast(tr("recentProjects_renameFailed"), { status: "failed", sticky: true });
|
|
46432
|
+
input.focus();
|
|
45898
46433
|
return;
|
|
45899
46434
|
}
|
|
45900
|
-
|
|
46435
|
+
input.remove();
|
|
46436
|
+
titleEl.hidden = false;
|
|
46437
|
+
await refreshDashboardView().catch(function() {
|
|
45901
46438
|
});
|
|
45902
46439
|
};
|
|
45903
46440
|
input.addEventListener("keydown", function(event) {
|
|
@@ -45935,16 +46472,12 @@ ${lines}`
|
|
|
45935
46472
|
});
|
|
45936
46473
|
} catch (_error) {
|
|
45937
46474
|
}
|
|
45938
|
-
|
|
45939
|
-
|
|
45940
|
-
|
|
45941
|
-
|
|
45942
|
-
|
|
45943
|
-
})));
|
|
45944
|
-
}
|
|
45945
|
-
} catch (_error) {
|
|
46475
|
+
if (StorageDb) {
|
|
46476
|
+
await StorageDb.putRecord("sessions", StorageDb.buildSessionRecord(Object.assign({}, record, {
|
|
46477
|
+
title: next.title,
|
|
46478
|
+
titleSource: next.titleSource
|
|
46479
|
+
}), { preserveRunActionPayload: true }));
|
|
45946
46480
|
}
|
|
45947
|
-
await refreshDashboardView();
|
|
45948
46481
|
}
|
|
45949
46482
|
function ensureRecentProjectsRoot() {
|
|
45950
46483
|
if (!getPanel()) {
|
|
@@ -46166,6 +46699,7 @@ ${lines}`
|
|
|
46166
46699
|
openProjectFromRow,
|
|
46167
46700
|
renderRecentProjectRow,
|
|
46168
46701
|
renderRecentProjectsVariant,
|
|
46702
|
+
refreshDashboardView,
|
|
46169
46703
|
mountDashboardShell,
|
|
46170
46704
|
resetProjectNameCache,
|
|
46171
46705
|
renderPerProjectVariant
|
|
@@ -47298,6 +47832,12 @@ ${lines}`
|
|
|
47298
47832
|
let appendRunEvent;
|
|
47299
47833
|
let appendRunRecordEvent;
|
|
47300
47834
|
let pendingMirrorRefresh = null;
|
|
47835
|
+
const mirrorSettlementOwners = /* @__PURE__ */ new Map();
|
|
47836
|
+
const mirrorReuseFences = /* @__PURE__ */ new Map();
|
|
47837
|
+
const mirrorFenceWrites = /* @__PURE__ */ new Map();
|
|
47838
|
+
const mirrorFenceRevisions = /* @__PURE__ */ new Map();
|
|
47839
|
+
const MIRROR_INVALIDATION_TIMEOUT_MS = 2e4;
|
|
47840
|
+
const MIRROR_FENCE_STORAGE_TIMEOUT_MS = 2e3;
|
|
47301
47841
|
let appendChangeSummary;
|
|
47302
47842
|
let appendCompletionReport;
|
|
47303
47843
|
let appendOperationsPreview;
|
|
@@ -47308,6 +47848,8 @@ ${lines}`
|
|
|
47308
47848
|
let callPageBridge;
|
|
47309
47849
|
let sendBackgroundNative;
|
|
47310
47850
|
let getCurrentProjectId;
|
|
47851
|
+
let getAccountScopeId;
|
|
47852
|
+
let mirrorFenceStore;
|
|
47311
47853
|
let resetContextProject;
|
|
47312
47854
|
let sanitizeRunProjectSnapshot;
|
|
47313
47855
|
let getAssistantAnswerForCurrentRun;
|
|
@@ -47345,34 +47887,169 @@ ${lines}`
|
|
|
47345
47887
|
function buildSettlement(input = {}) {
|
|
47346
47888
|
return writebackSettlement?.settle instanceof Function ? writebackSettlement.settle(input) : null;
|
|
47347
47889
|
}
|
|
47348
|
-
function
|
|
47349
|
-
|
|
47350
|
-
|
|
47351
|
-
|
|
47352
|
-
|
|
47353
|
-
|
|
47354
|
-
|
|
47890
|
+
function mirrorFenceScope(projectId, accountScopeId = getAccountScopeId?.() || "") {
|
|
47891
|
+
return { projectId, accountScopeId };
|
|
47892
|
+
}
|
|
47893
|
+
function mirrorFenceKey(scope) {
|
|
47894
|
+
return JSON.stringify([scope.accountScopeId, scope.projectId]);
|
|
47895
|
+
}
|
|
47896
|
+
function getMirrorReuseFence(projectId, accountScopeId) {
|
|
47897
|
+
return mirrorReuseFences.get(mirrorFenceKey(mirrorFenceScope(projectId, accountScopeId))) || null;
|
|
47898
|
+
}
|
|
47899
|
+
function updateMirrorReuseFence(scope, generations, unknown = false) {
|
|
47900
|
+
const key = mirrorFenceKey(scope), current = mirrorReuseFences.get(key);
|
|
47901
|
+
const ids = [...new Set(generations)].sort();
|
|
47902
|
+
if (current && current.unknown === unknown && current.generations.join(":") === ids.join(":")) return current;
|
|
47903
|
+
const fence = ids.length || unknown ? { scope, generations: ids, unknown, syncAttempted: false } : null;
|
|
47904
|
+
if (fence) mirrorReuseFences.set(key, fence);
|
|
47905
|
+
else mirrorReuseFences.delete(key);
|
|
47906
|
+
mirrorFenceRevisions.set(key, (mirrorFenceRevisions.get(key) || 0) + 1);
|
|
47907
|
+
return fence;
|
|
47908
|
+
}
|
|
47909
|
+
async function awaitMirrorFenceStorage(work) {
|
|
47910
|
+
let timer;
|
|
47911
|
+
try {
|
|
47912
|
+
return await Promise.race([
|
|
47913
|
+
Promise.resolve().then(work),
|
|
47914
|
+
new Promise((_resolve, reject) => {
|
|
47915
|
+
timer = setTimeout(() => reject(new Error("Mirror fence storage timed out.")), MIRROR_FENCE_STORAGE_TIMEOUT_MS);
|
|
47916
|
+
})
|
|
47917
|
+
]);
|
|
47918
|
+
} finally {
|
|
47919
|
+
clearTimeout(timer);
|
|
47920
|
+
}
|
|
47921
|
+
}
|
|
47922
|
+
async function refreshMirrorReuseFence(projectId, accountScopeId) {
|
|
47923
|
+
const scope = mirrorFenceScope(projectId, accountScopeId), key = mirrorFenceKey(scope);
|
|
47924
|
+
if (!mirrorFenceStore) return getMirrorReuseFence(projectId, scope.accountScopeId);
|
|
47925
|
+
const revision = mirrorFenceRevisions.get(key) || 0;
|
|
47926
|
+
try {
|
|
47927
|
+
const stored = await awaitMirrorFenceStorage(() => mirrorFenceStore.getMirrorReuseFences(scope));
|
|
47928
|
+
const writes = mirrorFenceWrites.get(key) || /* @__PURE__ */ new Map();
|
|
47929
|
+
const changed = revision !== (mirrorFenceRevisions.get(key) || 0);
|
|
47930
|
+
const generations = new Set(stored.filter((id) => !writes.get(id)?.retired));
|
|
47931
|
+
for (const [id, write] of writes) {
|
|
47932
|
+
if (!write.retired && (!write.persisted || changed)) generations.add(id);
|
|
47355
47933
|
}
|
|
47356
|
-
if (
|
|
47357
|
-
|
|
47358
|
-
await callPageBridge("invalidateProjectSnapshot", { invalidateFileList: true });
|
|
47934
|
+
if (changed) for (const id of mirrorReuseFences.get(key)?.generations || []) {
|
|
47935
|
+
if (!writes.get(id)?.retired) generations.add(id);
|
|
47359
47936
|
}
|
|
47360
|
-
return
|
|
47361
|
-
}
|
|
47362
|
-
|
|
47363
|
-
|
|
47364
|
-
|
|
47365
|
-
|
|
47366
|
-
|
|
47367
|
-
|
|
47368
|
-
|
|
47369
|
-
|
|
47937
|
+
return updateMirrorReuseFence(scope, [...generations]);
|
|
47938
|
+
} catch (_error) {
|
|
47939
|
+
return updateMirrorReuseFence(scope, mirrorReuseFences.get(key)?.generations || [], true);
|
|
47940
|
+
}
|
|
47941
|
+
}
|
|
47942
|
+
async function recordMirrorReuseFence(target) {
|
|
47943
|
+
const scope = mirrorFenceScope(target.runProjectId, target.runAccountScopeId);
|
|
47944
|
+
const key = mirrorFenceKey(scope);
|
|
47945
|
+
const generation = globalThis.crypto?.randomUUID?.() || Date.now().toString(36) + "-" + Math.random().toString(36).slice(2) + "-" + Math.random().toString(36).slice(2);
|
|
47946
|
+
const writes = mirrorFenceWrites.get(key) || /* @__PURE__ */ new Map();
|
|
47947
|
+
mirrorFenceWrites.set(key, writes);
|
|
47948
|
+
const write = { persisted: false, retired: false, clearAfterWrite: false };
|
|
47949
|
+
writes.set(generation, write);
|
|
47950
|
+
updateMirrorReuseFence(scope, [...mirrorReuseFences.get(key)?.generations || [], generation]);
|
|
47951
|
+
const token = { scope, generation };
|
|
47952
|
+
if (!mirrorFenceStore) return token;
|
|
47953
|
+
const pending = Promise.resolve().then(() => mirrorFenceStore.setMirrorReuseFence(scope, generation));
|
|
47954
|
+
pending.then(() => {
|
|
47955
|
+
write.persisted = true;
|
|
47956
|
+
mirrorFenceRevisions.set(key, (mirrorFenceRevisions.get(key) || 0) + 1);
|
|
47957
|
+
if (write.clearAfterWrite) {
|
|
47958
|
+
awaitMirrorFenceStorage(() => mirrorFenceStore.clearMirrorReuseFences(scope, [generation])).then(() => {
|
|
47959
|
+
write.retired = true;
|
|
47960
|
+
}).catch(() => {
|
|
47961
|
+
});
|
|
47962
|
+
}
|
|
47963
|
+
}, () => {
|
|
47964
|
+
});
|
|
47965
|
+
try {
|
|
47966
|
+
await awaitMirrorFenceStorage(() => pending);
|
|
47967
|
+
} catch (_error) {
|
|
47968
|
+
}
|
|
47969
|
+
return token;
|
|
47970
|
+
}
|
|
47971
|
+
async function clearMirrorReuseFenceGenerations(scope, generations) {
|
|
47972
|
+
const writes = mirrorFenceWrites.get(mirrorFenceKey(scope));
|
|
47973
|
+
for (const id of generations) if (writes?.has(id)) writes.get(id).clearAfterWrite = true;
|
|
47974
|
+
const clearing = Promise.resolve().then(() => mirrorFenceStore?.clearMirrorReuseFences(scope, generations));
|
|
47975
|
+
clearing.then(() => {
|
|
47976
|
+
for (const id of generations) if (writes?.has(id)) writes.get(id).retired = true;
|
|
47977
|
+
}, () => {
|
|
47978
|
+
});
|
|
47979
|
+
await awaitMirrorFenceStorage(() => clearing);
|
|
47980
|
+
}
|
|
47981
|
+
async function settleFullMirrorSync(projectId, project, fence, response, options = {}) {
|
|
47982
|
+
if (!fence || fence.unknown || getMirrorReuseFence(projectId, fence.scope.accountScopeId) !== fence || response?.ok !== true || project?.capabilities?.fullProjectSnapshot !== true || project.capabilities.contentComplete === false || project.capabilities.skipped?.length) return false;
|
|
47983
|
+
try {
|
|
47984
|
+
options.assertCurrent?.();
|
|
47985
|
+
const status = await (options.sendNative || sendBackgroundNative)({ method: "mirror.status", params: { projectId } });
|
|
47986
|
+
options.assertCurrent?.();
|
|
47987
|
+
const current = await refreshMirrorReuseFence(projectId, fence.scope.accountScopeId);
|
|
47988
|
+
options.assertCurrent?.();
|
|
47989
|
+
if (getCurrentProjectId() !== projectId || current !== fence || status?.ok !== true || status.result?.exists !== true || status.result.dirty === true) return false;
|
|
47990
|
+
await clearMirrorReuseFenceGenerations(fence.scope, fence.generations);
|
|
47991
|
+
options.assertCurrent?.();
|
|
47992
|
+
if (getMirrorReuseFence(projectId, fence.scope.accountScopeId) === fence) updateMirrorReuseFence(fence.scope, []);
|
|
47993
|
+
return !await refreshMirrorReuseFence(projectId, fence.scope.accountScopeId);
|
|
47994
|
+
} catch (_error) {
|
|
47995
|
+
options.assertCurrent?.();
|
|
47996
|
+
return false;
|
|
47997
|
+
}
|
|
47998
|
+
}
|
|
47999
|
+
async function syncFencedMirror(projectId, project, options = {}) {
|
|
48000
|
+
const fence = options.fence;
|
|
48001
|
+
if (!fence || fence.unknown || getMirrorReuseFence(projectId, fence.scope.accountScopeId) !== fence || fence.syncAttempted || project?.id !== projectId || project.capabilities?.fullProjectSnapshot !== true || project.capabilities.contentComplete === false || project.capabilities.skipped?.length) return false;
|
|
48002
|
+
options.assertCurrent();
|
|
48003
|
+
fence.syncAttempted = true;
|
|
48004
|
+
try {
|
|
48005
|
+
const response = await options.sendNative({ method: "mirror.sync", params: { projectId, project } });
|
|
48006
|
+
options.assertCurrent();
|
|
48007
|
+
return await settleFullMirrorSync(projectId, project, fence, response, options);
|
|
48008
|
+
} catch (_error) {
|
|
48009
|
+
options.assertCurrent();
|
|
48010
|
+
return false;
|
|
48011
|
+
}
|
|
48012
|
+
}
|
|
48013
|
+
function trackWritebackMirror(work, target, onSettled) {
|
|
48014
|
+
const key = JSON.stringify([target.runProjectId, target.sessionId, target.recordId]);
|
|
48015
|
+
const owner = {};
|
|
48016
|
+
mirrorSettlementOwners.set(key, owner);
|
|
48017
|
+
const refresh = Promise.resolve(work).then(async (state) => {
|
|
48018
|
+
if (mirrorSettlementOwners.get(key) !== owner) return state;
|
|
48019
|
+
onSettled?.(state);
|
|
48020
|
+
await onMirrorRefreshSettled?.({ ...target, state: state || "not-attempted" });
|
|
48021
|
+
return state;
|
|
48022
|
+
}).finally(() => {
|
|
48023
|
+
if (mirrorSettlementOwners.get(key) === owner) mirrorSettlementOwners.delete(key);
|
|
48024
|
+
});
|
|
48025
|
+
const pending = Promise.allSettled([pendingMirrorRefresh, refresh]).then(([, result]) => {
|
|
48026
|
+
if (result.status === "rejected") throw result.reason;
|
|
48027
|
+
return result.value;
|
|
47370
48028
|
}).finally(() => {
|
|
47371
48029
|
if (pendingMirrorRefresh === pending) pendingMirrorRefresh = null;
|
|
47372
48030
|
});
|
|
47373
48031
|
pendingMirrorRefresh = pending;
|
|
47374
48032
|
return pending;
|
|
47375
48033
|
}
|
|
48034
|
+
function invalidateMirrorAfterUndo(runId, projectId, result = {}, owner = {}) {
|
|
48035
|
+
if (!projectId || result?.changedDocument !== true && !result?.applied?.length) return Promise.resolve("not-attempted");
|
|
48036
|
+
const target = {
|
|
48037
|
+
recordId: runId,
|
|
48038
|
+
runProjectId: projectId,
|
|
48039
|
+
runAccountScopeId: owner.runAccountScopeId || getAccountScopeId?.() || "",
|
|
48040
|
+
sessionId: owner.sessionId || ""
|
|
48041
|
+
};
|
|
48042
|
+
const pending = Promise.resolve(pendingMirrorRefresh).catch(() => {
|
|
48043
|
+
}).then(() => invalidateWritebackMirror(target, {
|
|
48044
|
+
pageFirst: true,
|
|
48045
|
+
nativeTimeoutMs: MIRROR_INVALIDATION_TIMEOUT_MS,
|
|
48046
|
+
undo: true
|
|
48047
|
+
})).then((state) => state === "not-attempted" ? "invalidated" : state).finally(() => {
|
|
48048
|
+
if (pendingMirrorRefresh === pending) pendingMirrorRefresh = null;
|
|
48049
|
+
});
|
|
48050
|
+
pendingMirrorRefresh = pending;
|
|
48051
|
+
return pending;
|
|
48052
|
+
}
|
|
47376
48053
|
function selectionViolationNextStep() {
|
|
47377
48054
|
return tx(
|
|
47378
48055
|
"Select the intended region again and request only changes within it. Valid written parts can be undone.",
|
|
@@ -47401,7 +48078,12 @@ ${lines}`
|
|
|
47401
48078
|
}
|
|
47402
48079
|
async function applySyncChangesToOverleaf(syncChanges = [], project = {}, options = {}) {
|
|
47403
48080
|
const activeRun = getCurrentRunView?.();
|
|
47404
|
-
const saveTarget = {
|
|
48081
|
+
const saveTarget = {
|
|
48082
|
+
runProjectId: activeRun?.runProjectId || "",
|
|
48083
|
+
runAccountScopeId: activeRun?.runAccountScopeId || getAccountScopeId?.() || "",
|
|
48084
|
+
recordId: activeRun?.recordId || "",
|
|
48085
|
+
sessionId: activeRun?.sessionId || ""
|
|
48086
|
+
};
|
|
47405
48087
|
const runMode = options.mode || getState().mode;
|
|
47406
48088
|
const runRequireReviewing = typeof options.requireReviewing === "boolean" ? options.requireReviewing : getState().requireReviewing === true;
|
|
47407
48089
|
const assistantMessage = cleanFinalAnswer(options.assistantMessage || getAssistantAnswerForCurrentRun());
|
|
@@ -47694,28 +48376,57 @@ ${tx("Sync note: no changes were written to Overleaf; every change was blocked b
|
|
|
47694
48376
|
skipped: skippedEntries.length
|
|
47695
48377
|
}
|
|
47696
48378
|
});
|
|
47697
|
-
|
|
48379
|
+
let confirmation;
|
|
48380
|
+
try {
|
|
48381
|
+
confirmation = appliedPaths.length ? await verifyPostWriteSaveState(applied, project, saveTarget) : { verification: { ok: false, state: "not_checked", reason: "No applied writeback operations were returned." } };
|
|
48382
|
+
} catch (error) {
|
|
48383
|
+
if (!appliedPaths.length || error?.code !== "codex_cancelled" && error?.name !== "AbortError") throw error;
|
|
48384
|
+
const saveVerification2 = {
|
|
48385
|
+
ok: false,
|
|
48386
|
+
state: "unknown_timeout",
|
|
48387
|
+
signal: "unavailable",
|
|
48388
|
+
reason: "Save confirmation was cancelled.",
|
|
48389
|
+
recoveryReason: "codex_cancelled",
|
|
48390
|
+
attempts: []
|
|
48391
|
+
};
|
|
48392
|
+
error.writebackOutcome = {
|
|
48393
|
+
operations,
|
|
48394
|
+
applied,
|
|
48395
|
+
saveVerification: saveVerification2,
|
|
48396
|
+
settlement: buildSettlement({ operations, applyResult: applied, saveVerification: saveVerification2, mirror: { state: "unknown" } })
|
|
48397
|
+
};
|
|
48398
|
+
trackWritebackMirror(
|
|
48399
|
+
invalidateWritebackMirror(saveTarget, {
|
|
48400
|
+
pageFirst: true,
|
|
48401
|
+
nativeTimeoutMs: MIRROR_INVALIDATION_TIMEOUT_MS
|
|
48402
|
+
}),
|
|
48403
|
+
saveTarget,
|
|
48404
|
+
(state) => {
|
|
48405
|
+
error.writebackOutcome.settlement = buildSettlement({ operations, applyResult: applied, saveVerification: saveVerification2, mirror: { state } });
|
|
48406
|
+
}
|
|
48407
|
+
);
|
|
48408
|
+
try {
|
|
48409
|
+
await settleWritebackRecovery?.(applied, project, saveVerification2, saveTarget, runRequireReviewing);
|
|
48410
|
+
} catch (recoveryError) {
|
|
48411
|
+
appendRunRecordEvent?.(saveTarget.recordId, {
|
|
48412
|
+
kind: "technical",
|
|
48413
|
+
status: "warning",
|
|
48414
|
+
title: tx("Writeback recovery persistence failed", "\u5199\u56DE\u6062\u590D\u4FE1\u606F\u4FDD\u5B58\u5931\u8D25"),
|
|
48415
|
+
detail: { reason: recoveryError.message }
|
|
48416
|
+
});
|
|
48417
|
+
}
|
|
48418
|
+
throw error;
|
|
48419
|
+
}
|
|
47698
48420
|
const saveVerification = confirmation.verification;
|
|
47699
48421
|
await settleWritebackRecovery?.(applied, project, saveVerification, saveTarget, runRequireReviewing);
|
|
47700
48422
|
if (appliedPaths.length) {
|
|
47701
48423
|
appendPostWriteSaveVerificationWarning(saveVerification, saveTarget);
|
|
47702
48424
|
appendRunEvent({ kind: "technical", title: "Post-write save confirmation", status: "info", detail: saveVerification });
|
|
47703
48425
|
}
|
|
47704
|
-
|
|
47705
|
-
pendingMirrorRefresh = refreshProjectMirrorAfterWriteback(project, applied, saveVerification, { target: saveTarget, snapshot: confirmation.snapshot }).catch(async (error) => {
|
|
48426
|
+
trackWritebackMirror(refreshProjectMirrorAfterWriteback(project, applied, saveVerification, { target: saveTarget, snapshot: confirmation.snapshot }).catch(async (error) => {
|
|
47706
48427
|
appendRunRecordEvent(saveTarget.recordId, { kind: "technical", title: "Mirror refresh requires a fresh read", status: "info", detail: { reason: error.message } });
|
|
47707
48428
|
return invalidateWritebackMirror(saveTarget);
|
|
47708
|
-
})
|
|
47709
|
-
if (typeof onMirrorRefreshSettled !== "function") return;
|
|
47710
|
-
return onMirrorRefreshSettled({
|
|
47711
|
-
recordId: mirrorSettlementTarget?.recordId || "",
|
|
47712
|
-
sessionId: mirrorSettlementTarget?.sessionId || "",
|
|
47713
|
-
runProjectId: mirrorSettlementTarget?.runProjectId || "",
|
|
47714
|
-
state: state || "not-attempted"
|
|
47715
|
-
});
|
|
47716
|
-
}).finally(() => {
|
|
47717
|
-
pendingMirrorRefresh = null;
|
|
47718
|
-
});
|
|
48429
|
+
}), saveTarget);
|
|
47719
48430
|
const compileSummary = appliedPaths.length ? await autoRecompileAfterWriteback(appliedPaths, saveVerification, {
|
|
47720
48431
|
autoRecompile: options.autoRecompile,
|
|
47721
48432
|
mode: runMode,
|
|
@@ -47782,7 +48493,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
47782
48493
|
// the run by inspecting the `applied.skipped` entries' failure codes.
|
|
47783
48494
|
// Existing call sites that only read `summaryLine` / `hasSkippedOperations`
|
|
47784
48495
|
// / `audit` are unaffected.
|
|
48496
|
+
operations,
|
|
47785
48497
|
applied,
|
|
48498
|
+
saveVerification,
|
|
47786
48499
|
settlement: buildSettlement({
|
|
47787
48500
|
operations,
|
|
47788
48501
|
applyResult: applied,
|
|
@@ -47831,27 +48544,65 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
47831
48544
|
if (target.recordId) appendRunRecordEvent(target.recordId, { title, status: "warning" });
|
|
47832
48545
|
else appendRunEvent({ title, status: "warning" });
|
|
47833
48546
|
}
|
|
47834
|
-
async function invalidateWritebackMirror(target = {}) {
|
|
48547
|
+
async function invalidateWritebackMirror(target = {}, options = {}) {
|
|
48548
|
+
const invalidatePage = async () => {
|
|
48549
|
+
if (getCurrentProjectId() !== target.runProjectId || target.runAccountScopeId && getAccountScopeId?.() !== target.runAccountScopeId) return true;
|
|
48550
|
+
try {
|
|
48551
|
+
resetContextProject();
|
|
48552
|
+
const response = await callPageBridge("invalidateProjectSnapshot", { invalidateFileList: true, runProjectId: target.runProjectId });
|
|
48553
|
+
return response?.ok === true;
|
|
48554
|
+
} catch (_error) {
|
|
48555
|
+
return false;
|
|
48556
|
+
}
|
|
48557
|
+
};
|
|
48558
|
+
const pageInvalidation = options.pageFirst === true ? invalidatePage() : null;
|
|
48559
|
+
const pendingFence = options.pageFirst === true && target.runProjectId ? await recordMirrorReuseFence(target) : null;
|
|
47835
48560
|
let invalidated = false;
|
|
48561
|
+
let failureReason = "Native host did not confirm mirror invalidation.";
|
|
48562
|
+
let timer;
|
|
47836
48563
|
try {
|
|
47837
48564
|
if (target.runProjectId) {
|
|
47838
|
-
const
|
|
48565
|
+
const pending = sendBackgroundNative({ method: "mirror.invalidate", params: { projectId: target.runProjectId } });
|
|
48566
|
+
pending.catch(() => {
|
|
48567
|
+
});
|
|
48568
|
+
const response = options.nativeTimeoutMs ? await Promise.race([
|
|
48569
|
+
pending,
|
|
48570
|
+
new Promise((resolve) => {
|
|
48571
|
+
timer = setTimeout(() => resolve(null), options.nativeTimeoutMs);
|
|
48572
|
+
})
|
|
48573
|
+
]) : await pending;
|
|
47839
48574
|
invalidated = response?.ok === true && response.result?.invalidated === true;
|
|
48575
|
+
if (!invalidated && response?.error?.message) failureReason = response.error.message;
|
|
47840
48576
|
}
|
|
47841
|
-
} catch (
|
|
48577
|
+
} catch (error) {
|
|
48578
|
+
failureReason = error?.message || failureReason;
|
|
48579
|
+
} finally {
|
|
48580
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
47842
48581
|
}
|
|
47843
|
-
|
|
47844
|
-
if (
|
|
47845
|
-
|
|
47846
|
-
|
|
47847
|
-
|
|
47848
|
-
|
|
47849
|
-
|
|
48582
|
+
const pageInvalidated = await (pageInvalidation || invalidatePage());
|
|
48583
|
+
if (invalidated && pageInvalidated) {
|
|
48584
|
+
if (pendingFence) {
|
|
48585
|
+
try {
|
|
48586
|
+
await clearMirrorReuseFenceGenerations(pendingFence.scope, [pendingFence.generation]);
|
|
48587
|
+
const current = getMirrorReuseFence(target.runProjectId, pendingFence.scope.accountScopeId);
|
|
48588
|
+
if (current) updateMirrorReuseFence(
|
|
48589
|
+
pendingFence.scope,
|
|
48590
|
+
current.generations.filter((id) => id !== pendingFence.generation),
|
|
48591
|
+
current.unknown
|
|
48592
|
+
);
|
|
48593
|
+
await refreshMirrorReuseFence(target.runProjectId, pendingFence.scope.accountScopeId);
|
|
48594
|
+
} catch (_error) {
|
|
48595
|
+
}
|
|
47850
48596
|
}
|
|
48597
|
+
return "not-attempted";
|
|
47851
48598
|
}
|
|
47852
|
-
if (
|
|
48599
|
+
if (target.runProjectId && !pendingFence) await recordMirrorReuseFence(target);
|
|
48600
|
+
if (invalidated && !pageInvalidated) failureReason = "The page did not confirm snapshot invalidation.";
|
|
47853
48601
|
const event = {
|
|
47854
|
-
title: tx(
|
|
48602
|
+
title: options.undo === true ? tx(
|
|
48603
|
+
`Overleaf undo finished, but local mirror invalidation failed: ${failureReason}. Refresh this project or reconnect the native host before running again.`,
|
|
48604
|
+
`Overleaf \u64A4\u9500\u5DF2\u5B8C\u6210\uFF0C\u4F46\u672C\u5730\u955C\u50CF\u5931\u6548\u5904\u7406\u5931\u8D25\uFF1A${failureReason}\u3002\u8BF7\u5237\u65B0\u9879\u76EE\u6216\u91CD\u65B0\u8FDE\u63A5 Native Host \u540E\u518D\u8FD0\u884C\u3002`
|
|
48605
|
+
) : tx(
|
|
47855
48606
|
"The local project cache could not be reset. Check the local connection before starting another task.",
|
|
47856
48607
|
"\u672C\u5730\u9879\u76EE\u7F13\u5B58\u672A\u80FD\u91CD\u7F6E\u3002\u8BF7\u68C0\u67E5\u672C\u5730\u8FDE\u63A5\u540E\u518D\u5F00\u59CB\u4E0B\u4E00\u8F6E\u4EFB\u52A1\u3002"
|
|
47857
48608
|
),
|
|
@@ -47888,6 +48639,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
47888
48639
|
if (!Array.isArray(applied?.applied) || !applied.applied.length) {
|
|
47889
48640
|
return "not-attempted";
|
|
47890
48641
|
}
|
|
48642
|
+
const mirrorFence = await refreshMirrorReuseFence(target.runProjectId, target.runAccountScopeId);
|
|
47891
48643
|
if (!confirmation.snapshot && await tryConfirmMirrorWriteback(applied, target.runProjectId)) {
|
|
47892
48644
|
appendRunEvent({
|
|
47893
48645
|
title: tx(
|
|
@@ -47933,6 +48685,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
47933
48685
|
}
|
|
47934
48686
|
});
|
|
47935
48687
|
if (response?.ok) {
|
|
48688
|
+
await settleFullMirrorSync(target.runProjectId, syncedProject, mirrorFence, response);
|
|
47936
48689
|
appendRunEvent({
|
|
47937
48690
|
title: tx("Local Codex workspace refreshed. The next run will start from the latest Overleaf content.", "\u5DF2\u5237\u65B0\u672C\u5730 Codex workspace\uFF0C\u4E0B\u4E00\u8F6E\u4F1A\u4ECE\u6700\u65B0 Overleaf \u5185\u5BB9\u5F00\u59CB\u3002"),
|
|
47938
48691
|
status: "completed"
|
|
@@ -48139,6 +48892,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
48139
48892
|
getCurrentRunView
|
|
48140
48893
|
} = deps);
|
|
48141
48894
|
assetTransferBroker = deps.assetTransferBroker;
|
|
48895
|
+
mirrorFenceStore = deps.mirrorFenceStore;
|
|
48896
|
+
getAccountScopeId = deps.getAccountScopeId;
|
|
48142
48897
|
stageWritebackRecovery = deps.stageWritebackRecovery;
|
|
48143
48898
|
settleWritebackRecovery = deps.settleWritebackRecovery;
|
|
48144
48899
|
onMirrorRefreshSettled = deps.onMirrorRefreshSettled;
|
|
@@ -48148,6 +48903,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
48148
48903
|
applySyncChangesToOverleaf,
|
|
48149
48904
|
resolveCompileLogContext,
|
|
48150
48905
|
invalidateMirrorAfterUndo,
|
|
48906
|
+
getMirrorReuseFence,
|
|
48907
|
+
refreshMirrorReuseFence,
|
|
48908
|
+
syncFencedMirror,
|
|
48151
48909
|
getPendingMirrorRefresh: () => pendingMirrorRefresh
|
|
48152
48910
|
};
|
|
48153
48911
|
}
|
|
@@ -48831,6 +49589,10 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
48831
49589
|
showPluginToast(tx("Nothing to refill: the original task text is unavailable.", "\u65E0\u6CD5\u56DE\u586B\uFF1A\u539F\u4EFB\u52A1\u6587\u672C\u4E0D\u53EF\u7528\u3002"));
|
|
48832
49590
|
return;
|
|
48833
49591
|
}
|
|
49592
|
+
if (input.value.trim() && input.value.trim() !== task.trim()) {
|
|
49593
|
+
showPluginToast(tx("Kept your draft. Clear the composer, then try again to refill this task.", "\u5DF2\u4FDD\u7559\u4F60\u7684\u8349\u7A3F\u3002\u6E05\u7A7A\u8F93\u5165\u6846\u540E\u518D\u8BD5\u4E00\u6B21\uFF0C\u5373\u53EF\u56DE\u586B\u8FD9\u6761\u4EFB\u52A1\u3002"));
|
|
49594
|
+
return;
|
|
49595
|
+
}
|
|
48834
49596
|
prepareRetryReplacement?.(run || null, task);
|
|
48835
49597
|
input.value = task;
|
|
48836
49598
|
getState().task = task;
|
|
@@ -50195,9 +50957,21 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50195
50957
|
input.dataset.styleFocus = "project-search";
|
|
50196
50958
|
input.placeholder = tx("Search all Overleaf projects", "\u641C\u7D22\u5168\u90E8 Overleaf \u9879\u76EE");
|
|
50197
50959
|
input.setAttribute("aria-label", input.placeholder);
|
|
50198
|
-
|
|
50960
|
+
let composing = false;
|
|
50961
|
+
const updateResults = () => {
|
|
50199
50962
|
query = input.value;
|
|
50200
|
-
|
|
50963
|
+
const results = input.closest(".ws2-picker")?.querySelector(".ws2-projects");
|
|
50964
|
+
if (results) renderProjectResults(results);
|
|
50965
|
+
};
|
|
50966
|
+
input.addEventListener("compositionstart", () => {
|
|
50967
|
+
composing = true;
|
|
50968
|
+
});
|
|
50969
|
+
input.addEventListener("compositionend", () => {
|
|
50970
|
+
composing = false;
|
|
50971
|
+
updateResults();
|
|
50972
|
+
});
|
|
50973
|
+
input.addEventListener("input", (event) => {
|
|
50974
|
+
if (!composing && !event.isComposing) updateResults();
|
|
50201
50975
|
});
|
|
50202
50976
|
search.append(input);
|
|
50203
50977
|
panel.append(search);
|
|
@@ -50215,6 +50989,22 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50215
50989
|
const list = node("div", "ws2-projects");
|
|
50216
50990
|
list.setAttribute("role", "group");
|
|
50217
50991
|
list.setAttribute("aria-label", tx("Overleaf projects", "Overleaf \u9879\u76EE"));
|
|
50992
|
+
renderProjectResults(list);
|
|
50993
|
+
panel.append(list);
|
|
50994
|
+
const footer = node("div", "ws2-picker-footer");
|
|
50995
|
+
footer.append(
|
|
50996
|
+
node("span", "", tx(sources.length + " of 3 references selected", "\u5DF2\u9009 " + sources.length + " / 3 \u4EFD\u8D44\u6599")),
|
|
50997
|
+
button(tx("Done", "\u5B8C\u6210"), () => {
|
|
50998
|
+
pickerOpen = false;
|
|
50999
|
+
render();
|
|
51000
|
+
}, "ws2-button ws2-button-primary", "picker-done")
|
|
51001
|
+
);
|
|
51002
|
+
panel.append(footer);
|
|
51003
|
+
return panel;
|
|
51004
|
+
}
|
|
51005
|
+
function renderProjectResults(list) {
|
|
51006
|
+
const oldScroll = list.scrollTop;
|
|
51007
|
+
list.replaceChildren();
|
|
50218
51008
|
if (projectLoading) {
|
|
50219
51009
|
const loading = node("div", "ws2-picker-state");
|
|
50220
51010
|
loading.append(node("span", "ws2-pulse"), node("span", "", tx("Loading project directory\u2026", "\u6B63\u5728\u52A0\u8F7D\u9879\u76EE\u76EE\u5F55\u2026")));
|
|
@@ -50263,17 +51053,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50263
51053
|
query ? tx("No projects match this search.", "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\u3002") : tx("No projects in this group.", "\u6B64\u5206\u7EC4\u6682\u65E0\u9879\u76EE\u3002")
|
|
50264
51054
|
));
|
|
50265
51055
|
}
|
|
50266
|
-
|
|
50267
|
-
const footer = node("div", "ws2-picker-footer");
|
|
50268
|
-
footer.append(
|
|
50269
|
-
node("span", "", tx(sources.length + " of 3 references selected", "\u5DF2\u9009 " + sources.length + " / 3 \u4EFD\u8D44\u6599")),
|
|
50270
|
-
button(tx("Done", "\u5B8C\u6210"), () => {
|
|
50271
|
-
pickerOpen = false;
|
|
50272
|
-
render();
|
|
50273
|
-
}, "ws2-button ws2-button-primary", "picker-done")
|
|
50274
|
-
);
|
|
50275
|
-
panel.append(footer);
|
|
50276
|
-
return panel;
|
|
51056
|
+
list.scrollTop = oldScroll;
|
|
50277
51057
|
}
|
|
50278
51058
|
function renderSources() {
|
|
50279
51059
|
const section = node("section", "ws2-library");
|
|
@@ -50381,6 +51161,36 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50381
51161
|
}
|
|
50382
51162
|
return section;
|
|
50383
51163
|
}
|
|
51164
|
+
function replaceAround(parent, fresh, retained, replacement) {
|
|
51165
|
+
for (const child of Array.from(parent.childNodes)) {
|
|
51166
|
+
if (child !== retained) child.remove();
|
|
51167
|
+
}
|
|
51168
|
+
let before = true;
|
|
51169
|
+
for (const child of Array.from(fresh.childNodes)) {
|
|
51170
|
+
if (child === replacement) before = false;
|
|
51171
|
+
else parent.insertBefore(child, before ? retained : null);
|
|
51172
|
+
}
|
|
51173
|
+
}
|
|
51174
|
+
function renderKeepingProjectSearch(content) {
|
|
51175
|
+
const library = host.querySelector(".ws2-library");
|
|
51176
|
+
const picker = library?.querySelector(".ws2-picker");
|
|
51177
|
+
const search = picker?.querySelector(".ws2-search");
|
|
51178
|
+
const nextLibrary = content.querySelector(".ws2-library");
|
|
51179
|
+
const nextPicker = nextLibrary?.querySelector(".ws2-picker");
|
|
51180
|
+
if (!search || !nextPicker) {
|
|
51181
|
+
host.replaceChildren(content);
|
|
51182
|
+
return false;
|
|
51183
|
+
}
|
|
51184
|
+
const input = search.querySelector("input");
|
|
51185
|
+
const nextSearch = nextPicker.querySelector(".ws2-search");
|
|
51186
|
+
input.placeholder = nextSearch.querySelector("input").placeholder;
|
|
51187
|
+
input.setAttribute("aria-label", input.placeholder);
|
|
51188
|
+
picker.setAttribute("aria-label", nextPicker.getAttribute("aria-label"));
|
|
51189
|
+
replaceAround(picker, nextPicker, search, nextSearch);
|
|
51190
|
+
replaceAround(library, nextLibrary, picker, nextPicker);
|
|
51191
|
+
replaceAround(host, content, library, nextLibrary);
|
|
51192
|
+
return document.activeElement === input;
|
|
51193
|
+
}
|
|
50384
51194
|
function render() {
|
|
50385
51195
|
if (!host?.isConnected) return;
|
|
50386
51196
|
alignScope();
|
|
@@ -50389,7 +51199,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50389
51199
|
const heading = host.closest("[data-set-group]")?.querySelector("[data-writing-style-heading]");
|
|
50390
51200
|
if (heading) heading.textContent = tx("Writing style", "\u5199\u4F5C\u98CE\u683C");
|
|
50391
51201
|
host.classList.add("ws2");
|
|
50392
|
-
|
|
51202
|
+
const content = document.createDocumentFragment();
|
|
50393
51203
|
const top = node("div", "ws2-heading");
|
|
50394
51204
|
const copy = node("div", "ws2-heading-copy");
|
|
50395
51205
|
const title = node("label", "ws2-title", tx("Write in My Style", "\u6CBF\u7528\u5199\u4F5C\u98CE\u683C"));
|
|
@@ -50409,7 +51219,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50409
51219
|
void toggle(toggleInput.checked);
|
|
50410
51220
|
});
|
|
50411
51221
|
top.append(copy, toggleInput);
|
|
50412
|
-
|
|
51222
|
+
content.append(top);
|
|
50413
51223
|
if (meta?.ready) {
|
|
50414
51224
|
const summary = node("div", "ws2-profile");
|
|
50415
51225
|
const mark = node("span", "ws2-profile-icon");
|
|
@@ -50432,7 +51242,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50432
51242
|
);
|
|
50433
51243
|
view.disabled = previewBusy;
|
|
50434
51244
|
summary.append(mark, info, view);
|
|
50435
|
-
|
|
51245
|
+
content.append(summary);
|
|
50436
51246
|
}
|
|
50437
51247
|
const editing = expanded || working();
|
|
50438
51248
|
const manage = button(
|
|
@@ -50448,9 +51258,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50448
51258
|
manage.setAttribute("aria-expanded", String(editing));
|
|
50449
51259
|
manage.disabled = working();
|
|
50450
51260
|
manage.append(icon("arrow"));
|
|
50451
|
-
|
|
51261
|
+
content.append(manage);
|
|
50452
51262
|
if (editing) {
|
|
50453
|
-
|
|
51263
|
+
content.append(renderSources());
|
|
50454
51264
|
if (working()) {
|
|
50455
51265
|
const progress = node("div", "ws2-progress");
|
|
50456
51266
|
progress.setAttribute("role", "status");
|
|
@@ -50472,7 +51282,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50472
51282
|
}, "ws2-button", "cancel-generation");
|
|
50473
51283
|
stop.disabled = cancelling;
|
|
50474
51284
|
progress.append(stop);
|
|
50475
|
-
|
|
51285
|
+
content.append(progress);
|
|
50476
51286
|
} else {
|
|
50477
51287
|
const footer = node("div", "ws2-actions");
|
|
50478
51288
|
const help = node("div", "ws2-action-copy");
|
|
@@ -50497,8 +51307,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50497
51307
|
);
|
|
50498
51308
|
generateButton.disabled = !scope || !meta || !sources.length || deps.isRunning();
|
|
50499
51309
|
footer.append(generateButton);
|
|
50500
|
-
|
|
50501
|
-
if (deps.isRunning())
|
|
51310
|
+
content.append(footer);
|
|
51311
|
+
if (deps.isRunning()) content.append(node("p", "ws2-caption", tx("Available after the current task finishes.", "\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u540E\u53EF\u751F\u6210\u3002")));
|
|
50502
51312
|
}
|
|
50503
51313
|
}
|
|
50504
51314
|
if (message || !meta) {
|
|
@@ -50512,12 +51322,13 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
50512
51322
|
void ensureLoaded(true).catch(() => {
|
|
50513
51323
|
});
|
|
50514
51324
|
}, "ws2-button", "retry-settings"));
|
|
50515
|
-
|
|
51325
|
+
content.append(status);
|
|
50516
51326
|
}
|
|
50517
|
-
if (preview)
|
|
51327
|
+
if (preview) content.append(renderPreview());
|
|
51328
|
+
const searchKeptFocus = renderKeepingProjectSearch(content);
|
|
50518
51329
|
const scroll = host.querySelector(".ws2-projects");
|
|
50519
51330
|
if (scroll) scroll.scrollTop = oldScroll;
|
|
50520
|
-
restoreFocus(focus);
|
|
51331
|
+
if (!searchKeptFocus) restoreFocus(focus);
|
|
50521
51332
|
}
|
|
50522
51333
|
function mount(panel) {
|
|
50523
51334
|
const next = panel?.querySelector("[data-writing-style-settings]");
|
|
@@ -51256,6 +52067,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
51256
52067
|
getSkippedEntries
|
|
51257
52068
|
});
|
|
51258
52069
|
const writebackOrchestrator = Modules.WritebackOrchestrator.create({
|
|
52070
|
+
mirrorFenceStore: root.CodexOverleafModuleRegistry.resolve("ScopedPersistenceBrowserAdapter"),
|
|
52071
|
+
getAccountScopeId: () => cachedAccountScopeId,
|
|
51259
52072
|
tr,
|
|
51260
52073
|
tx,
|
|
51261
52074
|
getLocale,
|
|
@@ -51405,24 +52218,20 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
51405
52218
|
});
|
|
51406
52219
|
let dashboardRefreshTimer = null;
|
|
51407
52220
|
function refreshDashboardSoon() {
|
|
51408
|
-
if (panel?.dataset.view !== "recent-projects") {
|
|
52221
|
+
if (panel?.dataset.view !== "recent-projects" || document.visibilityState !== "visible") {
|
|
51409
52222
|
return;
|
|
51410
52223
|
}
|
|
51411
52224
|
clearTimeout(dashboardRefreshTimer);
|
|
51412
52225
|
dashboardRefreshTimer = setTimeout(() => {
|
|
51413
|
-
if (panel?.dataset.view !== "recent-projects") {
|
|
52226
|
+
if (panel?.dataset.view !== "recent-projects" || document.visibilityState !== "visible") {
|
|
51414
52227
|
return;
|
|
51415
52228
|
}
|
|
51416
|
-
if (panel.querySelector(".recent-projects-
|
|
52229
|
+
if (panel.querySelector(".recent-projects-session-rename-input")) {
|
|
51417
52230
|
refreshDashboardSoon();
|
|
51418
52231
|
return;
|
|
51419
52232
|
}
|
|
51420
52233
|
const expanded = Array.from(panel.querySelectorAll('[data-project-row-wrap][data-expanded="true"]')).map((wrap) => wrap.getAttribute("data-project-row-wrap")).filter(Boolean);
|
|
51421
|
-
|
|
51422
|
-
recentProjects.renderRecentProjectsVariant({
|
|
51423
|
-
restoreExpanded: expanded,
|
|
51424
|
-
restoreScrollTop: rootEl ? rootEl.scrollTop : void 0
|
|
51425
|
-
}).catch(() => {
|
|
52234
|
+
recentProjects.refreshDashboardView({ restoreExpanded: expanded }).catch(() => {
|
|
51426
52235
|
});
|
|
51427
52236
|
}, 400);
|
|
51428
52237
|
}
|
|
@@ -51993,7 +52802,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
51993
52802
|
primeCodexLocalSkillsCatalog().catch(() => {
|
|
51994
52803
|
});
|
|
51995
52804
|
}
|
|
51996
|
-
PanelRenderer.setVisible(
|
|
52805
|
+
PanelRenderer.setVisible(panelRendererInstance, true);
|
|
51997
52806
|
}
|
|
51998
52807
|
let codexOverleafSkillsCatalogPromise = null;
|
|
51999
52808
|
async function primeCodexOverleafSkillsCatalog({ required = false } = {}) {
|
|
@@ -52645,9 +53454,11 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
52645
53454
|
return;
|
|
52646
53455
|
}
|
|
52647
53456
|
let focusFiles = [...executionSnapshot.focusFiles];
|
|
53457
|
+
const mirrorOwner = currentRunView, mirrorRouteGeneration = spaRouteGeneration;
|
|
52648
53458
|
const warmStart = await awaitRunStep(resolveWarmRunStart({ focusFiles, mode: submittedMode }));
|
|
53459
|
+
const mirrorFence = await awaitRunStep(writebackOrchestrator.refreshMirrorReuseFence(mirrorOwner.runProjectId, mirrorOwner.runAccountScopeId));
|
|
52649
53460
|
let project = warmStart.project || null;
|
|
52650
|
-
let useExistingMirror = warmStart.useExistingMirror;
|
|
53461
|
+
let useExistingMirror = warmStart.useExistingMirror && !mirrorFence;
|
|
52651
53462
|
let fileOverlays = warmStart.fileOverlays || null;
|
|
52652
53463
|
let otWarmStart = warmStart.otWarmStart === true;
|
|
52653
53464
|
if (!useExistingMirror) {
|
|
@@ -52656,6 +53467,17 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
52656
53467
|
status: "running"
|
|
52657
53468
|
});
|
|
52658
53469
|
project = await awaitRunStep(getRunProjectSnapshot());
|
|
53470
|
+
if (mirrorFence) {
|
|
53471
|
+
const assertCurrent = () => {
|
|
53472
|
+
throwIfRunCancellationRequested();
|
|
53473
|
+
if (mirrorOwner !== currentRunView || mirrorRouteGeneration !== spaRouteGeneration || mirrorOwner.runProjectId !== getCurrentProjectId() || mirrorOwner.runAccountScopeId !== cachedAccountScopeId) throw createRunCancellationError();
|
|
53474
|
+
};
|
|
53475
|
+
await awaitRunStep(writebackOrchestrator.syncFencedMirror(mirrorOwner.runProjectId, project, {
|
|
53476
|
+
fence: mirrorFence,
|
|
53477
|
+
assertCurrent,
|
|
53478
|
+
sendNative: (payload) => nativeCompatibilityController.sendBackgroundNative(payload, { assertCurrent })
|
|
53479
|
+
}));
|
|
53480
|
+
}
|
|
52659
53481
|
}
|
|
52660
53482
|
throwIfRunCancellationRequested();
|
|
52661
53483
|
if (!useExistingMirror) {
|
|
@@ -52800,7 +53622,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
52800
53622
|
skillInvocation: submittedSkillInvocation,
|
|
52801
53623
|
submittedMode
|
|
52802
53624
|
})));
|
|
52803
|
-
if (!response.ok && response.error?.code
|
|
53625
|
+
if (!response.ok && ["mirror_stale", "document_identity_mismatch"].includes(response.error?.code) && useExistingMirror) {
|
|
52804
53626
|
appendRunEvent({ title: tr("warmMirrorStaleRetryTitle"), status: "running" });
|
|
52805
53627
|
const staleRetry = await awaitRunStep(prepareMirrorStaleRetry({
|
|
52806
53628
|
project: await awaitRunStep(getRunProjectSnapshot()),
|
|
@@ -53041,7 +53863,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53041
53863
|
});
|
|
53042
53864
|
runSettlementPersistence.applyToCurrentRun(syncOutcome.settlement);
|
|
53043
53865
|
if (runCancellationRequested) {
|
|
53044
|
-
throw createRunCancellationError();
|
|
53866
|
+
throw Object.assign(createRunCancellationError(), { writebackOutcome: syncOutcome });
|
|
53045
53867
|
}
|
|
53046
53868
|
await finalizeAuditRecord(runAuditDraft, {
|
|
53047
53869
|
...syncOutcome.audit || {},
|
|
@@ -53130,7 +53952,10 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53130
53952
|
}),
|
|
53131
53953
|
nextStep: tr("failureReason_reviewing_unavailable_cancelled_next")
|
|
53132
53954
|
});
|
|
53133
|
-
} else
|
|
53955
|
+
} else {
|
|
53956
|
+
runSettlementPersistence.applyToCurrentRun(error.writebackOutcome?.settlement);
|
|
53957
|
+
appendRunCancelledReport(error.writebackOutcome);
|
|
53958
|
+
}
|
|
53134
53959
|
await finishRunView(tx("Cancelled", "\u5DF2\u53D6\u6D88"), "cancelled");
|
|
53135
53960
|
void finalizeAuditRecord(runAuditDraft, { resultStatus: "cancelled" });
|
|
53136
53961
|
return;
|
|
@@ -53218,9 +54043,13 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53218
54043
|
stopRunElapsedTick();
|
|
53219
54044
|
await flushQueuedSaveState().catch(() => {
|
|
53220
54045
|
});
|
|
54046
|
+
if (settlement.continueQueue) {
|
|
54047
|
+
settlement.continueQueue = await waitForCancelledNativeRun(settledView);
|
|
54048
|
+
}
|
|
53221
54049
|
currentRunView = null;
|
|
53222
54050
|
runCancellationRequested = false;
|
|
53223
54051
|
runCancellationController = null;
|
|
54052
|
+
syncComposerSendAvailability();
|
|
53224
54053
|
activeTurnControl.release(settlement.requestId);
|
|
53225
54054
|
if (isExperimentalOtEnabled()) {
|
|
53226
54055
|
try {
|
|
@@ -53640,7 +54469,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53640
54469
|
if (state?.activeSessionId !== sessionId || !isProjectEditorRoute(window.location)) return false;
|
|
53641
54470
|
if (sessionManager.isTransitioning()) {
|
|
53642
54471
|
deferredSessionStart = { sessionId, scope: getComposerDraftScope() };
|
|
53643
|
-
return
|
|
54472
|
+
return "session_transition";
|
|
53644
54473
|
}
|
|
53645
54474
|
return true;
|
|
53646
54475
|
}
|
|
@@ -53680,17 +54509,19 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53680
54509
|
title: tx("Cancelling the current Codex task.", "\u6B63\u5728\u4E2D\u65AD\u5F53\u524D Codex \u4EFB\u52A1\u3002"),
|
|
53681
54510
|
status: "running"
|
|
53682
54511
|
});
|
|
53683
|
-
const activeRequestId =
|
|
54512
|
+
const activeRequestId = currentRunView.nativeRequestId;
|
|
53684
54513
|
const projectKey = currentRunView?.runProjectId || getCurrentProjectId() || "";
|
|
53685
54514
|
const cancelTargets = [];
|
|
53686
|
-
if (activeRequestId
|
|
54515
|
+
if (activeRequestId != null && activeRequestId !== "") {
|
|
53687
54516
|
cancelTargets.push(sendBackgroundNative({
|
|
53688
54517
|
method: "codex.cancel",
|
|
53689
54518
|
params: {
|
|
53690
|
-
requestId: activeRequestId
|
|
54519
|
+
requestId: activeRequestId,
|
|
53691
54520
|
projectKey: projectKey || void 0
|
|
53692
54521
|
}
|
|
53693
54522
|
}));
|
|
54523
|
+
} else {
|
|
54524
|
+
cancelTargets.push(Promise.resolve(null));
|
|
53694
54525
|
}
|
|
53695
54526
|
cancelTargets.push(callPageBridge("cancelActiveWrite", {}).catch(() => ({ ok: false })));
|
|
53696
54527
|
Promise.allSettled(cancelTargets).then((results) => {
|
|
@@ -53761,6 +54592,22 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53761
54592
|
Promise.resolve(value).then((result) => settle(resolve, result), (error) => settle(reject, error));
|
|
53762
54593
|
});
|
|
53763
54594
|
}
|
|
54595
|
+
async function waitForCancelledNativeRun(runView) {
|
|
54596
|
+
const pending = runView?.pendingNativeRun;
|
|
54597
|
+
if (!pending) return true;
|
|
54598
|
+
const CANCELLED_NATIVE_SETTLEMENT_TIMEOUT_MS = 2e4;
|
|
54599
|
+
let timer;
|
|
54600
|
+
try {
|
|
54601
|
+
return await Promise.race([
|
|
54602
|
+
pending.then(() => true, () => true),
|
|
54603
|
+
new Promise((resolve) => {
|
|
54604
|
+
timer = setTimeout(() => resolve(false), CANCELLED_NATIVE_SETTLEMENT_TIMEOUT_MS);
|
|
54605
|
+
})
|
|
54606
|
+
]);
|
|
54607
|
+
} finally {
|
|
54608
|
+
clearTimeout(timer);
|
|
54609
|
+
}
|
|
54610
|
+
}
|
|
53764
54611
|
function isRunCancellationError(error = {}) {
|
|
53765
54612
|
return error.code === "codex_cancelled" || /cancelled by the user|was cancelled/i.test(error.message || "");
|
|
53766
54613
|
}
|
|
@@ -53894,21 +54741,25 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
53894
54741
|
method: "codex.run",
|
|
53895
54742
|
params
|
|
53896
54743
|
}, compatibilityGate.compatibility));
|
|
53897
|
-
if (
|
|
53898
|
-
|
|
53899
|
-
|
|
54744
|
+
if (owner) {
|
|
54745
|
+
owner.nativeRequestId = tracked.id;
|
|
54746
|
+
owner.pendingNativeRun = tracked.promise;
|
|
54747
|
+
const record = findRunRecord(owner.recordId, owner.sessionId);
|
|
53900
54748
|
if (record) {
|
|
53901
54749
|
record.nativeRequestId = tracked.id;
|
|
53902
54750
|
}
|
|
53903
54751
|
activeTurnControl.bind({
|
|
53904
54752
|
requestId: tracked.id,
|
|
53905
|
-
projectKey:
|
|
53906
|
-
clientRunId:
|
|
53907
|
-
sessionId:
|
|
54753
|
+
projectKey: owner.runProjectId,
|
|
54754
|
+
clientRunId: owner.recordId,
|
|
54755
|
+
sessionId: owner.sessionId
|
|
53908
54756
|
});
|
|
53909
54757
|
saveStateSoon();
|
|
53910
54758
|
}
|
|
53911
54759
|
return tracked.promise.finally(() => {
|
|
54760
|
+
if (owner?.pendingNativeRun === tracked.promise) {
|
|
54761
|
+
owner.pendingNativeRun = null;
|
|
54762
|
+
}
|
|
53912
54763
|
if (currentRunView?.nativeRequestId === tracked.id) {
|
|
53913
54764
|
currentRunView.activeTurn = null;
|
|
53914
54765
|
renderPendingInputs();
|
|
@@ -54046,8 +54897,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54046
54897
|
tx
|
|
54047
54898
|
}).run(options);
|
|
54048
54899
|
}
|
|
54049
|
-
function appendRunCancelledReport() {
|
|
54050
|
-
const hasQueuedFollowUp = (getActiveSession(state)?.pendingInputs || []).some((item) => item?.status === "queued");
|
|
54900
|
+
function appendRunCancelledReport(writebackOutcome = {}, continueQueue = true) {
|
|
54901
|
+
const hasQueuedFollowUp = continueQueue && (getActiveSession(state)?.pendingInputs || []).some((item) => item?.status === "queued");
|
|
54051
54902
|
appendRunEvent({
|
|
54052
54903
|
title: tx("Current Codex task was cancelled.", "\u5DF2\u4E2D\u65AD\u5F53\u524D Codex \u4EFB\u52A1\u3002"),
|
|
54053
54904
|
status: "info",
|
|
@@ -54057,8 +54908,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54057
54908
|
conclusionKey: "cancelled",
|
|
54058
54909
|
conclusion: tx("This run was cancelled. It did not continue syncing or writing to Overleaf.", "\u8FD9\u8F6E\u5DF2\u4E2D\u65AD\uFF0C\u6CA1\u6709\u7EE7\u7EED\u540C\u6B65\u6216\u5199\u5165 Overleaf\u3002"),
|
|
54059
54910
|
status: "cancelled",
|
|
54060
|
-
operations: [],
|
|
54061
|
-
applyResults: [],
|
|
54911
|
+
operations: writebackOutcome.operations || [],
|
|
54912
|
+
applyResults: writebackOutcome.applied ? [writebackOutcome.applied] : [],
|
|
54913
|
+
saveVerification: writebackOutcome.saveVerification,
|
|
54062
54914
|
nextStep: hasQueuedFollowUp ? tx("The first queued follow-up will start next.", "\u63A5\u4E0B\u6765\u4F1A\u81EA\u52A8\u542F\u52A8\u961F\u9996\u7684\u540E\u7EED\u4EFB\u52A1\u3002") : tx("Edit the task and run again.", "\u53EF\u4EE5\u4FEE\u6539\u4EFB\u52A1\u540E\u91CD\u65B0\u8FD0\u884C\u3002")
|
|
54063
54915
|
});
|
|
54064
54916
|
}
|
|
@@ -54077,11 +54929,13 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54077
54929
|
}
|
|
54078
54930
|
const hasInput = Boolean(String(panel?.querySelector("[data-task]")?.value || "").trim());
|
|
54079
54931
|
const running = typeof runningOverride === "boolean" ? runningOverride : Boolean(currentRunView);
|
|
54932
|
+
const runningInActiveSession = running && (!currentRunView || currentRunView.sessionId === state?.activeSessionId);
|
|
54080
54933
|
const transitioning = sessionManager.isTransitioning();
|
|
54081
|
-
const action =
|
|
54082
|
-
const
|
|
54934
|
+
const action = runningInActiveSession && (!hasInput || transitioning) ? "cancel" : "send";
|
|
54935
|
+
const attachmentsLoading = composerAttachmentController.hasPendingReads();
|
|
54936
|
+
const label = action === "cancel" ? tr("cancelRun") : attachmentsLoading ? tr("attachmentsLoading") : running && hasInput ? tr("queueNextInput") : tr("send");
|
|
54083
54937
|
runButton.dataset.action = action;
|
|
54084
|
-
runButton.disabled = action === "cancel" ? runCancellationRequested : !hasInput || transitioning;
|
|
54938
|
+
runButton.disabled = action === "cancel" ? runCancellationRequested : !hasInput || transitioning || attachmentsLoading;
|
|
54085
54939
|
runButton.title = label;
|
|
54086
54940
|
runButton.setAttribute("aria-label", label);
|
|
54087
54941
|
if (currentRunView?.writebackRetry && hasInput && action !== "cancel") runButton.disabled = true;
|
|
@@ -54091,6 +54945,10 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54091
54945
|
if (event.key === "Enter" && !event.isComposing && event.keyCode !== 229) event.preventDefault();
|
|
54092
54946
|
return;
|
|
54093
54947
|
}
|
|
54948
|
+
if (composerAttachmentController.hasPendingReads() && event.key === "Enter" && !event.shiftKey && !event.isComposing && event.keyCode !== 229) {
|
|
54949
|
+
event.preventDefault();
|
|
54950
|
+
return;
|
|
54951
|
+
}
|
|
54094
54952
|
if (handleSlashMenuKeydown(event)) {
|
|
54095
54953
|
return;
|
|
54096
54954
|
}
|
|
@@ -54140,7 +54998,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54140
54998
|
if (!isCodexOverleafSkillEnabled(id)) {
|
|
54141
54999
|
continue;
|
|
54142
55000
|
}
|
|
54143
|
-
const title = String(skill?.title || skill?.name || id).trim().slice(0, 80) || id;
|
|
55001
|
+
const title = id === "reviewer-response" ? tx("Reviewer response", "\u5BA1\u7A3F\u56DE\u590D") : String(skill?.title || skill?.name || id).trim().slice(0, 80) || id;
|
|
54144
55002
|
commands.push({
|
|
54145
55003
|
id: `skill:${id}`,
|
|
54146
55004
|
kind: "codex-overleaf-skill",
|
|
@@ -54754,6 +55612,8 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
54754
55612
|
setState: (next) => {
|
|
54755
55613
|
state = next;
|
|
54756
55614
|
},
|
|
55615
|
+
isDashboard: () => panel?.dataset.view === "recent-projects",
|
|
55616
|
+
refreshDashboard: refreshDashboardSoon,
|
|
54757
55617
|
// An in-flight Accept/Undo keeps its view until it settles; refresh applies afterwards.
|
|
54758
55618
|
isBusy: () => Boolean(pendingDraftSave || readLiveRunViewForSaveStateGuard() || trackedChangeInFlight.size || runReviewController?.hasActiveReview?.() || document.querySelector("dialog[open]")),
|
|
54759
55619
|
hasLocalDraft: (current) => Boolean(current.task) && composerDraftEditedHere,
|
|
@@ -55593,8 +56453,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55593
56453
|
)
|
|
55594
56454
|
};
|
|
55595
56455
|
}
|
|
55596
|
-
async function getRunProjectSnapshot() {
|
|
56456
|
+
async function getRunProjectSnapshot(expectedProjectId = getCurrentProjectId()) {
|
|
55597
56457
|
const project = await callPageBridge("getProjectSnapshot", {
|
|
56458
|
+
projectId: expectedProjectId,
|
|
55598
56459
|
force: true,
|
|
55599
56460
|
maxAgeMs: 0,
|
|
55600
56461
|
preferLightweight: true,
|
|
@@ -55606,11 +56467,12 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55606
56467
|
zipTimeoutMs: RUN_SNAPSHOT_ZIP_TIMEOUT_MS,
|
|
55607
56468
|
focusFiles: getActiveFocusFiles()
|
|
55608
56469
|
});
|
|
55609
|
-
const sanitizedProject = sanitizeRunProjectSnapshot(project);
|
|
56470
|
+
const sanitizedProject = sanitizeRunProjectSnapshot(project, expectedProjectId);
|
|
55610
56471
|
if (sanitizedProject?.capabilities?.fullProjectSnapshot || sanitizedProject?.capabilities?.pathIdentityComplete === false) {
|
|
55611
56472
|
return sanitizedProject;
|
|
55612
56473
|
}
|
|
55613
56474
|
const pageStateProject = await callPageBridge("getProjectSnapshot", {
|
|
56475
|
+
projectId: expectedProjectId,
|
|
55614
56476
|
force: true,
|
|
55615
56477
|
maxAgeMs: 0,
|
|
55616
56478
|
preferLightweight: true,
|
|
@@ -55620,16 +56482,22 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55620
56482
|
includeBinaryFiles: false,
|
|
55621
56483
|
focusFiles: getActiveFocusFiles()
|
|
55622
56484
|
});
|
|
55623
|
-
const sanitizedPageStateProject = sanitizeRunProjectSnapshot(pageStateProject);
|
|
56485
|
+
const sanitizedPageStateProject = sanitizeRunProjectSnapshot(pageStateProject, expectedProjectId);
|
|
55624
56486
|
if (sanitizedPageStateProject?.capabilities?.fullProjectSnapshot) {
|
|
55625
56487
|
return sanitizedPageStateProject;
|
|
55626
56488
|
}
|
|
55627
56489
|
return sanitizedProject;
|
|
55628
56490
|
}
|
|
55629
|
-
function sanitizeRunProjectSnapshot(project) {
|
|
56491
|
+
function sanitizeRunProjectSnapshot(project, expectedProjectId = project?.id) {
|
|
55630
56492
|
if (!project || typeof project !== "object") return project;
|
|
56493
|
+
if (project.id !== expectedProjectId) return { ...project, files: [], capabilities: {
|
|
56494
|
+
...project.capabilities,
|
|
56495
|
+
fullProjectSnapshot: false,
|
|
56496
|
+
skipped: [{ path: "", reason: "document_identity_mismatch" }]
|
|
56497
|
+
} };
|
|
55631
56498
|
const normalize = Modules.ProjectFiles.normalizeSafeProjectPath;
|
|
55632
|
-
const files = Array.isArray(project.files) ? project.files : [];
|
|
56499
|
+
const files = Array.isArray(project.files) ? project.files.map((file) => file?.documentIdentity === void 0 ? file : { ...file, documentIdentity: snapshotDocumentIdentity(file.documentIdentity, file.path, project.id) }) : [];
|
|
56500
|
+
project = { ...project, files };
|
|
55633
56501
|
const counts = /* @__PURE__ */ new Map();
|
|
55634
56502
|
for (const file of files) {
|
|
55635
56503
|
const path = normalize(file?.path);
|
|
@@ -55669,12 +56537,16 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55669
56537
|
};
|
|
55670
56538
|
}
|
|
55671
56539
|
async function getMirrorFreshness() {
|
|
56540
|
+
const projectId = getCurrentProjectId(), accountScopeId = cachedAccountScopeId;
|
|
56541
|
+
if (await writebackOrchestrator.refreshMirrorReuseFence(projectId, accountScopeId)) return null;
|
|
56542
|
+
if (getCurrentProjectId() !== projectId || cachedAccountScopeId !== accountScopeId) return null;
|
|
55672
56543
|
try {
|
|
55673
56544
|
const response = await sendBackgroundNative({
|
|
55674
56545
|
method: "mirror.status",
|
|
55675
|
-
params: { projectId
|
|
56546
|
+
params: { projectId }
|
|
55676
56547
|
});
|
|
55677
|
-
|
|
56548
|
+
const fence = await writebackOrchestrator.refreshMirrorReuseFence(projectId, accountScopeId);
|
|
56549
|
+
if (response?.ok && !fence && getCurrentProjectId() === projectId && cachedAccountScopeId === accountScopeId) {
|
|
55678
56550
|
return response.result;
|
|
55679
56551
|
}
|
|
55680
56552
|
} catch (error) {
|
|
@@ -55702,7 +56574,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55702
56574
|
return { useExistingMirror: false, reason: "missing_focus_overlay" };
|
|
55703
56575
|
}
|
|
55704
56576
|
const mirrorStatus = await getMirrorFreshness();
|
|
55705
|
-
const mirrorHealth2 = Modules.MirrorHealth.classifyMirrorHealth(mirrorStatus);
|
|
56577
|
+
const mirrorHealth2 = Modules.MirrorHealth.classifyMirrorHealth(mirrorStatus || {});
|
|
55706
56578
|
if (!mirrorStatus?.exists || !mirrorHealth2.reusable) {
|
|
55707
56579
|
return { useExistingMirror: false, reason: "mirror_not_fresh", mirrorStatus };
|
|
55708
56580
|
}
|
|
@@ -55727,12 +56599,27 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55727
56599
|
});
|
|
55728
56600
|
const seen = /* @__PURE__ */ new Set();
|
|
55729
56601
|
return candidates.filter(
|
|
55730
|
-
(file) => typeof file.content === "string" && Modules.ProjectFiles.isUsableProjectFileContent(file.content) && file.path && !seen.has(file.path) && seen.add(file.path)
|
|
56602
|
+
(file) => typeof file.content === "string" && (Modules.ProjectFiles.isUsableProjectFileContent(file.content) || file.content === "") && file.path && !seen.has(file.path) && seen.add(file.path)
|
|
55731
56603
|
).map((file) => ({
|
|
55732
56604
|
path: file.path,
|
|
55733
|
-
content: file.content
|
|
56605
|
+
content: file.content,
|
|
56606
|
+
kind: "text",
|
|
56607
|
+
source: file.source,
|
|
56608
|
+
...file.documentIdentity !== void 0 ? { documentIdentity: snapshotDocumentIdentity(file.documentIdentity, file.path, project.id) } : {}
|
|
55734
56609
|
}));
|
|
55735
56610
|
}
|
|
56611
|
+
function snapshotDocumentIdentity(identity, path, projectId) {
|
|
56612
|
+
if (!identity || identity.version !== 1 || identity.source !== "cm-ranges-v1" || identity.path !== path || identity.projectId !== projectId || typeof identity.documentId !== "string" || !/^[a-f0-9]{24}$/.test(identity.documentId) || typeof identity.targetDocumentId !== "string" || !/^[a-f0-9]{24}$/.test(identity.targetDocumentId) || typeof identity.contentSha256 !== "string" || !/^[a-f0-9]{64}$/.test(identity.contentSha256)) return null;
|
|
56613
|
+
return {
|
|
56614
|
+
version: 1,
|
|
56615
|
+
source: "cm-ranges-v1",
|
|
56616
|
+
projectId,
|
|
56617
|
+
path,
|
|
56618
|
+
documentId: identity.documentId,
|
|
56619
|
+
targetDocumentId: identity.targetDocumentId,
|
|
56620
|
+
contentSha256: identity.contentSha256
|
|
56621
|
+
};
|
|
56622
|
+
}
|
|
55736
56623
|
function normalizeSnapshotPath(path) {
|
|
55737
56624
|
return Modules.ProjectFiles.normalizeSafeProjectPath(path);
|
|
55738
56625
|
}
|
|
@@ -55954,10 +56841,15 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
55954
56841
|
if (!accountScopeId || isScopedPersistenceIdentityFailure(error)) {
|
|
55955
56842
|
throw error;
|
|
55956
56843
|
}
|
|
56844
|
+
const fallbackProjectId = getCurrentProjectId();
|
|
56845
|
+
const fallbackGeneration = spaRouteGeneration;
|
|
55957
56846
|
const fallbackKey = buildScopedFallbackStorageKey(storageKey, accountScopeId);
|
|
55958
56847
|
const stored = await chrome.storage.local.get([fallbackKey]);
|
|
55959
56848
|
const fallback = stored[fallbackKey] || {};
|
|
55960
56849
|
if (fallback?.__codexOverleafCompactFallback === true && fallback.__codexOverleafFallbackAccountScopeId === accountScopeId) {
|
|
56850
|
+
if (accountScopeId === cachedAccountScopeId && fallbackProjectId === getCurrentProjectId() && fallbackGeneration === spaRouteGeneration) {
|
|
56851
|
+
Modules.StorageMigration.adoptProjectPreferenceBaseline(fallback, accountScopeId, fallbackProjectId);
|
|
56852
|
+
}
|
|
55961
56853
|
return {
|
|
55962
56854
|
mode: fallback.mode || "",
|
|
55963
56855
|
providerId: fallback.providerId || "builtin",
|
|
@@ -56024,7 +56916,20 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
56024
56916
|
compactState.customInstructionsByProject = state.customInstructionsByProject;
|
|
56025
56917
|
compactState.reviewingAvailabilityByProject = state.reviewingAvailabilityByProject;
|
|
56026
56918
|
compactState.governanceRulesByProject = state.governanceRulesByProject;
|
|
56919
|
+
const projectPreferenceBaseline = Migration.getProjectPreferenceBaseline(
|
|
56920
|
+
options?.draftScope?.accountScopeId || cachedAccountScopeId,
|
|
56921
|
+
projectId
|
|
56922
|
+
);
|
|
56027
56923
|
const stateSnapshot = typeof structuredClone === "function" ? structuredClone(state) : JSON.parse(JSON.stringify(state));
|
|
56924
|
+
const projectPreferenceWrite = Migration.captureProjectPreferenceWrite({
|
|
56925
|
+
state: stateSnapshot,
|
|
56926
|
+
baseline: projectPreferenceBaseline,
|
|
56927
|
+
accountScopeId: options?.draftScope?.accountScopeId || cachedAccountScopeId,
|
|
56928
|
+
projectId,
|
|
56929
|
+
normalizeExperimentalOtByProject,
|
|
56930
|
+
normalizeGovernanceRulesByProject,
|
|
56931
|
+
normalizeCustomInstructionsByProject
|
|
56932
|
+
});
|
|
56028
56933
|
const consumedSession = liveRunView?.draftConsumption && liveRunView.runProjectId === projectId && liveRunView.runAccountScopeId === cachedAccountScopeId ? stateSnapshot.sessions?.find((session) => session.id === liveRunView.sessionId) : null;
|
|
56029
56934
|
if (consumedSession?.task === "") consumedSession.draftConsumption = { ...liveRunView.draftConsumption };
|
|
56030
56935
|
const compactStateSnapshot = typeof structuredClone === "function" ? structuredClone(compactState) : JSON.parse(JSON.stringify(compactState));
|
|
@@ -56044,6 +56949,27 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
56044
56949
|
normalizeExperimentalOtByProject,
|
|
56045
56950
|
normalizeGovernanceRulesByProject,
|
|
56046
56951
|
normalizeCustomInstructionsByProject,
|
|
56952
|
+
projectPreferenceBaseline,
|
|
56953
|
+
projectPreferenceWrite,
|
|
56954
|
+
applyProjectPreferences: (prefs, captured, fields) => {
|
|
56955
|
+
if (retentionScope.accountScopeId !== cachedAccountScopeId || retentionScope.projectId !== getCurrentProjectId() || retentionScope.generation !== spaRouteGeneration) return false;
|
|
56956
|
+
const adopted = [];
|
|
56957
|
+
for (const field of fields) {
|
|
56958
|
+
if (JSON.stringify(state[field]?.[projectId]) !== JSON.stringify(captured[field]?.[projectId])) continue;
|
|
56959
|
+
if (JSON.stringify(state[field]?.[projectId]) === JSON.stringify(prefs[field]?.[projectId])) continue;
|
|
56960
|
+
state[field] = { ...state[field], ...prefs[field] };
|
|
56961
|
+
if (!Object.hasOwn(prefs[field] || {}, projectId)) delete state[field][projectId];
|
|
56962
|
+
adopted.push(field);
|
|
56963
|
+
}
|
|
56964
|
+
if (adopted.includes("customInstructionsByProject")) syncCustomInstructionsEditorForProject(projectId);
|
|
56965
|
+
if (adopted.includes("governanceRulesByProject")) syncProjectSettingsEditorForProject();
|
|
56966
|
+
if (adopted.includes("experimentalOtByProject")) syncExperimentalOtToggleForProject(projectId);
|
|
56967
|
+
if (adopted.includes("reviewingAvailabilityByProject")) {
|
|
56968
|
+
syncReviewingTooltip();
|
|
56969
|
+
syncProbeStatus();
|
|
56970
|
+
}
|
|
56971
|
+
return true;
|
|
56972
|
+
},
|
|
56047
56973
|
persistenceContext
|
|
56048
56974
|
});
|
|
56049
56975
|
if (!options?.draftScope) {
|
|
@@ -56441,11 +57367,17 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
56441
57367
|
if (!composerDraftPersistence) composerDraftPersistence = Modules.ComposerAttachmentDraft.createController({
|
|
56442
57368
|
getScope: () => ({ accountScopeId: cachedAccountScopeId, projectId: getCurrentProjectId() }),
|
|
56443
57369
|
getAttachments: () => composerAttachmentController.serializePersistableAttachments(),
|
|
57370
|
+
getOmittedAttachmentNames: () => composerAttachmentController.getOmittedAttachmentNames(),
|
|
56444
57371
|
setAttachments: (value) => {
|
|
56445
57372
|
state.composerAttachments = value;
|
|
57373
|
+
syncComposerSendAvailability();
|
|
56446
57374
|
},
|
|
56447
57375
|
clear: () => composerAttachmentController.clear({ notify: false }),
|
|
56448
57376
|
restore: (value) => composerAttachmentController.restorePersistedAttachments(value),
|
|
57377
|
+
onRestoreOmittedAttachments: ({ count, names }) => appendPlainLog(tx(
|
|
57378
|
+
`${count} attachment${count === 1 ? "" : "s"} could not be saved in the draft. Reattach before sending: ${names.join(", ")}.`,
|
|
57379
|
+
`${count} \u4E2A\u9644\u4EF6\u672A\u80FD\u4FDD\u5B58\u5230\u8349\u7A3F\u4E2D\uFF0C\u8BF7\u5728\u53D1\u9001\u524D\u91CD\u65B0\u6DFB\u52A0\uFF1A${names.join("\u3001")}\u3002`
|
|
57380
|
+
)),
|
|
56449
57381
|
read: (scope) => Modules.StorageDb.readComposerAttachmentDraft(scope),
|
|
56450
57382
|
write: (scope, value) => Modules.StorageDb.writeComposerAttachmentDraft(scope, value),
|
|
56451
57383
|
scheduleSave: () => saveStateSoon()
|
|
@@ -56534,7 +57466,9 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
56534
57466
|
writingStyleSettings.sync();
|
|
56535
57467
|
applyPanelTheme(getThemePreference());
|
|
56536
57468
|
if ((state.providerId || "builtin") === "builtin" && !modelSelectHasOption(state.model)) {
|
|
56537
|
-
renderModelOptions(getModelCatalog().FALLBACK_MODELS, state.model
|
|
57469
|
+
renderModelOptions(getModelCatalog().FALLBACK_MODELS, state.model, {
|
|
57470
|
+
provisionalSelected: getModelDiscovery().provisional === true
|
|
57471
|
+
});
|
|
56538
57472
|
}
|
|
56539
57473
|
panel.querySelector("[data-model]").value = state.model;
|
|
56540
57474
|
const renderedModels = getRenderedModelEntries();
|
|
@@ -57444,11 +58378,13 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
57444
58378
|
if (!record || record.forkSnapshot || !owner || owner.projectId !== getCurrentProjectId() || owner.accountScopeId !== cachedAccountScopeId || owner.sessionId !== session.id || owner.runId !== record.id || record.undoStatus === "applied" || record.trackedChangeStatus === "rejected") return;
|
|
57445
58379
|
const originalStatus = record.status;
|
|
57446
58380
|
const retryAutoRecompile = typeof record.executionSnapshot?.autoRecompile === "boolean" ? record.executionSnapshot.autoRecompile : void 0;
|
|
57447
|
-
const
|
|
58381
|
+
const generation = spaRouteGeneration;
|
|
58382
|
+
const isOwnerScope = () => generation === spaRouteGeneration && owner.projectId === getCurrentProjectId() && owner.accountScopeId === cachedAccountScopeId;
|
|
58383
|
+
const live = () => isOwnerScope() && findRunRecord(runId, session.id) || record;
|
|
57448
58384
|
let finished = false;
|
|
58385
|
+
let retryOutcome = null;
|
|
57449
58386
|
runCancellationRequested = false;
|
|
57450
58387
|
runCancellationController = new AbortController();
|
|
57451
|
-
const generation = spaRouteGeneration;
|
|
57452
58388
|
const requestId = record.nativeRequestId || `writeback:${owner.sessionId}:${runId}`;
|
|
57453
58389
|
const ownerToken = crypto.randomUUID();
|
|
57454
58390
|
const retryView = {
|
|
@@ -57466,7 +58402,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
57466
58402
|
if (runCancellationRequested || currentRunView !== retryView) {
|
|
57467
58403
|
throw Object.assign(new Error("Save checking was cancelled."), { code: "codex_cancelled" });
|
|
57468
58404
|
}
|
|
57469
|
-
if (
|
|
58405
|
+
if (!isOwnerScope()) {
|
|
57470
58406
|
throw Object.assign(new Error("The project or account changed."), { code: "aborted_project_changed" });
|
|
57471
58407
|
}
|
|
57472
58408
|
};
|
|
@@ -57492,6 +58428,10 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
57492
58428
|
runProcess: root2?.querySelector("[data-run-process]"),
|
|
57493
58429
|
processLabel: root2?.querySelector("[data-run-process-summary]")
|
|
57494
58430
|
});
|
|
58431
|
+
const pendingMirror = getPendingMirrorRefresh?.();
|
|
58432
|
+
if (pendingMirror) await awaitRunStep(pendingMirror.catch(() => {
|
|
58433
|
+
}));
|
|
58434
|
+
assertOwner();
|
|
57495
58435
|
if (intent?.requestId) {
|
|
57496
58436
|
const receipt = await callPageBridge("getWritebackReceipt", { requestId: intent.requestId, runProjectId: owner.projectId });
|
|
57497
58437
|
if (receipt?.state === "running") throw new Error(tx("The previous upload is still finishing. Try again shortly.", "\u4E0A\u4E00\u8F6E\u4E0A\u4F20\u4ECD\u5728\u6536\u5C3E\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002"));
|
|
@@ -57510,6 +58450,7 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
57510
58450
|
assistantMessage: tx("Retried the remaining file transfers for this task.", "\u5DF2\u91CD\u8BD5\u672C\u8F6E\u672A\u5B8C\u6210\u7684\u6587\u4EF6\u540C\u6B65\u3002")
|
|
57511
58451
|
}
|
|
57512
58452
|
);
|
|
58453
|
+
retryOutcome = result;
|
|
57513
58454
|
assertOwner();
|
|
57514
58455
|
if (result.settlement?.facts) live().settlement = WritebackSettlement.mergeRetrySettlement(live().settlement, result.settlement.facts);
|
|
57515
58456
|
await finishRunView(
|
|
@@ -57533,6 +58474,17 @@ ${tx("Writeback note: Codex could not confirm any Overleaf write result entries,
|
|
|
57533
58474
|
}
|
|
57534
58475
|
await flushQueuedSaveState();
|
|
57535
58476
|
} catch (error) {
|
|
58477
|
+
const outcome = error.writebackOutcome || retryOutcome;
|
|
58478
|
+
const current = findRunRecord(runId, session.id);
|
|
58479
|
+
if (outcome && (runCancellationRequested || isRunCancellationError(error)) && currentRunView === retryView && isOwnerScope() && current && !current.forkSnapshot && current.runProjectId === owner.projectId) {
|
|
58480
|
+
if (outcome.settlement?.facts) current.settlement = WritebackSettlement.mergeRetrySettlement(
|
|
58481
|
+
current.settlement,
|
|
58482
|
+
outcome.settlement.facts
|
|
58483
|
+
);
|
|
58484
|
+
appendRunCancelledReport(outcome, false);
|
|
58485
|
+
await finishRunView(tx("Cancelled", "\u5DF2\u53D6\u6D88"), "cancelled");
|
|
58486
|
+
finished = true;
|
|
58487
|
+
}
|
|
57536
58488
|
showPluginToast(error.message || String(error));
|
|
57537
58489
|
} finally {
|
|
57538
58490
|
if (currentRunView !== retryView) {
|