codex-overleaf-link 1.1.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/LICENSE +21 -0
- package/README.md +457 -0
- package/bin/codex-overleaf-link.mjs +223 -0
- package/extension/src/shared/agentTranscript.js +1175 -0
- package/extension/src/shared/auditRecords.js +568 -0
- package/extension/src/shared/compatibility.js +372 -0
- package/extension/src/shared/compileAdapter.js +176 -0
- package/extension/src/shared/governanceRules.js +252 -0
- package/extension/src/shared/i18n.js +565 -0
- package/extension/src/shared/models.js +106 -0
- package/extension/src/shared/otText.js +505 -0
- package/extension/src/shared/projectFiles.js +180 -0
- package/extension/src/shared/reviewing.js +99 -0
- package/extension/src/shared/sensitiveScan.js +116 -0
- package/extension/src/shared/sessionState.js +1084 -0
- package/extension/src/shared/staleGuard.js +150 -0
- package/extension/src/shared/storageDb.js +986 -0
- package/extension/src/shared/storageKeys.js +29 -0
- package/extension/src/shared/storageMigration.js +168 -0
- package/extension/src/shared/summary.js +248 -0
- package/extension/src/shared/undoOperations.js +369 -0
- package/native-host/src/codexArgs.js +43 -0
- package/native-host/src/codexHome.js +538 -0
- package/native-host/src/codexModels.js +247 -0
- package/native-host/src/codexPrompt.js +192 -0
- package/native-host/src/codexPromptAssembly.js +411 -0
- package/native-host/src/codexSessionRunner.js +1247 -0
- package/native-host/src/commandApproval.js +914 -0
- package/native-host/src/debugLog.js +78 -0
- package/native-host/src/diffEngine.js +247 -0
- package/native-host/src/index.js +132 -0
- package/native-host/src/launcher.js +81 -0
- package/native-host/src/localSkills.js +476 -0
- package/native-host/src/manifest.js +226 -0
- package/native-host/src/mirrorSensitiveScan.js +119 -0
- package/native-host/src/mirrorWorkspace.js +1019 -0
- package/native-host/src/nativeDoctor.js +826 -0
- package/native-host/src/nativeEnvironment.js +315 -0
- package/native-host/src/nativeHostPlatform.js +112 -0
- package/native-host/src/nativeMessaging.js +60 -0
- package/native-host/src/nativeQuotas.js +294 -0
- package/native-host/src/nativeResponseBudget.js +194 -0
- package/native-host/src/runtimeInstaller.js +357 -0
- package/native-host/src/taskRunner.js +3 -0
- package/native-host/src/taskRunnerRuntime.js +1083 -0
- package/native-host/src/textPatch.js +287 -0
- package/package.json +40 -0
- package/scripts/codex-json-agent.mjs +269 -0
- package/scripts/install-native-host.mjs +255 -0
- package/scripts/npm-package-files-v1.1.1.txt +52 -0
- package/scripts/uninstall-native-host.mjs +298 -0
- package/scripts/verify-npm-package.mjs +296 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { spawnSync } = require('node:child_process');
|
|
7
|
+
|
|
8
|
+
const TOOL_NAMES = ['codex', 'latexmk', 'pdflatex', 'xelatex', 'lualatex', 'bibtex', 'biber'];
|
|
9
|
+
const LATEX_TOOL_NAMES = ['latexmk', 'pdflatex', 'xelatex', 'lualatex', 'bibtex', 'biber'];
|
|
10
|
+
const SUPPORTED_PLATFORMS = new Set(['darwin', 'linux', 'win32']);
|
|
11
|
+
|
|
12
|
+
function buildNativeRuntimeEnv(baseEnv = process.env, options = {}) {
|
|
13
|
+
const env = { ...baseEnv };
|
|
14
|
+
const runtimeOptions = { ...options, platform: getNativeRuntimePlatform(options) };
|
|
15
|
+
const loginShellEnv = options.readLoginShellEnv
|
|
16
|
+
? options.readLoginShellEnv(baseEnv, runtimeOptions)
|
|
17
|
+
: readLoginShellEnv(baseEnv, runtimeOptions);
|
|
18
|
+
const defaultPathSegments = Object.hasOwn(options, 'defaultPathSegments')
|
|
19
|
+
? options.defaultPathSegments
|
|
20
|
+
: getDefaultPathSegments(baseEnv, runtimeOptions);
|
|
21
|
+
const pathSegments = [
|
|
22
|
+
...getPathValues(loginShellEnv, runtimeOptions),
|
|
23
|
+
...getPathValues(baseEnv, runtimeOptions),
|
|
24
|
+
...defaultPathSegments
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
env.PATH = mergePathSegments(pathSegments, runtimeOptions);
|
|
28
|
+
normalizePathKeys(env, env.PATH, runtimeOptions);
|
|
29
|
+
env.CODEX_OVERLEAF_ENV_READY = '1';
|
|
30
|
+
env.CODEX_OVERLEAF_PLATFORM = runtimeOptions.platform;
|
|
31
|
+
|
|
32
|
+
for (const tool of TOOL_NAMES) {
|
|
33
|
+
env[getToolEnvName(tool)] = resolveExecutable(tool, env.PATH, { ...runtimeOptions, env }) || '';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readLoginShellEnv(baseEnv = process.env, options = {}) {
|
|
40
|
+
if (getNativeRuntimePlatform(options) === 'win32') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (baseEnv.CODEX_OVERLEAF_DISABLE_SHELL_ENV === '1') {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const shell = selectLoginShell(baseEnv, options);
|
|
48
|
+
if (!shell) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const command = [
|
|
53
|
+
'printf "__CODEX_OVERLEAF_ENV_START__\\n"',
|
|
54
|
+
'printf "PATH=%s\\n" "$PATH"',
|
|
55
|
+
'printf "__CODEX_OVERLEAF_ENV_END__\\n"'
|
|
56
|
+
].join('; ');
|
|
57
|
+
const args = shouldUseLoginFlag(shell) ? ['-l', '-i', '-c', command] : ['-c', command];
|
|
58
|
+
const result = spawnSync(shell, args, {
|
|
59
|
+
env: {
|
|
60
|
+
...baseEnv,
|
|
61
|
+
PATH: baseEnv.PATH || '/usr/bin:/bin:/usr/sbin:/sbin'
|
|
62
|
+
},
|
|
63
|
+
encoding: 'utf8',
|
|
64
|
+
timeout: 1500,
|
|
65
|
+
maxBuffer: 64 * 1024
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (result.error || result.status !== 0) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return parseMarkedShellEnv(result.stdout || '');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseMarkedShellEnv(output) {
|
|
76
|
+
const match = String(output).match(/__CODEX_OVERLEAF_ENV_START__\n([\s\S]*?)\n__CODEX_OVERLEAF_ENV_END__/);
|
|
77
|
+
if (!match) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const env = {};
|
|
82
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
83
|
+
const index = line.indexOf('=');
|
|
84
|
+
if (index <= 0) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
env[line.slice(0, index)] = line.slice(index + 1);
|
|
88
|
+
}
|
|
89
|
+
return env;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function selectLoginShell(env = process.env, options = {}) {
|
|
93
|
+
if (getNativeRuntimePlatform(options) === 'win32') {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const candidates = [
|
|
98
|
+
env.SHELL,
|
|
99
|
+
'/bin/zsh',
|
|
100
|
+
'/bin/bash',
|
|
101
|
+
'/bin/sh'
|
|
102
|
+
].filter(Boolean);
|
|
103
|
+
|
|
104
|
+
for (const candidate of candidates) {
|
|
105
|
+
if (!path.isAbsolute(candidate)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
110
|
+
return candidate;
|
|
111
|
+
} catch {
|
|
112
|
+
// Try the next common shell.
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function shouldUseLoginFlag(shell) {
|
|
119
|
+
return ['zsh', 'bash'].includes(path.basename(shell));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getDefaultPathSegments(env = process.env, options = {}) {
|
|
123
|
+
const platform = getNativeRuntimePlatform(options);
|
|
124
|
+
const platformPath = platform === 'win32' ? path.win32 : path.posix;
|
|
125
|
+
const home = env.HOME || os.homedir();
|
|
126
|
+
const commonSegments = [
|
|
127
|
+
path.dirname(process.execPath),
|
|
128
|
+
platformPath.join(home, '.local/bin'),
|
|
129
|
+
platformPath.join(home, '.npm-global/bin'),
|
|
130
|
+
platformPath.join(home, 'bin'),
|
|
131
|
+
'/usr/local/bin',
|
|
132
|
+
'/usr/local/sbin',
|
|
133
|
+
'/usr/bin',
|
|
134
|
+
'/bin',
|
|
135
|
+
'/usr/sbin',
|
|
136
|
+
'/sbin'
|
|
137
|
+
];
|
|
138
|
+
if (platform === 'linux') {
|
|
139
|
+
return [
|
|
140
|
+
...commonSegments.slice(0, 4),
|
|
141
|
+
'/usr/local/texlive/2026/bin/x86_64-linux',
|
|
142
|
+
'/usr/local/texlive/2025/bin/x86_64-linux',
|
|
143
|
+
'/usr/local/texlive/bin/x86_64-linux',
|
|
144
|
+
...commonSegments.slice(4)
|
|
145
|
+
];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (platform === 'win32') {
|
|
149
|
+
return commonSegments;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return [
|
|
153
|
+
...commonSegments.slice(0, 4),
|
|
154
|
+
'/Library/TeX/texbin',
|
|
155
|
+
'/opt/homebrew/bin',
|
|
156
|
+
'/opt/homebrew/sbin',
|
|
157
|
+
...commonSegments.slice(4)
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function mergePathSegments(values, options = {}) {
|
|
162
|
+
const delimiter = getPathDelimiter(options);
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
const merged = [];
|
|
165
|
+
for (const value of values) {
|
|
166
|
+
for (const segment of splitPathValue(value, delimiter)) {
|
|
167
|
+
const clean = segment.trim();
|
|
168
|
+
if (!clean || seen.has(clean)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
seen.add(clean);
|
|
172
|
+
merged.push(clean);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return merged.join(delimiter);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function resolveExecutable(name, pathValue, options = {}) {
|
|
179
|
+
const delimiter = getPathDelimiter(options);
|
|
180
|
+
const executableNames = getExecutableCandidates(name, options);
|
|
181
|
+
for (const directory of splitPathValue(pathValue, delimiter)) {
|
|
182
|
+
if (!directory) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
for (const executableName of executableNames) {
|
|
186
|
+
const candidate = path.join(directory, executableName);
|
|
187
|
+
try {
|
|
188
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
189
|
+
return candidate;
|
|
190
|
+
} catch {
|
|
191
|
+
// Keep searching PATH.
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return '';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function summarizeNativeEnvironment(env = process.env, options = {}) {
|
|
199
|
+
const runtimeOptions = { ...options, platform: getNativeRuntimePlatform({ ...options, env }) };
|
|
200
|
+
const availableLatex = LATEX_TOOL_NAMES.filter(tool => Boolean(env[getToolEnvName(tool)]));
|
|
201
|
+
const missingLatex = LATEX_TOOL_NAMES.filter(tool => !env[getToolEnvName(tool)]);
|
|
202
|
+
return {
|
|
203
|
+
codex: {
|
|
204
|
+
ok: Boolean(env.CODEX_OVERLEAF_CODEX_PATH),
|
|
205
|
+
path: env.CODEX_OVERLEAF_CODEX_PATH || ''
|
|
206
|
+
},
|
|
207
|
+
latex: {
|
|
208
|
+
ok: availableLatex.length > 0,
|
|
209
|
+
available: availableLatex,
|
|
210
|
+
missing: missingLatex,
|
|
211
|
+
tools: Object.fromEntries(LATEX_TOOL_NAMES.map(tool => [tool, env[getToolEnvName(tool)] || '']))
|
|
212
|
+
},
|
|
213
|
+
pathPreview: splitPathValue(env.PATH, getPathDelimiter(runtimeOptions)).filter(Boolean).slice(0, 12)
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function getToolEnvName(tool) {
|
|
218
|
+
return `CODEX_OVERLEAF_${String(tool).replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}_PATH`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function getNativeRuntimePlatform(options = {}) {
|
|
222
|
+
return validateNativeRuntimePlatform(options.platform)
|
|
223
|
+
|| validateNativeRuntimePlatform(options.env?.CODEX_OVERLEAF_PLATFORM)
|
|
224
|
+
|| validateNativeRuntimePlatform(process.platform)
|
|
225
|
+
|| 'linux';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function validateNativeRuntimePlatform(platform) {
|
|
229
|
+
return SUPPORTED_PLATFORMS.has(platform) ? platform : '';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function getPathDelimiter(options = {}) {
|
|
233
|
+
if (options.delimiter) {
|
|
234
|
+
return options.delimiter;
|
|
235
|
+
}
|
|
236
|
+
return getNativeRuntimePlatform(options) === 'win32' ? ';' : ':';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function getPathValues(env, options = {}) {
|
|
240
|
+
if (!env) {
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
if (getNativeRuntimePlatform(options) !== 'win32') {
|
|
244
|
+
return [env.PATH];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const values = [];
|
|
248
|
+
if (Object.hasOwn(env, 'Path')) {
|
|
249
|
+
values.push(env.Path);
|
|
250
|
+
}
|
|
251
|
+
if (Object.hasOwn(env, 'PATH')) {
|
|
252
|
+
values.push(env.PATH);
|
|
253
|
+
}
|
|
254
|
+
if (!values.length) {
|
|
255
|
+
for (const [key, value] of Object.entries(env)) {
|
|
256
|
+
if (key.toLowerCase() === 'path') {
|
|
257
|
+
values.push(value);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return values;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function splitPathValue(value, delimiter) {
|
|
265
|
+
return String(value || '').split(delimiter);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function getExecutableCandidates(name, options = {}) {
|
|
269
|
+
const candidates = [name];
|
|
270
|
+
if (getNativeRuntimePlatform(options) !== 'win32' || path.extname(name)) {
|
|
271
|
+
return candidates;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const extension of getWindowsPathExtensions(options.env || process.env)) {
|
|
275
|
+
candidates.push(`${name}${extension}`);
|
|
276
|
+
}
|
|
277
|
+
return [...new Set(candidates)];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function getWindowsPathExtensions(env) {
|
|
281
|
+
const raw = env.PATHEXT || '.COM;.EXE;.BAT;.CMD';
|
|
282
|
+
const extensions = [];
|
|
283
|
+
for (const extension of String(raw).split(';')) {
|
|
284
|
+
const clean = extension.trim();
|
|
285
|
+
if (!clean) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
extensions.push(clean.toLowerCase(), clean.toUpperCase(), clean);
|
|
289
|
+
}
|
|
290
|
+
return [...new Set(extensions)];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function normalizePathKeys(env, pathValue, options = {}) {
|
|
294
|
+
if (getNativeRuntimePlatform(options) !== 'win32') {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
for (const key of Object.keys(env)) {
|
|
299
|
+
if (key.toLowerCase() === 'path') {
|
|
300
|
+
delete env[key];
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
env.PATH = pathValue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
module.exports = {
|
|
307
|
+
buildNativeRuntimeEnv,
|
|
308
|
+
getDefaultPathSegments,
|
|
309
|
+
getNativeRuntimePlatform,
|
|
310
|
+
mergePathSegments,
|
|
311
|
+
parseMarkedShellEnv,
|
|
312
|
+
readLoginShellEnv,
|
|
313
|
+
resolveExecutable,
|
|
314
|
+
summarizeNativeEnvironment
|
|
315
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('node:os');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const {
|
|
6
|
+
getNativeHostManifestPath,
|
|
7
|
+
getWindowsRegistryMetadata
|
|
8
|
+
} = require('./manifest');
|
|
9
|
+
|
|
10
|
+
function getNativeHostPlatform(options = {}) {
|
|
11
|
+
return options.platform || process.platform;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getCodexOverleafHome(options = {}) {
|
|
15
|
+
const platform = getNativeHostPlatform(options);
|
|
16
|
+
if (platform === 'win32') {
|
|
17
|
+
return path.win32.join(getWindowsLocalAppData(options), 'CodexOverleaf');
|
|
18
|
+
}
|
|
19
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
20
|
+
return path.posix.join(getHomeDir(options), '.codex-overleaf');
|
|
21
|
+
}
|
|
22
|
+
throwUnsupportedPlatform(platform);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getDefaultRuntimeRoot(options = {}) {
|
|
26
|
+
const platformPath = getPathModule(options);
|
|
27
|
+
return platformPath.join(getCodexOverleafHome(options), 'native-host-runtime');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getDefaultBridgePath(options = {}) {
|
|
31
|
+
const platformPath = getPathModule(options);
|
|
32
|
+
const bridgeName = getNativeHostPlatform(options) === 'win32'
|
|
33
|
+
? 'codex-overleaf-bridge.cmd'
|
|
34
|
+
: 'codex-overleaf-bridge';
|
|
35
|
+
return platformPath.join(getCodexOverleafHome(options), bridgeName);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getNativeHostRegistrationTarget(options = {}) {
|
|
39
|
+
const platform = getNativeHostPlatform(options);
|
|
40
|
+
const browser = getNativeHostBrowser(options);
|
|
41
|
+
const manifestPath = getNativeHostManifestPath({ ...options, platform, browser });
|
|
42
|
+
|
|
43
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
44
|
+
return {
|
|
45
|
+
kind: 'file',
|
|
46
|
+
browser,
|
|
47
|
+
manifestPath
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (platform === 'win32') {
|
|
52
|
+
const metadata = getWindowsRegistryMetadata({ ...options, browser });
|
|
53
|
+
return {
|
|
54
|
+
kind: 'registry',
|
|
55
|
+
browser: metadata.browser,
|
|
56
|
+
root: metadata.root,
|
|
57
|
+
registryKey: metadata.registryKey,
|
|
58
|
+
manifestPath: metadata.manifestPath
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throwUnsupportedPlatform(platform);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getNativeManifestPath(options = {}) {
|
|
66
|
+
const platform = getNativeHostPlatform(options);
|
|
67
|
+
const browser = getNativeHostBrowser(options);
|
|
68
|
+
return getNativeHostManifestPath({ ...options, platform, browser });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getNativeHostBrowser(options) {
|
|
72
|
+
const browser = options.browser || 'chrome';
|
|
73
|
+
return browser === 'auto' ? 'chrome' : browser;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getHomeDir(options) {
|
|
77
|
+
const env = options.env || process.env;
|
|
78
|
+
if (getNativeHostPlatform(options) === 'win32') {
|
|
79
|
+
return options.homeDir || env.USERPROFILE || env.HOME || os.homedir();
|
|
80
|
+
}
|
|
81
|
+
return options.homeDir || env.HOME || env.USERPROFILE || os.homedir();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getWindowsLocalAppData(options) {
|
|
85
|
+
const env = options.env || process.env;
|
|
86
|
+
if (env.LOCALAPPDATA) {
|
|
87
|
+
return env.LOCALAPPDATA;
|
|
88
|
+
}
|
|
89
|
+
return path.win32.join(getHomeDir(options), 'AppData', 'Local');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getPathModule(options) {
|
|
93
|
+
return getNativeHostPlatform(options) === 'win32' ? path.win32 : path.posix;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function throwUnsupportedPlatform(platform) {
|
|
97
|
+
throw new Error(`Unsupported native host platform: ${platform}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function throwUnsupportedBrowser(platform, browser) {
|
|
101
|
+
throw new Error(`Unsupported native host browser for ${platform}: ${browser}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
getCodexOverleafHome,
|
|
106
|
+
getDefaultBridgePath,
|
|
107
|
+
getDefaultRuntimeRoot,
|
|
108
|
+
getHomeDir,
|
|
109
|
+
getNativeHostPlatform,
|
|
110
|
+
getNativeHostRegistrationTarget,
|
|
111
|
+
getNativeManifestPath
|
|
112
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MAX_NATIVE_OUTPUT_MESSAGE_BYTES = 1024 * 1024;
|
|
4
|
+
const MAX_NATIVE_INPUT_MESSAGE_BYTES = 128 * 1024 * 1024;
|
|
5
|
+
const MAX_NATIVE_BUFFER_BYTES = 160 * 1024 * 1024;
|
|
6
|
+
|
|
7
|
+
function encodeMessage(message) {
|
|
8
|
+
const payload = Buffer.from(JSON.stringify(message), 'utf8');
|
|
9
|
+
if (payload.length > MAX_NATIVE_OUTPUT_MESSAGE_BYTES) {
|
|
10
|
+
throw new Error(`Native message frame is too large: ${payload.length} bytes`);
|
|
11
|
+
}
|
|
12
|
+
const frame = Buffer.alloc(4 + payload.length);
|
|
13
|
+
frame.writeUInt32LE(payload.length, 0);
|
|
14
|
+
payload.copy(frame, 4);
|
|
15
|
+
return frame;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function decodeFrames(buffer) {
|
|
19
|
+
if (buffer.length > MAX_NATIVE_BUFFER_BYTES) {
|
|
20
|
+
throw new Error(`Native message buffer is too large: ${buffer.length} bytes`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const messages = [];
|
|
24
|
+
let offset = 0;
|
|
25
|
+
|
|
26
|
+
while (buffer.length - offset >= 4) {
|
|
27
|
+
const length = buffer.readUInt32LE(offset);
|
|
28
|
+
if (length > MAX_NATIVE_INPUT_MESSAGE_BYTES) {
|
|
29
|
+
throw new Error(`Native message frame is too large: ${length} bytes`);
|
|
30
|
+
}
|
|
31
|
+
const frameStart = offset + 4;
|
|
32
|
+
const frameEnd = frameStart + length;
|
|
33
|
+
|
|
34
|
+
if (buffer.length < frameEnd) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const payload = buffer.subarray(frameStart, frameEnd).toString('utf8');
|
|
39
|
+
try {
|
|
40
|
+
messages.push(JSON.parse(payload));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new Error(`Invalid JSON in native message: ${error.message}`);
|
|
43
|
+
}
|
|
44
|
+
offset = frameEnd;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
messages,
|
|
49
|
+
remainder: buffer.subarray(offset)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
MAX_NATIVE_BUFFER_BYTES,
|
|
55
|
+
MAX_NATIVE_INPUT_MESSAGE_BYTES,
|
|
56
|
+
MAX_NATIVE_MESSAGE_BYTES: MAX_NATIVE_OUTPUT_MESSAGE_BYTES,
|
|
57
|
+
MAX_NATIVE_OUTPUT_MESSAGE_BYTES,
|
|
58
|
+
decodeFrames,
|
|
59
|
+
encodeMessage
|
|
60
|
+
};
|