codex-overleaf-link 2.5.1 → 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 +149 -398
- package/README.zh-CN.md +153 -404
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/background.js +78 -3
- package/extension/src/backgroundSharedSessions.js +55 -2
- package/extension/src/backgroundUpdateCoordinator.js +128 -12
- package/extension/src/content/activeTurnControl.js +164 -7
- package/extension/src/content/composerAttachments.js +11 -2
- package/extension/src/content/composerPanel.js +92 -12
- package/extension/src/content/contentRuntime.js +920 -276
- package/extension/src/content/contextTray.js +8 -2
- package/extension/src/content/contextUsageView.js +267 -0
- package/extension/src/content/diagnosticsPanel.js +18 -0
- package/extension/src/content/generated/content.bundle.js +4496 -924
- package/extension/src/content/generated/content.bundle.meta.json +6 -3
- package/extension/src/content/legacyGlobalRegistry.js +4 -0
- package/extension/src/content/localSkillsPanel.js +2 -2
- package/extension/src/content/markdownDomRenderer.js +5 -3
- package/extension/src/content/markdownText.js +42 -5
- package/extension/src/content/modelPicker.js +1 -0
- package/extension/src/content/nativeCompatibilityController.js +29 -10
- package/extension/src/content/otWarmMirror.js +1 -1
- package/extension/src/content/pageBridgeClient.js +2 -2
- package/extension/src/content/panelMaintenance.js +6 -2
- package/extension/src/content/panelRenderer.js +51 -27
- package/extension/src/content/pendingInputView.js +1 -1
- package/extension/src/content/projectSettingsCoordinator.js +30 -6
- package/extension/src/content/providerSettingsDialog.js +2 -1
- package/extension/src/content/recentProjects.js +4 -3
- package/extension/src/content/runActivitySummary.js +122 -14
- package/extension/src/content/runCompletionMeta.js +194 -6
- package/extension/src/content/runController.js +2 -1
- package/extension/src/content/runFailureNotice.js +8 -1
- package/extension/src/content/runPresence.js +18 -8
- package/extension/src/content/runQueueScheduler.js +9 -5
- package/extension/src/content/runRecoveryActions.js +2 -1
- package/extension/src/content/runResultActions.js +22 -20
- package/extension/src/content/runReviewController.js +94 -35
- package/extension/src/content/runTimelineView.js +224 -25
- package/extension/src/content/scopedPersistencePanelState.js +92 -23
- package/extension/src/content/sensitivePreflight.js +14 -1
- package/extension/src/content/sessionManager.js +49 -3
- package/extension/src/content/sessionMenuView.js +54 -18
- package/extension/src/content/sessionPersistence.js +25 -5
- package/extension/src/content/settingsPanel.js +15 -2
- package/extension/src/content/settingsWorkbench.js +127 -89
- package/extension/src/content/sharedSessionViewSync.js +4 -3
- package/extension/src/content/subagentActivityView.js +23 -7
- package/extension/src/content/updateNotice.js +60 -6
- package/extension/src/content/writebackOrchestrator.js +35 -22
- package/extension/src/page/compileBridge.js +193 -180
- package/extension/src/page/overleafCapabilities.js +4 -1
- package/extension/src/page/textCoordinates.js +17 -1
- package/extension/src/page/textFileCreator.js +9 -1
- package/extension/src/page/writebackRouter.js +24 -77
- package/extension/src/pageBridge.js +107 -66
- package/extension/src/popup.js +1 -1
- package/extension/src/shared/agentTranscript.js +350 -17
- package/extension/src/shared/auditRecords.js +2 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/compileAdapter.js +58 -17
- package/extension/src/shared/composerAttachmentDraft.js +6 -1
- package/extension/src/shared/contextUsage.js +125 -0
- package/extension/src/shared/failureReasons.js +42 -3
- package/extension/src/shared/i18n.js +299 -29
- package/extension/src/shared/lineReferences.js +38 -31
- package/extension/src/shared/pageRpcContract.js +1 -1
- package/extension/src/shared/panelIcons.js +39 -0
- 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/sessionState.js +63 -4
- package/extension/src/shared/sessionTitle.js +14 -1
- package/extension/src/shared/sharedSessionBridge.js +81 -13
- package/extension/src/shared/staleGuard.js +72 -63
- package/extension/src/shared/storageDb.js +35 -3
- package/extension/src/shared/storageMigration.js +7 -1
- package/extension/src/shared/storageRunActions.js +62 -8
- package/extension/src/shared/undoOperations.js +126 -28
- package/extension/src/shared/updateRuntimeIdentity.js +16 -2
- package/extension/src/shared/writebackSettlement.js +21 -3
- package/extension/styles/panel.css +1106 -490
- package/native-host/src/bootstrapUpdate.js +52 -16
- package/native-host/src/chatBridgeRequest.js +60 -6
- package/native-host/src/chatBridgeResponse.js +10 -1
- package/native-host/src/chatCompletionsBridge.js +29 -2
- package/native-host/src/codexPromptAssembly.js +86 -118
- package/native-host/src/codexSessionRunner.js +126 -17
- package/native-host/src/providerContextError.js +20 -0
- package/native-host/src/taskRunnerRuntime.js +18 -6
- package/native-host/src/textPatch.js +473 -377
- package/native-host/src/updateManager.js +120 -15
- package/package.json +5 -8
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"entry": "extension/entries/content-entry.mjs",
|
|
4
4
|
"output": "extension/src/content/generated/content.bundle.js",
|
|
5
|
-
"sourceDigest": "
|
|
6
|
-
"outputDigest": "
|
|
7
|
-
"byteLength":
|
|
5
|
+
"sourceDigest": "0cf851b033afb0885464fd86506f423f35fe82d6da8c1f1644012350cab0ddc4",
|
|
6
|
+
"outputDigest": "0abf629ca414d00be2ab6bbde553c66a7f66ad2d0a4551bb272f3a5948a7d461",
|
|
7
|
+
"byteLength": 3387559,
|
|
8
8
|
"inputs": [
|
|
9
9
|
"extension/entries/content-entry.mjs",
|
|
10
10
|
"extension/src/content/activeTurnControl.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"extension/src/content/composerPanel.js",
|
|
16
16
|
"extension/src/content/contentRuntime.js",
|
|
17
17
|
"extension/src/content/contextTray.js",
|
|
18
|
+
"extension/src/content/contextUsageView.js",
|
|
18
19
|
"extension/src/content/diagnosticsController.js",
|
|
19
20
|
"extension/src/content/diagnosticsExport.js",
|
|
20
21
|
"extension/src/content/diagnosticsPanel.js",
|
|
@@ -89,6 +90,7 @@
|
|
|
89
90
|
"extension/src/shared/compatibility.js",
|
|
90
91
|
"extension/src/shared/compileAdapter.js",
|
|
91
92
|
"extension/src/shared/composerAttachmentDraft.js",
|
|
93
|
+
"extension/src/shared/contextUsage.js",
|
|
92
94
|
"extension/src/shared/directoryCleanupProof.js",
|
|
93
95
|
"extension/src/shared/failureReasons.js",
|
|
94
96
|
"extension/src/shared/globalPreferences.js",
|
|
@@ -99,6 +101,7 @@
|
|
|
99
101
|
"extension/src/shared/models.js",
|
|
100
102
|
"extension/src/shared/otText.js",
|
|
101
103
|
"extension/src/shared/pageRpcContract.js",
|
|
104
|
+
"extension/src/shared/panelIcons.js",
|
|
102
105
|
"extension/src/shared/pathRedaction.js",
|
|
103
106
|
"extension/src/shared/projectFiles.js",
|
|
104
107
|
"extension/src/shared/providerProfiles.js",
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
'ComposerPanel',
|
|
30
30
|
'ContentRuntime',
|
|
31
31
|
'ContextTray',
|
|
32
|
+
'ContextUsage',
|
|
33
|
+
'ContextUsageView',
|
|
32
34
|
'DiagnosticsController',
|
|
33
35
|
'DiagnosticsExport',
|
|
34
36
|
'DiagnosticsPanel',
|
|
@@ -55,10 +57,12 @@
|
|
|
55
57
|
'PostNavigationSettlementPersistence',
|
|
56
58
|
'ProjectFiles',
|
|
57
59
|
'ProjectProviderSelection',
|
|
60
|
+
'PanelIcons',
|
|
58
61
|
'ProjectSettingsCoordinator',
|
|
59
62
|
'ProviderSettingsCoordinator',
|
|
60
63
|
'RecentProjects',
|
|
61
64
|
'ReviewHunks',
|
|
65
|
+
'Reviewing',
|
|
62
66
|
'RunActivitySummary',
|
|
63
67
|
'RunPresence',
|
|
64
68
|
'RunActivityModel',
|
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
toggle.disabled = true;
|
|
321
321
|
confirmBtn.textContent = tr('localSkillRemoving');
|
|
322
322
|
removeCodexOverleafSkill(id).catch(error => {
|
|
323
|
-
setProjectSettingsStatus(tx(`Failed to remove Codex Overleaf skill: ${error.message}`, `删除 Codex Overleaf 技能失败:${error.message}`), 'failed');
|
|
323
|
+
setProjectSettingsStatus(tx(`Failed to remove Codex Overleaf skill: ${error.message}`, `删除 Codex Overleaf 技能失败:${error.message}`), 'failed', { page: 'context' });
|
|
324
324
|
// Restore row on failure so the user can retry.
|
|
325
325
|
confirmBtn.disabled = false;
|
|
326
326
|
cancelBtn.disabled = false;
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
if (activeSkill?.scope === 'codex-overleaf' && activeSkill.id === id) {
|
|
382
382
|
clearComposerSkillInvocation();
|
|
383
383
|
}
|
|
384
|
-
setProjectSettingsStatus(tr('codexOverleafSkillRemoveDone'), 'completed');
|
|
384
|
+
setProjectSettingsStatus(tr('codexOverleafSkillRemoveDone'), 'completed', { page: 'context' });
|
|
385
385
|
clearSlashCodexOverleafSkills();
|
|
386
386
|
await refreshLocalSkills();
|
|
387
387
|
await saveState?.();
|
|
@@ -468,10 +468,10 @@
|
|
|
468
468
|
textNode.textContent = `${match[1]}${text.slice(match[0].length)}`;
|
|
469
469
|
textNode.parentNode.insertBefore(label, textNode);
|
|
470
470
|
}
|
|
471
|
-
decorateChangeReceipts(container, document, tx);
|
|
471
|
+
decorateChangeReceipts(container, document, tx, options.formatOperationType);
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
function decorateChangeReceipts(container, document, tx) {
|
|
474
|
+
function decorateChangeReceipts(container, document, tx, formatOperationType = type => type) {
|
|
475
475
|
const label = container.querySelector?.('.run-system-label[data-system-label="changes"]');
|
|
476
476
|
const list = label?.closest?.('p')?.nextElementSibling;
|
|
477
477
|
if (!list || !['UL', 'OL'].includes(list.tagName)) return;
|
|
@@ -508,7 +508,9 @@
|
|
|
508
508
|
file.textContent = receipt.file;
|
|
509
509
|
const operation = document.createElement('span');
|
|
510
510
|
operation.className = 'run-change-receipt__operation';
|
|
511
|
-
|
|
511
|
+
const type = ({ 编辑: 'edit', 新建: 'create', 重命名: 'rename', 移动: 'move', 删除: 'delete' })[receipt.operation]
|
|
512
|
+
|| receipt.operation.toLowerCase();
|
|
513
|
+
operation.textContent = formatOperationType(type);
|
|
512
514
|
receipt.item.classList.add('run-change-receipt');
|
|
513
515
|
receipt.item.setAttribute('aria-label', receipt.original);
|
|
514
516
|
receipt.item.title = receipt.original;
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
index = next.end;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
return nodes;
|
|
102
|
+
return groupLineReferenceNodes(nodes);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function buildInlineCodeNodes(value) {
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
cursor = start + rawText.length;
|
|
153
153
|
}
|
|
154
154
|
appendSanitizedTextNode(nodes, source.slice(cursor));
|
|
155
|
-
return nodes;
|
|
155
|
+
return groupLineReferenceNodes(nodes);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
function buildMarkdownLinkNodes(text, href) {
|
|
@@ -187,6 +187,24 @@
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
function groupLineReferenceNodes(nodes) {
|
|
191
|
+
const grouped = [];
|
|
192
|
+
for (const node of nodes) {
|
|
193
|
+
const previous = grouped[grouped.length - 1];
|
|
194
|
+
if (node.classList?.contains('codex-line-reference') && previous?.nodeType === 3 &&
|
|
195
|
+
previous.textContent.endsWith('(')) {
|
|
196
|
+
previous.textContent = previous.textContent.slice(0, -1);
|
|
197
|
+
const group = document.createElement('span');
|
|
198
|
+
group.className = 'codex-line-reference-group';
|
|
199
|
+
group.append(document.createTextNode('('), node);
|
|
200
|
+
grouped.push(group);
|
|
201
|
+
} else {
|
|
202
|
+
grouped.push(node);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return grouped;
|
|
206
|
+
}
|
|
207
|
+
|
|
190
208
|
function resolveMarkdownLineReference(text, href) {
|
|
191
209
|
const candidates = [
|
|
192
210
|
{ value: href, mode: 'markdown-link-target' },
|
|
@@ -230,12 +248,16 @@
|
|
|
230
248
|
return null;
|
|
231
249
|
}
|
|
232
250
|
const line = Number(ref?.line);
|
|
251
|
+
const endLine = ref?.endLine === undefined ? null : Number(ref.endLine);
|
|
233
252
|
const column = ref?.column === null || ref?.column === undefined || ref?.column === ''
|
|
234
253
|
? null
|
|
235
254
|
: Number(ref.column);
|
|
236
255
|
if (!Number.isSafeInteger(line) || line < 1 || (column !== null && (!Number.isSafeInteger(column) || column < 1))) {
|
|
237
256
|
return null;
|
|
238
257
|
}
|
|
258
|
+
if (endLine !== null && (!Number.isSafeInteger(endLine) || endLine < line)) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
239
261
|
let resolved;
|
|
240
262
|
try {
|
|
241
263
|
resolved = LineReferences.resolveProjectReference({
|
|
@@ -251,6 +273,7 @@
|
|
|
251
273
|
return {
|
|
252
274
|
path: resolved.path,
|
|
253
275
|
line,
|
|
276
|
+
...(endLine > line ? { endLine } : {}),
|
|
254
277
|
column
|
|
255
278
|
};
|
|
256
279
|
}
|
|
@@ -262,10 +285,15 @@
|
|
|
262
285
|
button.textContent = formatLineReferenceText(reference);
|
|
263
286
|
button.dataset.path = reference.path;
|
|
264
287
|
button.dataset.line = String(reference.line);
|
|
288
|
+
if (reference.endLine) {
|
|
289
|
+
button.dataset.endLine = String(reference.endLine);
|
|
290
|
+
}
|
|
265
291
|
if (reference.column) {
|
|
266
292
|
button.dataset.column = String(reference.column);
|
|
267
293
|
}
|
|
268
|
-
const ariaLabel = reference.
|
|
294
|
+
const ariaLabel = reference.endLine
|
|
295
|
+
? `Open ${reference.path} lines ${reference.line} to ${reference.endLine}`
|
|
296
|
+
: reference.column
|
|
269
297
|
? `Open ${reference.path} line ${reference.line} column ${reference.column}`
|
|
270
298
|
: `Open ${reference.path} line ${reference.line}`;
|
|
271
299
|
button.setAttribute('aria-label', ariaLabel);
|
|
@@ -278,7 +306,10 @@
|
|
|
278
306
|
line: reference.line,
|
|
279
307
|
selectLine: !reference.column
|
|
280
308
|
};
|
|
281
|
-
if (reference.
|
|
309
|
+
if (reference.endLine) {
|
|
310
|
+
params.endLine = reference.endLine;
|
|
311
|
+
params.selectLine = true;
|
|
312
|
+
} else if (reference.column) {
|
|
282
313
|
params.column = reference.column;
|
|
283
314
|
params.selectLine = false;
|
|
284
315
|
}
|
|
@@ -310,7 +341,7 @@
|
|
|
310
341
|
}
|
|
311
342
|
|
|
312
343
|
function formatLineReferenceText(reference) {
|
|
313
|
-
return `${reference.path}:${reference.line}${reference.column ? `:${reference.column}` : ''}`;
|
|
344
|
+
return `${reference.path}:${reference.line}${reference.endLine ? `–${reference.endLine}` : reference.column ? `:${reference.column}` : ''}`;
|
|
314
345
|
}
|
|
315
346
|
|
|
316
347
|
function normalizeReferencePathForRuntime(value) {
|
|
@@ -499,6 +530,12 @@
|
|
|
499
530
|
renderText: text => buildMarkdownInlineNodes(text) }),
|
|
500
531
|
recordDiagnostic: recordRenderingDiagnostic
|
|
501
532
|
});
|
|
533
|
+
// The DOM renderer emits text and links from separate Markdown tokens.
|
|
534
|
+
const parents = new Set(Array.from(target.querySelectorAll('.codex-line-reference'), button => button.parentNode)
|
|
535
|
+
.filter(parent => !parent.classList.contains('codex-line-reference-group')));
|
|
536
|
+
for (const parent of parents) {
|
|
537
|
+
parent.replaceChildren(...groupLineReferenceNodes(Array.from(parent.childNodes)));
|
|
538
|
+
}
|
|
502
539
|
return;
|
|
503
540
|
} catch (error) {
|
|
504
541
|
recordRenderingDiagnostic({
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
requiredVersion: compatibility.requiredVersion || Compatibility?.BUILD_TARGET_VERSION || '',
|
|
89
89
|
releaseUrl: compatibility.releaseUrl || ''
|
|
90
90
|
};
|
|
91
|
-
notifyBlocked(error, compatibility);
|
|
91
|
+
notifyBlocked(error, compatibility, method);
|
|
92
92
|
return { ok: false, compatibility, response: { ok: false, error } };
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
function notifyBlocked(error, compatibility = {}) {
|
|
106
|
+
function notifyBlocked(error, compatibility = {}, method) {
|
|
107
107
|
const message = error?.message || String(error || '');
|
|
108
108
|
if (options.getCurrentRunView?.()) {
|
|
109
109
|
options.appendRunEvent?.({ title: message, status: 'failed' });
|
|
@@ -111,7 +111,17 @@
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
showUpdateGuidance(compatibility);
|
|
114
|
-
|
|
114
|
+
const missing = compatibility.status === 'native_missing';
|
|
115
|
+
options.showPluginToast?.(missing ? tr('nativeCompatibilityMissingGuidance') : message, {
|
|
116
|
+
status: 'failed',
|
|
117
|
+
sticky: true,
|
|
118
|
+
...(missing ? {
|
|
119
|
+
title: tr('nativeCompatibilityMissingTitle'),
|
|
120
|
+
groupKey: 'native-missing',
|
|
121
|
+
groupItem: method || 'native request',
|
|
122
|
+
groupSummary: count => tr('nativeCompatibilityUnavailableFeatures', { count })
|
|
123
|
+
} : {})
|
|
124
|
+
});
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
async function refreshBadge() {
|
|
@@ -197,11 +207,24 @@
|
|
|
197
207
|
);
|
|
198
208
|
const card = options.document.createElement('section');
|
|
199
209
|
card.className = 'codex-plugin-confirm-card';
|
|
210
|
+
const head = options.document.createElement('div');
|
|
211
|
+
head.className = 'codex-plugin-confirm-head';
|
|
212
|
+
const icon = options.document.createElement('img');
|
|
213
|
+
icon.className = 'codex-plugin-confirm-icon';
|
|
214
|
+
icon.alt = '';
|
|
215
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
216
|
+
icon.src = options.getIconUrl?.() || '';
|
|
217
|
+
const titleWrap = options.document.createElement('div');
|
|
218
|
+
const brand = options.document.createElement('div');
|
|
219
|
+
brand.className = 'codex-plugin-confirm-brand';
|
|
220
|
+
brand.textContent = 'Codex Overleaf Link';
|
|
200
221
|
const title = options.document.createElement('div');
|
|
201
222
|
title.className = 'codex-plugin-confirm-title';
|
|
202
223
|
title.textContent = nativeMissing
|
|
203
224
|
? tx('One step left: install the native host', '还差一步:安装 Native host')
|
|
204
225
|
: tx('Native host update available', 'Native host 可更新');
|
|
226
|
+
titleWrap.append(brand, title);
|
|
227
|
+
head.append(icon, titleWrap);
|
|
205
228
|
const body = options.document.createElement('div');
|
|
206
229
|
body.className = 'codex-plugin-confirm-body';
|
|
207
230
|
body.textContent = [
|
|
@@ -222,20 +245,16 @@
|
|
|
222
245
|
? tx(' Use PowerShell.', ' 请使用 PowerShell。') : '')
|
|
223
246
|
].join('\n\n');
|
|
224
247
|
const commandCode = options.document.createElement('code');
|
|
248
|
+
commandCode.className = 'codex-native-guidance-command';
|
|
225
249
|
commandCode.textContent = command;
|
|
226
|
-
Object.assign(commandCode.style, {
|
|
227
|
-
display: 'block',
|
|
228
|
-
whiteSpace: 'pre-wrap',
|
|
229
|
-
marginTop: '0.75rem'
|
|
230
|
-
});
|
|
231
250
|
body.append(commandCode);
|
|
232
251
|
if (releaseUrl) {
|
|
233
252
|
const link = options.document.createElement('a');
|
|
253
|
+
link.className = 'codex-native-guidance-link';
|
|
234
254
|
link.href = releaseUrl;
|
|
235
255
|
link.target = '_blank';
|
|
236
256
|
link.rel = 'noopener noreferrer';
|
|
237
257
|
link.textContent = tx('Open GitHub Release', '打开 GitHub Release');
|
|
238
|
-
Object.assign(link.style, { display: 'block', marginTop: '0.75rem' });
|
|
239
258
|
body.append(link);
|
|
240
259
|
}
|
|
241
260
|
const actions = options.document.createElement('div');
|
|
@@ -256,7 +275,7 @@
|
|
|
256
275
|
close.textContent = tx('Close', '关闭');
|
|
257
276
|
close.addEventListener('click', () => overlay.remove());
|
|
258
277
|
actions.append(close, copy);
|
|
259
|
-
card.append(
|
|
278
|
+
card.append(head, body, actions);
|
|
260
279
|
overlay.append(card);
|
|
261
280
|
overlay.addEventListener('click', event => {
|
|
262
281
|
if (event.target === overlay) overlay.remove();
|
|
@@ -895,7 +895,7 @@
|
|
|
895
895
|
appendLog(tx(`Cannot continue: ${formatProjectSnapshotWarning(warning)}`, `无法继续:${formatProjectSnapshotWarning(warning)}`));
|
|
896
896
|
}
|
|
897
897
|
appendCompletionReport({
|
|
898
|
-
conclusion: tr('warmMirrorStaleBlockedConclusion'),
|
|
898
|
+
conclusion: tr('warmMirrorStaleBlockedConclusion'), conclusionKey: 'warm_mirror_stale',
|
|
899
899
|
status: 'blocked',
|
|
900
900
|
operations: [],
|
|
901
901
|
applyResults: [],
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const PAGE_WORLD_SCRIPTS = Object.freeze([
|
|
9
|
-
['src/shared/reviewing.js', 'codex-overleaf-reviewing-script'],
|
|
9
|
+
['src/shared/reviewing.js', 'codex-overleaf-reviewing-script', true],
|
|
10
10
|
['src/shared/projectFiles.js', 'codex-overleaf-project-files-script'],
|
|
11
11
|
['src/shared/compatibility.js', 'codex-overleaf-compatibility-page-script'],
|
|
12
12
|
['src/shared/pageRpcContract.js', 'codex-overleaf-page-rpc-contract-script', true],
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
['src/shared/sensitiveScan.js', 'codex-overleaf-sensitive-scan-script'],
|
|
16
16
|
['src/shared/auditRecords.js', 'codex-overleaf-audit-records-script'],
|
|
17
17
|
['src/page/saveState.js', 'codex-overleaf-save-state-script', true],
|
|
18
|
-
['src/page/overleafCapabilities.js', 'codex-overleaf-capabilities-script'],
|
|
18
|
+
['src/page/overleafCapabilities.js', 'codex-overleaf-capabilities-script', true],
|
|
19
19
|
['src/page/compileBridge.js', 'codex-overleaf-compile-bridge-script'],
|
|
20
20
|
['src/page/overleafEditor.js', 'codex-overleaf-editor-script'],
|
|
21
21
|
['src/page/overleafProjectSnapshot.js', 'codex-overleaf-project-snapshot-script'],
|
|
@@ -181,6 +181,7 @@
|
|
|
181
181
|
// the failed task usually needs a tweak before it is worth resending.
|
|
182
182
|
function refillComposerForRetry(run, textOverride) {
|
|
183
183
|
const input = getPanel()?.querySelector('[data-task]');
|
|
184
|
+
if (input?.readOnly) return;
|
|
184
185
|
const task = typeof textOverride === 'string' && textOverride.trim()
|
|
185
186
|
? textOverride
|
|
186
187
|
: String(run?.task || '');
|
|
@@ -310,7 +311,9 @@
|
|
|
310
311
|
// Settings history card, expanded and loaded.
|
|
311
312
|
function openChangeHistory() {
|
|
312
313
|
openCustomInstructionsSettings();
|
|
313
|
-
|
|
314
|
+
// The workbench shows one page at a time; switch to the page holding the card.
|
|
315
|
+
const card = getSettingsPanelInstance()?.revealGroup?.('history')
|
|
316
|
+
|| getSettingsPanelInstance()?.container?.querySelector('[data-history-card]');
|
|
314
317
|
if (card) {
|
|
315
318
|
if (!card.open) {
|
|
316
319
|
card.open = true;
|
|
@@ -322,7 +325,8 @@
|
|
|
322
325
|
|
|
323
326
|
function openStorageSettings() {
|
|
324
327
|
openCustomInstructionsSettings();
|
|
325
|
-
const card =
|
|
328
|
+
const card = getSettingsPanelInstance()?.revealGroup?.('storage')
|
|
329
|
+
|| getPanel()?.querySelector('[data-storage-card]');
|
|
326
330
|
if (card) {
|
|
327
331
|
card.open = true;
|
|
328
332
|
card.scrollIntoView({ block: 'center' });
|
|
@@ -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?.());
|
|
@@ -320,7 +327,7 @@
|
|
|
320
327
|
}
|
|
321
328
|
const panel = options.getPanel?.();
|
|
322
329
|
if (!panel) {
|
|
323
|
-
return Promise.resolve(false);
|
|
330
|
+
return Promise.resolve(config.choices?.length ? 'cancel' : false);
|
|
324
331
|
}
|
|
325
332
|
dismiss(false);
|
|
326
333
|
const tr = options.tr || (key => key);
|
|
@@ -329,6 +336,8 @@
|
|
|
329
336
|
const confirmLabel = config.confirmLabel || tr('confirmDefaultConfirm');
|
|
330
337
|
const cancelLabel = config.cancelLabel || tr('confirmDefaultCancel');
|
|
331
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;
|
|
332
341
|
const doc = panel.ownerDocument || document;
|
|
333
342
|
|
|
334
343
|
return new Promise(resolve => {
|
|
@@ -369,54 +378,69 @@
|
|
|
369
378
|
body.textContent = String(message);
|
|
370
379
|
const actions = doc.createElement('div');
|
|
371
380
|
actions.className = 'codex-plugin-confirm-actions';
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
+
});
|
|
382
395
|
card.append(head, body, actions);
|
|
383
396
|
overlay.append(card);
|
|
384
397
|
panel.append(overlay);
|
|
385
398
|
overlay.showModal?.();
|
|
386
399
|
|
|
400
|
+
let timeout, ownerCheck, removalObserver;
|
|
401
|
+
const onAbort = () => cleanup(cancelled);
|
|
387
402
|
const cleanup = value => {
|
|
388
403
|
if (settled) return;
|
|
389
404
|
settled = true;
|
|
390
405
|
activeResolve = null;
|
|
391
406
|
doc.removeEventListener('keydown', onKeydown, true);
|
|
407
|
+
config.signal?.removeEventListener('abort', onAbort);
|
|
408
|
+
clearTimeout(timeout);
|
|
409
|
+
clearInterval(ownerCheck);
|
|
410
|
+
removalObserver?.disconnect();
|
|
392
411
|
overlay.close?.();
|
|
393
412
|
overlay.remove();
|
|
394
413
|
returnFocus?.focus?.();
|
|
395
|
-
resolve(value);
|
|
414
|
+
resolve(choices && !choices.some(choice => choice.value === value) ? cancelled : value);
|
|
396
415
|
};
|
|
397
416
|
activeResolve = cleanup;
|
|
398
417
|
const onKeydown = event => {
|
|
399
418
|
if (event.key === 'Escape') {
|
|
400
|
-
event.preventDefault();
|
|
401
|
-
cleanup(false);
|
|
419
|
+
event.preventDefault(); cleanup(cancelled);
|
|
402
420
|
} else if (event.key === 'Enter') {
|
|
403
421
|
event.preventDefault();
|
|
404
|
-
if (
|
|
405
|
-
else if (
|
|
406
|
-
else if (event.target === confirm) cleanup(true);
|
|
422
|
+
if (buttons.includes(event.target)) event.target.click();
|
|
423
|
+
else if (!choices && !destructive) cleanup(true);
|
|
407
424
|
} else if (event.key === 'Tab') {
|
|
408
425
|
event.preventDefault();
|
|
409
|
-
|
|
426
|
+
const index = buttons.indexOf(event.target);
|
|
427
|
+
buttons[(index + (event.shiftKey ? buttons.length - 1 : 1)) % buttons.length].focus();
|
|
410
428
|
}
|
|
411
429
|
};
|
|
412
|
-
overlay.addEventListener('click', event => {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
overlay.addEventListener('cancel', event => { event.preventDefault(); cleanup(false); });
|
|
416
|
-
cancel.addEventListener('click', () => cleanup(false));
|
|
417
|
-
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));
|
|
418
433
|
doc.addEventListener('keydown', onKeydown, true);
|
|
419
|
-
(
|
|
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();
|
|
420
444
|
});
|
|
421
445
|
}
|
|
422
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;
|
|
@@ -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() {
|
|
@@ -242,6 +245,25 @@
|
|
|
242
245
|
});
|
|
243
246
|
}
|
|
244
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
|
+
|
|
245
267
|
function getThemePreference() {
|
|
246
268
|
return CodexOverleafTheme.normalizeThemePreference(getState()?.theme);
|
|
247
269
|
}
|
|
@@ -316,11 +338,11 @@
|
|
|
316
338
|
const pending = deps.updateGlobalPreferences({ codexLocalSkillEnabled: { [skillId]: Boolean(enabled) } });
|
|
317
339
|
Promise.resolve(pending).then(() => saveStateSoon()).catch(() => {
|
|
318
340
|
renderLocalSkillList();
|
|
319
|
-
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed');
|
|
341
|
+
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed', SKILLS_STATUS);
|
|
320
342
|
});
|
|
321
343
|
} catch (_error) {
|
|
322
344
|
renderLocalSkillList();
|
|
323
|
-
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed');
|
|
345
|
+
setProjectSettingsStatus(tx('Could not save the local skill selection. Try again.', '无法保存本地技能选择,请重试。'), 'failed', SKILLS_STATUS);
|
|
324
346
|
}
|
|
325
347
|
} else {
|
|
326
348
|
setState({ ...getState(), codexLocalSkillEnabled: { ...getCodexLocalSkillEnabled(), [skillId]: Boolean(enabled) } });
|
|
@@ -348,8 +370,8 @@
|
|
|
348
370
|
renderLocalSkillList();
|
|
349
371
|
}
|
|
350
372
|
|
|
351
|
-
function setProjectSettingsStatus(text, status = 'info') {
|
|
352
|
-
SettingsPanel.setStatus(getSettingsPanelInstance(), text, status);
|
|
373
|
+
function setProjectSettingsStatus(text, status = 'info', options) {
|
|
374
|
+
SettingsPanel.setStatus(getSettingsPanelInstance(), text, status, options);
|
|
353
375
|
}
|
|
354
376
|
|
|
355
377
|
function clearProjectSettingsStatus() {
|
|
@@ -378,6 +400,8 @@
|
|
|
378
400
|
getGovernanceRulesForCurrentProject,
|
|
379
401
|
getSkillLoadingSettings,
|
|
380
402
|
getThemePreference,
|
|
403
|
+
getReviewingAvailability,
|
|
404
|
+
observeReviewingAvailability,
|
|
381
405
|
isCodexOverleafSkillEnabled,
|
|
382
406
|
normalizeCustomInstructionsByProject,
|
|
383
407
|
normalizeGovernanceRules,
|
|
@@ -1296,7 +1296,8 @@
|
|
|
1296
1296
|
|
|
1297
1297
|
function renderTemplatePicker(instance, detail) {
|
|
1298
1298
|
const tx = instance.tx;
|
|
1299
|
-
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>'
|
|
1300
1301
|
+ escapeHtml(tx('Back', '返回')) + '</button><h3>' + escapeHtml(tx('Add a connection', '添加连接')) + '</h3></div>'
|
|
1301
1302
|
+ '<p class="codex-provider-help">' + escapeHtml(tx(
|
|
1302
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.',
|
|
@@ -199,10 +199,11 @@
|
|
|
199
199
|
} catch (_error) { /* swallow */ }
|
|
200
200
|
try {
|
|
201
201
|
var docTitle = (document.title || '').trim();
|
|
202
|
-
// Overleaf
|
|
203
|
-
// "<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.
|
|
204
205
|
if (docTitle) {
|
|
205
|
-
var stripped = docTitle.replace(/\s
|
|
206
|
+
var stripped = docTitle.replace(/\s+[-–|]\s+[^-–|]*Overleaf[^-–|]*$/i, '').trim();
|
|
206
207
|
if (stripped && stripped.toLowerCase() !== 'overleaf') {
|
|
207
208
|
return stripped;
|
|
208
209
|
}
|