codex-overleaf-link 1.8.6 → 1.9.1
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 +45 -21
- package/bin/codex-overleaf-link.mjs +58 -0
- package/extension/assets/icons/codex-overleaf-dialog-icon.png +0 -0
- package/extension/assets/icons/codex-overleaf-icon.png +0 -0
- package/extension/assets/icons/icon128.png +0 -0
- package/extension/assets/icons/icon16.png +0 -0
- package/extension/assets/icons/icon32.png +0 -0
- package/extension/assets/icons/icon48.png +0 -0
- package/extension/bootstrap/background.js +404 -0
- package/extension/bootstrap/manifest.template.json +51 -0
- package/extension/bootstrap/popup.css +26 -0
- package/extension/bootstrap/popup.html +38 -0
- package/extension/bootstrap/popup.js +44 -0
- package/extension/bootstrap/runtimeContext.js +2 -0
- package/extension/runtime-manifest.json +60 -0
- package/extension/src/background.js +532 -0
- package/extension/src/content/applyResultFormatters.js +387 -0
- package/extension/src/content/composerAttachments.js +522 -0
- package/extension/src/content/composerPanel.js +254 -0
- package/extension/src/content/contentRuntime.js +8897 -0
- package/extension/src/content/contextTray.js +686 -0
- package/extension/src/content/diagnosticsController.js +659 -0
- package/extension/src/content/diagnosticsPanel.js +342 -0
- package/extension/src/content/diffReviewPanel.js +797 -0
- package/extension/src/content/localSkillsPanel.js +280 -0
- package/extension/src/content/markdownText.js +606 -0
- package/extension/src/content/mirrorHealth.js +92 -0
- package/extension/src/content/modelPicker.js +489 -0
- package/extension/src/content/nativeChannel.js +62 -0
- package/extension/src/content/otWarmMirror.js +964 -0
- package/extension/src/content/otWarmMirrorController.js +174 -0
- package/extension/src/content/panelMaintenance.js +367 -0
- package/extension/src/content/panelRenderer.js +253 -0
- package/extension/src/content/recentProjects.js +1063 -0
- package/extension/src/content/reviewHunks.js +247 -0
- package/extension/src/content/runController.js +242 -0
- package/extension/src/content/runTimelineView.js +1131 -0
- package/extension/src/content/sessionManager.js +487 -0
- package/extension/src/content/sessionPanel.js +263 -0
- package/extension/src/content/settingsPanel.js +527 -0
- package/extension/src/content/themeController.js +91 -0
- package/extension/src/content/updateIdle.js +67 -0
- package/extension/src/content/writebackController.js +300 -0
- package/extension/src/content/writebackOrchestrator.js +850 -0
- package/extension/src/contentScript.js +8 -0
- package/extension/src/page/compileBridge.js +460 -0
- package/extension/src/page/overleafCapabilities.js +100 -0
- package/extension/src/page/overleafEditor.js +282 -0
- package/extension/src/page/overleafProjectSnapshot.js +234 -0
- package/extension/src/page/overleafRealtimeObserver.js +491 -0
- package/extension/src/page/pageBridgeCapability.js +71 -0
- package/extension/src/page/snapshotRouter.js +948 -0
- package/extension/src/page/trackedChangesLifecycle.js +1506 -0
- package/extension/src/page/treeOperations.js +1584 -0
- package/extension/src/page/writeGuard.js +142 -0
- package/extension/src/page/writebackRouter.js +1934 -0
- package/extension/src/pageBridge.js +2224 -0
- package/extension/src/popup.js +247 -0
- package/extension/src/shared/agentTranscript.js +18 -4
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/styles/panel.css +4048 -0
- package/native-host/src/index.js +9 -2
- package/native-host/src/managedInstall.js +393 -0
- package/native-host/src/managedLauncherRuntime.js +71 -0
- package/native-host/src/nativeHostPlatform.js +16 -0
- package/native-host/src/runtimeInstaller.js +6 -1
- package/native-host/src/taskRunnerRuntime.js +8 -0
- package/native-host/src/updateArchive.js +253 -0
- package/native-host/src/updateManager.js +548 -0
- package/native-host/src/updateTrust.js +156 -0
- package/package.json +11 -2
- package/scripts/install-managed.mjs +64 -0
- package/scripts/uninstall-managed.mjs +48 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
(function initCodexOverleafDiagnosticsPanel() {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
function create(options = {}) {
|
|
5
|
+
const container = options.container;
|
|
6
|
+
if (!container) {
|
|
7
|
+
throw new Error('CodexOverleafDiagnosticsPanel requires a container');
|
|
8
|
+
}
|
|
9
|
+
const instance = {
|
|
10
|
+
container,
|
|
11
|
+
callbacks: options.callbacks || {},
|
|
12
|
+
i18n: options.i18n || {},
|
|
13
|
+
dismissInstalled: false
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
container.innerHTML = `
|
|
17
|
+
<div class="codex-diagnostics-wrap">
|
|
18
|
+
<button type="button" class="codex-diagnostics-trigger" data-diagnostics-menu title="Diagnostics" aria-label="Diagnostics" aria-expanded="false">
|
|
19
|
+
<span class="codex-diagnostics-dot" data-diagnostics-health-dot data-health="unknown"></span>
|
|
20
|
+
</button>
|
|
21
|
+
<div class="codex-diagnostics-menu" data-diagnostics-popover hidden>
|
|
22
|
+
<div class="codex-diagnostics-hint" data-i18n="diagnosticsHint">Use when Codex cannot run, write, or read files</div>
|
|
23
|
+
<button type="button" class="codex-diagnostics-runall" data-diagnostics-run-all>
|
|
24
|
+
<span data-i18n="diagnosticsRunAllTitle">Run all checks</span>
|
|
25
|
+
<small data-i18n="diagnosticsRunAllSubtitle">Connection, write access, project read, OT mirror</small>
|
|
26
|
+
</button>
|
|
27
|
+
<div class="codex-diagnostics-menu-sep"></div>
|
|
28
|
+
<button type="button" data-diagnostics-native-env>
|
|
29
|
+
<span data-i18n="diagnosticsNativeTitle">Check Local Connection</span>
|
|
30
|
+
<small data-i18n="diagnosticsNativeSubtitle">Codex, Native Host, LaTeX tools</small>
|
|
31
|
+
</button>
|
|
32
|
+
<button type="button" data-diagnostics-page-state>
|
|
33
|
+
<span data-i18n="diagnosticsPageTitle">Check Overleaf Write Access</span>
|
|
34
|
+
<small data-i18n="diagnosticsPageSubtitle">Current file, write access, track changes</small>
|
|
35
|
+
</button>
|
|
36
|
+
<button type="button" data-diagnostics-snapshot>
|
|
37
|
+
<span data-i18n="diagnosticsSnapshotTitle">Check Project Read</span>
|
|
38
|
+
<small data-i18n="diagnosticsSnapshotSubtitle">Full project, assets, read source</small>
|
|
39
|
+
</button>
|
|
40
|
+
<button type="button" data-diagnostics-ot>
|
|
41
|
+
<span data-i18n="diagnosticsOtTitle">Check Experimental OT Mirror</span>
|
|
42
|
+
<small data-i18n="diagnosticsOtSubtitle">Status, fresh files, fallback</small>
|
|
43
|
+
</button>
|
|
44
|
+
<button type="button" data-diagnostics-export>
|
|
45
|
+
<span data-i18n="diagnosticsExportTitle">Export Diagnostics</span>
|
|
46
|
+
<small data-i18n="diagnosticsExportSubtitle">Redacted audit and environment bundle</small>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<section class="codex-diagnostics-result" data-diagnostics-result hidden>
|
|
50
|
+
<div class="codex-diagnostics-result-head">
|
|
51
|
+
<div>
|
|
52
|
+
<div class="codex-diagnostics-result-title" data-diagnostics-result-title></div>
|
|
53
|
+
<div class="codex-diagnostics-result-subtitle" data-diagnostics-result-subtitle></div>
|
|
54
|
+
</div>
|
|
55
|
+
<button type="button" data-diagnostics-result-close title="Close" aria-label="Close diagnostics result">×</button>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="codex-diagnostics-result-body" data-diagnostics-result-body></div>
|
|
58
|
+
<details class="codex-diagnostics-technical" data-diagnostics-result-details>
|
|
59
|
+
<summary data-i18n="technicalDetails">Technical Details</summary>
|
|
60
|
+
<pre data-diagnostics-result-technical></pre>
|
|
61
|
+
</details>
|
|
62
|
+
</section>
|
|
63
|
+
</div>
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
bindStaticActions(instance);
|
|
67
|
+
installDismiss(instance);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
show: () => toggleMenu(instance, true),
|
|
71
|
+
hide: () => closeMenu(instance),
|
|
72
|
+
updateStatus: status => updateStatus(instance, status),
|
|
73
|
+
destroy: () => destroy(instance),
|
|
74
|
+
_instance: instance
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function bindStaticActions(instance) {
|
|
79
|
+
const root = instance.container;
|
|
80
|
+
root.querySelector('[data-diagnostics-menu]')?.addEventListener('click', () => toggleMenu(instance));
|
|
81
|
+
root.querySelector('[data-diagnostics-run-all]')?.addEventListener('click', () => instance.callbacks.onRunAll?.());
|
|
82
|
+
root.querySelector('[data-diagnostics-native-env]')?.addEventListener('click', () => instance.callbacks.onNativeEnvironment?.());
|
|
83
|
+
root.querySelector('[data-diagnostics-page-state]')?.addEventListener('click', () => instance.callbacks.onPageState?.());
|
|
84
|
+
root.querySelector('[data-diagnostics-snapshot]')?.addEventListener('click', () => instance.callbacks.onSnapshot?.());
|
|
85
|
+
root.querySelector('[data-diagnostics-ot]')?.addEventListener('click', () => instance.callbacks.onOtDiagnostics?.());
|
|
86
|
+
root.querySelector('[data-diagnostics-export]')?.addEventListener('click', () => instance.callbacks.onExport?.());
|
|
87
|
+
root.querySelector('[data-diagnostics-result-close]')?.addEventListener('click', () => closeResult(instance));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function toggleMenu(target, forceOpen) {
|
|
91
|
+
const instance = target?._instance || target;
|
|
92
|
+
const popover = instance?.container?.querySelector('[data-diagnostics-popover]');
|
|
93
|
+
const button = instance?.container?.querySelector('[data-diagnostics-menu]');
|
|
94
|
+
if (!popover || !button) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const open = typeof forceOpen === 'boolean' ? forceOpen : popover.hidden;
|
|
98
|
+
if (open) {
|
|
99
|
+
instance.callbacks.onBeforeOpen?.();
|
|
100
|
+
}
|
|
101
|
+
popover.hidden = !open;
|
|
102
|
+
button.dataset.active = open ? 'true' : 'false';
|
|
103
|
+
button.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function closeMenu(target) {
|
|
107
|
+
const instance = target?._instance || target;
|
|
108
|
+
const popover = instance?.container?.querySelector('[data-diagnostics-popover]');
|
|
109
|
+
const button = instance?.container?.querySelector('[data-diagnostics-menu]');
|
|
110
|
+
if (!popover || !button) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
popover.hidden = true;
|
|
114
|
+
button.dataset.active = 'false';
|
|
115
|
+
button.setAttribute('aria-expanded', 'false');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function closeResult(target) {
|
|
119
|
+
const instance = target?._instance || target;
|
|
120
|
+
const result = instance?.container?.querySelector('[data-diagnostics-result]');
|
|
121
|
+
if (result) {
|
|
122
|
+
result.hidden = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function showLoading(target, title, subtitle) {
|
|
127
|
+
const instance = target?._instance || target;
|
|
128
|
+
showResult(instance, {
|
|
129
|
+
title,
|
|
130
|
+
subtitle: subtitle || t(instance, 'diagnosticsLoading'),
|
|
131
|
+
status: 'running',
|
|
132
|
+
summary: t(instance, 'diagnosticsLoadingSummary')
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function showResult(target, result = {}) {
|
|
137
|
+
const instance = target?._instance || target;
|
|
138
|
+
const root = instance?.container?.querySelector('[data-diagnostics-result]');
|
|
139
|
+
if (!root) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
root.hidden = false;
|
|
144
|
+
root.dataset.status = result.status || 'info';
|
|
145
|
+
root.querySelector('[data-diagnostics-result-title]').textContent = result.title || t(instance, 'diagnosticsResult');
|
|
146
|
+
root.querySelector('[data-diagnostics-result-subtitle]').textContent = result.subtitle || '';
|
|
147
|
+
|
|
148
|
+
const body = root.querySelector('[data-diagnostics-result-body]');
|
|
149
|
+
body.textContent = '';
|
|
150
|
+
if (result.summary) {
|
|
151
|
+
appendParagraph(body, result.summary);
|
|
152
|
+
}
|
|
153
|
+
// Aggregated health report: one status row per check (Run all checks).
|
|
154
|
+
if (Array.isArray(result.checks) && result.checks.length) {
|
|
155
|
+
renderCheckRows(body, result.checks);
|
|
156
|
+
} else if (!result.summary) {
|
|
157
|
+
appendParagraph(body, t(instance, 'diagnosticsNoResult'));
|
|
158
|
+
}
|
|
159
|
+
if (Array.isArray(result.bullets) && result.bullets.length) {
|
|
160
|
+
const list = document.createElement('ul');
|
|
161
|
+
for (const item of result.bullets) {
|
|
162
|
+
const li = document.createElement('li');
|
|
163
|
+
li.textContent = item;
|
|
164
|
+
list.append(li);
|
|
165
|
+
}
|
|
166
|
+
body.append(list);
|
|
167
|
+
}
|
|
168
|
+
if (result.nextStep) {
|
|
169
|
+
const next = document.createElement('p');
|
|
170
|
+
next.className = 'codex-diagnostics-next-step';
|
|
171
|
+
next.textContent = `${t(instance, 'nextStepPrefix')}${result.nextStep}`;
|
|
172
|
+
body.append(next);
|
|
173
|
+
}
|
|
174
|
+
if (result.installCommand) {
|
|
175
|
+
renderInstallCommand(instance, body, result.installCommand);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const details = root.querySelector('[data-diagnostics-result-details]');
|
|
179
|
+
const technical = root.querySelector('[data-diagnostics-result-technical]');
|
|
180
|
+
const technicalText = String(result.technical || '').trim();
|
|
181
|
+
details.open = false;
|
|
182
|
+
details.hidden = !technicalText;
|
|
183
|
+
technical.textContent = technicalText;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function renderInstallCommand(instance, container, command) {
|
|
187
|
+
const wrap = document.createElement('div');
|
|
188
|
+
wrap.className = 'codex-install-command';
|
|
189
|
+
|
|
190
|
+
const label = document.createElement('div');
|
|
191
|
+
label.className = 'codex-install-command-label';
|
|
192
|
+
label.textContent = t(instance, 'runInTerminal');
|
|
193
|
+
wrap.append(label);
|
|
194
|
+
|
|
195
|
+
const code = document.createElement('code');
|
|
196
|
+
code.textContent = command;
|
|
197
|
+
wrap.append(code);
|
|
198
|
+
|
|
199
|
+
const copyButton = document.createElement('button');
|
|
200
|
+
copyButton.type = 'button';
|
|
201
|
+
copyButton.textContent = t(instance, 'copyInstallCommand');
|
|
202
|
+
copyButton.addEventListener('click', async () => {
|
|
203
|
+
await navigator.clipboard.writeText(command);
|
|
204
|
+
copyButton.textContent = t(instance, 'copied');
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
copyButton.textContent = t(instance, 'copyInstallCommand');
|
|
207
|
+
}, 1400);
|
|
208
|
+
});
|
|
209
|
+
wrap.append(copyButton);
|
|
210
|
+
|
|
211
|
+
container.append(wrap);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function appendParagraph(container, text) {
|
|
215
|
+
const paragraph = document.createElement('p');
|
|
216
|
+
paragraph.textContent = text;
|
|
217
|
+
container.append(paragraph);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Map a result status to a coarse health bucket used for the row glyph + the
|
|
221
|
+
// overall dot. 'completed' reads as a pass; anything not-ok is attention.
|
|
222
|
+
function healthBucket(status) {
|
|
223
|
+
if (status === 'completed' || status === 'ok') return 'ok';
|
|
224
|
+
if (status === 'warning' || status === 'warn') return 'warn';
|
|
225
|
+
if (status === 'failed' || status === 'fail') return 'fail';
|
|
226
|
+
return 'info';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Render the aggregated report as one scannable row per check: a status glyph
|
|
230
|
+
// (via CSS [data-status]), a plain-language title + summary, and an optional
|
|
231
|
+
// actionable next step.
|
|
232
|
+
function renderCheckRows(container, checks) {
|
|
233
|
+
const list = document.createElement('div');
|
|
234
|
+
list.className = 'codex-diagnostics-checks';
|
|
235
|
+
for (const check of checks) {
|
|
236
|
+
if (!check) continue;
|
|
237
|
+
const row = document.createElement('div');
|
|
238
|
+
row.className = 'codex-diagnostics-check';
|
|
239
|
+
row.dataset.status = healthBucket(check.status);
|
|
240
|
+
|
|
241
|
+
const glyph = document.createElement('span');
|
|
242
|
+
glyph.className = 'codex-diagnostics-check-glyph';
|
|
243
|
+
glyph.setAttribute('aria-hidden', 'true');
|
|
244
|
+
|
|
245
|
+
const textWrap = document.createElement('div');
|
|
246
|
+
textWrap.className = 'codex-diagnostics-check-text';
|
|
247
|
+
const title = document.createElement('div');
|
|
248
|
+
title.className = 'codex-diagnostics-check-title';
|
|
249
|
+
title.textContent = check.title || '';
|
|
250
|
+
textWrap.append(title);
|
|
251
|
+
if (check.summary) {
|
|
252
|
+
const summary = document.createElement('div');
|
|
253
|
+
summary.className = 'codex-diagnostics-check-summary';
|
|
254
|
+
summary.textContent = check.summary;
|
|
255
|
+
textWrap.append(summary);
|
|
256
|
+
}
|
|
257
|
+
if (check.nextStep) {
|
|
258
|
+
const next = document.createElement('div');
|
|
259
|
+
next.className = 'codex-diagnostics-check-next';
|
|
260
|
+
next.textContent = `→ ${check.nextStep}`;
|
|
261
|
+
textWrap.append(next);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
row.append(glyph, textWrap);
|
|
265
|
+
list.append(row);
|
|
266
|
+
}
|
|
267
|
+
container.append(list);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function installDismiss(instance) {
|
|
271
|
+
if (instance.dismissInstalled) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
instance.dismissInstalled = true;
|
|
275
|
+
document.addEventListener('click', event => {
|
|
276
|
+
const wrap = instance.container?.querySelector('.codex-diagnostics-wrap');
|
|
277
|
+
if (!wrap || wrap.contains(event.target)) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
closeMenu(instance);
|
|
281
|
+
}, true);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Drive the trigger's health dot. `health` is one of ok / warn / fail /
|
|
285
|
+
// unknown; the dot colors via [data-health] in CSS so the button signals the
|
|
286
|
+
// overall state without being opened. Driven by the native-compatibility
|
|
287
|
+
// status, and refreshed by a Run-all diagnostics pass.
|
|
288
|
+
const HEALTH_STATES = ['ok', 'warn', 'fail', 'unknown'];
|
|
289
|
+
function updateStatus(target, status = {}) {
|
|
290
|
+
const instance = target?._instance || target;
|
|
291
|
+
if (!Object.prototype.hasOwnProperty.call(status, 'health')) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const dot = instance?.container?.querySelector('[data-diagnostics-health-dot]');
|
|
295
|
+
if (!dot) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const health = HEALTH_STATES.indexOf(status.health) !== -1 ? status.health : 'unknown';
|
|
299
|
+
dot.dataset.health = health;
|
|
300
|
+
// The 9px dot carries the whole health signal; give the trigger a
|
|
301
|
+
// per-state tooltip so the colors are decodable without opening the menu.
|
|
302
|
+
const trigger = instance?.container?.querySelector('[data-diagnostics-menu]');
|
|
303
|
+
if (trigger) {
|
|
304
|
+
const tooltipKey = {
|
|
305
|
+
ok: 'diagnosticsDotOk',
|
|
306
|
+
warn: 'diagnosticsDotWarn',
|
|
307
|
+
fail: 'diagnosticsDotFail',
|
|
308
|
+
unknown: 'diagnosticsDotUnknown'
|
|
309
|
+
}[health] || 'diagnosticsDotUnknown';
|
|
310
|
+
const tooltip = t(instance, tooltipKey);
|
|
311
|
+
trigger.title = tooltip;
|
|
312
|
+
trigger.setAttribute('aria-label', tooltip);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function t(instance, key, params) {
|
|
317
|
+
if (typeof instance?.i18n === 'function') {
|
|
318
|
+
return instance.i18n(key, params);
|
|
319
|
+
}
|
|
320
|
+
if (typeof instance?.i18n?.tr === 'function') {
|
|
321
|
+
return instance.i18n.tr(key, params);
|
|
322
|
+
}
|
|
323
|
+
if (typeof instance?.i18n?.t === 'function') {
|
|
324
|
+
return instance.i18n.t(key, params);
|
|
325
|
+
}
|
|
326
|
+
return key;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function destroy(instance) {
|
|
330
|
+
instance.container.textContent = '';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
window.CodexOverleafDiagnosticsPanel = {
|
|
334
|
+
create,
|
|
335
|
+
updateStatus,
|
|
336
|
+
toggleMenu,
|
|
337
|
+
closeMenu,
|
|
338
|
+
closeResult,
|
|
339
|
+
showLoading,
|
|
340
|
+
showResult
|
|
341
|
+
};
|
|
342
|
+
})();
|