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
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
plus: '<path d="M8 3.2v9.6"/><path d="M3.2 8h9.6"/>',
|
|
13
13
|
panel: '<rect x="2.3" y="2.3" width="11.4" height="11.4" rx="2"/><path d="M9.2 2.5v11"/><path d="M5.1 6.1h1.5M5.1 8h1.5M5.1 9.9h1.5"/>',
|
|
14
14
|
collapse: '<path d="m6.1 3.3 4.7 4.7-4.7 4.7"/>',
|
|
15
|
+
chevronDown: '<path d="m4.4 6.4 3.6 3.6 3.6-3.6"/>',
|
|
15
16
|
settings: '<path d="M3.4 5.2h5.9"/><path d="M11.7 5.2h.9"/><path d="M10.1 3.6v3.2"/><path d="M3.4 10.8h1"/><path d="M6.8 10.8h5.8"/><path d="M5.9 9.2v3.2"/>'
|
|
16
17
|
};
|
|
17
18
|
const safeName = Object.prototype.hasOwnProperty.call(icons, name) ? name : 'settings';
|
|
@@ -53,8 +54,15 @@
|
|
|
53
54
|
<div class="codex-panel-resize-handle" data-panel-resize-handle title="Drag to resize the Codex panel. Double click to reset." aria-label="Drag to resize the Codex panel. Double click to reset." role="separator"></div>
|
|
54
55
|
<div class="codex-vscode-head" data-panel-header>
|
|
55
56
|
<div class="codex-vscode-title">CODEX</div>
|
|
57
|
+
<div class="codex-thread-title codex-head-session" data-session-label>
|
|
58
|
+
<button type="button" class="codex-thread-title-trigger" data-session-menu-trigger aria-haspopup="menu" aria-expanded="false">
|
|
59
|
+
<span class="codex-thread-title-text" data-session-label-text></span>
|
|
60
|
+
<span class="codex-thread-title-chevron">${codexIcon('chevronDown')}</span>
|
|
61
|
+
</button>
|
|
62
|
+
<input type="text" class="codex-thread-title-input" data-session-rename-input maxlength="80" hidden>
|
|
63
|
+
<div class="codex-session-menu" data-session-menu role="menu" hidden></div>
|
|
64
|
+
</div>
|
|
56
65
|
<div class="codex-vscode-head-actions" aria-label="Codex actions">
|
|
57
|
-
<button type="button" data-refresh title="Refresh current file status. This will not sync or modify files." aria-label="Refresh current file status. This will not sync or modify files.">${codexIcon('refresh')}</button>
|
|
58
66
|
<div data-diagnostics-slot></div>
|
|
59
67
|
<button type="button" data-new-session title="New Session" aria-label="New Session">${codexIcon('plus')}</button>
|
|
60
68
|
<button type="button" data-custom-instructions-settings title="Project Settings" aria-label="Project Settings" aria-expanded="false">${codexIcon('settings')}</button>
|
|
@@ -86,7 +94,6 @@
|
|
|
86
94
|
|
|
87
95
|
bind(instance, panelEl, 'click', event => event.stopPropagation());
|
|
88
96
|
bind(instance, panelEl, 'mousedown', event => event.stopPropagation());
|
|
89
|
-
bind(instance, panelEl.querySelector('[data-refresh]'), 'click', () => callbacks.onRefresh?.());
|
|
90
97
|
bind(instance, panelEl.querySelector('[data-new-session]'), 'click', () => callbacks.onNewSession?.());
|
|
91
98
|
bind(instance, panelEl.querySelector('[data-custom-instructions-settings]'), 'click', () => callbacks.onSettingsClick?.());
|
|
92
99
|
bind(instance, panelEl.querySelector('[data-close-panel]'), 'click', () => callbacks.onClosePanel?.());
|
|
@@ -117,6 +124,12 @@
|
|
|
117
124
|
sessionSlot: instance.sessionSlot,
|
|
118
125
|
composerSlot: instance.composerSlot,
|
|
119
126
|
setView: view => { panelEl.dataset.view = view; },
|
|
127
|
+
setLocale: labels => {
|
|
128
|
+
launcherEl.title = labels.launcher;
|
|
129
|
+
launcherEl.setAttribute('aria-label', labels.launcher);
|
|
130
|
+
const close = panelEl.querySelector('[data-close-panel]');
|
|
131
|
+
if (close) { close.title = labels.close; close.setAttribute('aria-label', labels.close); }
|
|
132
|
+
},
|
|
120
133
|
destroy: () => destroy(instance),
|
|
121
134
|
_instance: instance
|
|
122
135
|
};
|
|
@@ -314,7 +327,7 @@
|
|
|
314
327
|
}
|
|
315
328
|
const panel = options.getPanel?.();
|
|
316
329
|
if (!panel) {
|
|
317
|
-
return Promise.resolve(false);
|
|
330
|
+
return Promise.resolve(config.choices?.length ? 'cancel' : false);
|
|
318
331
|
}
|
|
319
332
|
dismiss(false);
|
|
320
333
|
const tr = options.tr || (key => key);
|
|
@@ -323,6 +336,8 @@
|
|
|
323
336
|
const confirmLabel = config.confirmLabel || tr('confirmDefaultConfirm');
|
|
324
337
|
const cancelLabel = config.cancelLabel || tr('confirmDefaultCancel');
|
|
325
338
|
const destructive = config.destructive === true;
|
|
339
|
+
const choices = Array.isArray(config.choices) && config.choices.length ? config.choices : null;
|
|
340
|
+
const cancelled = choices ? 'cancel' : false;
|
|
326
341
|
const doc = panel.ownerDocument || document;
|
|
327
342
|
|
|
328
343
|
return new Promise(resolve => {
|
|
@@ -363,54 +378,69 @@
|
|
|
363
378
|
body.textContent = String(message);
|
|
364
379
|
const actions = doc.createElement('div');
|
|
365
380
|
actions.className = 'codex-plugin-confirm-actions';
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
381
|
+
const buttons = (choices || [
|
|
382
|
+
{ value: false, label: cancelLabel }, { value: true, label: confirmLabel }
|
|
383
|
+
]).map(choice => {
|
|
384
|
+
const button = doc.createElement('button');
|
|
385
|
+
button.type = 'button';
|
|
386
|
+
const cancel = choice.value === false || choice.value === 'cancel';
|
|
387
|
+
// Only one primary action: other affirmative choices can ask for the secondary style.
|
|
388
|
+
button.className = cancel || choice.secondary === true ? 'codex-plugin-confirm-cancel' : 'codex-plugin-confirm-confirm';
|
|
389
|
+
if (destructive && !cancel) button.dataset.destructive = 'true';
|
|
390
|
+
button.textContent = choice.label;
|
|
391
|
+
button.addEventListener('click', () => cleanup(choice.value));
|
|
392
|
+
actions.append(button);
|
|
393
|
+
return button;
|
|
394
|
+
});
|
|
376
395
|
card.append(head, body, actions);
|
|
377
396
|
overlay.append(card);
|
|
378
397
|
panel.append(overlay);
|
|
379
398
|
overlay.showModal?.();
|
|
380
399
|
|
|
400
|
+
let timeout, ownerCheck, removalObserver;
|
|
401
|
+
const onAbort = () => cleanup(cancelled);
|
|
381
402
|
const cleanup = value => {
|
|
382
403
|
if (settled) return;
|
|
383
404
|
settled = true;
|
|
384
405
|
activeResolve = null;
|
|
385
406
|
doc.removeEventListener('keydown', onKeydown, true);
|
|
407
|
+
config.signal?.removeEventListener('abort', onAbort);
|
|
408
|
+
clearTimeout(timeout);
|
|
409
|
+
clearInterval(ownerCheck);
|
|
410
|
+
removalObserver?.disconnect();
|
|
386
411
|
overlay.close?.();
|
|
387
412
|
overlay.remove();
|
|
388
413
|
returnFocus?.focus?.();
|
|
389
|
-
resolve(value);
|
|
414
|
+
resolve(choices && !choices.some(choice => choice.value === value) ? cancelled : value);
|
|
390
415
|
};
|
|
391
416
|
activeResolve = cleanup;
|
|
392
417
|
const onKeydown = event => {
|
|
393
418
|
if (event.key === 'Escape') {
|
|
394
|
-
event.preventDefault();
|
|
395
|
-
cleanup(false);
|
|
419
|
+
event.preventDefault(); cleanup(cancelled);
|
|
396
420
|
} else if (event.key === 'Enter') {
|
|
397
421
|
event.preventDefault();
|
|
398
|
-
if (
|
|
399
|
-
else if (
|
|
400
|
-
else if (event.target === confirm) cleanup(true);
|
|
422
|
+
if (buttons.includes(event.target)) event.target.click();
|
|
423
|
+
else if (!choices && !destructive) cleanup(true);
|
|
401
424
|
} else if (event.key === 'Tab') {
|
|
402
425
|
event.preventDefault();
|
|
403
|
-
|
|
426
|
+
const index = buttons.indexOf(event.target);
|
|
427
|
+
buttons[(index + (event.shiftKey ? buttons.length - 1 : 1)) % buttons.length].focus();
|
|
404
428
|
}
|
|
405
429
|
};
|
|
406
|
-
overlay.addEventListener('click', event => {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
overlay.addEventListener('cancel', event => { event.preventDefault(); cleanup(false); });
|
|
410
|
-
cancel.addEventListener('click', () => cleanup(false));
|
|
411
|
-
confirm.addEventListener('click', () => cleanup(true));
|
|
430
|
+
overlay.addEventListener('click', event => { if (event.target === overlay) cleanup(cancelled); });
|
|
431
|
+
overlay.addEventListener('cancel', event => { event.preventDefault(); cleanup(cancelled); });
|
|
432
|
+
overlay.addEventListener('close', () => cleanup(cancelled));
|
|
412
433
|
doc.addEventListener('keydown', onKeydown, true);
|
|
413
|
-
(
|
|
434
|
+
config.signal?.addEventListener('abort', onAbort, { once: true });
|
|
435
|
+
if (config.timeoutMs > 0) timeout = setTimeout(onAbort, config.timeoutMs);
|
|
436
|
+
if (config.isCurrent) ownerCheck = setInterval(() => { if (!config.isCurrent()) onAbort(); }, 100);
|
|
437
|
+
const Observer = doc.defaultView?.MutationObserver;
|
|
438
|
+
if (choices && Observer) {
|
|
439
|
+
removalObserver = new Observer(() => { if (!overlay.isConnected) onAbort(); });
|
|
440
|
+
removalObserver.observe(panel, { childList: true });
|
|
441
|
+
}
|
|
442
|
+
(choices ? buttons[0] : buttons[destructive ? 0 : 1]).focus();
|
|
443
|
+
if (config.signal?.aborted || config.isCurrent?.() === false) onAbort();
|
|
414
444
|
});
|
|
415
445
|
}
|
|
416
446
|
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
// Pull a queued message back into the composer. A typed draft is never overwritten.
|
|
116
116
|
function pullBack(item) {
|
|
117
117
|
const task = container?.parentElement?.querySelector('[data-task]');
|
|
118
|
-
if (!task || (item.status || 'queued') !== 'queued') return;
|
|
118
|
+
if (!task || task.readOnly || (item.status || 'queued') !== 'queued') return;
|
|
119
119
|
if (String(task.value || '').trim()) { options.onToast?.(tr('queuedInputEditBlocked')); return; }
|
|
120
120
|
options.onRemove?.(item.id);
|
|
121
121
|
task.value = item.text;
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
function create(deps = {}) {
|
|
5
|
-
|
|
5
|
+
function assertSwitchAllowed() {
|
|
6
6
|
if ((deps.getRunningSessionIds?.() || []).length) {
|
|
7
|
-
|
|
7
|
+
throw Object.assign(new Error(deps.tx(
|
|
8
8
|
'Wait for the running task to finish before switching providers.',
|
|
9
9
|
'请等待正在运行的任务结束后再切换模型服务。'
|
|
10
|
-
), {
|
|
10
|
+
)), { code: 'provider_switch_running' });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function confirmSwitch({ providerName } = {}) {
|
|
15
|
+
try {
|
|
16
|
+
assertSwitchAllowed();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
deps.showToast?.(error.message, { status: 'warning' });
|
|
11
19
|
return false;
|
|
12
20
|
}
|
|
13
21
|
return deps.showConfirm?.({
|
|
@@ -33,6 +41,7 @@
|
|
|
33
41
|
const providerConfigurationChanged = nextProviderId === (state.providerId || 'builtin')
|
|
34
42
|
&& nextProviderRevision !== Number(state.providerRevision || 0);
|
|
35
43
|
const resetProviderThread = providerChanged || providerConfigurationChanged;
|
|
44
|
+
if (resetProviderThread) assertSwitchAllowed();
|
|
36
45
|
const sessions = (state.sessions || []).map(session => ({
|
|
37
46
|
...session,
|
|
38
47
|
providerId: nextProviderId,
|
|
@@ -53,7 +62,7 @@
|
|
|
53
62
|
deps.applyStateToPanel?.();
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
return { confirmSwitch, commit };
|
|
65
|
+
return { assertSwitchAllowed, confirmSwitch, commit };
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
window.CodexOverleafProjectProviderSelection = { create };
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
function create(deps = {}) {
|
|
7
7
|
const {
|
|
8
8
|
tr,
|
|
9
|
+
tx = en => en,
|
|
9
10
|
getAccountScopeId,
|
|
10
11
|
showPluginConfirm,
|
|
11
12
|
showPluginToast,
|
|
@@ -22,79 +23,125 @@
|
|
|
22
23
|
return !Number.isFinite(touched) || (Date.now() - touched) <= FRESH_RUNNING_WINDOW_MS;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
async function clearProjectSessions(projectId, projectName) {
|
|
26
|
+
async function clearProjectSessions(projectId, projectName, options = {}) {
|
|
26
27
|
const StorageDb = deps.StorageDb;
|
|
27
28
|
const SessionState = deps.SessionState;
|
|
28
29
|
if (!StorageDb || !SessionState) {
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
|
-
const scope = getAccountScopeId();
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
cancelLabel: tr('confirmDefaultCancel'),
|
|
47
|
-
destructive: true
|
|
48
|
-
});
|
|
49
|
-
if (!approved) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const Migration = deps.StorageMigration;
|
|
53
|
-
if (Migration?.addSessionTombstones) {
|
|
54
|
-
await Migration.addSessionTombstones(projectId, records.map(record => record.id));
|
|
55
|
-
}
|
|
32
|
+
const scope = options.accountScopeId ?? getAccountScopeId();
|
|
33
|
+
const scopeChanged = error => error?.code === 'history_cleanup_scope_changed'
|
|
34
|
+
|| error?.code === 'account_scope_unavailable';
|
|
35
|
+
const assertCurrent = () => {
|
|
36
|
+
if (!scope || getAccountScopeId() !== scope || options.isCurrent?.() === false
|
|
37
|
+
|| options.generation !== undefined && deps.getViewGeneration?.() !== options.generation) {
|
|
38
|
+
throw Object.assign(new Error('History cleanup identity changed.'), { code: 'history_cleanup_scope_changed' });
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const readRecords = async () => {
|
|
42
|
+
assertCurrent();
|
|
43
|
+
const records = await StorageDb.getAllByIndex('sessions', 'projectId', projectId);
|
|
44
|
+
assertCurrent();
|
|
45
|
+
return records.filter(record => record && record.accountScopeId === scope);
|
|
46
|
+
};
|
|
56
47
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
48
|
+
let records = await readRecords();
|
|
49
|
+
if (!records.length) {
|
|
50
|
+
await renderRecentProjectsVariant();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (records.some(record => isFreshRunningRecord(StorageDb, record))) {
|
|
54
|
+
showPluginToast(tr('recentProjects_clearProject_running'), { status: 'warning', sticky: true });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const approved = await showPluginConfirm({
|
|
58
|
+
title: tr('recentProjects_clearProject_title', { project: projectName }),
|
|
59
|
+
message: tr('recentProjects_clearProject_message', { count: String(records.length), project: projectName }),
|
|
60
|
+
confirmLabel: tr('recentProjects_clearProject_confirm'),
|
|
61
|
+
cancelLabel: tr('confirmDefaultCancel'),
|
|
62
|
+
destructive: true
|
|
63
|
+
});
|
|
64
|
+
if (!approved) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Re-read after the destructive dialog: another tab can have started a
|
|
68
|
+
// run or added a conversation while the original count was displayed.
|
|
69
|
+
const approvedIds = new Set(records.map(record => record.id));
|
|
70
|
+
const latest = await readRecords();
|
|
71
|
+
if (latest.some(record => isFreshRunningRecord(StorageDb, record))) {
|
|
72
|
+
showPluginToast(tr('recentProjects_clearProject_running'), { status: 'warning', sticky: true });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
records = latest.filter(record => approvedIds.has(record.id));
|
|
76
|
+
if (!records.length) { await renderRecentProjectsVariant(); return; }
|
|
77
|
+
const Migration = deps.StorageMigration;
|
|
78
|
+
if (Migration?.addSessionTombstones) {
|
|
79
|
+
assertCurrent();
|
|
80
|
+
await Migration.addSessionTombstones(projectId, records.map(record => record.id));
|
|
81
|
+
assertCurrent();
|
|
82
|
+
}
|
|
70
83
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
assertCurrent();
|
|
85
|
+
await mutateProjectPanelState(projectId, state => records.reduce(
|
|
86
|
+
(nextState, record) => SessionState.deleteSession(nextState, record.id),
|
|
87
|
+
state
|
|
88
|
+
), { assertCurrent });
|
|
89
|
+
assertCurrent();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (scopeChanged(error)) throw error;
|
|
92
|
+
assertCurrent(); // Other legacy-blob failures do not replace shared deletion.
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let removed = 0;
|
|
96
|
+
let historyFailures = 0;
|
|
97
|
+
for (const record of records) {
|
|
98
|
+
try {
|
|
99
|
+
assertCurrent();
|
|
100
|
+
await StorageDb.deleteRecord('sessions', record.id, { accountScopeId: scope, projectId });
|
|
101
|
+
assertCurrent();
|
|
102
|
+
removed++;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (scopeChanged(error)) throw error;
|
|
105
|
+
assertCurrent(); // The remaining record can be retried in the same scope.
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
assertCurrent();
|
|
109
|
+
const response = await sendBackgroundNative({
|
|
110
|
+
method: 'codex.history.clearPlugin',
|
|
111
|
+
params: { sessionId: record.id, threadId: record.codexThreadId || '' }
|
|
112
|
+
});
|
|
113
|
+
assertCurrent();
|
|
114
|
+
if (!response || !response.ok) {
|
|
115
|
+
historyFailures++;
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (scopeChanged(error)) throw error;
|
|
119
|
+
assertCurrent();
|
|
76
120
|
historyFailures++;
|
|
77
121
|
}
|
|
78
|
-
} catch (_error) {
|
|
79
|
-
historyFailures++;
|
|
80
122
|
}
|
|
123
|
+
if (removed < records.length) {
|
|
124
|
+
showPluginToast(tr('recentProjects_clearProject_partial', {
|
|
125
|
+
removed: String(removed),
|
|
126
|
+
count: String(records.length)
|
|
127
|
+
}), { status: 'warning', sticky: true });
|
|
128
|
+
} else if (historyFailures) {
|
|
129
|
+
showPluginToast(tr('recentProjects_clearProject_historyPartial', {
|
|
130
|
+
count: String(historyFailures)
|
|
131
|
+
}), { status: 'warning', sticky: true });
|
|
132
|
+
} else {
|
|
133
|
+
showPluginToast(tr('recentProjects_clearProject_done', {
|
|
134
|
+
count: String(removed),
|
|
135
|
+
project: projectName
|
|
136
|
+
}), { status: 'completed' });
|
|
137
|
+
}
|
|
138
|
+
await renderRecentProjectsVariant();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (!scopeChanged(error)) throw error;
|
|
141
|
+
showPluginToast(tx('History view or account changed. Reopen the history list before deleting sessions.',
|
|
142
|
+
'历史视图或账号已变化,请重新打开历史列表后再清理会话。'), { status: 'warning', sticky: true });
|
|
143
|
+
return false;
|
|
81
144
|
}
|
|
82
|
-
if (removed < records.length) {
|
|
83
|
-
showPluginToast(tr('recentProjects_clearProject_partial', {
|
|
84
|
-
removed: String(removed),
|
|
85
|
-
count: String(records.length)
|
|
86
|
-
}), { status: 'warning', sticky: true });
|
|
87
|
-
} else if (historyFailures) {
|
|
88
|
-
showPluginToast(tr('recentProjects_clearProject_historyPartial', {
|
|
89
|
-
count: String(historyFailures)
|
|
90
|
-
}), { status: 'warning', sticky: true });
|
|
91
|
-
} else {
|
|
92
|
-
showPluginToast(tr('recentProjects_clearProject_done', {
|
|
93
|
-
count: String(removed),
|
|
94
|
-
project: projectName
|
|
95
|
-
}), { status: 'completed' });
|
|
96
|
-
}
|
|
97
|
-
await renderRecentProjectsVariant();
|
|
98
145
|
}
|
|
99
146
|
|
|
100
147
|
return { clearProjectSessions };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
(function initCodexOverleafProjectSettingsCoordinator() {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
// Skill messages belong to the settings workbench page that holds the Skills group.
|
|
5
|
+
const SKILLS_STATUS = Object.freeze({ page: 'context' });
|
|
6
|
+
|
|
4
7
|
function create(deps = {}) {
|
|
5
8
|
const {
|
|
6
9
|
CodexOverleafTheme,
|
|
@@ -100,7 +103,7 @@
|
|
|
100
103
|
refreshLocalSkills().catch(error => setProjectSettingsStatus(tx(
|
|
101
104
|
`Could not list local skills: ${error.message}`,
|
|
102
105
|
`无法列出本地技能:${error.message}`
|
|
103
|
-
), 'failed'));
|
|
106
|
+
), 'failed', SKILLS_STATUS));
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
function toggleCustomInstructionsSettings() {
|
|
@@ -128,7 +131,7 @@
|
|
|
128
131
|
refreshLocalSkills().catch(error => setProjectSettingsStatus(tx(
|
|
129
132
|
`Could not list local skills: ${error.message}`,
|
|
130
133
|
`无法列出本地技能:${error.message}`
|
|
131
|
-
), 'failed'));
|
|
134
|
+
), 'failed', SKILLS_STATUS));
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
function closeSkillsView() {
|
|
@@ -140,9 +143,13 @@
|
|
|
140
143
|
if (!settingsPanelInstance) {
|
|
141
144
|
return;
|
|
142
145
|
}
|
|
143
|
-
const
|
|
146
|
+
const settings = getSkillLoadingSettings();
|
|
147
|
+
const localCount = settings.loadCodexLocalSkills === false ? 0
|
|
148
|
+
: (deps.getCodexLocalSkills?.() || []).filter(skill => isCodexLocalSkillEnabled(skill.id, skill)).length;
|
|
149
|
+
const overleafCount = settings.loadCodexOverleafSkills === false ? 0 : countEnabledCodexOverleafSkills();
|
|
150
|
+
const summary = settings.loadCodexLocalSkills === false && settings.loadCodexOverleafSkills === false
|
|
144
151
|
? tr('codexOverleafSkillsSummaryOff')
|
|
145
|
-
: tr('codexOverleafSkillsSummaryCount', { count:
|
|
152
|
+
: tr('codexOverleafSkillsSummaryCount', { count: localCount + overleafCount });
|
|
146
153
|
SettingsPanel.setSkillsSummary(settingsPanelInstance, summary);
|
|
147
154
|
}
|
|
148
155
|
|
|
@@ -238,6 +245,25 @@
|
|
|
238
245
|
});
|
|
239
246
|
}
|
|
240
247
|
|
|
248
|
+
function getReviewingAvailability() {
|
|
249
|
+
return getState()?.reviewingAvailabilityByProject?.[getCurrentProjectId()] || null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function observeReviewingAvailability(status, evidence) {
|
|
253
|
+
const projectId = getCurrentProjectId();
|
|
254
|
+
if (!projectId || !['available', 'unavailable', 'unknown'].includes(status)) return;
|
|
255
|
+
const previous = getReviewingAvailability();
|
|
256
|
+
// A remembered failure must not renew its own expiry.
|
|
257
|
+
if (previous?.status === status && previous.evidence === evidence && status === 'available') return;
|
|
258
|
+
// Preserve ordering even when a retry and its previous observation share a millisecond.
|
|
259
|
+
const observedAt = Math.max(Date.now(), Number.isFinite(previous?.observedAt) ? previous.observedAt + 1 : 0);
|
|
260
|
+
setState({ ...getState(), reviewingAvailabilityByProject: {
|
|
261
|
+
...getState()?.reviewingAvailabilityByProject,
|
|
262
|
+
[projectId]: { status, evidence, observedAt }
|
|
263
|
+
} });
|
|
264
|
+
saveStateSoon(0);
|
|
265
|
+
}
|
|
266
|
+
|
|
241
267
|
function getThemePreference() {
|
|
242
268
|
return CodexOverleafTheme.normalizeThemePreference(getState()?.theme);
|
|
243
269
|
}
|
|
@@ -296,6 +322,36 @@
|
|
|
296
322
|
deps.updateGlobalPreferences?.({ codexOverleafSkillEnabled: { [skillId]: Boolean(enabled) } })?.catch(() => {});
|
|
297
323
|
}
|
|
298
324
|
|
|
325
|
+
function getCodexLocalSkillEnabled() {
|
|
326
|
+
const map = getState()?.codexLocalSkillEnabled;
|
|
327
|
+
return map && typeof map === 'object' && !Array.isArray(map) ? map : {};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function isCodexLocalSkillEnabled(skillId, skill) {
|
|
331
|
+
const map = getCodexLocalSkillEnabled();
|
|
332
|
+
return Object.prototype.hasOwnProperty.call(map, skillId) ? map[skillId] !== false : skill?.enabled !== false;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function setCodexLocalSkillEnabled(skillId, enabled) {
|
|
336
|
+
if (deps.updateGlobalPreferences) {
|
|
337
|
+
try {
|
|
338
|
+
const pending = deps.updateGlobalPreferences({ codexLocalSkillEnabled: { [skillId]: Boolean(enabled) } });
|
|
339
|
+
Promise.resolve(pending).then(() => saveStateSoon()).catch(() => {
|
|
340
|
+
renderLocalSkillList();
|
|
341
|
+
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed', SKILLS_STATUS);
|
|
342
|
+
});
|
|
343
|
+
} catch (_error) {
|
|
344
|
+
renderLocalSkillList();
|
|
345
|
+
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed', SKILLS_STATUS);
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
setState({ ...getState(), codexLocalSkillEnabled: { ...getCodexLocalSkillEnabled(), [skillId]: Boolean(enabled) } });
|
|
349
|
+
saveStateSoon();
|
|
350
|
+
renderLocalSkillList();
|
|
351
|
+
}
|
|
352
|
+
deps.onSkillsChange?.();
|
|
353
|
+
}
|
|
354
|
+
|
|
299
355
|
function readSkillLoadingSettingsFromSettings() {
|
|
300
356
|
return SettingsPanel.readState(getSettingsPanelInstance()).skillToggles;
|
|
301
357
|
}
|
|
@@ -314,8 +370,8 @@
|
|
|
314
370
|
renderLocalSkillList();
|
|
315
371
|
}
|
|
316
372
|
|
|
317
|
-
function setProjectSettingsStatus(text, status = 'info') {
|
|
318
|
-
SettingsPanel.setStatus(getSettingsPanelInstance(), text, status);
|
|
373
|
+
function setProjectSettingsStatus(text, status = 'info', options) {
|
|
374
|
+
SettingsPanel.setStatus(getSettingsPanelInstance(), text, status, options);
|
|
319
375
|
}
|
|
320
376
|
|
|
321
377
|
function clearProjectSettingsStatus() {
|
|
@@ -337,10 +393,15 @@
|
|
|
337
393
|
closeCustomInstructionsSettings,
|
|
338
394
|
closeSkillsView,
|
|
339
395
|
getCodexOverleafSkillEnabled,
|
|
396
|
+
getCodexLocalSkillEnabled,
|
|
397
|
+
isCodexLocalSkillEnabled,
|
|
398
|
+
setCodexLocalSkillEnabled,
|
|
340
399
|
getCustomInstructionsForCurrentProject,
|
|
341
400
|
getGovernanceRulesForCurrentProject,
|
|
342
401
|
getSkillLoadingSettings,
|
|
343
402
|
getThemePreference,
|
|
403
|
+
getReviewingAvailability,
|
|
404
|
+
observeReviewingAvailability,
|
|
344
405
|
isCodexOverleafSkillEnabled,
|
|
345
406
|
normalizeCustomInstructionsByProject,
|
|
346
407
|
normalizeGovernanceRules,
|