codex-overleaf-link 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -392
- package/README.zh-CN.md +154 -393
- package/extension/bootstrap/background.js +52 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/bootstrap/popup.html +1 -0
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/src/background.js +283 -55
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +129 -16
- package/extension/src/backgroundUpdateCoordinator.js +242 -29
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +171 -8
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +72 -14
- package/extension/src/content/composerAttachments.js +104 -47
- package/extension/src/content/composerPanel.js +110 -12
- package/extension/src/content/contentRuntime.js +1555 -926
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsController.js +122 -96
- package/extension/src/content/diagnosticsExport.js +19 -5
- package/extension/src/content/diagnosticsPanel.js +48 -0
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +11077 -3412
- package/extension/src/content/generated/content.bundle.meta.json +14 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +10 -0
- package/extension/src/content/localSkillsPanel.js +104 -14
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +47 -11
- package/extension/src/content/modelPicker.js +8 -4
- package/extension/src/content/nativeCompatibilityController.js +74 -30
- package/extension/src/content/otWarmMirror.js +5 -6
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +17 -4
- package/extension/src/content/panelMaintenance.js +46 -14
- package/extension/src/content/panelRenderer.js +57 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +67 -6
- package/extension/src/content/providerSettingsCoordinator.js +46 -8
- package/extension/src/content/providerSettingsDialog.js +73 -14
- package/extension/src/content/recentProjects.js +15 -8
- package/extension/src/content/runActivitySummary.js +160 -18
- package/extension/src/content/runCompletionMeta.js +532 -0
- package/extension/src/content/runController.js +39 -15
- package/extension/src/content/runFailureNotice.js +29 -13
- package/extension/src/content/runGuidanceController.js +72 -27
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +157 -47
- package/extension/src/content/runRecoveryActions.js +147 -0
- package/extension/src/content/runResultActions.js +28 -143
- package/extension/src/content/runReviewController.js +633 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +367 -175
- package/extension/src/content/scopedPersistencePanelState.js +134 -20
- package/extension/src/content/selectionContextView.js +1 -1
- package/extension/src/content/sensitivePreflight.js +153 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +50 -4
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +22 -5
- package/extension/src/content/settingsWorkbench.js +132 -89
- package/extension/src/content/sharedSessionViewSync.js +49 -11
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +118 -12
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +53 -4
- package/extension/src/content/writebackOrchestrator.js +116 -94
- package/extension/src/content/writingStyleSettings.js +35 -11
- package/extension/src/page/binaryAssetUploader.js +136 -14
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +1 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +6 -4
- package/extension/src/page/snapshotRouter.js +84 -39
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +114 -26
- package/extension/src/page/trackedChangeCapture.js +12 -2
- package/extension/src/page/trackedChangeOwnership.js +19 -1
- package/extension/src/page/trackedChangeReplay.js +41 -21
- package/extension/src/page/trackedChangesLifecycle.js +217 -199
- package/extension/src/page/treeOperations.js +7 -10
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +2 -0
- package/extension/src/page/writebackRouter.js +103 -155
- package/extension/src/pageBridge.js +126 -69
- package/extension/src/popup.js +62 -10
- package/extension/src/shared/agentTranscript.js +373 -17
- package/extension/src/shared/auditRecords.js +4 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +129 -66
- package/extension/src/shared/composerAttachmentDraft.js +156 -0
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +349 -4
- package/extension/src/shared/globalPreferences.js +30 -13
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +590 -24
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/managedUpdateProjection.js +2 -2
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +5 -4
- package/extension/src/shared/panelIcons.js +39 -0
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +5 -3
- package/extension/src/shared/reviewing.js +130 -1
- package/extension/src/shared/runActivityModel.js +70 -4
- package/extension/src/shared/runExecutionSnapshot.js +13 -0
- package/extension/src/shared/runInputQueue.js +48 -5
- package/extension/src/shared/selectionContext.js +12 -3
- package/extension/src/shared/sessionState.js +132 -28
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +118 -27
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +166 -52
- package/extension/src/shared/storageDb.js +90 -26
- package/extension/src/shared/storageMigration.js +78 -112
- package/extension/src/shared/storageRunActions.js +267 -30
- package/extension/src/shared/subagentActivityModel.js +1 -1
- package/extension/src/shared/undoOperations.js +253 -32
- package/extension/src/shared/updateConsent.js +6 -4
- package/extension/src/shared/updateRuntimeIdentity.js +17 -3
- package/extension/src/shared/writebackIntent.js +16 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +58 -40
- package/extension/styles/panel.css +1123 -493
- package/native-host/src/anthropicBridgeRequest.js +4 -2
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +269 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +20 -1
- package/native-host/src/chatCompletionsBridge.js +48 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexPromptAssembly.js +114 -127
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexSessionRunner.js +234 -198
- package/native-host/src/codexSessionTiming.js +18 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +110 -35
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/processStopBarrier.js +42 -7
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerProfile.js +4 -2
- package/native-host/src/providerReasoning.js +2 -7
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +72 -14
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +36 -8
- package/native-host/src/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +79 -66
- package/native-host/src/subagentTelemetry.js +19 -10
- package/native-host/src/subagentWorkspacePath.js +5 -2
- package/native-host/src/taskRunnerRuntime.js +92 -57
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/updateManager.js +409 -46
- package/native-host/src/writingStyleRuntime.js +57 -29
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +5 -8
- package/scripts/install-managed.mjs +1 -0
|
@@ -7,16 +7,23 @@
|
|
|
7
7
|
if (!Profiles || !Dialog?.create) {
|
|
8
8
|
throw new Error('Provider settings require explicit profile and dialog dependencies.');
|
|
9
9
|
}
|
|
10
|
+
const statusTranslations = new Map();
|
|
11
|
+
const translate = options.tx || (english => english);
|
|
10
12
|
const instance = {
|
|
11
13
|
Profiles,
|
|
12
|
-
tx:
|
|
14
|
+
tx: (english, chinese) => {
|
|
15
|
+
statusTranslations.set(english, [english, chinese]); statusTranslations.set(chinese, [english, chinese]);
|
|
16
|
+
return translate(english, chinese);
|
|
17
|
+
},
|
|
13
18
|
sendBackgroundNative: options.sendBackgroundNative,
|
|
14
19
|
getSettingsPanelInstance: options.getSettingsPanelInstance || (() => null),
|
|
15
20
|
getSelectedModel: options.getSelectedModel || (() => ''),
|
|
16
21
|
getSelectedProviderId: options.getSelectedProviderId || (() => 'builtin'),
|
|
22
|
+
getSelectedProviderRevision: options.getSelectedProviderRevision || (() => undefined),
|
|
17
23
|
hasCurrentProject: options.hasCurrentProject || (() => true),
|
|
18
24
|
setSelectedProviderId: options.setSelectedProviderId || (() => {}),
|
|
19
25
|
confirmProviderSwitch: options.confirmProviderSwitch || (() => true),
|
|
26
|
+
assertProviderSwitchAllowed: options.assertProviderSwitchAllowed || (() => {}),
|
|
20
27
|
clearSelectedModel: options.clearSelectedModel || (() => {}),
|
|
21
28
|
refreshModelOptions: options.refreshModelOptions || (() => {}),
|
|
22
29
|
persistInputs: options.persistInputs || (() => {}),
|
|
@@ -42,6 +49,7 @@
|
|
|
42
49
|
instance.dialog = Dialog.create({
|
|
43
50
|
document: options.document || document,
|
|
44
51
|
tx: instance.tx,
|
|
52
|
+
translateStatusText: text => statusTranslations.has(text) ? translate(...statusTranslations.get(text)) : text,
|
|
45
53
|
ProviderProfiles: Profiles,
|
|
46
54
|
callbacks: {
|
|
47
55
|
hasCurrentProject: instance.hasCurrentProject,
|
|
@@ -61,6 +69,7 @@
|
|
|
61
69
|
open: () => open(instance),
|
|
62
70
|
refreshSummary: () => refreshSummary(instance),
|
|
63
71
|
renderSummary: () => updateSettingsSummary(instance),
|
|
72
|
+
refreshLocale: () => instance.dialog.refreshLocale?.(),
|
|
64
73
|
ensureLoaded: () => ensureLoaded(instance),
|
|
65
74
|
getRunSelection: providerId => instance.loaded
|
|
66
75
|
? Profiles.buildRunSelection(instance.catalog, providerId || instance.getSelectedProviderId())
|
|
@@ -195,15 +204,20 @@
|
|
|
195
204
|
}
|
|
196
205
|
}
|
|
197
206
|
const changedProviderIds = Array.isArray(change.changedProviderIds) ? change.changedProviderIds : [];
|
|
198
|
-
const
|
|
207
|
+
const selectedRevision = instance.getSelectedProviderRevision();
|
|
208
|
+
const providerConfigurationChanged = changedProviderIds.includes(requestedProviderId)
|
|
209
|
+
|| (requestedProviderId === previousProviderId && selectedRevision !== undefined
|
|
210
|
+
&& Number(selectedRevision) !== Number(instance.Profiles.getProviderById(catalog, requestedProviderId)?.revision || 0));
|
|
199
211
|
if (!change.forceSessionRefresh && !projectProviderChanged && !providerConfigurationChanged) {
|
|
200
212
|
return;
|
|
201
213
|
}
|
|
214
|
+
if (projectProviderChanged || providerConfigurationChanged) instance.assertProviderSwitchAllowed();
|
|
202
215
|
const loadResult = change.modelsPreloaded === true
|
|
203
216
|
? { stale: false, selectedModel: change.preloadedModelId || '' }
|
|
204
217
|
: await instance.refreshModelOptions(
|
|
205
218
|
instance.Profiles.buildRunSelection(catalog, requestedProviderId),
|
|
206
|
-
{ persist: false
|
|
219
|
+
{ persist: false, ...(projectProviderChanged || providerConfigurationChanged
|
|
220
|
+
? { assertCurrent: instance.assertProviderSwitchAllowed } : {}) }
|
|
207
221
|
);
|
|
208
222
|
if (loadResult?.stale || loadResult?.error) {
|
|
209
223
|
const error = createClientError(
|
|
@@ -223,6 +237,7 @@
|
|
|
223
237
|
|
|
224
238
|
async function prepareProviderActivation(instance, providerId) {
|
|
225
239
|
requireCurrentProject(instance);
|
|
240
|
+
instance.assertProviderSwitchAllowed();
|
|
226
241
|
const previousProviderId = instance.getSelectedProviderId() || 'builtin';
|
|
227
242
|
const provider = instance.Profiles.getProviderById(instance.catalog, providerId);
|
|
228
243
|
if (providerId !== previousProviderId) {
|
|
@@ -234,9 +249,10 @@
|
|
|
234
249
|
return { cancelled: true, previousProviderId };
|
|
235
250
|
}
|
|
236
251
|
}
|
|
252
|
+
instance.assertProviderSwitchAllowed();
|
|
237
253
|
const result = await instance.refreshModelOptions(
|
|
238
254
|
instance.Profiles.buildRunSelection(instance.catalog, providerId),
|
|
239
|
-
{ persist: false }
|
|
255
|
+
{ persist: false, assertCurrent: instance.assertProviderSwitchAllowed }
|
|
240
256
|
);
|
|
241
257
|
if (result?.stale || result?.error) {
|
|
242
258
|
if (providerId !== previousProviderId) {
|
|
@@ -252,6 +268,7 @@
|
|
|
252
268
|
error.details = result?.error || {};
|
|
253
269
|
throw error;
|
|
254
270
|
}
|
|
271
|
+
instance.assertProviderSwitchAllowed();
|
|
255
272
|
return {
|
|
256
273
|
cancelled: false,
|
|
257
274
|
previousProviderId,
|
|
@@ -316,7 +333,10 @@
|
|
|
316
333
|
async function saveProvider(instance, context, action = {}) {
|
|
317
334
|
instance.dialog.setBusy('saving', instance.tx('Saving provider…', '正在保存模型服务…'));
|
|
318
335
|
try {
|
|
319
|
-
if (action.activate === true)
|
|
336
|
+
if (action.activate === true) {
|
|
337
|
+
requireCurrentProject(instance);
|
|
338
|
+
instance.assertProviderSwitchAllowed();
|
|
339
|
+
}
|
|
320
340
|
const result = await request(instance, 'codex.providers.upsert', {
|
|
321
341
|
profileId: context.profileId,
|
|
322
342
|
expectedRevision: context.expectedRevision,
|
|
@@ -347,8 +367,8 @@
|
|
|
347
367
|
tone: fellBackToBuiltin ? 'warning' : 'success',
|
|
348
368
|
title: fellBackToBuiltin
|
|
349
369
|
? instance.tx(
|
|
350
|
-
'Provider saved. Its endpoint changed, so Built-in Codex is
|
|
351
|
-
'
|
|
370
|
+
'Provider saved. Its endpoint changed, so the Native Host default is Built-in Codex. The project provider is unchanged; approve the new endpoint before using it.',
|
|
371
|
+
'模型服务已保存。端点变更使 Native Host 默认项回退到内置 Codex,当前项目的服务选择保持不变;使用新端点前仍需确认披露。'
|
|
352
372
|
)
|
|
353
373
|
: action.activate
|
|
354
374
|
? instance.tx('Provider saved and activated.', '模型服务已保存并启用。')
|
|
@@ -376,7 +396,7 @@
|
|
|
376
396
|
instance.dialog.setStatus({
|
|
377
397
|
tone: 'success',
|
|
378
398
|
title: result.activeProviderId === 'builtin'
|
|
379
|
-
? instance.tx('API key removed. Built-in Codex is
|
|
399
|
+
? instance.tx('API key removed. The Native Host default is Built-in Codex; the project provider is unchanged.', 'API 密钥已删除。Native Host 默认项为内置 Codex,当前项目的服务选择保持不变。')
|
|
380
400
|
: instance.tx('Stored API key removed.', '已删除存储的 API 密钥。')
|
|
381
401
|
});
|
|
382
402
|
} catch (error) {
|
|
@@ -387,6 +407,7 @@
|
|
|
387
407
|
async function deleteProvider(instance, context) {
|
|
388
408
|
instance.dialog.setBusy('deleting', instance.tx('Deleting provider…', '正在删除模型服务…'));
|
|
389
409
|
try {
|
|
410
|
+
if (context.profileId === instance.getSelectedProviderId()) instance.assertProviderSwitchAllowed();
|
|
390
411
|
const result = await request(instance, 'codex.providers.delete', {
|
|
391
412
|
providerId: context.profileId,
|
|
392
413
|
expectedRevision: context.expectedRevision
|
|
@@ -665,6 +686,23 @@
|
|
|
665
686
|
provider_revision_conflict: instance.tx('This provider changed in another tab. Reload it and retry.', '此模型服务已在其他标签页发生变化,请刷新后重试。'),
|
|
666
687
|
provider_protocol_negotiation_required: instance.tx('The Auto protocol could not be negotiated for this model.', '无法为此模型自动协商 API 协议。')
|
|
667
688
|
};
|
|
689
|
+
Object.assign(messages, {
|
|
690
|
+
provider_store_busy: instance.tx('Provider settings are being updated by another Native Host. Retry shortly.', '其他 Native Host 正在更新模型服务设置,请稍后重试。'),
|
|
691
|
+
provider_store_too_large: instance.tx('Provider settings exceed the storage limit. Reduce the configuration and retry.', '模型服务设置超过存储上限,请精简配置后重试。'),
|
|
692
|
+
provider_store_unavailable: instance.tx('Provider settings could not be read or saved. Check the local service and retry.', '无法读取或保存模型服务设置,请检查本机服务后重试。'),
|
|
693
|
+
provider_store_corrupt: instance.tx('Stored provider settings are inconsistent or invalid. Repair the local configuration before retrying.', '已存储的模型服务设置不一致或无效,请修复本机配置后重试。'),
|
|
694
|
+
provider_not_found: instance.tx('The selected provider no longer exists. Refresh the provider list.', '所选模型服务已不存在,请刷新服务列表。'),
|
|
695
|
+
provider_dns_failed: instance.tx('The provider hostname could not be resolved. Check the endpoint and network.', '无法解析模型服务域名,请检查端点和网络。'),
|
|
696
|
+
provider_tls_failed: instance.tx('A secure connection to the provider could not be established. Check the endpoint certificate.', '无法与模型服务建立安全连接,请检查端点证书。'),
|
|
697
|
+
provider_rate_limited: instance.tx('The provider is rate limiting requests. Retry later.', '模型服务已限制请求频率,请稍后重试。'),
|
|
698
|
+
provider_model_not_configured: instance.tx('The selected model is not configured for this provider.', '当前模型服务未配置所选模型。'),
|
|
699
|
+
provider_selection_unavailable: instance.tx('The selected provider or model is unavailable. Review the project selection.', '所选模型服务或模型不可用,请检查当前项目的选择。'),
|
|
700
|
+
provider_disclosure_required: instance.tx('Confirm the provider endpoint before activation.', '启用前请确认模型服务端点。'),
|
|
701
|
+
provider_secret_invalid: instance.tx('The API key change could not be accepted. Review the key settings.', '无法接受此次 API 密钥变更,请检查密钥设置。'),
|
|
702
|
+
provider_model_catalog_unavailable: instance.tx('The provider model catalog could not be loaded. Retry shortly.', '无法加载模型服务的模型目录,请稍后重试。'),
|
|
703
|
+
native_unavailable: instance.tx('The local service is unavailable. Check the Native Host connection.', '本机服务不可用,请检查 Native Host 连接。'),
|
|
704
|
+
provider_request_failed: instance.tx('The provider operation failed. Review the settings and retry.', '模型服务操作失败,请检查设置后重试。')
|
|
705
|
+
});
|
|
668
706
|
return messages[code] || error?.message || instance.tx('Provider operation failed.', '模型服务操作失败。');
|
|
669
707
|
}
|
|
670
708
|
|
|
@@ -47,10 +47,16 @@
|
|
|
47
47
|
if (!Profiles) {
|
|
48
48
|
throw new Error('Provider settings dialog requires provider profiles.');
|
|
49
49
|
}
|
|
50
|
+
const translations = new Map();
|
|
51
|
+
const translate = options.tx || (english => english);
|
|
50
52
|
const instance = {
|
|
51
53
|
Profiles,
|
|
52
54
|
document: options.document || document,
|
|
53
|
-
tx:
|
|
55
|
+
tx: (english, chinese) => {
|
|
56
|
+
translations.set(english, [english, chinese]); translations.set(chinese, [english, chinese]);
|
|
57
|
+
return translate(english, chinese);
|
|
58
|
+
},
|
|
59
|
+
translateStatusText: text => translations.has(text) ? translate(...translations.get(text)) : options.translateStatusText?.(text) || text,
|
|
54
60
|
callbacks: options.callbacks || {},
|
|
55
61
|
catalog: Profiles.normalizeCatalog({}),
|
|
56
62
|
selectedId: 'builtin',
|
|
@@ -83,6 +89,7 @@
|
|
|
83
89
|
setVerification: verification => setVerification(instance, verification),
|
|
84
90
|
setVerificationFailure: failure => setVerificationFailure(instance, failure),
|
|
85
91
|
setTestProgress: progress => setTestProgress(instance, progress),
|
|
92
|
+
refreshLocale: () => refreshLocale(instance),
|
|
86
93
|
hasUnsavedChanges: () => instance.dirty || Boolean(instance.modelEditor || instance.confirmation),
|
|
87
94
|
isOpen: () => Boolean(instance.root && !instance.root.hidden),
|
|
88
95
|
destroy: () => destroy(instance),
|
|
@@ -245,6 +252,7 @@
|
|
|
245
252
|
|
|
246
253
|
function render(instance) {
|
|
247
254
|
const tx = instance.tx;
|
|
255
|
+
instance.root.querySelector('[data-provider-action="close"]')?.setAttribute('aria-label', tx('Close', '关闭'));
|
|
248
256
|
const reload = instance.root.querySelector('[data-provider-action="reload"]');
|
|
249
257
|
if (reload) {
|
|
250
258
|
reload.hidden = !instance.embedded;
|
|
@@ -292,6 +300,45 @@
|
|
|
292
300
|
+ escapeHtml(tx('Add provider', '添加模型服务')) + '</button>';
|
|
293
301
|
}
|
|
294
302
|
|
|
303
|
+
// Render a detached reference, then change only owned copy in the live DOM.
|
|
304
|
+
// Inputs, focus, selection, modal ownership, listeners and secret values stay put.
|
|
305
|
+
function refreshLocale(instance) {
|
|
306
|
+
if (!instance.root || instance.root.hidden) return;
|
|
307
|
+
const reference = { ...instance, root: instance.root.cloneNode(true) };
|
|
308
|
+
if (instance.root.querySelector('[data-provider-field="name"]')) reference.draft = readContext(instance).draft;
|
|
309
|
+
render(reference);
|
|
310
|
+
if (instance.modelEditor) openModelEditor(reference, instance.modelEditor.id, { show: false });
|
|
311
|
+
patchLocaleCopy(instance.root, reference.root);
|
|
312
|
+
if (instance.lastStatus) setStatus(instance, instance.lastStatus);
|
|
313
|
+
const confirmation = instance.root.querySelector('[data-provider-confirmation]');
|
|
314
|
+
if (instance.confirmation && confirmation) {
|
|
315
|
+
for (const node of confirmation.querySelectorAll('h3, p, button')) node.textContent = instance.translateStatusText(node.textContent);
|
|
316
|
+
}
|
|
317
|
+
const secret = instance.root.querySelector('[data-provider-field="apiKey"]');
|
|
318
|
+
const toggle = instance.root.querySelector('[data-provider-action="toggle-secret"]');
|
|
319
|
+
if (toggle) toggle.textContent = instance.tx(secret?.type === 'text' ? 'Hide' : 'Show', secret?.type === 'text' ? '隐藏' : '显示');
|
|
320
|
+
refreshTestState(instance); updateDisclosureText(instance);
|
|
321
|
+
if (instance.modelEditor) {
|
|
322
|
+
updateModelReasoningSummary(instance);
|
|
323
|
+
const error = instance.root.querySelector('[data-model-error]');
|
|
324
|
+
if (error && instance.modelEditor.error) error.textContent = formatModelEditorError(instance, instance.modelEditor.error);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function patchLocaleCopy(current, reference) {
|
|
329
|
+
if (!current || !reference || current.nodeType !== reference.nodeType) return;
|
|
330
|
+
if (current.nodeType === 3) { if (current.nodeValue !== reference.nodeValue) current.nodeValue = reference.nodeValue; return; }
|
|
331
|
+
if (current.nodeType !== 1 || current.tagName !== reference.tagName) return;
|
|
332
|
+
for (const attr of ['title', 'aria-label', 'placeholder']) {
|
|
333
|
+
const next = reference.getAttribute(attr);
|
|
334
|
+
if (next !== null && current.getAttribute(attr) !== next) current.setAttribute(attr, next);
|
|
335
|
+
}
|
|
336
|
+
if (['INPUT', 'TEXTAREA'].includes(current.tagName)) return;
|
|
337
|
+
const actual = current.childNodes, expected = reference.childNodes;
|
|
338
|
+
if (actual.length !== expected.length) return;
|
|
339
|
+
for (let index = 0; index < actual.length; index++) patchLocaleCopy(actual[index], expected[index]);
|
|
340
|
+
}
|
|
341
|
+
|
|
295
342
|
function renderDetail(instance) {
|
|
296
343
|
const detail = instance.root.querySelector('[data-provider-detail]');
|
|
297
344
|
if (instance.templatePicker) { renderTemplatePicker(instance, detail); return; }
|
|
@@ -303,6 +350,10 @@
|
|
|
303
350
|
const tx = instance.tx;
|
|
304
351
|
const draft = instance.draft || provider;
|
|
305
352
|
const active = provider.id && provider.id === getCurrentProjectProviderId(instance);
|
|
353
|
+
const profileStatus = !provider.id
|
|
354
|
+
? tx('Unsaved provider profile', '尚未保存的模型服务配置')
|
|
355
|
+
: active ? tx('Used by new runs in this project', '当前项目的新任务将使用此服务')
|
|
356
|
+
: tx('Saved provider profile', '已保存的模型服务配置');
|
|
306
357
|
const acceptedHost = getEndpointHost(draft.baseUrl);
|
|
307
358
|
const secretSavedAt = formatSecretSavedAt(instance, provider.secretUpdatedAt);
|
|
308
359
|
const disclosureSatisfied = Boolean(
|
|
@@ -314,7 +365,7 @@
|
|
|
314
365
|
<div class="codex-provider-detail-titleline">
|
|
315
366
|
<div>
|
|
316
367
|
<h3>${escapeHtml(draft.name || tx('Custom provider', '自定义模型服务'))}</h3>
|
|
317
|
-
<p>${escapeHtml(
|
|
368
|
+
<p>${escapeHtml(profileStatus)}</p>
|
|
318
369
|
</div>
|
|
319
370
|
${active ? `<span class="codex-provider-active-badge">${escapeHtml(tx('Current project', '当前项目'))}</span>` : ''}
|
|
320
371
|
</div>
|
|
@@ -444,12 +495,12 @@
|
|
|
444
495
|
<small>${escapeHtml(tx('Vendor-specific fields only; core model, messages, tools, and stream fields are protected.', '仅填写服务商特有字段;model、messages、tools 和 stream 等核心字段不可覆盖。'))}</small>
|
|
445
496
|
</label>
|
|
446
497
|
<label class="codex-provider-field">
|
|
447
|
-
<span
|
|
498
|
+
<span>${escapeHtml(tx('Anthropic version', 'Anthropic 版本'))}</span>
|
|
448
499
|
<input type="text" data-provider-field="anthropicVersion" value="${escapeAttr(draft.anthropicVersion || '2023-06-01')}" spellcheck="false">
|
|
449
500
|
</label>
|
|
450
501
|
<label class="codex-provider-field">
|
|
451
502
|
<span>Anthropic beta</span>
|
|
452
|
-
<input type="text" data-provider-field="anthropicBeta" value="${escapeAttr(draft.anthropicBeta || '')}" placeholder="optional" spellcheck="false">
|
|
503
|
+
<input type="text" data-provider-field="anthropicBeta" value="${escapeAttr(draft.anthropicBeta || '')}" placeholder="${escapeAttr(tx('optional', '可选'))}" spellcheck="false">
|
|
453
504
|
</label>
|
|
454
505
|
<label class="codex-provider-field">
|
|
455
506
|
<span>${escapeHtml(tx('Anthropic thinking mode', 'Anthropic 思考模式'))}</span>
|
|
@@ -910,6 +961,7 @@
|
|
|
910
961
|
,anthropicPromptCaching: Boolean(get('anthropicPromptCaching')?.checked)
|
|
911
962
|
,impersonateClaudeCode: Boolean(get('impersonateClaudeCode')?.checked)
|
|
912
963
|
,maxOutputTokens: Number(get('maxOutputTokens')?.value || 65536)
|
|
964
|
+
,outputBudgetVersion: 1
|
|
913
965
|
};
|
|
914
966
|
const apiKey = String(get('apiKey')?.value || '');
|
|
915
967
|
const secretMutation = instance.secretAction === 'replace' && apiKey
|
|
@@ -992,9 +1044,10 @@
|
|
|
992
1044
|
}
|
|
993
1045
|
|
|
994
1046
|
function setStatus(instance, status = {}) {
|
|
1047
|
+
instance.lastStatus = status;
|
|
995
1048
|
const element = instance.root.querySelector('[data-provider-status]');
|
|
996
1049
|
element.dataset.tone = status.tone || '';
|
|
997
|
-
element.textContent = [status.title, status.detail].filter(Boolean).join(' ');
|
|
1050
|
+
element.textContent = [status.title, status.detail].filter(Boolean).map(text => instance.translateStatusText?.(text) || text).join(' ');
|
|
998
1051
|
}
|
|
999
1052
|
|
|
1000
1053
|
function setVerification(instance, verification = {}) {
|
|
@@ -1243,7 +1296,8 @@
|
|
|
1243
1296
|
|
|
1244
1297
|
function renderTemplatePicker(instance, detail) {
|
|
1245
1298
|
const tx = instance.tx;
|
|
1246
|
-
detail.innerHTML = '<div class="codex-provider-template-head"><button type="button" class="codex-provider-inline-button" data-provider-action="templates-back">'
|
|
1299
|
+
detail.innerHTML = '<div class="codex-provider-template-head"><button type="button" class="codex-provider-inline-button codex-provider-back-button" data-provider-action="templates-back">'
|
|
1300
|
+
+ '<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="m9.8 3.6-4.4 4.4 4.4 4.4"/></svg>'
|
|
1247
1301
|
+ escapeHtml(tx('Back', '返回')) + '</button><h3>' + escapeHtml(tx('Add a connection', '添加连接')) + '</h3></div>'
|
|
1248
1302
|
+ '<p class="codex-provider-help">' + escapeHtml(tx(
|
|
1249
1303
|
'Service shortcuts default to Anthropic Messages. Chat Completions remains available; preset addresses follow the selected protocol. Add the matching API key and model IDs separately.',
|
|
@@ -1379,7 +1433,7 @@
|
|
|
1379
1433
|
}
|
|
1380
1434
|
}
|
|
1381
1435
|
|
|
1382
|
-
function openModelEditor(instance, id) {
|
|
1436
|
+
function openModelEditor(instance, id, options = {}) {
|
|
1383
1437
|
const provider = readContext(instance).draft;
|
|
1384
1438
|
const existing = provider.models.find(model => model.id === id);
|
|
1385
1439
|
if (id && !existing) return;
|
|
@@ -1450,7 +1504,7 @@
|
|
|
1450
1504
|
+ escapeHtml(tx('Cancel', '取消')) + '</button><button type="button" class="codex-provider-primary-button" data-provider-model-action="apply-editor">'
|
|
1451
1505
|
+ escapeHtml(id ? tx('Apply', '应用') : tx('Add model', '添加模型')) + '</button></footer>';
|
|
1452
1506
|
updateModelReasoningSummary(instance);
|
|
1453
|
-
if (modal.showModal) modal.showModal(); else modal.setAttribute('open', '');
|
|
1507
|
+
if (options.show !== false) { if (modal.showModal) modal.showModal(); else modal.setAttribute('open', ''); }
|
|
1454
1508
|
}
|
|
1455
1509
|
|
|
1456
1510
|
function updateModelReasoningSummary(instance) {
|
|
@@ -1499,16 +1553,21 @@
|
|
|
1499
1553
|
closeModelEditor(instance, false);
|
|
1500
1554
|
if (!unchanged) replaceModelDraft(instance, next);
|
|
1501
1555
|
} catch (error) {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
contextWindow: instance.tx(error.message, '上下文窗口必须为 8192 至 4000000 之间的整数。'),
|
|
1505
|
-
maxOutputTokens: instance.tx(error.message, '输出上限须为 256 至 65536 之间的整数,并小于上下文窗口。')
|
|
1506
|
-
};
|
|
1507
|
-
modal.querySelector('[data-model-error]').textContent = translated[error.field] || error.message;
|
|
1556
|
+
editor.error = { field: error.field, message: error.message };
|
|
1557
|
+
modal.querySelector('[data-model-error]').textContent = formatModelEditorError(instance, editor.error);
|
|
1508
1558
|
if (error.field) get(error.field)?.focus();
|
|
1509
1559
|
}
|
|
1510
1560
|
}
|
|
1511
1561
|
|
|
1562
|
+
function formatModelEditorError(instance, error) {
|
|
1563
|
+
const chinese = {
|
|
1564
|
+
id: '请检查模型 ID:必填、最多 200 字符、不可重复,且单个服务最多 32 个模型。',
|
|
1565
|
+
contextWindow: '上下文窗口必须为 8192 至 4000000 之间的整数。',
|
|
1566
|
+
maxOutputTokens: '输出上限须为 256 至 65536 之间的整数,并小于上下文窗口。'
|
|
1567
|
+
}[error.field];
|
|
1568
|
+
return chinese ? instance.tx(error.message, chinese) : error.message;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1512
1571
|
function validateConnectionForm(instance) {
|
|
1513
1572
|
const context = readContext(instance), tx = instance.tx;
|
|
1514
1573
|
let message = '';
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
ProjectSessionCleanup, SessionPersistence, SessionState, StorageDb, StorageKeys, StorageMigration
|
|
22
22
|
} = deps;
|
|
23
23
|
const projectSessionCleanup = ProjectSessionCleanup.create({
|
|
24
|
-
tr, getAccountScopeId: getCachedAccountScopeId, showPluginConfirm, showPluginToast,
|
|
24
|
+
tr, tx, getAccountScopeId: getCachedAccountScopeId, showPluginConfirm, showPluginToast,
|
|
25
|
+
getViewGeneration: () => dashboardRenderGeneration,
|
|
25
26
|
sendBackgroundNative, mutateProjectPanelState, renderRecentProjectsVariant,
|
|
26
27
|
SessionState, StorageDb, StorageMigration
|
|
27
28
|
});
|
|
@@ -198,10 +199,11 @@
|
|
|
198
199
|
} catch (_error) { /* swallow */ }
|
|
199
200
|
try {
|
|
200
201
|
var docTitle = (document.title || '').trim();
|
|
201
|
-
// Overleaf
|
|
202
|
-
// "<Project Name> - Online LaTeX Editor";
|
|
202
|
+
// Overleaf formats the title as "<Project Name> - Overleaf" or
|
|
203
|
+
// "<Project Name> - Online LaTeX Editor Overleaf" (localized); drop the
|
|
204
|
+
// last " - " segment when it names Overleaf.
|
|
203
205
|
if (docTitle) {
|
|
204
|
-
var stripped = docTitle.replace(/\s
|
|
206
|
+
var stripped = docTitle.replace(/\s+[-–|]\s+[^-–|]*Overleaf[^-–|]*$/i, '').trim();
|
|
205
207
|
if (stripped && stripped.toLowerCase() !== 'overleaf') {
|
|
206
208
|
return stripped;
|
|
207
209
|
}
|
|
@@ -492,6 +494,7 @@
|
|
|
492
494
|
// Kept as a compatibility entry point and as the recovery path for invalid project links.
|
|
493
495
|
function renderRecentProjectRow(row) {
|
|
494
496
|
var projectId = row && row.projectId;
|
|
497
|
+
var cleanupScope = { accountScopeId: getCachedAccountScopeId(), generation: dashboardRenderGeneration };
|
|
495
498
|
var valid = isValidProjectId(projectId);
|
|
496
499
|
var wrap = createViewElement('div', 'recent-projects-row-wrap recent-projects-unavailable-row');
|
|
497
500
|
wrap.setAttribute('data-project-id', projectId || '');
|
|
@@ -501,7 +504,7 @@
|
|
|
501
504
|
link.appendChild(textNode(projectDisplayName(projectId), 'recent-projects-row-name'));
|
|
502
505
|
if (valid) link.addEventListener('click', function () { openProjectFromRow(projectId); });
|
|
503
506
|
var cleanup = createViewButton(tr(valid ? 'recentProjects_clearProject' : 'recentProjects_cleanup'), function () {
|
|
504
|
-
if (valid) projectSessionCleanup.clearProjectSessions(projectId, projectDisplayName(projectId)).catch(function () {});
|
|
507
|
+
if (valid) projectSessionCleanup.clearProjectSessions(projectId, projectDisplayName(projectId), cleanupScope).catch(function () {});
|
|
505
508
|
else cleanupDeadProjectEntry(projectId).catch(function () {});
|
|
506
509
|
}, valid ? 'data-project-clear' : 'data-row-cleanup');
|
|
507
510
|
wrap.appendChild(link);
|
|
@@ -533,6 +536,7 @@
|
|
|
533
536
|
}
|
|
534
537
|
|
|
535
538
|
function renderProjectSessionRow(sessionsEl, projectId, record, options) {
|
|
539
|
+
var cleanupScope = { accountScopeId: getCachedAccountScopeId(), generation: dashboardRenderGeneration };
|
|
536
540
|
var featured = Boolean(options && options.featured);
|
|
537
541
|
var running = Boolean(StorageDb)
|
|
538
542
|
&& settleDashboardRunStatus(StorageDb.derivePrimaryStatusBadge(record), record.updatedAt || record.lastActivityAt) === 'running';
|
|
@@ -586,7 +590,7 @@
|
|
|
586
590
|
}, 'data-project-conversations');
|
|
587
591
|
var openProject = createViewButton(tr('recentProjects_openProject'), function () { openProjectFromRow(projectId); });
|
|
588
592
|
var clear = createViewButton(tr('recentProjects_clearProject'), function () {
|
|
589
|
-
projectSessionCleanup.clearProjectSessions(projectId, projectDisplayName(projectId)).catch(function () {});
|
|
593
|
+
projectSessionCleanup.clearProjectSessions(projectId, projectDisplayName(projectId), cleanupScope).catch(function () {});
|
|
590
594
|
}, 'data-project-clear');
|
|
591
595
|
row.appendChild(renderActionsMenu([rename, del, projectConversations, openProject, clear]));
|
|
592
596
|
|
|
@@ -697,9 +701,10 @@
|
|
|
697
701
|
// saveState uses, so opening the project later sees a coherent state.
|
|
698
702
|
// NOTE: if the project is open in another tab, that tab's in-memory state
|
|
699
703
|
// wins on its next save; the IndexedDB record mutation below still holds.
|
|
700
|
-
async function mutateProjectPanelState(projectId, mutate) {
|
|
704
|
+
async function mutateProjectPanelState(projectId, mutate, options = {}) {
|
|
701
705
|
var key = projectPanelStateKey(projectId);
|
|
702
706
|
var stored = await chrome.storage.local.get(key);
|
|
707
|
+
options.assertCurrent?.();
|
|
703
708
|
var blob = stored && stored[key];
|
|
704
709
|
if (!blob || !SessionState) {
|
|
705
710
|
return false;
|
|
@@ -707,7 +712,9 @@
|
|
|
707
712
|
var nextState = mutate(SessionState.normalizePanelState(blob));
|
|
708
713
|
var payload = {};
|
|
709
714
|
payload[key] = SessionState.prepareStateForStorage(nextState);
|
|
715
|
+
options.assertCurrent?.();
|
|
710
716
|
await chrome.storage.local.set(payload);
|
|
717
|
+
options.assertCurrent?.();
|
|
711
718
|
return true;
|
|
712
719
|
}
|
|
713
720
|
|
|
@@ -752,7 +759,7 @@
|
|
|
752
759
|
}
|
|
753
760
|
});
|
|
754
761
|
if (!response || !response.ok) {
|
|
755
|
-
showPluginToast(tr('deleteSessionHistoryFailedToast', { message: (response && response.error && response.error.message) || '
|
|
762
|
+
showPluginToast(tr('deleteSessionHistoryFailedToast', { message: (response && response.error && response.error.message) || tr('deleteSessionNativeFailureDetail') }), { status: 'warning', sticky: true });
|
|
756
763
|
} else if (response.result && response.result.skipped) {
|
|
757
764
|
showPluginToast(tr('deleteSessionNoThreadToast'), { status: 'info' });
|
|
758
765
|
} else {
|