codex-overleaf-link 1.3.7 → 1.3.8
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/agentTranscript.js +273 -10
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/failureReasons.js +578 -0
- package/extension/src/shared/i18n.js +139 -2
- package/extension/src/shared/pathRedaction.js +143 -0
- package/extension/src/shared/sessionState.js +113 -4
- package/extension/src/shared/storageDb.js +217 -4
- package/native-host/src/codexPromptAssembly.js +10 -2
- package/native-host/src/codexSessionRunner.js +33 -1
- package/package.json +1 -1
|
@@ -130,6 +130,10 @@
|
|
|
130
130
|
runAcceptTrackedConfirming: 'Accepting…',
|
|
131
131
|
runAcceptTrackedDone: 'Accepted',
|
|
132
132
|
runAcceptTrackedDoneTitle: 'This run\'s tracked changes have been accepted',
|
|
133
|
+
runAcceptTrackedNeedsReview: 'Accept changes',
|
|
134
|
+
runAcceptTrackedNeedsReviewTitle: 'Accept this run\'s Overleaf tracked changes',
|
|
135
|
+
runUndoNeedsReview: 'Undo changes',
|
|
136
|
+
runUndoNeedsReviewTitle: 'Undo this run\'s changes',
|
|
133
137
|
runAcceptTrackedStarted: 'Starting to accept this run\'s Overleaf tracked changes',
|
|
134
138
|
runAcceptTrackedResult: 'Accept result: accepted {applied} tracked change(s), skipped {skipped}',
|
|
135
139
|
runAcceptTrackedFailed: 'Accept changes could not be completed',
|
|
@@ -298,7 +302,72 @@
|
|
|
298
302
|
processed: 'Done {elapsed}',
|
|
299
303
|
restoredRunStoppedTitle: 'Stopped tracking this run after a page refresh',
|
|
300
304
|
restoredRunStoppedDetail: 'The plugin reloaded while this run was still marked in progress. It has been marked interrupted to avoid showing a stale status — run the task again to continue.',
|
|
301
|
-
restoredRunStoppedStatus: 'Stopped tracking after a page refresh'
|
|
305
|
+
restoredRunStoppedStatus: 'Stopped tracking after a page refresh',
|
|
306
|
+
// FailureReason structured-block section headings (design spec §10–§11).
|
|
307
|
+
failureReason_section_heading: 'Reason',
|
|
308
|
+
failureReason_section_stage: 'Stage',
|
|
309
|
+
failureReason_section_code: 'Code',
|
|
310
|
+
failureReason_section_next: 'Next',
|
|
311
|
+
// FailureReason bilingual high-priority strings (design spec §15.4).
|
|
312
|
+
// Each entry follows the §9 catalog copy. {file} / {activeFile} interpolate from the failure record.
|
|
313
|
+
failureReason_project_snapshot_unavailable_user: 'Codex could not read the Overleaf project snapshot.',
|
|
314
|
+
failureReason_project_snapshot_unavailable_next: 'Refresh Overleaf, then rerun the task.',
|
|
315
|
+
failureReason_selected_context_unresolved_user: 'Codex could not resolve the requested selection or context.',
|
|
316
|
+
failureReason_selected_context_unresolved_next: 'Select the target again or specify the file/section explicitly.',
|
|
317
|
+
failureReason_target_file_not_found_user: 'Codex could not find {file} in this Overleaf project.',
|
|
318
|
+
failureReason_target_file_not_found_next: 'Check the file name/path in Overleaf and retry.',
|
|
319
|
+
failureReason_target_file_open_failed_user: 'Codex could not open {file} in Overleaf.',
|
|
320
|
+
failureReason_target_file_open_failed_next: 'Expand the folder or manually open {file}, then retry.',
|
|
321
|
+
failureReason_target_file_not_active_user: 'Codex could not write {file} because Overleaf was still focused on {activeFile}.',
|
|
322
|
+
failureReason_target_file_not_active_next: 'Open {file} in Overleaf, then retry this run.',
|
|
323
|
+
failureReason_target_editor_not_ready_user: '{file} is active but the editor was not ready before timeout.',
|
|
324
|
+
failureReason_target_editor_not_ready_next: 'Wait for Overleaf to finish loading, then retry.',
|
|
325
|
+
failureReason_stale_source_changed_user: '{file} changed while Codex was working, so Codex did not overwrite it.',
|
|
326
|
+
failureReason_stale_source_changed_next: 'Review the current file, then rerun the task.',
|
|
327
|
+
failureReason_patch_anchor_not_found_user: 'The edit anchor for {file} no longer matches current Overleaf content.',
|
|
328
|
+
failureReason_patch_anchor_not_found_next: 'Rerun the task against the current document.',
|
|
329
|
+
failureReason_write_observed_mismatch_user: 'Codex attempted to write {file}, but the content read back from Overleaf did not match the approved change.',
|
|
330
|
+
failureReason_write_observed_mismatch_next: 'Open Technical Details and compare expected vs observed; use Undo written parts if the document looks wrong.',
|
|
331
|
+
failureReason_reviewing_state_unknown_user: 'Codex could not determine whether Reviewing/Track Changes is enabled.',
|
|
332
|
+
failureReason_reviewing_state_unknown_next: 'Check Overleaf mode manually before retrying.',
|
|
333
|
+
failureReason_editing_not_confirmed_user: 'Editing mode could not be proven stable before writing {file}.',
|
|
334
|
+
failureReason_editing_not_confirmed_next: 'Do not write; check the mode selector and retry.',
|
|
335
|
+
failureReason_tracked_changes_remain_user: 'Accept/reject finished for {file}, but Overleaf still reports remaining tracked changes.',
|
|
336
|
+
failureReason_tracked_changes_remain_next: 'Open Overleaf Reviewing and inspect the remaining changes before continuing.',
|
|
337
|
+
failureReason_undo_not_verified_user: 'Undo ran for {file}, but Codex could not prove the file returned to its pre-run content.',
|
|
338
|
+
failureReason_undo_not_verified_next: 'Inspect {file} manually before continuing.',
|
|
339
|
+
failureReason_accept_not_verified_user: 'Accept appeared to run for {file}, but Codex could not prove the final content or Track Changes state.',
|
|
340
|
+
failureReason_accept_not_verified_next: 'Inspect Overleaf Reviewing before continuing.',
|
|
341
|
+
failureReason_native_bridge_unavailable_user: 'Extension cannot connect to the Codex native host.',
|
|
342
|
+
failureReason_native_bridge_unavailable_next: 'Run install-native or reload the extension.',
|
|
343
|
+
failureReason_codex_no_usable_result_user: 'Local Codex returned no usable final report or operations.',
|
|
344
|
+
failureReason_codex_no_usable_result_next: 'Open Technical Details and resolve the local Codex error.',
|
|
345
|
+
failureReason_codex_project_locked_user: 'Another Codex task is already running for this Overleaf project.',
|
|
346
|
+
failureReason_codex_project_locked_next: 'Wait for the active task to finish, or cancel it before retrying.',
|
|
347
|
+
failureReason_storage_quota_exceeded_user: 'Browser storage quota was exceeded.',
|
|
348
|
+
failureReason_storage_quota_exceeded_next: 'Clear old run history or reduce attachments.',
|
|
349
|
+
failureReason_aborted_project_changed_user: 'Codex stopped a write because Overleaf switched to a different project mid-run.',
|
|
350
|
+
failureReason_aborted_project_changed_next: 'Reopen the original project and rerun the task if you still want this change.',
|
|
351
|
+
failureReason_editor_project_id_unavailable_user: 'Codex could not confirm which Overleaf project the editor is showing, so it did not write.',
|
|
352
|
+
failureReason_editor_project_id_unavailable_next: 'Refresh the Overleaf tab and retry; if it persists, reload the extension.',
|
|
353
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Task 5): Recent-projects
|
|
354
|
+
// variant copy. Spec §5.3–§5.5, §5.8, §5.10 are the source of truth.
|
|
355
|
+
recentProjects_welcome: 'Codex Overleaf Link',
|
|
356
|
+
recentProjects_welcome_subtitle: 'Open a project from the Overleaf list on the left to start.',
|
|
357
|
+
recentProjects_empty: "You haven't run any Codex sessions yet. Open a project from the Overleaf list on the left to start.",
|
|
358
|
+
recentProjects_degraded: 'Sign in to Overleaf to see your recent Codex projects.',
|
|
359
|
+
recentProjects_row_projectLinkUnavailable: 'Project link unavailable.',
|
|
360
|
+
recentProjects_settings_entry: 'Settings & Diagnostics',
|
|
361
|
+
recentProjects_badge_pending: 'pending',
|
|
362
|
+
recentProjects_badge_accepted: 'accepted',
|
|
363
|
+
recentProjects_badge_rejected: 'rejected',
|
|
364
|
+
recentProjects_badge_needs_review: 'pending',
|
|
365
|
+
recentProjects_badge_running: 'running',
|
|
366
|
+
recentProjects_badge_completed: 'completed',
|
|
367
|
+
recentProjects_badge_failed: 'failed',
|
|
368
|
+
recentProjects_badge_background_completed: 'completed in background',
|
|
369
|
+
recentProjects_badge_needs_review_after_navigation: 'pending',
|
|
370
|
+
recentProjects_badge_abandoned_after_navigation: 'abandoned'
|
|
302
371
|
},
|
|
303
372
|
zh: {
|
|
304
373
|
resizePanel: '拖动调整 Codex 面板宽度,双击恢复默认宽度',
|
|
@@ -419,6 +488,10 @@
|
|
|
419
488
|
runAcceptTrackedConfirming: '接受中…',
|
|
420
489
|
runAcceptTrackedDone: '已接受',
|
|
421
490
|
runAcceptTrackedDoneTitle: '本轮留痕改动已被接受',
|
|
491
|
+
runAcceptTrackedNeedsReview: '接受改动 — 需待核对',
|
|
492
|
+
runAcceptTrackedNeedsReviewTitle: '本轮留痕未必已完全接受;请在 Overleaf 中核对后重试。',
|
|
493
|
+
runUndoNeedsReview: '撤销 — 需待核对',
|
|
494
|
+
runUndoNeedsReviewTitle: '本轮撤销未必已完全完成;请在 Overleaf 中核对后重试。',
|
|
422
495
|
runAcceptTrackedStarted: '开始接受本轮 Overleaf 留痕改动',
|
|
423
496
|
runAcceptTrackedResult: '接受结果:已接受 {applied} 条留痕,跳过 {skipped} 条',
|
|
424
497
|
runAcceptTrackedFailed: '没有完成接受改动',
|
|
@@ -587,7 +660,71 @@
|
|
|
587
660
|
processed: '已处理 {elapsed}',
|
|
588
661
|
restoredRunStoppedTitle: '页面刷新后已停止跟踪这轮任务',
|
|
589
662
|
restoredRunStoppedDetail: '插件重新加载时发现这轮任务还标记为处理中。为了避免继续显示过期状态,已把它标记为中断;可以重新运行任务。',
|
|
590
|
-
restoredRunStoppedStatus: '页面刷新后已停止跟踪'
|
|
663
|
+
restoredRunStoppedStatus: '页面刷新后已停止跟踪',
|
|
664
|
+
// FailureReason 结构块标题(设计规格 §10–§11)。
|
|
665
|
+
failureReason_section_heading: '原因',
|
|
666
|
+
failureReason_section_stage: '阶段',
|
|
667
|
+
failureReason_section_code: '代码',
|
|
668
|
+
failureReason_section_next: '下一步',
|
|
669
|
+
// FailureReason 高优先级双语文案(设计规格 §15.4)。文案对应 §9 目录的英文 fallback。
|
|
670
|
+
failureReason_project_snapshot_unavailable_user: 'Codex 没能读到 Overleaf 项目快照。',
|
|
671
|
+
failureReason_project_snapshot_unavailable_next: '请刷新 Overleaf,然后重试本轮任务。',
|
|
672
|
+
failureReason_selected_context_unresolved_user: 'Codex 没能解析所选的内容或上下文。',
|
|
673
|
+
failureReason_selected_context_unresolved_next: '请重新选择目标,或者显式指定文件 / 区段。',
|
|
674
|
+
failureReason_target_file_not_found_user: 'Codex 在当前 Overleaf 项目中没有找到 {file}。',
|
|
675
|
+
failureReason_target_file_not_found_next: '请在 Overleaf 中核对文件名和路径后重试。',
|
|
676
|
+
failureReason_target_file_open_failed_user: 'Codex 没能在 Overleaf 中打开 {file}。',
|
|
677
|
+
failureReason_target_file_open_failed_next: '请展开所在文件夹,或手动打开 {file},然后重试。',
|
|
678
|
+
failureReason_target_file_not_active_user: 'Codex 无法写入 {file},因为 Overleaf 仍停留在 {activeFile}。',
|
|
679
|
+
failureReason_target_file_not_active_next: '请在 Overleaf 中打开 {file},然后重试本轮任务。',
|
|
680
|
+
failureReason_target_editor_not_ready_user: '{file} 已成为当前文件,但编辑器在超时前没有就绪。',
|
|
681
|
+
failureReason_target_editor_not_ready_next: '请等 Overleaf 加载完成后再重试。',
|
|
682
|
+
failureReason_stale_source_changed_user: '{file} 在任务执行期间被修改过,Codex 没有覆盖它。',
|
|
683
|
+
failureReason_stale_source_changed_next: '请先查看当前文件内容,再重新运行本轮任务。',
|
|
684
|
+
failureReason_patch_anchor_not_found_user: '{file} 的修改锚点已经无法和当前 Overleaf 内容对齐。',
|
|
685
|
+
failureReason_patch_anchor_not_found_next: '请基于当前文档重新运行任务。',
|
|
686
|
+
failureReason_write_observed_mismatch_user: 'Codex 尝试写入 {file},但写入后从 Overleaf 读回的内容与批准的改动不一致。',
|
|
687
|
+
failureReason_write_observed_mismatch_next: '请打开“技术细节”比对预期与实际内容;如发现异常可使用“撤销已写入部分”。',
|
|
688
|
+
failureReason_reviewing_state_unknown_user: 'Codex 没能确认 Overleaf Reviewing/Track Changes 是否开启。',
|
|
689
|
+
failureReason_reviewing_state_unknown_next: '请在 Overleaf 手动检查留痕状态后再重试。',
|
|
690
|
+
failureReason_editing_not_confirmed_user: '写入 {file} 之前没能确认 Editing 模式已稳定。',
|
|
691
|
+
failureReason_editing_not_confirmed_next: '请暂停写入,检查模式选择器后再重试。',
|
|
692
|
+
failureReason_tracked_changes_remain_user: '{file} 的接受/拒绝操作完成了,但 Overleaf 仍报告存在未处理的留痕改动。',
|
|
693
|
+
failureReason_tracked_changes_remain_next: '请在 Overleaf 审阅面板查看剩余的留痕改动,再决定是否继续。',
|
|
694
|
+
failureReason_undo_not_verified_user: '{file} 的撤销已执行,但 Codex 没能确认文件恢复到本轮写入前的内容。',
|
|
695
|
+
failureReason_undo_not_verified_next: '请先在 Overleaf 手动确认 {file} 的内容,再继续操作。',
|
|
696
|
+
failureReason_accept_not_verified_user: '{file} 的接受改动似乎已执行,但 Codex 没能确认最终内容或留痕状态。',
|
|
697
|
+
failureReason_accept_not_verified_next: '请先在 Overleaf 审阅面板核对后再继续。',
|
|
698
|
+
failureReason_native_bridge_unavailable_user: '扩展无法连接到 Codex Native Host。',
|
|
699
|
+
failureReason_native_bridge_unavailable_next: '请运行 install-native,或者重新加载扩展。',
|
|
700
|
+
failureReason_codex_no_usable_result_user: '本地 Codex 没有返回可用的最终报告或操作。',
|
|
701
|
+
failureReason_codex_no_usable_result_next: '请打开“技术细节”排查本地 Codex 错误。',
|
|
702
|
+
failureReason_codex_project_locked_user: '同一个 Overleaf 项目里已经有一轮 Codex 任务正在运行。',
|
|
703
|
+
failureReason_codex_project_locked_next: '请等待当前任务完成,或先取消当前任务后再重试。',
|
|
704
|
+
failureReason_storage_quota_exceeded_user: '浏览器本地存储配额已超出。',
|
|
705
|
+
failureReason_storage_quota_exceeded_next: '请清理旧的运行历史,或减少附件大小。',
|
|
706
|
+
failureReason_aborted_project_changed_user: 'Codex 已停止一次写入,因为 Overleaf 在写入过程中切换到了另一个项目。',
|
|
707
|
+
failureReason_aborted_project_changed_next: '如仍需此次改动,请回到原项目后重新运行任务。',
|
|
708
|
+
failureReason_editor_project_id_unavailable_user: 'Codex 无法确认当前 Overleaf 编辑器对应的项目,因此没有写入。',
|
|
709
|
+
failureReason_editor_project_id_unavailable_next: '请刷新 Overleaf 页面后重试;如果仍然失败,请重新加载扩展。',
|
|
710
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Task 5): Recent-projects
|
|
711
|
+
// variant copy. 见 spec §5.3–§5.5、§5.8、§5.10。
|
|
712
|
+
recentProjects_welcome: 'Codex Overleaf Link',
|
|
713
|
+
recentProjects_welcome_subtitle: '从左侧 Overleaf 项目列表中打开任意项目即可开始。',
|
|
714
|
+
recentProjects_empty: '你还没有运行过 Codex 会话。从左侧 Overleaf 项目列表中打开任意项目即可开始。',
|
|
715
|
+
recentProjects_degraded: '请登录 Overleaf 后查看你最近的 Codex 项目。',
|
|
716
|
+
recentProjects_row_projectLinkUnavailable: '项目链接不可用。',
|
|
717
|
+
recentProjects_settings_entry: '设置与诊断',
|
|
718
|
+
recentProjects_badge_pending: '待处理',
|
|
719
|
+
recentProjects_badge_accepted: '已接受',
|
|
720
|
+
recentProjects_badge_rejected: '已撤回',
|
|
721
|
+
recentProjects_badge_needs_review: '待处理',
|
|
722
|
+
recentProjects_badge_running: '运行中',
|
|
723
|
+
recentProjects_badge_completed: '已完成',
|
|
724
|
+
recentProjects_badge_failed: '失败',
|
|
725
|
+
recentProjects_badge_background_completed: '后台已完成',
|
|
726
|
+
recentProjects_badge_needs_review_after_navigation: '待处理',
|
|
727
|
+
recentProjects_badge_abandoned_after_navigation: '已中止'
|
|
591
728
|
}
|
|
592
729
|
};
|
|
593
730
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
(function initPathRedaction(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafPathRedaction = factory();
|
|
6
|
+
}
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function pathRedactionFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
// -------------------------------------------------------------------------
|
|
11
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Fix C / spec §5.6.2).
|
|
12
|
+
//
|
|
13
|
+
// Canonical local-path sanitizer shared between `computeSafeTaskSummary`
|
|
14
|
+
// (sessionState) and the storage-side audit redaction helpers
|
|
15
|
+
// (`sanitizeBareLocalPaths` in storageDb). One regex set, one placeholder
|
|
16
|
+
// shape, one place to broaden coverage when a new path shape shows up.
|
|
17
|
+
//
|
|
18
|
+
// Spec §5.6.2 explicitly directs implementers NOT to hand-roll narrow
|
|
19
|
+
// path regexes inside individual sanitizers — the audit redaction layer
|
|
20
|
+
// already exists for this. This module is the extraction the spec calls
|
|
21
|
+
// for so both layers stay in sync.
|
|
22
|
+
//
|
|
23
|
+
// Coverage required by the task brief:
|
|
24
|
+
// - /Users/... (Unix macOS home)
|
|
25
|
+
// - /home/... (Unix Linux home)
|
|
26
|
+
// - /private/var/..., /private/... (macOS firmlinks)
|
|
27
|
+
// - /tmp/... (Unix temp)
|
|
28
|
+
// - /var/folders/... (macOS per-user tmp)
|
|
29
|
+
// - /Volumes/... (macOS mounted volumes)
|
|
30
|
+
// - /etc/..., /opt/..., /usr/... (system / opt / usr)
|
|
31
|
+
// - file:///Users/... (file URLs)
|
|
32
|
+
// - C:\Users\bob\foo (Windows backslash)
|
|
33
|
+
// - C:/Users/bob/foo (Windows forward-slash)
|
|
34
|
+
// - \\server\share\foo (Windows UNC)
|
|
35
|
+
// - .codex-overleaf/projects/... (this extension's local workspace)
|
|
36
|
+
//
|
|
37
|
+
// Pattern construction notes:
|
|
38
|
+
// - The Unix branch uses a non-capturing alternation over the top-level
|
|
39
|
+
// directory names so a future addition (e.g. /srv/...) is one entry,
|
|
40
|
+
// not a new regex.
|
|
41
|
+
// - The UNC branch matches `\\` (or `//`) followed by host + share +
|
|
42
|
+
// path. We deliberately accept the forward-slash form too because
|
|
43
|
+
// some tools normalize backslashes to forward slashes when logging.
|
|
44
|
+
// - The file:// branch matches `file://` followed by either two or
|
|
45
|
+
// three slashes (RFC + common mis-encoded variants).
|
|
46
|
+
// -------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
// Top-level Unix directories that mark an absolute local path. We include
|
|
49
|
+
// the most common ones plus a few opt/usr/etc trees so a stray reference
|
|
50
|
+
// does not leak. Adding a new entry is a one-line change here.
|
|
51
|
+
const UNIX_TOPLEVELS = [
|
|
52
|
+
'Users',
|
|
53
|
+
'home',
|
|
54
|
+
'root',
|
|
55
|
+
'private',
|
|
56
|
+
'var',
|
|
57
|
+
'tmp',
|
|
58
|
+
'Volumes',
|
|
59
|
+
'etc',
|
|
60
|
+
'opt',
|
|
61
|
+
'usr',
|
|
62
|
+
'srv',
|
|
63
|
+
'mnt',
|
|
64
|
+
'media'
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// Match a path token to its end-of-word boundary. We stop at whitespace,
|
|
68
|
+
// closing paren/bracket (markdown link form), backtick, double-quote, or
|
|
69
|
+
// single-quote so we don't over-consume into surrounding text.
|
|
70
|
+
// Note: trailing punctuation like '.,;!?' is allowed inside the path body
|
|
71
|
+
// because filenames legitimately contain dots; downstream callers strip
|
|
72
|
+
// a trailing sentence punctuation character separately when needed.
|
|
73
|
+
const PATH_BODY = '[^\\s)\\]`"\']+';
|
|
74
|
+
|
|
75
|
+
// Build the master pattern. Each branch is a complete absolute-path shape.
|
|
76
|
+
// Order matters for clarity but not correctness — alternation is greedy
|
|
77
|
+
// by default in `|`-separated branches; we still anchor each branch to
|
|
78
|
+
// its distinguishing prefix so they don't overlap.
|
|
79
|
+
const ABSOLUTE_PATH_PATTERN = new RegExp(
|
|
80
|
+
[
|
|
81
|
+
// file:// URLs with two or three slashes after the scheme.
|
|
82
|
+
'file:\\/{2,3}' + PATH_BODY,
|
|
83
|
+
// Windows UNC: \\server\share\path or //server/share/path
|
|
84
|
+
'(?:\\\\\\\\|\\/\\/)[A-Za-z0-9._-]+(?:[\\\\\\/][A-Za-z0-9._$-]+)+',
|
|
85
|
+
// Windows drive letter: C:\path or C:/path
|
|
86
|
+
'[A-Za-z]:[\\\\\\/]' + PATH_BODY,
|
|
87
|
+
// Unix absolute path under a known top-level directory.
|
|
88
|
+
'\\/(?:' + UNIX_TOPLEVELS.join('|') + ')\\/' + PATH_BODY,
|
|
89
|
+
// Local Codex workspace marker — appears with or without a leading
|
|
90
|
+
// slash; e.g. /home/x/.codex-overleaf/projects/p1 or ./.codex-
|
|
91
|
+
// overleaf/projects/p1. The Unix branch above already handles the
|
|
92
|
+
// common /home form; this branch catches the relative form.
|
|
93
|
+
'(?:^|[\\s\\\\/])\\.codex-overleaf[\\\\\\/]projects[\\\\\\/]' + PATH_BODY
|
|
94
|
+
].join('|'),
|
|
95
|
+
'gi'
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Quick predicate — used by callers that only want to do the (more
|
|
99
|
+
// expensive) substitution pass when there's actually something to strip.
|
|
100
|
+
const MIGHT_CONTAIN_LOCAL_PATH_PATTERN = new RegExp(
|
|
101
|
+
[
|
|
102
|
+
'file:\\/{2,3}',
|
|
103
|
+
'(?:\\\\\\\\|\\/\\/)[A-Za-z0-9._-]+[\\\\\\/]',
|
|
104
|
+
'[A-Za-z]:[\\\\\\/]',
|
|
105
|
+
'\\/(?:' + UNIX_TOPLEVELS.join('|') + ')\\/',
|
|
106
|
+
'\\.codex-overleaf[\\\\\\/]projects[\\\\\\/]'
|
|
107
|
+
].join('|'),
|
|
108
|
+
'i'
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Replace every absolute-local-path token in `value` with `placeholder`.
|
|
112
|
+
// Default placeholder is `<local-path>` to match the prior summary-side
|
|
113
|
+
// sanitizer. The storage-side audit redactor uses a richer `[local path]`
|
|
114
|
+
// (and `[local path:LINE]` when a `:line` suffix was present); that path
|
|
115
|
+
// continues to use its own formatter — this helper is the floor, not
|
|
116
|
+
// the only formatter.
|
|
117
|
+
function redactLocalPaths(value, placeholder) {
|
|
118
|
+
if (typeof value !== 'string' || !value) {
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
const token = typeof placeholder === 'string' ? placeholder : '<local-path>';
|
|
122
|
+
// Reset state (these are /g regexes) before reusing.
|
|
123
|
+
ABSOLUTE_PATH_PATTERN.lastIndex = 0;
|
|
124
|
+
return value.replace(ABSOLUTE_PATH_PATTERN, token);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function mightContainLocalPath(value) {
|
|
128
|
+
if (typeof value !== 'string' || !value) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return MIGHT_CONTAIN_LOCAL_PATH_PATTERN.test(value);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
redactLocalPaths,
|
|
136
|
+
mightContainLocalPath,
|
|
137
|
+
// Exposed so the storage-side audit redactor (which formats per-token
|
|
138
|
+
// placeholders with line-suffix preservation) can iterate the same set
|
|
139
|
+
// without duplicating the regex source.
|
|
140
|
+
ABSOLUTE_PATH_PATTERN,
|
|
141
|
+
UNIX_TOPLEVELS
|
|
142
|
+
};
|
|
143
|
+
});
|
|
@@ -38,10 +38,16 @@
|
|
|
38
38
|
const VALID_LOCALES = new Set(['en', 'zh']);
|
|
39
39
|
const VALID_EVENT_STATUSES = new Set(['info', 'running', 'completed', 'failed', 'warning', 'blocked', 'skipped', 'pending']);
|
|
40
40
|
const VALID_TITLE_SOURCES = new Set(['auto', 'manual']);
|
|
41
|
+
// `needs_review` is the §7 settlement state surfaced when Accept/Undo cannot
|
|
42
|
+
// prove a clean post-action state. It is non-terminal for UI purposes: both
|
|
43
|
+
// Accept and Undo remain visible AND actionable so the user can inspect
|
|
44
|
+
// Overleaf and reconcile. Step 3 (terminal payload cleanup) intentionally
|
|
45
|
+
// does NOT empty refs for `needs_review` — the user is supposed to retry.
|
|
41
46
|
const VALID_TRACKED_CHANGE_STATUS = new Set([
|
|
42
47
|
'pending',
|
|
43
48
|
'accepted',
|
|
44
|
-
'rejected'
|
|
49
|
+
'rejected',
|
|
50
|
+
'needs_review'
|
|
45
51
|
]);
|
|
46
52
|
const TERMINAL_TRACKED_CHANGE_STATUS = new Set(['accepted', 'rejected']);
|
|
47
53
|
const LEGACY_DEFAULT_SESSION_TITLE = 'New task';
|
|
@@ -93,6 +99,7 @@
|
|
|
93
99
|
/\b(?:api[_-]?key|token|password|passwd|secret)\b\s*[:=]\s*["']?[^"'\s,;]+["']?/gi
|
|
94
100
|
];
|
|
95
101
|
const LineReferences = loadLineReferences();
|
|
102
|
+
const PathRedaction = loadPathRedaction();
|
|
96
103
|
|
|
97
104
|
function normalizePanelState(input = {}, options = {}) {
|
|
98
105
|
const state = {
|
|
@@ -530,6 +537,7 @@
|
|
|
530
537
|
speedTier: typeof run.speedTier === 'string' ? run.speedTier : '',
|
|
531
538
|
status: shouldStopRestoredRun ? 'failed' : normalizeRunStatus(run.status),
|
|
532
539
|
statusText: shouldStopRestoredRun ? i18n.t(locale, 'restoredRunStoppedStatus') : sanitizeAssistantVisibleText(run.statusText),
|
|
540
|
+
runProjectId: normalizeProjectPrefKey(run.runProjectId),
|
|
533
541
|
startedAt: typeof run.startedAt === 'string' ? run.startedAt : '',
|
|
534
542
|
finishedAt: shouldStopRestoredRun ? new Date().toISOString() : typeof run.finishedAt === 'string' ? run.finishedAt : '',
|
|
535
543
|
events: events.slice(-MAX_RUN_EVENTS),
|
|
@@ -594,8 +602,30 @@
|
|
|
594
602
|
}
|
|
595
603
|
}
|
|
596
604
|
|
|
605
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Task 2): the run lifecycle now
|
|
606
|
+
// settles on three additional values when the user navigates away mid-run
|
|
607
|
+
// and the original run completes (or aborts) in the background. They land on
|
|
608
|
+
// the ORIGINAL project's session record, not the active one. The catalog is
|
|
609
|
+
// a `Set` so the recovery branch can defensively coerce any unknown legacy
|
|
610
|
+
// value to `pending` without throwing.
|
|
611
|
+
const VALID_RUN_STATUS = new Set([
|
|
612
|
+
'pending',
|
|
613
|
+
'running',
|
|
614
|
+
'completed',
|
|
615
|
+
'failed',
|
|
616
|
+
'background_completed',
|
|
617
|
+
'needs_review_after_navigation',
|
|
618
|
+
'abandoned_after_navigation'
|
|
619
|
+
]);
|
|
620
|
+
|
|
597
621
|
function normalizeRunStatus(status) {
|
|
598
|
-
|
|
622
|
+
if (VALID_RUN_STATUS.has(status)) return status;
|
|
623
|
+
// Legacy persisted runs without an explicit status fall back to `completed`
|
|
624
|
+
// (the historical default for the recovery branch); unknown values land on
|
|
625
|
+
// `pending` so the UI surfaces them as fresh / actionable rather than
|
|
626
|
+
// pretending they finished.
|
|
627
|
+
if (status === undefined || status === null || status === '') return 'completed';
|
|
628
|
+
return 'pending';
|
|
599
629
|
}
|
|
600
630
|
|
|
601
631
|
function normalizeEventStatus(status) {
|
|
@@ -860,7 +890,7 @@
|
|
|
860
890
|
function compactSessionForStorage(session, fallbackState, limits) {
|
|
861
891
|
const runs = compactRunsForStorage(session.runs, limits);
|
|
862
892
|
const titleSource = VALID_TITLE_SOURCES.has(session.titleSource) ? session.titleSource : 'auto';
|
|
863
|
-
|
|
893
|
+
const compact = {
|
|
864
894
|
id: session.id,
|
|
865
895
|
title: compactSessionTitleForStorage(session, titleSource, limits),
|
|
866
896
|
titleSource,
|
|
@@ -876,6 +906,24 @@
|
|
|
876
906
|
requireReviewing: session.requireReviewing !== false,
|
|
877
907
|
focusFiles: normalizeFocusFiles(session.focusFiles)
|
|
878
908
|
};
|
|
909
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Task 3): preserve the four
|
|
910
|
+
// Recent-projects fields through compaction so they round-trip when state
|
|
911
|
+
// is reloaded from chrome.storage.local. The active record builder in
|
|
912
|
+
// `buildSessionRecord` is the canonical writer; this branch preserves an
|
|
913
|
+
// existing value so it survives.
|
|
914
|
+
if (typeof session.lastActivityAt === 'string' && session.lastActivityAt) {
|
|
915
|
+
compact.lastActivityAt = session.lastActivityAt;
|
|
916
|
+
}
|
|
917
|
+
if (typeof session.accountScopeId === 'string' && session.accountScopeId) {
|
|
918
|
+
compact.accountScopeId = session.accountScopeId;
|
|
919
|
+
}
|
|
920
|
+
if (typeof session.accountScopeUnavailable === 'boolean') {
|
|
921
|
+
compact.accountScopeUnavailable = session.accountScopeUnavailable;
|
|
922
|
+
}
|
|
923
|
+
if (typeof session.safeTaskSummary === 'string' && session.safeTaskSummary) {
|
|
924
|
+
compact.safeTaskSummary = session.safeTaskSummary;
|
|
925
|
+
}
|
|
926
|
+
return compact;
|
|
879
927
|
}
|
|
880
928
|
|
|
881
929
|
function compactSessionTitleForStorage(session, titleSource, limits) {
|
|
@@ -927,6 +975,7 @@
|
|
|
927
975
|
speedTier: typeof run.speedTier === 'string' ? run.speedTier : '',
|
|
928
976
|
status: normalizeRunStatus(run.status),
|
|
929
977
|
statusText: summarizeTextForStorage(run.statusText, 'status text'),
|
|
978
|
+
runProjectId: normalizeProjectPrefKey(run.runProjectId),
|
|
930
979
|
startedAt: typeof run.startedAt === 'string' ? run.startedAt : '',
|
|
931
980
|
finishedAt: typeof run.finishedAt === 'string' ? run.finishedAt : '',
|
|
932
981
|
events: compactRunEvents(run.events, limits),
|
|
@@ -1080,6 +1129,51 @@
|
|
|
1080
1129
|
return Math.round(Math.min(760, Math.max(340, width)));
|
|
1081
1130
|
}
|
|
1082
1131
|
|
|
1132
|
+
// Welcome-panel + write-guard v1.3.8 add-on (Task 3): the Recent-projects
|
|
1133
|
+
// dashboard variant renders one sanitized line per project. `computeSafeTaskSummary`
|
|
1134
|
+
// is the privacy floor for that line. It is written on every `saveState` and
|
|
1135
|
+
// stored on the session record (`session.safeTaskSummary`), so the dashboard
|
|
1136
|
+
// never has to touch the raw `task` text on render.
|
|
1137
|
+
//
|
|
1138
|
+
// The `@` regex is intentionally broad — see spec §5.6.2:
|
|
1139
|
+
// > Replace `@<token>` references with `@…` (regex `/@[\w./-]+/g` → `'@…'`).
|
|
1140
|
+
// > This intentionally over-redacts: it will also strip plain email
|
|
1141
|
+
// > addresses, social handles, and any `@foo` mention in the task body.
|
|
1142
|
+
// > That is the conservative-privacy choice and is by design — future
|
|
1143
|
+
// > implementers must not narrow the pattern to "only known attachment
|
|
1144
|
+
// > tokens" because doing so would re-expose paths, citation keys,
|
|
1145
|
+
// > reviewer names, etc. that users frequently combine with `@` in task
|
|
1146
|
+
// > text.
|
|
1147
|
+
function computeSafeTaskSummary(task) {
|
|
1148
|
+
if (typeof task !== 'string' || !task) return '';
|
|
1149
|
+
let s = task;
|
|
1150
|
+
// Strip absolute local paths via the canonical shared helper
|
|
1151
|
+
// (spec §5.6.2 / Fix C). The helper covers Unix (/Users, /home,
|
|
1152
|
+
// /private/var, /tmp, /var/folders, /Volumes, /etc, /opt, /usr, ...),
|
|
1153
|
+
// Windows drive letters with both `\\` and `/`, UNC `\\server\share`,
|
|
1154
|
+
// and `file:///` URLs. Adding a new path shape is a one-line change
|
|
1155
|
+
// in `pathRedaction.js` and benefits both this summary and the
|
|
1156
|
+
// storage-side audit redaction in lockstep.
|
|
1157
|
+
if (PathRedaction && PathRedaction.redactLocalPaths instanceof Function) {
|
|
1158
|
+
s = PathRedaction.redactLocalPaths(s, '<local-path>');
|
|
1159
|
+
} else {
|
|
1160
|
+
// Defensive fallback for hosts where the shared helper failed to
|
|
1161
|
+
// load. The narrower legacy patterns ship a baseline (better than
|
|
1162
|
+
// nothing) and the test suite asserts the broad coverage path
|
|
1163
|
+
// succeeds, so this branch should never run in production.
|
|
1164
|
+
s = s.replace(/(?:\/Users\/[^\s]+|\/home\/[^\s]+|\/private\/var\/[^\s]+|\/tmp\/[^\s]+|\/Volumes\/[^\s]+)/g, '<local-path>');
|
|
1165
|
+
s = s.replace(/[A-Za-z]:[\\/][^\s]+/g, '<local-path>');
|
|
1166
|
+
}
|
|
1167
|
+
// INTENTIONALLY OVER-REDACT @<token>: spec §5.6.2 — do not narrow to
|
|
1168
|
+
// attachment tokens, that would re-expose user info / paths / handles.
|
|
1169
|
+
s = s.replace(/@[\w./-]+/g, '@…');
|
|
1170
|
+
// Collapse whitespace runs to single space; trim.
|
|
1171
|
+
s = s.replace(/\s+/g, ' ').trim();
|
|
1172
|
+
// Hard cap 80 visible chars.
|
|
1173
|
+
if (s.length > 80) s = s.slice(0, 79) + '…';
|
|
1174
|
+
return s;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1083
1177
|
function normalizeTextField(value, maxChars) {
|
|
1084
1178
|
const text = sanitizeAssistantVisibleText(value);
|
|
1085
1179
|
if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars) {
|
|
@@ -1161,6 +1255,20 @@
|
|
|
1161
1255
|
return null;
|
|
1162
1256
|
}
|
|
1163
1257
|
|
|
1258
|
+
function loadPathRedaction() {
|
|
1259
|
+
if (typeof globalThis !== 'undefined' && globalThis.CodexOverleafPathRedaction) {
|
|
1260
|
+
return globalThis.CodexOverleafPathRedaction;
|
|
1261
|
+
}
|
|
1262
|
+
if (typeof require === 'function') {
|
|
1263
|
+
try {
|
|
1264
|
+
return require('./pathRedaction');
|
|
1265
|
+
} catch (_error) {
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1164
1272
|
function fallbackSanitizeLocalReferences(value) {
|
|
1165
1273
|
return String(value || '')
|
|
1166
1274
|
.replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_raw, label, target) => {
|
|
@@ -1263,6 +1371,7 @@
|
|
|
1263
1371
|
updateActiveSession,
|
|
1264
1372
|
normalizeRuns,
|
|
1265
1373
|
prepareStateForStorage,
|
|
1266
|
-
estimateJsonBytes
|
|
1374
|
+
estimateJsonBytes,
|
|
1375
|
+
computeSafeTaskSummary
|
|
1267
1376
|
};
|
|
1268
1377
|
});
|