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,180 @@
|
|
|
1
|
+
(function initProjectFiles(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafProjectFiles = factory();
|
|
6
|
+
}
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function projectFilesFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const TEXT_EXTENSIONS = new Set([
|
|
11
|
+
'.tex',
|
|
12
|
+
'.bib',
|
|
13
|
+
'.sty',
|
|
14
|
+
'.cls',
|
|
15
|
+
'.bst',
|
|
16
|
+
'.bbx',
|
|
17
|
+
'.cbx',
|
|
18
|
+
'.lbx',
|
|
19
|
+
'.cfg',
|
|
20
|
+
'.def',
|
|
21
|
+
'.clo',
|
|
22
|
+
'.ist',
|
|
23
|
+
'.txt',
|
|
24
|
+
'.md',
|
|
25
|
+
'.latex'
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const BINARY_EXTENSIONS = new Set([
|
|
29
|
+
'.pdf',
|
|
30
|
+
'.png',
|
|
31
|
+
'.jpg',
|
|
32
|
+
'.jpeg',
|
|
33
|
+
'.gif',
|
|
34
|
+
'.svg',
|
|
35
|
+
'.eps',
|
|
36
|
+
'.zip',
|
|
37
|
+
'.gz',
|
|
38
|
+
'.tar',
|
|
39
|
+
'.doc',
|
|
40
|
+
'.docx',
|
|
41
|
+
'.ppt',
|
|
42
|
+
'.pptx',
|
|
43
|
+
'.xls',
|
|
44
|
+
'.xlsx'
|
|
45
|
+
]);
|
|
46
|
+
const MAX_SAFE_PROJECT_PATH_LENGTH = 2048;
|
|
47
|
+
|
|
48
|
+
function isTextProjectPath(path) {
|
|
49
|
+
const normalized = normalizeSafeProjectPath(path);
|
|
50
|
+
if (!normalized) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const extension = getExtension(normalized);
|
|
55
|
+
if (BINARY_EXTENSIONS.has(extension)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return TEXT_EXTENSIONS.has(extension);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function collectUniqueTextPaths(paths, limit = 80) {
|
|
62
|
+
const seen = new Set();
|
|
63
|
+
const result = [];
|
|
64
|
+
for (const path of paths || []) {
|
|
65
|
+
const normalized = normalizeSafeProjectPath(path);
|
|
66
|
+
if (!isTextProjectPath(normalized) || seen.has(normalized)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
seen.add(normalized);
|
|
70
|
+
result.push(normalized);
|
|
71
|
+
if (result.length >= limit) {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizePath(path) {
|
|
79
|
+
return String(path || '')
|
|
80
|
+
.replace(/\s+/g, ' ')
|
|
81
|
+
.replace(/\\/g, '/')
|
|
82
|
+
.trim()
|
|
83
|
+
.replace(/^\/+/, '');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeSafeProjectPath(value) {
|
|
87
|
+
if (typeof value !== 'string') {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
if (hasControlCharacter(value)) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
const trimmed = value.trim();
|
|
94
|
+
if (!trimmed || trimmed.length > MAX_SAFE_PROJECT_PATH_LENGTH) {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
if (trimmed.startsWith('/') || trimmed.includes('\\') || hasWindowsDrivePrefix(trimmed)) {
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let decoded = trimmed;
|
|
102
|
+
for (let index = 0; index < 3; index += 1) {
|
|
103
|
+
if (hasEncodedSeparator(decoded)) {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
let next;
|
|
107
|
+
try {
|
|
108
|
+
next = decodeURIComponent(decoded);
|
|
109
|
+
} catch (_error) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
if (next === decoded) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
decoded = next;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (hasControlCharacter(decoded)
|
|
119
|
+
|| decoded.startsWith('/')
|
|
120
|
+
|| decoded.includes('\\')
|
|
121
|
+
|| hasWindowsDrivePrefix(decoded)
|
|
122
|
+
|| decoded.length > MAX_SAFE_PROJECT_PATH_LENGTH) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const normalized = decoded.replace(/\/+/g, '/').trim();
|
|
127
|
+
if (!normalized || normalized.length > MAX_SAFE_PROJECT_PATH_LENGTH) {
|
|
128
|
+
return '';
|
|
129
|
+
}
|
|
130
|
+
const segments = normalized.split('/');
|
|
131
|
+
if (segments.some(segment => !segment || segment === '.' || segment === '..')) {
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
return normalized;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function assertSafeProjectPath(value, label = 'path') {
|
|
138
|
+
const normalized = normalizeSafeProjectPath(value);
|
|
139
|
+
if (!normalized) {
|
|
140
|
+
throw new Error(`Invalid ${label}`);
|
|
141
|
+
}
|
|
142
|
+
return normalized;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function hasControlCharacter(value) {
|
|
146
|
+
return /[\u0000-\u001f\u007f]/.test(String(value || ''));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function hasEncodedSeparator(value) {
|
|
150
|
+
return /%(?:2f|5c)/i.test(String(value || ''));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function hasWindowsDrivePrefix(value) {
|
|
154
|
+
return /^[A-Za-z]:/.test(String(value || ''));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function getExtension(path) {
|
|
158
|
+
const fileName = path.split('/').pop() || '';
|
|
159
|
+
const dotIndex = fileName.lastIndexOf('.');
|
|
160
|
+
return dotIndex >= 0 ? fileName.slice(dotIndex).toLowerCase() : '';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function isUsableProjectFileContent(content) {
|
|
164
|
+
const text = String(content || '').trim();
|
|
165
|
+
if (!text) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return !/^(loading|loading\.{3}|loading…)$/i.test(text);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
MAX_SAFE_PROJECT_PATH_LENGTH,
|
|
173
|
+
assertSafeProjectPath,
|
|
174
|
+
collectUniqueTextPaths,
|
|
175
|
+
isUsableProjectFileContent,
|
|
176
|
+
isTextProjectPath,
|
|
177
|
+
normalizePath,
|
|
178
|
+
normalizeSafeProjectPath
|
|
179
|
+
};
|
|
180
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
(function initReviewing(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafReviewing = factory();
|
|
6
|
+
}
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function reviewingFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const CONTROL_REVIEW_PATTERNS = [
|
|
11
|
+
/\breviewing\b/i,
|
|
12
|
+
/\btrack(?:ed)? changes?\s*(?:on|enabled)\b/i,
|
|
13
|
+
/\bsuggest(?:ing|ions?)\s*(?:on|enabled)\b/i
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const INTERNAL_ACTIVE_REVIEW_PATTERNS = [
|
|
17
|
+
/\b(?:mode|editingMode|reviewMode)\s*:\s*(?:reviewing|suggesting|track(?:ed)? changes?)\b/i
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const GENERIC_REVIEW_PATTERNS = [
|
|
21
|
+
/\breview panel\b/i,
|
|
22
|
+
/^\s*review\s*$/i
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function detectReviewingFromSignals(signals = {}) {
|
|
26
|
+
if (signals.manualOverride === true) {
|
|
27
|
+
return {
|
|
28
|
+
ok: true,
|
|
29
|
+
status: 'manual-override',
|
|
30
|
+
source: 'user-confirmed'
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const control of signals.controls || []) {
|
|
35
|
+
const controlText = normalize([
|
|
36
|
+
control.text,
|
|
37
|
+
control.innerText,
|
|
38
|
+
control.ariaLabel,
|
|
39
|
+
control.title,
|
|
40
|
+
control.value,
|
|
41
|
+
control.role,
|
|
42
|
+
control.id,
|
|
43
|
+
control.className,
|
|
44
|
+
control.dataTestId,
|
|
45
|
+
control.dataQa,
|
|
46
|
+
control.dataOlName,
|
|
47
|
+
control.ariaSelected,
|
|
48
|
+
control.ariaCurrent,
|
|
49
|
+
control.htmlSnippet,
|
|
50
|
+
control.ariaPressed === 'true' ? 'pressed' : ''
|
|
51
|
+
].filter(Boolean).join(' '));
|
|
52
|
+
|
|
53
|
+
if (matchesControlReview(controlText) && !isGenericReviewOnly(controlText)) {
|
|
54
|
+
return {
|
|
55
|
+
ok: true,
|
|
56
|
+
status: 'detected',
|
|
57
|
+
source: 'control-text'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const stateText of signals.internalStates || []) {
|
|
63
|
+
const normalized = normalize(stateText);
|
|
64
|
+
if (matchesInternalActiveReview(normalized)) {
|
|
65
|
+
return {
|
|
66
|
+
ok: true,
|
|
67
|
+
status: 'detected',
|
|
68
|
+
source: 'internal-state'
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
status: 'not-detected',
|
|
76
|
+
source: 'none'
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function matchesControlReview(text) {
|
|
81
|
+
return CONTROL_REVIEW_PATTERNS.some(pattern => pattern.test(text));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function matchesInternalActiveReview(text) {
|
|
85
|
+
return INTERNAL_ACTIVE_REVIEW_PATTERNS.some(pattern => pattern.test(text));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isGenericReviewOnly(text) {
|
|
89
|
+
return GENERIC_REVIEW_PATTERNS.some(pattern => pattern.test(text)) && !/\breviewing\b/i.test(text);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function normalize(value) {
|
|
93
|
+
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
detectReviewingFromSignals
|
|
98
|
+
};
|
|
99
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
(function initSensitiveScan(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafSensitiveScan = factory();
|
|
6
|
+
}
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function sensitiveScanFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const MAX_PREVIEW_CHARS = 96;
|
|
11
|
+
const DETECTORS = [
|
|
12
|
+
{ id: 'private-key', pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/gi },
|
|
13
|
+
{ id: 'bearer-token', pattern: /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/gi },
|
|
14
|
+
{ id: 'api-token', pattern: /\b(?:(?:ghp|github_pat|xox[baprs])_[A-Za-z0-9_=-]{16,}|sk-[A-Za-z0-9_-]{16,})\b/gi },
|
|
15
|
+
{
|
|
16
|
+
id: 'secret-assignment',
|
|
17
|
+
pattern: /\b(?:api[_-]?key|token|secret|password|passwd)\b\s*[:=]\s*["']?[^"'\s,;]{4,}/gi
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function scanSensitiveText(source, text, options = {}) {
|
|
22
|
+
const content = typeof text === 'string' ? text : '';
|
|
23
|
+
const findings = [];
|
|
24
|
+
const seen = new Set();
|
|
25
|
+
const sourceKey = typeof source === 'string' && source ? source : 'text';
|
|
26
|
+
|
|
27
|
+
for (const detector of DETECTORS) {
|
|
28
|
+
const pattern = new RegExp(detector.pattern.source, detector.pattern.flags);
|
|
29
|
+
let match;
|
|
30
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
31
|
+
const key = detector.id + ':' + sourceKey + ':' + (options.path || '');
|
|
32
|
+
if (seen.has(key)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
seen.add(key);
|
|
36
|
+
findings.push({
|
|
37
|
+
detectorId: detector.id,
|
|
38
|
+
source: sourceKey,
|
|
39
|
+
path: typeof options.path === 'string' ? options.path : undefined,
|
|
40
|
+
preview: buildRedactedPreview(content, match.index, match[0])
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return findings.map(removeUndefinedFields);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scanSensitiveProjectFiles(files) {
|
|
49
|
+
const findings = [];
|
|
50
|
+
for (const file of Array.isArray(files) ? files : []) {
|
|
51
|
+
const path = typeof file.path === 'string' ? file.path : '';
|
|
52
|
+
const content = typeof file.content === 'string' ? file.content : '';
|
|
53
|
+
const fileFindings = scanSensitiveText('project-file', content, { path });
|
|
54
|
+
findings.push(...fileFindings);
|
|
55
|
+
}
|
|
56
|
+
return findings;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function scanSensitiveInputs(input = {}) {
|
|
60
|
+
const findings = [];
|
|
61
|
+
if (typeof input.task === 'string') {
|
|
62
|
+
findings.push(...scanSensitiveText('task', input.task));
|
|
63
|
+
}
|
|
64
|
+
if (typeof input.prompt === 'string') {
|
|
65
|
+
findings.push(...scanSensitiveText('prompt', input.prompt));
|
|
66
|
+
}
|
|
67
|
+
findings.push(...scanSensitiveProjectFiles(input.files));
|
|
68
|
+
return findings;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function buildRedactedPreview(content, index, matchedText) {
|
|
72
|
+
const lineStart = content.lastIndexOf('\n', index) + 1;
|
|
73
|
+
const nextNewline = content.indexOf('\n', index);
|
|
74
|
+
const lineEnd = nextNewline === -1 ? content.length : nextNewline;
|
|
75
|
+
const line = content.slice(lineStart, lineEnd);
|
|
76
|
+
const localIndex = Math.max(0, index - lineStart);
|
|
77
|
+
const redacted = line.slice(0, localIndex) + '[REDACTED]' + line.slice(localIndex + matchedText.length);
|
|
78
|
+
return trimPreview(redactPreviewLine(redacted).replace(/\s+/g, ' '));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function redactPreviewLine(line) {
|
|
82
|
+
let redacted = String(line || '');
|
|
83
|
+
for (const detector of DETECTORS) {
|
|
84
|
+
const pattern = new RegExp(detector.pattern.source, detector.pattern.flags);
|
|
85
|
+
redacted = redacted.replace(pattern, '[REDACTED]');
|
|
86
|
+
}
|
|
87
|
+
return redacted;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function trimPreview(value) {
|
|
91
|
+
const text = String(value || '').trim();
|
|
92
|
+
if (text.length <= MAX_PREVIEW_CHARS) {
|
|
93
|
+
return text;
|
|
94
|
+
}
|
|
95
|
+
return text.slice(0, MAX_PREVIEW_CHARS - 1) + '…';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function removeUndefinedFields(value) {
|
|
99
|
+
const result = {};
|
|
100
|
+
for (const key of Object.keys(value)) {
|
|
101
|
+
if (value[key] !== undefined) {
|
|
102
|
+
result[key] = value[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
DETECTORS,
|
|
110
|
+
scanSensitiveText,
|
|
111
|
+
scanSensitiveProjectFiles,
|
|
112
|
+
scanSensitiveInputs,
|
|
113
|
+
buildRedactedPreview,
|
|
114
|
+
redactPreviewLine
|
|
115
|
+
};
|
|
116
|
+
});
|