codex-overleaf-link 1.3.9 → 1.4.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 +21 -21
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/i18n.js +12 -0
- package/extension/src/shared/sensitiveScan.js +6 -0
- package/extension/src/shared/sessionState.js +31 -10
- package/extension/src/shared/storageDb.js +40 -0
- package/native-host/src/codexPromptAssembly.js +30 -3
- package/native-host/src/index.js +67 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<h1>Codex Overleaf Link</h1>
|
|
4
4
|
<p><strong>Empower Overleaf with Codex.</strong></p>
|
|
5
5
|
<p>
|
|
6
|
-
<img src="https://img.shields.io/badge/version-1.
|
|
6
|
+
<img src="https://img.shields.io/badge/version-1.4.0-blue" alt="version">
|
|
7
7
|
<img src="https://img.shields.io/badge/platform-macOS%20%2F%20Windows%20%2F%20Linux-lightgrey" alt="platform">
|
|
8
8
|
<img src="https://img.shields.io/badge/chrome-MV3-green" alt="chrome manifest v3">
|
|
9
9
|
<img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen" alt="node version">
|
|
@@ -38,14 +38,14 @@ One command installs the native host **and** sets up the extension: the script r
|
|
|
38
38
|
macOS / Linux:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
CODEX_OVERLEAF_REF=v1.
|
|
41
|
+
CODEX_OVERLEAF_REF=v1.4.0 bash -c "$(curl -fsSL https://raw.githubusercontent.com/Ghqqqq/codex-overleaf-link/v1.4.0/install.sh)"
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Windows PowerShell:
|
|
45
45
|
|
|
46
46
|
```powershell
|
|
47
|
-
iwr https://raw.githubusercontent.com/Ghqqqq/codex-overleaf-link/v1.
|
|
48
|
-
$env:CODEX_OVERLEAF_REF='v1.
|
|
47
|
+
iwr https://raw.githubusercontent.com/Ghqqqq/codex-overleaf-link/v1.4.0/install.ps1 -OutFile install.ps1
|
|
48
|
+
$env:CODEX_OVERLEAF_REF='v1.4.0'
|
|
49
49
|
powershell -ExecutionPolicy Bypass -File install.ps1
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -56,10 +56,10 @@ Then, in the `chrome://extensions` tab the script opened: enable **Developer mod
|
|
|
56
56
|
`npm exec` installs and updates the **native host only** — it does not include the Chrome extension. Use it if you prefer a pinned npm package to a source checkout.
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
npm exec --yes codex-overleaf-link@1.
|
|
59
|
+
npm exec --yes codex-overleaf-link@1.4.0 -- install-native
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Then add the extension yourself: download `codex-overleaf-link-extension-v1.
|
|
62
|
+
Then add the extension yourself: download `codex-overleaf-link-extension-v1.4.0.zip` from the [v1.4.0 GitHub Release](https://github.com/Ghqqqq/codex-overleaf-link/releases/tag/v1.4.0), unzip it to a stable folder, and in `chrome://extensions` enable **Developer mode**, click **Load unpacked**, and select that folder.
|
|
63
63
|
|
|
64
64
|
### Open Overleaf
|
|
65
65
|
|
|
@@ -86,9 +86,9 @@ npm installs, updates, uninstalls, and diagnoses the native host only. npm does
|
|
|
86
86
|
|
|
87
87
|
| Action | Command |
|
|
88
88
|
|--------|---------|
|
|
89
|
-
| Install / update | `npm exec --yes codex-overleaf-link@1.
|
|
90
|
-
| Diagnose | `npm exec --yes codex-overleaf-link@1.
|
|
91
|
-
| Uninstall | `npm exec --yes codex-overleaf-link@1.
|
|
89
|
+
| Install / update | `npm exec --yes codex-overleaf-link@1.4.0 -- install-native` |
|
|
90
|
+
| Diagnose | `npm exec --yes codex-overleaf-link@1.4.0 -- doctor` |
|
|
91
|
+
| Uninstall | `npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native` |
|
|
92
92
|
|
|
93
93
|
Use `--extension-id <chrome-extension-id>` only for a custom/dev unpacked extension id that differs from the official bundled id.
|
|
94
94
|
|
|
@@ -98,13 +98,13 @@ To update, re-run any of the [native host installers](#install) — they install
|
|
|
98
98
|
|
|
99
99
|
## GitHub Release Artifacts
|
|
100
100
|
|
|
101
|
-
The v1.
|
|
101
|
+
The v1.4.0 GitHub Release contains:
|
|
102
102
|
|
|
103
|
-
- `codex-overleaf-link-extension-v1.
|
|
104
|
-
- `codex-overleaf-native-host-v1.
|
|
105
|
-
- `codex-overleaf-link-1.
|
|
106
|
-
- `install.sh`: release-pinned macOS / Linux installer that defaults to `v1.
|
|
107
|
-
- `install.ps1`: release-pinned Windows PowerShell installer that defaults to `v1.
|
|
103
|
+
- `codex-overleaf-link-extension-v1.4.0.zip`: loadable Chrome extension package for manual unpacked installation.
|
|
104
|
+
- `codex-overleaf-native-host-v1.4.0.tar.gz`: native host runtime files used by the installer and release verification.
|
|
105
|
+
- `codex-overleaf-link-1.4.0.tgz`: npm native host CLI package for pinned install, doctor, and uninstall flows.
|
|
106
|
+
- `install.sh`: release-pinned macOS / Linux installer that defaults to `v1.4.0` when run directly from the release artifact.
|
|
107
|
+
- `install.ps1`: release-pinned Windows PowerShell installer that defaults to `v1.4.0` when run directly from the release artifact.
|
|
108
108
|
- `uninstall-native-host.mjs`: native host uninstaller that removes the Chrome Native Messaging manifest, bridge executable, and runtime copy.
|
|
109
109
|
- `nativeHostPlatform.js`, `manifest.js`, `runtimeInstaller.js`: helper files required by the loose uninstaller asset.
|
|
110
110
|
- `SHA256SUMS` and `release-manifest.json`: checksum and artifact metadata for release verification.
|
|
@@ -115,7 +115,7 @@ The v1.3.9 GitHub Release contains:
|
|
|
115
115
|
Remove the native host (use `--browser chromium` on Linux Chromium):
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
npm exec --yes codex-overleaf-link@1.
|
|
118
|
+
npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
The same command works on Windows PowerShell. If you installed from a manual checkout or source installer, you can also run `npm run uninstall:native` inside the repo, use `node ~/.codex-overleaf/source/scripts/uninstall-native-host.mjs` on macOS / Linux, or use `node $env:LOCALAPPDATA\CodexOverleaf\source\scripts\uninstall-native-host.mjs` on Windows PowerShell.
|
|
@@ -150,13 +150,13 @@ Then remove the extension from `chrome://extensions`. To delete local data: on m
|
|
|
150
150
|
Linux Chromium install or update:
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
|
-
CODEX_OVERLEAF_REF=v1.
|
|
153
|
+
CODEX_OVERLEAF_REF=v1.4.0 bash -c "$(curl -fsSL https://raw.githubusercontent.com/Ghqqqq/codex-overleaf-link/v1.4.0/install.sh)" -- --browser chromium
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
Linux Chromium uninstall:
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
|
-
npm exec --yes codex-overleaf-link@1.
|
|
159
|
+
npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native --browser chromium
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
## Features
|
|
@@ -289,7 +289,7 @@ Composer attachments are turn-scoped Codex context. Limits are 8 attachments per
|
|
|
289
289
|
Re-run any [native host installer](#install), reload the extension in `chrome://extensions`, then refresh the Overleaf tab. This also fixes extension/native version mismatch and native protocol mismatch.
|
|
290
290
|
|
|
291
291
|
```bash
|
|
292
|
-
npm exec --yes codex-overleaf-link@1.
|
|
292
|
+
npm exec --yes codex-overleaf-link@1.4.0 -- install-native
|
|
293
293
|
```
|
|
294
294
|
|
|
295
295
|
**The Windows popup or panel shows a Bash recovery command**
|
|
@@ -338,8 +338,8 @@ Use this matrix for release-candidate signoff and compatibility reports. Record
|
|
|
338
338
|
| Browser/channel/version | Google Chrome channel and version. | Google Chrome channel and version. | Google Chrome channel and version. | Chromium channel/package and version. |
|
|
339
339
|
| Install mode | Manual unpacked extension from GitHub Release zip or checkout. | Manual unpacked extension from GitHub Release zip or checkout. | Manual unpacked extension from GitHub Release zip or checkout. | Manual unpacked extension from GitHub Release zip or checkout; native host installed with `--browser chromium`. |
|
|
340
340
|
| Extension id | Bundled id `illdpneeeopfffmiepaejglgmhpmdhdc`, or actual custom id passed with `--extension-id`. | Bundled id `illdpneeeopfffmiepaejglgmhpmdhdc`, or actual custom id passed with `--extension-id`. | Bundled id `illdpneeeopfffmiepaejglgmhpmdhdc`, or actual custom id passed with `--extension-id`. | Bundled id `illdpneeeopfffmiepaejglgmhpmdhdc`, or actual custom id passed with `--extension-id`. |
|
|
341
|
-
| Installer/update command | `npm exec --yes codex-overleaf-link@1.
|
|
342
|
-
| Uninstall command | `npm exec --yes codex-overleaf-link@1.
|
|
341
|
+
| Installer/update command | `npm exec --yes codex-overleaf-link@1.4.0 -- install-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- install-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- install-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- install-native --browser chromium` |
|
|
342
|
+
| Uninstall command | `npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native` | `npm exec --yes codex-overleaf-link@1.4.0 -- uninstall-native --browser chromium` |
|
|
343
343
|
| Manifest/registry path | `~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.codex.overleaf.json` | `HKCU\Software\Google\Chrome\NativeMessagingHosts\com.codex.overleaf` -> `%LOCALAPPDATA%\CodexOverleaf\native-host-runtime\com.codex.overleaf.json` | `~/.config/google-chrome/NativeMessagingHosts/com.codex.overleaf.json` | `~/.config/chromium/NativeMessagingHosts/com.codex.overleaf.json` |
|
|
344
344
|
| Bridge/runtime/source path | Bridge `~/.codex-overleaf/codex-overleaf-bridge`; runtime `~/.codex-overleaf/native-host-runtime`; source `~/.codex-overleaf/source`. | Bridge `%LOCALAPPDATA%\CodexOverleaf\codex-overleaf-bridge.cmd`; runtime `%LOCALAPPDATA%\CodexOverleaf\native-host-runtime`; source `%LOCALAPPDATA%\CodexOverleaf\source`. | Bridge `~/.codex-overleaf/codex-overleaf-bridge`; runtime `~/.codex-overleaf/native-host-runtime`; source `~/.codex-overleaf/source`. | Bridge `~/.codex-overleaf/codex-overleaf-bridge`; runtime `~/.codex-overleaf/native-host-runtime`; source `~/.codex-overleaf/source`. |
|
|
345
345
|
| Node/Git/Codex/TeX | Node.js >= 20; Git; Codex CLI installed and logged in; TeX optional. | Node.js >= 20; Git; Codex CLI installed and logged in; TeX optional. | Node.js >= 20; Git; Codex CLI installed and logged in; TeX optional. | Node.js >= 20; Git; Codex CLI installed and logged in; TeX optional. |
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const MIN_NATIVE_VERSION = '1.0.0';
|
|
13
13
|
const MIN_COMPATIBLE_NATIVE_VERSION = '1.0.0';
|
|
14
14
|
const MIN_COMPATIBLE_EXTENSION_VERSION = '1.0.0';
|
|
15
|
-
const BUILD_TARGET_VERSION = '1.
|
|
15
|
+
const BUILD_TARGET_VERSION = '1.4.0';
|
|
16
16
|
const DEFAULT_CHROME_EXTENSION_ID = 'illdpneeeopfffmiepaejglgmhpmdhdc';
|
|
17
17
|
const REQUIRED_CAPABILITIES = Object.freeze([
|
|
18
18
|
'bridgePing',
|
|
@@ -188,9 +188,13 @@
|
|
|
188
188
|
settingsScopeGlobalSubtitle: 'Skill loading settings that apply across all Overleaf projects.',
|
|
189
189
|
governanceRulesTitle: 'Governance Rules',
|
|
190
190
|
governanceReadonlyPatterns: 'Read-only patterns',
|
|
191
|
+
governanceReadonlyHelp: 'Files Codex must never modify — one glob per line.',
|
|
191
192
|
governanceWritablePatterns: 'Writable patterns',
|
|
193
|
+
governanceWritableHelp: 'Files Codex may edit — one glob per line.',
|
|
192
194
|
sensitiveCheckEnabled: 'Check for sensitive content before Codex runs',
|
|
195
|
+
sensitiveCheckHelp: 'Scan project files for secrets and personal data before each run.',
|
|
193
196
|
sensitiveConfirmAllowed: 'Allow explicit confirmation when sensitive findings exist',
|
|
197
|
+
sensitiveConfirmHelp: 'Lets you review and proceed when the scan flags something.',
|
|
194
198
|
sensitiveConfirmTitle: 'Sensitive Content Found',
|
|
195
199
|
sensitiveConfirmMessage: 'Codex found possible sensitive content. Raw detected secrets are not shown here. Continue only if this project context may be sent to Codex.',
|
|
196
200
|
sensitiveConfirmRun: 'Run anyway',
|
|
@@ -198,6 +202,7 @@
|
|
|
198
202
|
codexOverleafSkillsEmpty: 'No Codex Overleaf skills installed.',
|
|
199
203
|
codexOverleafSkillsDisabled: 'Codex Overleaf skills are disabled for runs.',
|
|
200
204
|
loadCodexLocalSkills: 'Load local Codex skills',
|
|
205
|
+
loadCodexLocalSkillsHelp: 'Pull skills from your local Codex installation.',
|
|
201
206
|
loadCodexOverleafSkills: 'Load Codex Overleaf skills',
|
|
202
207
|
localSkillRemove: 'Remove',
|
|
203
208
|
localSkillRemoveConfirm: 'Confirm',
|
|
@@ -221,6 +226,7 @@
|
|
|
221
226
|
binaryAssetConfirm: 'Write assets',
|
|
222
227
|
binaryAssetCancel: 'Skip assets',
|
|
223
228
|
personalizationConfig: 'Personalization',
|
|
229
|
+
personalizationHelp: 'Style, terminology, and LaTeX conventions Codex should follow in this project.',
|
|
224
230
|
settingsSaved: 'Saved',
|
|
225
231
|
settingsSaving: 'Saving…',
|
|
226
232
|
technicalDetails: 'Technical Details',
|
|
@@ -552,9 +558,13 @@
|
|
|
552
558
|
settingsScopeGlobalSubtitle: '适用于所有 Overleaf 项目的技能加载设置。',
|
|
553
559
|
governanceRulesTitle: '治理规则',
|
|
554
560
|
governanceReadonlyPatterns: '只读路径规则',
|
|
561
|
+
governanceReadonlyHelp: 'Codex 绝不可修改的文件,每行一个 glob 规则。',
|
|
555
562
|
governanceWritablePatterns: '可写路径规则',
|
|
563
|
+
governanceWritableHelp: 'Codex 允许编辑的文件,每行一个 glob 规则。',
|
|
556
564
|
sensitiveCheckEnabled: 'Codex 运行前检查敏感内容',
|
|
565
|
+
sensitiveCheckHelp: '每次运行前扫描项目文件中的密钥和个人信息。',
|
|
557
566
|
sensitiveConfirmAllowed: '发现敏感内容时允许显式确认后继续',
|
|
567
|
+
sensitiveConfirmHelp: '当扫描发现可疑内容时,允许你审阅后再继续。',
|
|
558
568
|
sensitiveConfirmTitle: '发现敏感内容',
|
|
559
569
|
sensitiveConfirmMessage: 'Codex 发现了可能的敏感内容。这里不会显示原始密钥或秘密值。只有在确认可以把这些项目上下文发送给 Codex 时才继续。',
|
|
560
570
|
sensitiveConfirmRun: '仍然运行',
|
|
@@ -562,6 +572,7 @@
|
|
|
562
572
|
codexOverleafSkillsEmpty: '没有安装 Codex Overleaf 专属技能。',
|
|
563
573
|
codexOverleafSkillsDisabled: '运行时已禁用 Codex Overleaf 专属技能。',
|
|
564
574
|
loadCodexLocalSkills: '加载 Codex 本地技能',
|
|
575
|
+
loadCodexLocalSkillsHelp: '从本地 Codex 安装中拉取技能。',
|
|
565
576
|
loadCodexOverleafSkills: '加载 Codex Overleaf 专属技能',
|
|
566
577
|
localSkillRemove: '删除',
|
|
567
578
|
localSkillRemoveConfirm: '确认',
|
|
@@ -585,6 +596,7 @@
|
|
|
585
596
|
binaryAssetConfirm: '写入资源',
|
|
586
597
|
binaryAssetCancel: '跳过资源',
|
|
587
598
|
personalizationConfig: '个性化配置',
|
|
599
|
+
personalizationHelp: 'Codex 在本项目中应遵循的风格、术语和 LaTeX 约定。',
|
|
588
600
|
settingsSaved: '已保存',
|
|
589
601
|
settingsSaving: '保存中…',
|
|
590
602
|
technicalDetails: '技术细节',
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
{ id: 'private-key', pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/gi },
|
|
13
13
|
{ id: 'bearer-token', pattern: /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/gi },
|
|
14
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
|
+
{ id: 'aws-access-key', pattern: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
16
|
+
{ id: 'google-api-key', pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
17
|
+
{ id: 'huggingface-token', pattern: /\bhf_[A-Za-z0-9]{20,}\b/g },
|
|
18
|
+
{ id: 'gitlab-token', pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
19
|
+
{ id: 'stripe-live-secret', pattern: /\bsk_live_[A-Za-z0-9]{16,}\b/g },
|
|
20
|
+
{ id: 'jwt-token', pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
15
21
|
{
|
|
16
22
|
id: 'secret-assignment',
|
|
17
23
|
pattern: /\b(?:api[_-]?key|token|secret|password|passwd)\b\s*[:=]\s*["']?[^"'\s,;]{4,}/gi
|
|
@@ -635,16 +635,29 @@
|
|
|
635
635
|
function normalizeRunEvents(events) {
|
|
636
636
|
return (Array.isArray(events) ? events : [])
|
|
637
637
|
.filter(event => event && typeof event.title === 'string')
|
|
638
|
-
.map(event =>
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
638
|
+
.map(event => {
|
|
639
|
+
const normalized = {
|
|
640
|
+
title: sanitizeAssistantVisibleText(event.title) || 'Event',
|
|
641
|
+
status: typeof event.status === 'string' ? event.status : 'info',
|
|
642
|
+
detail: sanitizeAssistantVisibleValue(event.detail),
|
|
643
|
+
timestamp: typeof event.timestamp === 'string' ? event.timestamp : '',
|
|
644
|
+
kind: typeof event.kind === 'string' ? event.kind : 'activity',
|
|
645
|
+
technicalDetail: sanitizeAssistantVisibleValue(event.technicalDetail),
|
|
646
|
+
streamKey: sanitizeAssistantVisibleText(event.streamKey),
|
|
647
|
+
streamRole: sanitizeAssistantVisibleText(event.streamRole)
|
|
648
|
+
};
|
|
649
|
+
// Preserve the structured completion-report payload and the structured
|
|
650
|
+
// failure across reload. Without these the report re-renders via the
|
|
651
|
+
// flat legacy path (Write result / Undo / Next NOT demoted into the
|
|
652
|
+
// muted meta block) and the recovery action button disappears.
|
|
653
|
+
if (event.detailStructured) {
|
|
654
|
+
normalized.detailStructured = sanitizeAssistantVisibleValue(event.detailStructured);
|
|
655
|
+
}
|
|
656
|
+
if (event.failure) {
|
|
657
|
+
normalized.failure = sanitizeAssistantVisibleValue(event.failure);
|
|
658
|
+
}
|
|
659
|
+
return normalized;
|
|
660
|
+
})
|
|
648
661
|
.slice(-MAX_RUN_EVENTS);
|
|
649
662
|
}
|
|
650
663
|
|
|
@@ -1010,6 +1023,14 @@
|
|
|
1010
1023
|
if (detail !== undefined) {
|
|
1011
1024
|
compact.detail = detail;
|
|
1012
1025
|
}
|
|
1026
|
+
// Keep the structured report payload + structured failure so the
|
|
1027
|
+
// demoted meta block and the recovery action survive a reload.
|
|
1028
|
+
if (event.detailStructured) {
|
|
1029
|
+
compact.detailStructured = sanitizeAssistantVisibleValue(event.detailStructured);
|
|
1030
|
+
}
|
|
1031
|
+
if (event.failure) {
|
|
1032
|
+
compact.failure = sanitizeAssistantVisibleValue(event.failure);
|
|
1033
|
+
}
|
|
1013
1034
|
return compact;
|
|
1014
1035
|
});
|
|
1015
1036
|
}
|
|
@@ -680,10 +680,50 @@
|
|
|
680
680
|
if (detail !== undefined) {
|
|
681
681
|
compact.detail = detail;
|
|
682
682
|
}
|
|
683
|
+
// Preserve the structured completion-report payload + structured
|
|
684
|
+
// failure with their object shape intact (the generic detail
|
|
685
|
+
// compactor would redact unknown objects to a {redacted,hash}
|
|
686
|
+
// summary). Without this the report re-renders flat on reload —
|
|
687
|
+
// Write result / Undo / Next no longer demote into the muted meta
|
|
688
|
+
// block — and the recovery action button disappears.
|
|
689
|
+
if (event.detailStructured) {
|
|
690
|
+
compact.detailStructured = compactStructuredEventValueForStorage(event.detailStructured, 0);
|
|
691
|
+
}
|
|
692
|
+
if (event.failure) {
|
|
693
|
+
compact.failure = compactStructuredEventValueForStorage(event.failure, 0);
|
|
694
|
+
}
|
|
683
695
|
return compact;
|
|
684
696
|
});
|
|
685
697
|
}
|
|
686
698
|
|
|
699
|
+
// Deep-copies a known-safe structured event value (the completion-report
|
|
700
|
+
// {conclusion, body, meta[]} payload, or a FailureReason object) preserving
|
|
701
|
+
// its shape while redacting + truncating every string field. Bounded depth +
|
|
702
|
+
// breadth so a pathological value can't blow up the stored record.
|
|
703
|
+
function compactStructuredEventValueForStorage(value, depth) {
|
|
704
|
+
var d = depth || 0;
|
|
705
|
+
if (typeof value === 'string') {
|
|
706
|
+
return normalizeDisplayTextForStorage(value, SESSION_STORAGE_LIMITS.reportDetailChars);
|
|
707
|
+
}
|
|
708
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') {
|
|
709
|
+
return value;
|
|
710
|
+
}
|
|
711
|
+
if (d > 6 || typeof value !== 'object') {
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
if (Array.isArray(value)) {
|
|
715
|
+
return value.slice(0, 32).map(function (item) {
|
|
716
|
+
return compactStructuredEventValueForStorage(item, d + 1);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
var out = {};
|
|
720
|
+
var keys = Object.keys(value).slice(0, 32);
|
|
721
|
+
for (var i = 0; i < keys.length; i++) {
|
|
722
|
+
out[keys[i]] = compactStructuredEventValueForStorage(value[keys[i]], d + 1);
|
|
723
|
+
}
|
|
724
|
+
return out;
|
|
725
|
+
}
|
|
726
|
+
|
|
687
727
|
function getEventDetailLimit(event) {
|
|
688
728
|
return event && event.kind === 'report'
|
|
689
729
|
? SESSION_STORAGE_LIMITS.reportDetailChars
|
|
@@ -279,13 +279,13 @@ function formatFocusFiles(files) {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
function formatCompileLogContext(context = {}) {
|
|
282
|
-
const log = String(context.compileLog || '').trim();
|
|
282
|
+
const log = redactCompileLogText(String(context.compileLog || '').trim());
|
|
283
283
|
if (!log) {
|
|
284
284
|
return '- none provided.';
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
const errors = normalizeCompileMessages(context.compileErrors);
|
|
288
|
-
const warnings = normalizeCompileMessages(context.compileWarnings);
|
|
287
|
+
const errors = normalizeCompileMessages(context.compileErrors).map(redactCompileLogText);
|
|
288
|
+
const warnings = normalizeCompileMessages(context.compileWarnings).map(redactCompileLogText);
|
|
289
289
|
const fresh = context.compileLogFresh === false
|
|
290
290
|
? 'possibly stale'
|
|
291
291
|
: 'fresh';
|
|
@@ -305,6 +305,33 @@ function formatCompileLogContext(context = {}) {
|
|
|
305
305
|
].filter(Boolean).join('\n');
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
function redactCompileLogText(value) {
|
|
309
|
+
let text = String(value || '');
|
|
310
|
+
const replacements = [
|
|
311
|
+
[/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/g, 'Bearer [REDACTED]'],
|
|
312
|
+
[/\b(?:ghp|github_pat|xox[baprs]|glpat)-?[_A-Za-z0-9=-]{16,}\b/g, '[REDACTED_TOKEN]'],
|
|
313
|
+
[/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g, '[REDACTED_TOKEN]'],
|
|
314
|
+
[/\bsk-[A-Za-z0-9_-]{16,}\b/g, '[REDACTED_TOKEN]'],
|
|
315
|
+
[/\bAKIA[0-9A-Z]{16}\b/g, '[REDACTED_AWS_KEY]'],
|
|
316
|
+
[/\bAIza[0-9A-Za-z_-]{35}\b/g, '[REDACTED_GOOGLE_KEY]'],
|
|
317
|
+
[/\bhf_[A-Za-z0-9]{20,}\b/g, '[REDACTED_HF_TOKEN]'],
|
|
318
|
+
[/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, '[REDACTED_JWT]'],
|
|
319
|
+
[/file:\/\/\/[^\s'"<>]+/g, '<local-path>'],
|
|
320
|
+
[/(^|[\s({["'=])\/Users\/[^:\s'"<>)]*/g, '$1<local-path>'],
|
|
321
|
+
[/(^|[\s({["'=])\/private\/var\/[^:\s'"<>)]*/g, '$1<local-path>'],
|
|
322
|
+
[/(^|[\s({["'=])\/var\/folders\/[^:\s'"<>)]*/g, '$1<local-path>'],
|
|
323
|
+
[/(^|[\s({["'=])\/tmp\/[^:\s'"<>)]*/g, '$1<local-path>'],
|
|
324
|
+
[/(^|[\s({["'=])\/Library\/TeX\/[^:\s'"<>)]*/g, '$1<TEXLIVE_PATH>'],
|
|
325
|
+
[/(^|[\s({["'=])\/usr\/local\/texlive\/[^:\s'"<>)]*/g, '$1<TEXLIVE_PATH>'],
|
|
326
|
+
[/[A-Za-z]:\\Users\\[^:\s'"<>)]*/g, '<local-path>'],
|
|
327
|
+
[/[A-Za-z]:\\(?:Program Files|texlive)\\[^:\s'"<>)]*/gi, '<local-path>']
|
|
328
|
+
];
|
|
329
|
+
for (const [pattern, replacement] of replacements) {
|
|
330
|
+
text = text.replace(pattern, replacement);
|
|
331
|
+
}
|
|
332
|
+
return text;
|
|
333
|
+
}
|
|
334
|
+
|
|
308
335
|
function formatCustomInstructionsContext(customInstructions = '') {
|
|
309
336
|
const instructions = truncateText(
|
|
310
337
|
String(customInstructions || '').trim(),
|
package/native-host/src/index.js
CHANGED
|
@@ -84,11 +84,77 @@ process.on('unhandledRejection', reason => {
|
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
function writeResponse(response) {
|
|
87
|
-
|
|
87
|
+
let frame;
|
|
88
|
+
try {
|
|
89
|
+
frame = encodeMessage(response);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
const fallback = buildOversizeResponseFallback(response, error);
|
|
92
|
+
try {
|
|
93
|
+
frame = encodeMessage(fallback);
|
|
94
|
+
} catch (fallbackError) {
|
|
95
|
+
frame = encodeMessage({
|
|
96
|
+
id: response?.id,
|
|
97
|
+
ok: false,
|
|
98
|
+
error: {
|
|
99
|
+
code: 'native_response_too_large',
|
|
100
|
+
message: truncateForNativeFrame(fallbackError.message || error.message || 'Native response exceeded the browser frame limit.', 800)
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
88
105
|
logDebug('stdout.write', { bytes: frame.length, ok: response?.ok, code: response?.error?.code });
|
|
89
106
|
process.stdout.write(frame);
|
|
90
107
|
}
|
|
91
108
|
|
|
109
|
+
function buildOversizeResponseFallback(response, error) {
|
|
110
|
+
if (response?.event) {
|
|
111
|
+
const event = response.event || {};
|
|
112
|
+
return {
|
|
113
|
+
id: response.id,
|
|
114
|
+
ok: true,
|
|
115
|
+
event: {
|
|
116
|
+
type: event.type || 'native.event.truncated',
|
|
117
|
+
title: truncateForNativeFrame(event.title || 'Native event was truncated', 500),
|
|
118
|
+
status: event.status || 'warning',
|
|
119
|
+
detail: {
|
|
120
|
+
code: 'native_event_truncated',
|
|
121
|
+
reason: truncateForNativeFrame(error?.message || 'Native event exceeded the browser frame limit.', 800),
|
|
122
|
+
originalType: truncateForNativeFrame(event.type || '', 160),
|
|
123
|
+
originalTitle: truncateForNativeFrame(event.title || '', 500),
|
|
124
|
+
originalDetailBytes: stringByteLength(safeJsonStringify(event.detail))
|
|
125
|
+
},
|
|
126
|
+
timestamp: event.timestamp || new Date().toISOString()
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
id: response?.id,
|
|
133
|
+
ok: false,
|
|
134
|
+
error: {
|
|
135
|
+
code: 'native_response_too_large',
|
|
136
|
+
message: truncateForNativeFrame(error?.message || 'Native response exceeded the browser frame limit.', 800),
|
|
137
|
+
originalOk: response?.ok === true
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function truncateForNativeFrame(value, limit) {
|
|
143
|
+
const text = String(value || '');
|
|
144
|
+
if (text.length <= limit) {
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
return `${text.slice(0, Math.max(0, limit - 24))}... [truncated]`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function safeJsonStringify(value) {
|
|
151
|
+
try {
|
|
152
|
+
return JSON.stringify(value);
|
|
153
|
+
} catch (_error) {
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
92
158
|
function summarizeRequest(message) {
|
|
93
159
|
const params = message?.params || {};
|
|
94
160
|
return {
|