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
|
@@ -2,85 +2,87 @@
|
|
|
2
2
|
|
|
3
3
|
const { truncateText } = require('./debugLog');
|
|
4
4
|
const { formatOverleafWorkspaceRules } = require('./overleafWorkspaceRules');
|
|
5
|
+
const { buildReadProgressRules } = require('./readProgressGuard');
|
|
5
6
|
|
|
6
7
|
const PROJECT_CUSTOM_INSTRUCTIONS_MAX_CHARS = 12000;
|
|
7
8
|
const NATIVE_MESSAGE_PROMPT_MAX_CHARS = 1024 * 1024;
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
/** Stable parent-thread guidance; the active mode and task belong to the turn. */
|
|
11
|
+
function buildCodexDeveloperInstructions(options = {}) {
|
|
12
|
+
const params = options.params && typeof options.params === 'object' ? options.params : options;
|
|
13
|
+
const locale = (options.locale ?? params.locale) === 'zh' ? 'Chinese (zh)' : 'English (en)';
|
|
14
|
+
const skillInvocation = options.skillInvocation || params.skillInvocation;
|
|
15
|
+
return [
|
|
16
|
+
'You are Codex working inside the Codex Overleaf Link panel, helping an academic author with their LaTeX project in Overleaf. The user reads your answer in a narrow (~380px) side panel.',
|
|
17
|
+
[
|
|
18
|
+
'Reply language and style:',
|
|
19
|
+
`- Reply in the language of the user's latest request. If unclear, use the UI language: ${locale}. Keep LaTeX source, file paths, and identifiers unchanged.`,
|
|
20
|
+
'- Lead with the answer or outcome. Use short paragraphs and lists; avoid wide tables and long code dumps. Do not restate the request.',
|
|
21
|
+
'- Complete the requested analysis or edit within this turn. Do not end with only a plan or a promise to act later.',
|
|
22
|
+
'- For edits, summarize what changed per file with citations. The panel already shows written files, diffs, and Undo; do not paste whole diffs.'
|
|
23
|
+
].join('\n'),
|
|
24
|
+
...(isSkillInstallerInvocation(skillInvocation) ? [] : [formatOverleafWorkspaceRules()]),
|
|
25
|
+
['Project location citation rules:', formatProjectLocationCitationRules()].join('\n'),
|
|
26
|
+
['Answer formatting:', formatMathOutputRules()].join('\n'),
|
|
27
|
+
[
|
|
28
|
+
'Academic integrity:',
|
|
29
|
+
'- Never invent citations, BibTeX entries, data, results, or quotations.',
|
|
30
|
+
'- When a claim needs a source you cannot verify in the project, say so and suggest what kind of source is needed instead of adding one.'
|
|
31
|
+
].join('\n'),
|
|
32
|
+
[
|
|
33
|
+
'Editing discipline for writable turns:',
|
|
34
|
+
'- Change only what the request needs. Keep unrelated text, whitespace, and formatting untouched; small diffs keep Overleaf tracked changes and Undo reviewable.',
|
|
35
|
+
'- Keep \\label, \\ref, and \\cite keys and file names stable unless asked to change them.',
|
|
36
|
+
'- Keep the document compilable, with balanced braces and environments.'
|
|
37
|
+
].join('\n'),
|
|
38
|
+
[
|
|
39
|
+
'Modes:',
|
|
40
|
+
'- Each turn states its active mode. These modes govern project work; explicit skill-install turns follow their separate installation scope.',
|
|
41
|
+
'- Ask is read-only: inspect and explain. When suggesting edits, show short LaTeX snippets with citations and mention that Auto mode can apply them.',
|
|
42
|
+
'- Auto may edit the local workspace. The browser bridge handles authorization, deletion approval, and syncing to Overleaf.'
|
|
43
|
+
].join('\n'),
|
|
44
|
+
buildReadProgressRules()
|
|
45
|
+
].join('\n\n');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Build dynamic per-turn context and the current user request. */
|
|
22
49
|
function buildCodexTurnPrompt(options = {}) {
|
|
23
50
|
const context = normalizePromptOptions(options);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
'
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
'
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'',
|
|
60
|
-
'Selected Codex skill:',
|
|
61
|
-
formatSkillInvocationContext(context),
|
|
62
|
-
'',
|
|
63
|
-
'Attachments for this turn:',
|
|
64
|
-
formatTurnAttachmentsContext(context.attachments),
|
|
65
|
-
'',
|
|
66
|
-
'Mode for this turn:',
|
|
67
|
-
`- ${context.mode}`,
|
|
68
|
-
'- ask: inspect and explain only; do not edit files.',
|
|
69
|
-
'- auto: edit the local workspace directly when the request calls for changes. The browser bridge handles authorization, deletion approval, and syncing back to Overleaf.',
|
|
70
|
-
'',
|
|
71
|
-
'Write expectation for this turn:',
|
|
72
|
-
formatWriteExpectation({
|
|
73
|
-
mode: context.mode,
|
|
74
|
-
task: context.userTask,
|
|
75
|
-
skillInvocation: context.skillInvocation
|
|
76
|
-
})
|
|
77
|
-
].join('\n');
|
|
78
|
-
|
|
79
|
-
const userPrompt = [
|
|
80
|
-
'Current user request:',
|
|
81
|
-
context.userTask || '(empty request)'
|
|
82
|
-
].join('\n');
|
|
83
|
-
|
|
51
|
+
const sections = [
|
|
52
|
+
`Mode for this turn: ${context.mode}`,
|
|
53
|
+
['Write expectation for this turn:', formatWriteExpectation(context)].join('\n')
|
|
54
|
+
];
|
|
55
|
+
if (!isSkillInstallerInvocation(context.skillInvocation)) {
|
|
56
|
+
sections.push([
|
|
57
|
+
'Current Overleaf workspace:',
|
|
58
|
+
...(context.projectKey || context.projectId ? [`- Project: ${context.projectKey || context.projectId}`] : []),
|
|
59
|
+
...formatWorkspaceSnapshotContext(context.unreadFiles)
|
|
60
|
+
].join('\n'));
|
|
61
|
+
}
|
|
62
|
+
if (!context.threadId && Array.isArray(context.session.history) && context.session.history.length) {
|
|
63
|
+
sections.push(['Recent turns in this UI session:', formatSessionHistory(context.session.history)].join('\n'));
|
|
64
|
+
}
|
|
65
|
+
if (context.focusFiles.length) {
|
|
66
|
+
sections.push(['Focus files:', formatFocusFiles(context.focusFiles)].join('\n'));
|
|
67
|
+
}
|
|
68
|
+
if (String(context.compileLog || '').trim()) {
|
|
69
|
+
sections.push(['Compilation context (@compile-log):', formatCompileLogContext(context)].join('\n'));
|
|
70
|
+
}
|
|
71
|
+
if (String(context.customInstructions || '').trim()) {
|
|
72
|
+
sections.push(['Project custom instructions:', formatCustomInstructionsContext(context.customInstructions)].join('\n'));
|
|
73
|
+
}
|
|
74
|
+
if (context.selectedSkillIds.length && (context.projectLocalSkills.skills?.length || context.projectLocalSkills.missing?.length)) {
|
|
75
|
+
sections.push(['Project local skills:', formatProjectLocalSkillsContext(context)].join('\n'));
|
|
76
|
+
}
|
|
77
|
+
if (normalizeSkillInvocation(context.skillInvocation) || normalizeSkillInvocation(context.codexSkillInvocationContext?.invocation)
|
|
78
|
+
|| context.codexSkillInvocationContext?.ignored?.length || context.codexSkillInvocationContext?.missing?.length) {
|
|
79
|
+
sections.push(['Selected Codex skill:', formatSkillInvocationContext(context)].join('\n'));
|
|
80
|
+
}
|
|
81
|
+
if (context.attachments.length) {
|
|
82
|
+
sections.push(['Attachments for this turn:', formatTurnAttachmentsContext(context.attachments)].join('\n'));
|
|
83
|
+
}
|
|
84
|
+
const systemPrompt = sections.join('\n\n');
|
|
85
|
+
const userPrompt = ['Current user request:', context.userTask || '(empty request)'].join('\n');
|
|
84
86
|
return { systemPrompt, userPrompt };
|
|
85
87
|
}
|
|
86
88
|
|
|
@@ -88,10 +90,12 @@ function buildCodexTurnPrompt(options = {}) {
|
|
|
88
90
|
* Validate prompt size against native messaging limits.
|
|
89
91
|
* @param {string} systemPrompt
|
|
90
92
|
* @param {string} userPrompt
|
|
93
|
+
* @param {string} developerInstructions
|
|
91
94
|
* @returns {{ ok: boolean, totalChars: number, exceedsLimit: boolean }}
|
|
92
95
|
*/
|
|
93
|
-
function validatePromptSize(systemPrompt, userPrompt) {
|
|
94
|
-
const totalChars = String(systemPrompt || '').length + String(userPrompt || '').length
|
|
96
|
+
function validatePromptSize(systemPrompt, userPrompt, developerInstructions = '') {
|
|
97
|
+
const totalChars = String(systemPrompt || '').length + String(userPrompt || '').length
|
|
98
|
+
+ String(developerInstructions || '').length;
|
|
95
99
|
const exceedsLimit = totalChars > NATIVE_MESSAGE_PROMPT_MAX_CHARS;
|
|
96
100
|
return {
|
|
97
101
|
ok: !exceedsLimit,
|
|
@@ -128,9 +132,11 @@ function normalizePromptOptions(options = {}) {
|
|
|
128
132
|
return {
|
|
129
133
|
params,
|
|
130
134
|
session,
|
|
135
|
+
threadId: String(options.threadId ?? params.threadId ?? '').trim(),
|
|
131
136
|
projectKey: mirror.projectKey || options.projectKey || params.projectId || params.project?.id || params.project?.projectId,
|
|
132
137
|
projectId: options.projectId || params.projectId || params.project?.id || params.project?.projectId,
|
|
133
138
|
workspacePath: mirror.workspacePath || options.workspacePath || '',
|
|
139
|
+
unreadFiles: Array.isArray(mirror.skippedFiles) ? mirror.skippedFiles : [],
|
|
134
140
|
userTask: String(options.task !== undefined ? options.task : params.task || '').trim(),
|
|
135
141
|
mode: options.mode || params.mode || 'auto',
|
|
136
142
|
customInstructions: options.customInstructions !== undefined ? options.customInstructions : params.customInstructions,
|
|
@@ -154,6 +160,18 @@ function normalizePromptOptions(options = {}) {
|
|
|
154
160
|
};
|
|
155
161
|
}
|
|
156
162
|
|
|
163
|
+
function formatWorkspaceSnapshotContext(unreadFiles) {
|
|
164
|
+
if (!unreadFiles.length) return [
|
|
165
|
+
'- The local workspace was synced from Overleaf before this turn; trust the files over conflicting session history.'
|
|
166
|
+
];
|
|
167
|
+
return [
|
|
168
|
+
'- The readable project files were synced from Overleaf before this turn.',
|
|
169
|
+
'- The following assets were not read because of the binary size limits. A retained local copy may be stale; a missing local copy does not mean the asset was deleted from Overleaf.',
|
|
170
|
+
'- Do not rely on these assets as current evidence or edit them. Their local changes cannot be written back until their current Overleaf content is read. Other readable files remain available for this task.',
|
|
171
|
+
...unreadFiles.map(file => `- Unavailable current content: ${JSON.stringify(file.path)} (${file.reason}).`)
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
|
|
157
175
|
function normalizeLoadedSkills(skills = []) {
|
|
158
176
|
return (Array.isArray(skills) ? skills : [])
|
|
159
177
|
.map(skill => ({
|
|
@@ -183,7 +201,7 @@ function formatTurnAttachmentsContext(attachments = []) {
|
|
|
183
201
|
].join('\n');
|
|
184
202
|
}
|
|
185
203
|
|
|
186
|
-
function formatWriteExpectation({ mode = 'auto',
|
|
204
|
+
function formatWriteExpectation({ mode = 'auto', skillInvocation = null } = {}) {
|
|
187
205
|
if (isSkillInstallerInvocation(skillInvocation)) {
|
|
188
206
|
return [
|
|
189
207
|
'- This is a skill-install turn.',
|
|
@@ -195,29 +213,7 @@ function formatWriteExpectation({ mode = 'auto', task = '', skillInvocation = nu
|
|
|
195
213
|
if (mode === 'ask') {
|
|
196
214
|
return '- This is read-only. Inspect and explain; do not edit files.';
|
|
197
215
|
}
|
|
198
|
-
if
|
|
199
|
-
const lines = [
|
|
200
|
-
'- The request asks for file changes. You must edit the local workspace when you find concrete fixes.',
|
|
201
|
-
'- Do not stop at a suggestion list or say you will not modify files unless no safe concrete edit exists.',
|
|
202
|
-
'- If you intentionally leave files unchanged, explain the specific blocker in the final answer.'
|
|
203
|
-
];
|
|
204
|
-
if (requestTargetsAbstract(task)) {
|
|
205
|
-
lines.push('- The request targets the abstract/summary. Locate the LaTeX abstract environment or summary paragraph and edit that local project file directly.');
|
|
206
|
-
}
|
|
207
|
-
return lines.join('\n');
|
|
208
|
-
}
|
|
209
|
-
return [
|
|
210
|
-
'- This mode can write. If the request asks for corrections, revisions, fixes, polishing, updates, or implementation, edit the local workspace directly.',
|
|
211
|
-
'- If the request is purely an inspection question, report findings without inventing unnecessary edits.'
|
|
212
|
-
].join('\n');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function requestImpliesFileChanges(task = '') {
|
|
216
|
-
return /修正|修复|修改|改[一-龥]*|完善|补全|补充|润色|重写|改写|整理|调整|应用|写入|fix|correct|repair|revise|edit|update|rewrite|polish|improve|apply/i.test(String(task || ''));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function requestTargetsAbstract(task = '') {
|
|
220
|
-
return /摘要|abstract|summary/i.test(String(task || ''));
|
|
216
|
+
return '- Decide from the request whether it asks for changes. If it asks you to fix, revise, polish, rewrite, apply or otherwise change the project, edit the workspace files directly instead of only suggesting; if it asks a question, answer it without editing. If you intentionally leave files unchanged for a change request, explain the blocker.';
|
|
221
217
|
}
|
|
222
218
|
|
|
223
219
|
function normalizeFocusFiles(value) {
|
|
@@ -258,8 +254,8 @@ function normalizeProjectPath(value) {
|
|
|
258
254
|
|
|
259
255
|
function formatProjectLocationCitationRules() {
|
|
260
256
|
return [
|
|
261
|
-
'- In any user-visible output, cite project locations using only Overleaf project-relative paths
|
|
262
|
-
'- Use path:LINE[:COLUMN] (for example, path/to/file.tex:12:3).',
|
|
257
|
+
'- In any user-visible output, cite project locations using only Overleaf project-relative paths of files in this workspace.',
|
|
258
|
+
'- Use path:LINE[:COLUMN] for a position and path:START-END for a span (for example, path/to/file.tex:12:3 or main.tex:12-20).',
|
|
263
259
|
'- Do not wrap project location citations in backticks or inline code; write main.tex:28 as normal text so the browser can turn it into a jump button.',
|
|
264
260
|
'- Do not cite local absolute paths, temporary workspace paths, file:// URLs, or markdown links to local files.',
|
|
265
261
|
'- If a line number is uncertain, cite only the project-relative file path.'
|
|
@@ -276,14 +272,6 @@ function formatMathOutputRules() {
|
|
|
276
272
|
].join('\n');
|
|
277
273
|
}
|
|
278
274
|
|
|
279
|
-
function formatFocusedProjectFileInventory(files) {
|
|
280
|
-
const focusFiles = normalizeFocusFiles(files);
|
|
281
|
-
if (!focusFiles.length) {
|
|
282
|
-
return '- none selected.';
|
|
283
|
-
}
|
|
284
|
-
return focusFiles.map(filePath => `- ${filePath}`).join('\n');
|
|
285
|
-
}
|
|
286
|
-
|
|
287
275
|
function formatFocusFiles(files) {
|
|
288
276
|
if (!files.length) {
|
|
289
277
|
return '- none; use the whole project when needed.';
|
|
@@ -383,29 +371,25 @@ function formatProjectLocalSkillsContext(context = {}) {
|
|
|
383
371
|
return sections.length ? sections.join('\n\n') : '- none loaded.';
|
|
384
372
|
}
|
|
385
373
|
|
|
386
|
-
function formatCodexSkillLoadingContext(context = {}) {
|
|
387
|
-
return [
|
|
388
|
-
`- Codex local skills: ${context.loadCodexLocalSkills === false ? 'disabled' : 'enabled'}`,
|
|
389
|
-
`- Codex Overleaf skills: ${context.loadCodexOverleafSkills === false ? 'disabled' : 'enabled'}`
|
|
390
|
-
].join('\n');
|
|
391
|
-
}
|
|
392
|
-
|
|
393
374
|
function formatSkillInvocationContext(context = {}) {
|
|
394
375
|
const invocation = normalizeSkillInvocation(context.skillInvocation);
|
|
395
376
|
const codexSkillInvocationContext = context.codexSkillInvocationContext || {};
|
|
396
377
|
const contextInvocation = normalizeSkillInvocation(codexSkillInvocationContext.invocation);
|
|
397
378
|
const effectiveInvocation = contextInvocation || invocation;
|
|
379
|
+
const skillLabel = effectiveInvocation?.scope === 'codex-local' ? 'local Codex' : 'Codex Overleaf';
|
|
398
380
|
if (Array.isArray(codexSkillInvocationContext.ignored) && codexSkillInvocationContext.ignored.length) {
|
|
399
381
|
return [
|
|
400
|
-
|
|
382
|
+
`Ignored selected ${skillLabel} skill:`,
|
|
401
383
|
...codexSkillInvocationContext.ignored.map(item => `- ${item.id}`),
|
|
402
|
-
|
|
384
|
+
effectiveInvocation?.scope === 'codex-local'
|
|
385
|
+
? '- Reason: The selected local Codex skill is disabled for this turn.'
|
|
386
|
+
: '- Reason: Codex Overleaf skills are disabled for this turn.',
|
|
403
387
|
'- The stale slash selection was ignored; no selected skill instructions were forced into this prompt.'
|
|
404
388
|
].join('\n');
|
|
405
389
|
}
|
|
406
390
|
if (Array.isArray(codexSkillInvocationContext.missing) && codexSkillInvocationContext.missing.length) {
|
|
407
391
|
return [
|
|
408
|
-
|
|
392
|
+
`Missing selected ${skillLabel} skill:`,
|
|
409
393
|
...codexSkillInvocationContext.missing.map(id => `- ${id}`),
|
|
410
394
|
'- The stale slash selection was ignored; no selected skill instructions were forced into this prompt.'
|
|
411
395
|
].join('\n');
|
|
@@ -427,17 +411,19 @@ function formatSkillInvocationContext(context = {}) {
|
|
|
427
411
|
if (loadedSkill) {
|
|
428
412
|
return [
|
|
429
413
|
`- ${effectiveInvocation.id} (${effectiveInvocation.title})`,
|
|
430
|
-
|
|
414
|
+
`- REQUIRED for this turn: read and use this selected ${skillLabel} skill before answering.`,
|
|
431
415
|
'- Follow the embedded SKILL.md instructions when they apply to the current user request.',
|
|
416
|
+
...(effectiveInvocation.scope === 'codex-local' && loadedSkill.path
|
|
417
|
+
? [`- Skill source: ${loadedSkill.path}`, '- Resolve relative skill resources against this SKILL.md directory.'] : []),
|
|
432
418
|
'',
|
|
433
|
-
|
|
419
|
+
`Selected ${skillLabel} SKILL.md:`,
|
|
434
420
|
`## ${loadedSkill.id}: ${loadedSkill.title || effectiveInvocation.title || loadedSkill.id}`,
|
|
435
421
|
fencedBlock(loadedSkill.content)
|
|
436
422
|
].join('\n');
|
|
437
423
|
}
|
|
438
424
|
return [
|
|
439
425
|
`- ${effectiveInvocation.id} (${effectiveInvocation.title})`,
|
|
440
|
-
|
|
426
|
+
`- Use this selected ${skillLabel} skill for the current turn.`,
|
|
441
427
|
'- Follow the skill instructions and workflow when they apply to the user request.'
|
|
442
428
|
].join('\n');
|
|
443
429
|
}
|
|
@@ -450,17 +436,18 @@ function normalizeSkillInvocation(value) {
|
|
|
450
436
|
const title = String(value?.title || value?.name || (id === 'skill-installer' ? 'Skill Installer' : id))
|
|
451
437
|
.trim()
|
|
452
438
|
.slice(0, 80) || 'Skill Installer';
|
|
453
|
-
if (id === 'skill-installer') {
|
|
439
|
+
if (id === 'skill-installer' && (!value?.scope || value.scope === 'builtin')) {
|
|
454
440
|
return { id, title };
|
|
455
441
|
}
|
|
456
|
-
if (
|
|
442
|
+
if (!['codex-overleaf', 'codex-local'].includes(value?.scope) && !Object.prototype.hasOwnProperty.call(value || {}, 'skillId')) {
|
|
457
443
|
return null;
|
|
458
444
|
}
|
|
459
|
-
return { id, title, scope: 'codex-overleaf' };
|
|
445
|
+
return { id, title, scope: value?.scope === 'codex-local' ? 'codex-local' : 'codex-overleaf' };
|
|
460
446
|
}
|
|
461
447
|
|
|
462
448
|
function isSkillInstallerInvocation(value) {
|
|
463
|
-
|
|
449
|
+
const invocation = normalizeSkillInvocation(value);
|
|
450
|
+
return invocation?.id === 'skill-installer' && !invocation.scope;
|
|
464
451
|
}
|
|
465
452
|
|
|
466
453
|
function isSafeSkillId(id) {
|
|
@@ -495,4 +482,4 @@ function formatSessionHistory(history) {
|
|
|
495
482
|
}).join('\n');
|
|
496
483
|
}
|
|
497
484
|
|
|
498
|
-
module.exports = { buildCodexTurnPrompt, validatePromptSize };
|
|
485
|
+
module.exports = { buildCodexDeveloperInstructions, buildCodexTurnPrompt, validatePromptSize };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { runOwnedNativeHelper } = require('./nativeHelperLifecycle');
|
|
4
|
+
const { stopCodexAppServer } = require('./codexSessionTiming');
|
|
5
|
+
const { spawn } = require('node:child_process');
|
|
4
6
|
const crypto = require('node:crypto');
|
|
5
7
|
const fs = require('node:fs');
|
|
6
8
|
const os = require('node:os');
|
|
@@ -12,16 +14,22 @@ const { providerError } = require('./providerProfile');
|
|
|
12
14
|
const MAX_OUTPUT_BYTES = 256 * 1024;
|
|
13
15
|
|
|
14
16
|
async function runProviderConnectionTest({ launch, env = process.env, signal } = {}) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
throwIfTestCancelled(signal);
|
|
18
|
+
return runOwnedNativeHelper(async ownedSignal => {
|
|
19
|
+
throwIfTestCancelled(ownedSignal);
|
|
20
|
+
const prepared = await prepareProviderLaunch(launch, { signal: ownedSignal });
|
|
21
|
+
try {
|
|
22
|
+
throwIfTestCancelled(ownedSignal);
|
|
23
|
+
return await runProviderConnectionTestProcess({ launch: prepared.launch, env, signal: ownedSignal });
|
|
24
|
+
} finally {
|
|
25
|
+
await prepared.close();
|
|
26
|
+
}
|
|
27
|
+
}, signal);
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
function runProviderConnectionTestProcess({ launch, env = process.env, signal } = {}) {
|
|
24
31
|
return new Promise((resolve, reject) => {
|
|
32
|
+
throwIfTestCancelled(signal);
|
|
25
33
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-overleaf-provider-test-'));
|
|
26
34
|
const codexHome = path.join(root, 'codex-home');
|
|
27
35
|
const workspace = path.join(root, 'workspace');
|
|
@@ -52,6 +60,7 @@ function runProviderConnectionTestProcess({ launch, env = process.env, signal }
|
|
|
52
60
|
const startedAt = Date.now();
|
|
53
61
|
let child;
|
|
54
62
|
try {
|
|
63
|
+
throwIfTestCancelled(signal);
|
|
55
64
|
child = spawn(command, args, {
|
|
56
65
|
cwd: workspace,
|
|
57
66
|
env: childEnv,
|
|
@@ -61,7 +70,8 @@ function runProviderConnectionTestProcess({ launch, env = process.env, signal }
|
|
|
61
70
|
});
|
|
62
71
|
} catch (error) {
|
|
63
72
|
cleanup(root);
|
|
64
|
-
reject(
|
|
73
|
+
reject(error?.code === 'provider_test_cancelled' ? error
|
|
74
|
+
: providerError('provider_test_spawn_failed', 'Codex could not start the provider connection test.', { cause: error }));
|
|
65
75
|
return;
|
|
66
76
|
}
|
|
67
77
|
let stdout = '';
|
|
@@ -121,10 +131,10 @@ function runProviderConnectionTestProcess({ launch, env = process.env, signal }
|
|
|
121
131
|
settled = true;
|
|
122
132
|
clearTimeout(timer);
|
|
123
133
|
signal?.removeEventListener('abort', onAbort);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
stopCodexAppServer(child, { processGroup: process.platform !== 'win32', reason: error }).then(() => {
|
|
135
|
+
cleanup(root);
|
|
136
|
+
if (error) reject(error); else resolve(result);
|
|
137
|
+
}, stopError => { cleanup(root); reject(stopError); });
|
|
128
138
|
}
|
|
129
139
|
});
|
|
130
140
|
}
|
|
@@ -168,20 +178,8 @@ function hasLeakedToolControlTokens(value) {
|
|
|
168
178
|
return /<\|tool_call_(?:begin|argument_begin|end)\|>/i.test(String(value || ''));
|
|
169
179
|
}
|
|
170
180
|
|
|
171
|
-
function
|
|
172
|
-
if (
|
|
173
|
-
try {
|
|
174
|
-
if (process.platform === 'win32') {
|
|
175
|
-
spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore', windowsHide: true });
|
|
176
|
-
} else {
|
|
177
|
-
process.kill(-child.pid, 'SIGTERM');
|
|
178
|
-
setTimeout(() => {
|
|
179
|
-
try { process.kill(-child.pid, 'SIGKILL'); } catch (_error) {}
|
|
180
|
-
}, 500).unref?.();
|
|
181
|
-
}
|
|
182
|
-
} catch (_error) {
|
|
183
|
-
try { child.kill('SIGKILL'); } catch (_killError) {}
|
|
184
|
-
}
|
|
181
|
+
function throwIfTestCancelled(signal) {
|
|
182
|
+
if (signal?.aborted) throw providerError('provider_test_cancelled', 'Provider connection test was cancelled.');
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
function cleanup(root) {
|