codex-overleaf-link 2.6.0 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/README.zh-CN.md +9 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/background.js +70 -0
- package/extension/src/content/composerAttachments.js +35 -8
- package/extension/src/content/contentRuntime.js +200 -51
- package/extension/src/content/diagnosticsController.js +77 -34
- package/extension/src/content/diagnosticsExport.js +1 -1
- package/extension/src/content/diagnosticsPanel.js +129 -42
- package/extension/src/content/generated/content.bundle.js +1283 -331
- package/extension/src/content/generated/content.bundle.meta.json +3 -3
- package/extension/src/content/localSkillsPanel.js +4 -2
- package/extension/src/content/markdownText.js +11 -9
- package/extension/src/content/modelPicker.js +28 -19
- package/extension/src/content/nativeCompatibilityController.js +23 -9
- package/extension/src/content/pageBridgeClient.js +5 -5
- package/extension/src/content/panelMaintenance.js +4 -0
- package/extension/src/content/panelRenderer.js +4 -1
- package/extension/src/content/providerSettingsDialog.js +26 -18
- package/extension/src/content/recentProjects.js +26 -16
- package/extension/src/content/runQueueScheduler.js +19 -9
- package/extension/src/content/runResultActions.js +51 -4
- package/extension/src/content/runReviewController.js +9 -3
- package/extension/src/content/scopedPersistencePanelState.js +34 -25
- package/extension/src/content/selectionContextView.js +30 -3
- package/extension/src/content/sharedSessionViewSync.js +9 -1
- package/extension/src/content/writebackOrchestrator.js +266 -50
- package/extension/src/content/writingStyleSettings.js +70 -17
- package/extension/src/page/overleafEditor.js +12 -3
- package/extension/src/page/overleafProjectSnapshot.js +56 -3
- package/extension/src/page/snapshotRouter.js +75 -66
- package/extension/src/page/treeOperations.js +200 -19
- package/extension/src/page/writebackRouter.js +152 -40
- package/extension/src/pageBridge.js +17 -7
- package/extension/src/shared/agentTranscript.js +23 -2
- package/extension/src/shared/auditRecords.js +1 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/composerAttachmentDraft.js +22 -7
- package/extension/src/shared/failureReasons.js +15 -0
- package/extension/src/shared/i18n.js +16 -0
- package/extension/src/shared/pageRpcContract.js +1 -1
- package/extension/src/shared/projectFiles.js +2 -1
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +34 -0
- package/extension/src/shared/staleGuard.js +58 -0
- package/extension/src/shared/storageMigration.js +104 -1
- package/extension/styles/panel.css +191 -63
- package/native-host/src/codexSessionRunner.js +1 -0
- package/native-host/src/debugLog.js +27 -3
- package/native-host/src/index.js +42 -11
- package/native-host/src/localSkills.js +1 -1
- package/native-host/src/mirrorWorkspace.js +47 -3
- package/native-host/src/nativeEnvironment.js +27 -5
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/skills/reviewer-response/SKILL.md +65 -0
- package/native-host/src/taskRunnerRuntime.js +11 -3
- package/native-host/src/updateManager.js +24 -6
- package/native-host/src/writingStyleRuntime.js +1 -1
- package/package.json +1 -1
|
@@ -40,6 +40,11 @@ function buildNativeRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
|
40
40
|
for (const tool of TOOL_NAMES) {
|
|
41
41
|
env[getToolEnvName(tool)] = resolveExecutable(tool, env.PATH, { ...runtimeOptions, env }) || '';
|
|
42
42
|
}
|
|
43
|
+
const startupContext = getCodexRuntimeRefreshContext({
|
|
44
|
+
...env,
|
|
45
|
+
CODEX_OVERLEAF_CODEX_PATH: explicitCodexPath || env.CODEX_OVERLEAF_CODEX_PATH,
|
|
46
|
+
CODEX_OVERLEAF_CODEX_RUNTIME_JSON: ''
|
|
47
|
+
}, runtimeOptions);
|
|
43
48
|
const codexRuntime = buildCodexRuntimeIdentity({
|
|
44
49
|
selectedPath: explicitCodexPath || env.CODEX_OVERLEAF_CODEX_PATH,
|
|
45
50
|
selectionPolicy: explicitCodexPath ? 'explicit-path' : 'newest-version',
|
|
@@ -53,12 +58,20 @@ function buildNativeRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
|
53
58
|
env.CODEX_OVERLEAF_CODEX_VERSION = codexRuntime.selected?.version || '';
|
|
54
59
|
env.CODEX_OVERLEAF_CODEX_SOURCE = codexRuntime.selected?.source || '';
|
|
55
60
|
|
|
61
|
+
const { key, pathValue, signatures } = getCodexRuntimeRefreshContext(env, runtimeOptions);
|
|
62
|
+
// Selection can reorder candidates, but discovery must not cache changed files.
|
|
63
|
+
if (pathValue === startupContext.pathValue
|
|
64
|
+
&& signatures.length === startupContext.signatures.length
|
|
65
|
+
&& signatures.every(signature => startupContext.signatures.some(before => JSON.stringify(before) === JSON.stringify(signature)))) {
|
|
66
|
+
cacheCodexRuntimeIdentity(key, codexRuntime);
|
|
67
|
+
}
|
|
68
|
+
|
|
56
69
|
return env;
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
const codexRuntimeRefreshCache = new Map();
|
|
60
73
|
|
|
61
|
-
function
|
|
74
|
+
function getCodexRuntimeRefreshContext(baseEnv, options) {
|
|
62
75
|
const runtimeOptions = { ...options, platform: getNativeRuntimePlatform({ ...options, env: baseEnv }) };
|
|
63
76
|
const previous = getCodexRuntimeIdentityFromEnv(baseEnv);
|
|
64
77
|
const selectedPath = previous.selected?.path || String(baseEnv.CODEX_OVERLEAF_CODEX_PATH || '');
|
|
@@ -78,6 +91,18 @@ function refreshCodexRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
|
78
91
|
} catch (_) { return [candidate, 'missing']; }
|
|
79
92
|
});
|
|
80
93
|
const key = JSON.stringify([runtimeOptions.platform, pinned ? selectedPath : '', pathValue, signatures]);
|
|
94
|
+
return { runtimeOptions, previous, selectedPath, pinned, pathValue, signatures, key };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function cacheCodexRuntimeIdentity(key, identity) {
|
|
98
|
+
codexRuntimeRefreshCache.set(key, { identity, createdAt: Date.now() });
|
|
99
|
+
while (codexRuntimeRefreshCache.size > 4) {
|
|
100
|
+
codexRuntimeRefreshCache.delete(codexRuntimeRefreshCache.keys().next().value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function refreshCodexRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
105
|
+
const { runtimeOptions, previous, selectedPath, pinned, pathValue, key } = getCodexRuntimeRefreshContext(baseEnv, options);
|
|
81
106
|
const cached = codexRuntimeRefreshCache.get(key);
|
|
82
107
|
let identity = cached?.identity;
|
|
83
108
|
if (options.force || !cached || Date.now() - cached.createdAt > 30000) {
|
|
@@ -89,10 +114,7 @@ function refreshCodexRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
|
89
114
|
env: { ...baseEnv, PATH: pathValue },
|
|
90
115
|
platform: runtimeOptions.platform
|
|
91
116
|
});
|
|
92
|
-
|
|
93
|
-
while (codexRuntimeRefreshCache.size > 4) {
|
|
94
|
-
codexRuntimeRefreshCache.delete(codexRuntimeRefreshCache.keys().next().value);
|
|
95
|
-
}
|
|
117
|
+
cacheCodexRuntimeIdentity(key, identity);
|
|
96
118
|
if (identity.selected?.path !== previous.selected?.path
|
|
97
119
|
|| identity.selected?.version !== previous.selected?.version) {
|
|
98
120
|
logDebug('codex.runtime.refreshed', {
|
|
@@ -237,6 +237,7 @@ function resolveProviderModels(params = {}, env = process.env, resolveBuiltInMod
|
|
|
237
237
|
providerId: profile.id,
|
|
238
238
|
providerRevision: profile.revision,
|
|
239
239
|
providerName: profile.name,
|
|
240
|
+
defaultModelId: profile.defaultModelId,
|
|
240
241
|
models: profile.models.map(model => {
|
|
241
242
|
const reasoning = getReasoningControl(profile, model);
|
|
242
243
|
return {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer-response
|
|
3
|
+
description: >
|
|
4
|
+
Use only when the user asks to respond to peer-review or reviewer comments,
|
|
5
|
+
write a rebuttal or response letter, or plan a revision from reviews.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Reviewer Response
|
|
9
|
+
|
|
10
|
+
Map reviewer comments to evidence in the paper, proposed edits, and reply
|
|
11
|
+
drafts. Keep missing evidence visible instead of filling it with assumptions.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
1. Split the reviews into atomic comments with stable IDs R<reviewer>.<n>,
|
|
16
|
+
such as R1.2. Keep the reviewer's own numbering when present; retain the
|
|
17
|
+
original label when splitting a numbered comment into smaller items.
|
|
18
|
+
2. For each comment, look for evidence in the project files. Cite actual
|
|
19
|
+
source lines as plain-text path:line or path:start-end, for example
|
|
20
|
+
main.tex:212-230. Do not wrap references in backticks: the panel turns
|
|
21
|
+
plain-text references into clickable links. If evidence is absent, write
|
|
22
|
+
"Not found"; distinguish files not read from files searched without a match.
|
|
23
|
+
3. Output a compact ledger table with these columns:
|
|
24
|
+
|
|
25
|
+
ID | Comment | Evidence in the paper | Proposed change | Status
|
|
26
|
+
|
|
27
|
+
Keep cells short for the narrow panel, with each Comment at most about
|
|
28
|
+
12 words. Put necessary explanations below the table. Use only these
|
|
29
|
+
statuses, adding a short reason:
|
|
30
|
+
- Ready to edit: the evidence supports a specific local edit.
|
|
31
|
+
- Needs an experiment: new experimental evidence is required.
|
|
32
|
+
- Needs author input: facts or a decision must come from the author.
|
|
33
|
+
- Unresolved: the comment remains open for another stated reason.
|
|
34
|
+
- No change: explain why the current paper already addresses the comment
|
|
35
|
+
or why a change is unwarranted.
|
|
36
|
+
|
|
37
|
+
Write the table and explanations in the user's language, translating
|
|
38
|
+
headings, statuses, and "Not found" accordingly. Keep the IDs unchanged.
|
|
39
|
+
4. After the ledger, draft replies only for the comments the user asked
|
|
40
|
+
about, or for every comment when they requested a full response letter.
|
|
41
|
+
Write reply drafts in English unless the user asks otherwise. Label each
|
|
42
|
+
draft with its comment ID and distinguish proposed work from completed work.
|
|
43
|
+
5. Finish with one "Next:" line, localized to the user's language, explaining
|
|
44
|
+
how to apply approved items. For example: Next: after approving R1.2,
|
|
45
|
+
switch to Auto and send "Apply R1.2".
|
|
46
|
+
|
|
47
|
+
## Integrity rules
|
|
48
|
+
|
|
49
|
+
- Never invent results, numbers, experiments, citations, or completed changes.
|
|
50
|
+
- Anything needed for a response that is not present in the paper or provided
|
|
51
|
+
by the user must be marked Needs an experiment or Needs author input.
|
|
52
|
+
- Reply drafts must not promise results. State missing evidence or pending
|
|
53
|
+
author input explicitly; do not describe planned edits as already made.
|
|
54
|
+
- Cite only files and lines actually inspected. User-provided facts are not
|
|
55
|
+
evidence already in the paper; identify their source separately.
|
|
56
|
+
|
|
57
|
+
## Editing rules
|
|
58
|
+
|
|
59
|
+
- In Ask mode, never edit files.
|
|
60
|
+
- In Auto mode, edit only the comment IDs the user explicitly approves.
|
|
61
|
+
Keep edits minimal and local, leaving unrelated text untouched. An approved
|
|
62
|
+
ID does not authorize inventing missing evidence or results.
|
|
63
|
+
- After editing, report which IDs changed with plain-text path:line or
|
|
64
|
+
path:start-end references. Keep pending items separate and do not claim
|
|
65
|
+
an edit, save, or experiment completed without evidence.
|
|
@@ -50,7 +50,7 @@ const activeRunEntries = new Map();
|
|
|
50
50
|
// Overleaf tab was reloaded — the requestId lived in content-side JS state
|
|
51
51
|
// and is gone, but the native-host-side controller is still running).
|
|
52
52
|
const activeRunByProject = new Map();
|
|
53
|
-
const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result', 'codex_context_limit', 'codex_process_stop_unconfirmed', 'selected_context_unresolved', 'codex_local_skill_unavailable']);
|
|
53
|
+
const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result', 'codex_context_limit', 'codex_process_stop_unconfirmed', 'selected_context_unresolved', 'codex_local_skill_unavailable', 'document_identity_mismatch']);
|
|
54
54
|
|
|
55
55
|
async function handleRequest(request, env = process.env, emit = () => {}) {
|
|
56
56
|
if (!request || typeof request !== 'object') {
|
|
@@ -308,7 +308,7 @@ async function handleCodexRun(request, env, emit) {
|
|
|
308
308
|
// OT overlays prove that the current page agrees with the trusted OT
|
|
309
309
|
// baseline; they must not rewrite it or supply a replacement hash.
|
|
310
310
|
if (!isOtWarmMirrorReuseRequest(params) && Array.isArray(params.fileOverlays) && params.fileOverlays.length) {
|
|
311
|
-
await applyFileOverlays({ projectId: projectKey, overlays: params.fileOverlays, rootDir });
|
|
311
|
+
await applyFileOverlays({ projectId: projectKey, evidenceProjectId: params.projectId, overlays: params.fileOverlays, rootDir });
|
|
312
312
|
}
|
|
313
313
|
} else if (params.operation !== 'compact' && !params.writingStyleBuild && !isSnapshotlessSkillInstallerRun(params) && !hasRunnableProjectSnapshotEvidence(params)) {
|
|
314
314
|
return errorResponse(
|
|
@@ -456,6 +456,13 @@ function handleCodexCancel(request, env = process.env) {
|
|
|
456
456
|
});
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
+
if (targetId != null && !force) {
|
|
460
|
+
return okResponse(request.id, {
|
|
461
|
+
cancelled: false,
|
|
462
|
+
reason: 'request_not_active'
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
459
466
|
if (projectKey) {
|
|
460
467
|
const entry = activeRunByProject.get(projectKey);
|
|
461
468
|
if (entry?.controller) {
|
|
@@ -733,6 +740,7 @@ async function handleMirrorSync(request, env) {
|
|
|
733
740
|
try {
|
|
734
741
|
const result = await syncOverleafToMirror({
|
|
735
742
|
projectId,
|
|
743
|
+
evidenceProjectId: params.projectId,
|
|
736
744
|
project: params.project || { files: [] },
|
|
737
745
|
rootDir
|
|
738
746
|
});
|
|
@@ -769,7 +777,7 @@ async function handleMirrorPatchFiles(request, env) {
|
|
|
769
777
|
});
|
|
770
778
|
return okResponse(request.id, result);
|
|
771
779
|
} catch (error) {
|
|
772
|
-
return errorResponse(request.id, 'mirror_patch_files_failed', error.message);
|
|
780
|
+
return errorResponse(request.id, error.code === 'document_identity_mismatch' ? error.code : 'mirror_patch_files_failed', error.message);
|
|
773
781
|
} finally {
|
|
774
782
|
releaseProjectLock(projectKey, lockToken);
|
|
775
783
|
}
|
|
@@ -999,12 +999,19 @@ function rollbackFiles(context, journal, options = {}) {
|
|
|
999
999
|
const runtime = path.join(context.extensionRoot, 'runtime');
|
|
1000
1000
|
const previousRuntime = path.join(context.extensionRoot, 'slots', 'previous', 'runtime');
|
|
1001
1001
|
// An early interrupted apply may still have the source in the current slot.
|
|
1002
|
-
// A missing previous slot is recoverable only when these actual
|
|
1003
|
-
// the source pair;
|
|
1004
|
-
|
|
1005
|
-
|
|
1002
|
+
// A missing or stale previous slot is recoverable only when these actual
|
|
1003
|
+
// bytes match the source pair; manifest and markers alone are insufficient.
|
|
1004
|
+
let sourceRuntime = fs.existsSync(previousRuntime) ? previousRuntime : runtime;
|
|
1005
|
+
let source;
|
|
1006
|
+
try {
|
|
1007
|
+
source = readManagedRuntimeEvidence(context, journal.sourceVersion, sourceRuntime);
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
if (journal.state !== 'applying' || sourceRuntime !== previousRuntime) throw error;
|
|
1010
|
+
source = readManagedRuntimeEvidence(context, journal.sourceVersion, runtime);
|
|
1011
|
+
sourceRuntime = runtime;
|
|
1012
|
+
}
|
|
1006
1013
|
if (journal.bootstrapMigration) BootstrapUpdate.restoreBootstrap(context, journal);
|
|
1007
|
-
if (
|
|
1014
|
+
if (sourceRuntime === previousRuntime) {
|
|
1008
1015
|
fs.rmSync(runtime, { recursive: true, force: true });
|
|
1009
1016
|
fs.renameSync(previousRuntime, runtime);
|
|
1010
1017
|
fs.rmSync(path.dirname(previousRuntime), { recursive: true, force: true });
|
|
@@ -1122,7 +1129,18 @@ function recoverAndReadStatus(context, params = {}) {
|
|
|
1122
1129
|
cleanupStage(journal.stageRoot);
|
|
1123
1130
|
}
|
|
1124
1131
|
}
|
|
1125
|
-
|
|
1132
|
+
const status = currentStatus(context, journal);
|
|
1133
|
+
if (journal?.state === 'rolled_back' && !journal.bootstrapMigration && status.restoredPair) {
|
|
1134
|
+
const authorization = readAuthorization(context);
|
|
1135
|
+
if (['bound', 'consumed'].includes(authorization?.state) && authorization.id === journal.authorizationId
|
|
1136
|
+
&& authorization.transactionId === journal.id && authorization.sourceVersion === journal.sourceVersion
|
|
1137
|
+
&& authorization.targetVersion === journal.targetVersion) {
|
|
1138
|
+
settleAuthorization(context, journal.authorizationId, 'revoked');
|
|
1139
|
+
status.authorization = publicAuthorization(readAuthorization(context));
|
|
1140
|
+
}
|
|
1141
|
+
cleanupStage(journal.stageRoot);
|
|
1142
|
+
}
|
|
1143
|
+
return status;
|
|
1126
1144
|
}
|
|
1127
1145
|
|
|
1128
1146
|
function finishSourceActivation(context, journal) {
|
|
@@ -374,7 +374,7 @@ async function build({ params, env, signal, execute, providerLaunch, onControlRe
|
|
|
374
374
|
reasoningEffort: params.reasoningEffort || '', speedTier: params.speedTier || 'standard',
|
|
375
375
|
sandboxMode: 'read-only', approvalPolicy: 'never',
|
|
376
376
|
loadCodexLocalSkills: false, loadCodexOverleafSkills: false,
|
|
377
|
-
disableCodexOverleafSkillIds: ['annotated-rewrite', 'parallel-subagents'],
|
|
377
|
+
disableCodexOverleafSkillIds: ['annotated-rewrite', 'parallel-subagents', 'reviewer-response'],
|
|
378
378
|
skillInvocation: null, projectLocalSkills: null, providerLaunch, env, signal,
|
|
379
379
|
onControlReady, emit: () => {}
|
|
380
380
|
};
|