codex-overleaf-link 1.3.6 → 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 +22 -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 +175 -2
- package/extension/src/shared/pathRedaction.js +143 -0
- package/extension/src/shared/sessionState.js +175 -5
- package/extension/src/shared/storageDb.js +226 -4
- package/native-host/src/codexPromptAssembly.js +10 -2
- package/native-host/src/codexSessionRunner.js +33 -1
- package/package.json +1 -1
|
@@ -123,6 +123,28 @@
|
|
|
123
123
|
undoCheckpointMissingReason: 'This run wrote while Reviewing/Track Changes was enabled, but the extension could not reliably identify the tracked changes generated by Overleaf. To avoid creating new redlines with text patches, automatic undo is disabled.',
|
|
124
124
|
undoCheckpointMissingNext: 'Reject this run manually in Overleaf review tools, or rerun and try again.',
|
|
125
125
|
undoCheckpointPlain: 'Undo point created: this run has {count} reversible write(s)',
|
|
126
|
+
runAcceptTracked: 'Accept changes',
|
|
127
|
+
runAcceptTrackedTitle: 'Accept this run\'s Overleaf tracked changes',
|
|
128
|
+
runAcceptTrackedConfirm: 'Confirm accept',
|
|
129
|
+
runAcceptTrackedCancel: 'Cancel',
|
|
130
|
+
runAcceptTrackedConfirming: 'Accepting…',
|
|
131
|
+
runAcceptTrackedDone: 'Accepted',
|
|
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',
|
|
137
|
+
runAcceptTrackedStarted: 'Starting to accept this run\'s Overleaf tracked changes',
|
|
138
|
+
runAcceptTrackedResult: 'Accept result: accepted {applied} tracked change(s), skipped {skipped}',
|
|
139
|
+
runAcceptTrackedFailed: 'Accept changes could not be completed',
|
|
140
|
+
runAcceptTrackedFailedReason: 'Overleaf editor content has drifted from this run\'s writeback, so Codex did not change the document. The run stays pending — retry Accept changes.',
|
|
141
|
+
runAcceptTrackedStepEditorUndo: 'Accept step 1/6 — Overleaf editor-undo of this run\'s tracked writeback',
|
|
142
|
+
runAcceptTrackedStepModeBefore: 'Accept step 2/6 — Reviewing/Track Changes state read BEFORE the Editing toggle',
|
|
143
|
+
runAcceptTrackedStepForceEditing: 'Accept step 3/6 — forcing Editing mode (Track Changes OFF) for the untracked replay',
|
|
144
|
+
runAcceptTrackedStepReplayStart: 'Accept step 4/6 — per-operation re-check of Editing mode before writing {path}',
|
|
145
|
+
runAcceptTrackedStepReplayDone: 'Accept step 5/6 — untracked replay write completed for {path}',
|
|
146
|
+
runAcceptTrackedStepRestoreReviewing: 'Accept step 6/6 — restoring the prior Reviewing/Track Changes mode',
|
|
147
|
+
detailAccepted: 'Accepted',
|
|
126
148
|
deleteFilePromptTitle: 'Allow Codex to delete files?',
|
|
127
149
|
deleteFilePromptMessage: '{files}\n\nOther changes can still sync if deletion is not confirmed.',
|
|
128
150
|
deleteFileConfirm: 'Allow delete',
|
|
@@ -280,7 +302,72 @@
|
|
|
280
302
|
processed: 'Done {elapsed}',
|
|
281
303
|
restoredRunStoppedTitle: 'Stopped tracking this run after a page refresh',
|
|
282
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.',
|
|
283
|
-
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'
|
|
284
371
|
},
|
|
285
372
|
zh: {
|
|
286
373
|
resizePanel: '拖动调整 Codex 面板宽度,双击恢复默认宽度',
|
|
@@ -394,6 +481,28 @@
|
|
|
394
481
|
undoCheckpointMissingReason: '本轮是在 Reviewing/Track Changes 下写入的,但插件没有可靠识别 Overleaf 生成的留痕记录。为了避免用文本补丁制造新的红线,自动撤销已禁用。',
|
|
395
482
|
undoCheckpointMissingNext: '请在 Overleaf 审阅面板手动拒绝这轮建议,或重新运行后再尝试。',
|
|
396
483
|
undoCheckpointPlain: '已创建撤销点:可撤销本轮 {count} 项写入',
|
|
484
|
+
runAcceptTracked: '接受改动',
|
|
485
|
+
runAcceptTrackedTitle: '接受本轮 Overleaf 留痕改动',
|
|
486
|
+
runAcceptTrackedConfirm: '确认接受',
|
|
487
|
+
runAcceptTrackedCancel: '取消',
|
|
488
|
+
runAcceptTrackedConfirming: '接受中…',
|
|
489
|
+
runAcceptTrackedDone: '已接受',
|
|
490
|
+
runAcceptTrackedDoneTitle: '本轮留痕改动已被接受',
|
|
491
|
+
runAcceptTrackedNeedsReview: '接受改动 — 需待核对',
|
|
492
|
+
runAcceptTrackedNeedsReviewTitle: '本轮留痕未必已完全接受;请在 Overleaf 中核对后重试。',
|
|
493
|
+
runUndoNeedsReview: '撤销 — 需待核对',
|
|
494
|
+
runUndoNeedsReviewTitle: '本轮撤销未必已完全完成;请在 Overleaf 中核对后重试。',
|
|
495
|
+
runAcceptTrackedStarted: '开始接受本轮 Overleaf 留痕改动',
|
|
496
|
+
runAcceptTrackedResult: '接受结果:已接受 {applied} 条留痕,跳过 {skipped} 条',
|
|
497
|
+
runAcceptTrackedFailed: '没有完成接受改动',
|
|
498
|
+
runAcceptTrackedFailedReason: 'Overleaf 编辑器内容已经和本轮写入不一致,Codex 没有改动文档。本轮仍为待处理状态——请重新点击接受改动。',
|
|
499
|
+
runAcceptTrackedStepEditorUndo: '接受步骤 1/6 — 通过 Overleaf 编辑器撤销,回退本轮留痕写入',
|
|
500
|
+
runAcceptTrackedStepModeBefore: '接受步骤 2/6 — 强制切换 Editing 之前读取的 Reviewing/Track Changes 状态',
|
|
501
|
+
runAcceptTrackedStepForceEditing: '接受步骤 3/6 — 强制切换到 Editing 模式(Track Changes OFF)以便重放为永久文本',
|
|
502
|
+
runAcceptTrackedStepReplayStart: '接受步骤 4/6 — 写入 {path} 前再次校验 Editing 模式',
|
|
503
|
+
runAcceptTrackedStepReplayDone: '接受步骤 5/6 — 已完成 {path} 的无留痕重放写入',
|
|
504
|
+
runAcceptTrackedStepRestoreReviewing: '接受步骤 6/6 — 恢复之前的 Reviewing/Track Changes 模式',
|
|
505
|
+
detailAccepted: '已接受',
|
|
397
506
|
deleteFilePromptTitle: '允许 Codex 删除文件?',
|
|
398
507
|
deleteFilePromptMessage: '{files}\n\n未确认删除时,其它改动仍可继续同步。',
|
|
399
508
|
deleteFileConfirm: '允许删除',
|
|
@@ -551,7 +660,71 @@
|
|
|
551
660
|
processed: '已处理 {elapsed}',
|
|
552
661
|
restoredRunStoppedTitle: '页面刷新后已停止跟踪这轮任务',
|
|
553
662
|
restoredRunStoppedDetail: '插件重新加载时发现这轮任务还标记为处理中。为了避免继续显示过期状态,已把它标记为中断;可以重新运行任务。',
|
|
554
|
-
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: '已中止'
|
|
555
728
|
}
|
|
556
729
|
};
|
|
557
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,6 +38,18 @@
|
|
|
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.
|
|
46
|
+
const VALID_TRACKED_CHANGE_STATUS = new Set([
|
|
47
|
+
'pending',
|
|
48
|
+
'accepted',
|
|
49
|
+
'rejected',
|
|
50
|
+
'needs_review'
|
|
51
|
+
]);
|
|
52
|
+
const TERMINAL_TRACKED_CHANGE_STATUS = new Set(['accepted', 'rejected']);
|
|
41
53
|
const LEGACY_DEFAULT_SESSION_TITLE = 'New task';
|
|
42
54
|
const SESSION_AUTO_TITLE_CHARS = 24;
|
|
43
55
|
const MAX_RUN_EVENTS = 300;
|
|
@@ -87,6 +99,7 @@
|
|
|
87
99
|
/\b(?:api[_-]?key|token|password|passwd|secret)\b\s*[:=]\s*["']?[^"'\s,;]+["']?/gi
|
|
88
100
|
];
|
|
89
101
|
const LineReferences = loadLineReferences();
|
|
102
|
+
const PathRedaction = loadPathRedaction();
|
|
90
103
|
|
|
91
104
|
function normalizePanelState(input = {}, options = {}) {
|
|
92
105
|
const state = {
|
|
@@ -515,7 +528,7 @@
|
|
|
515
528
|
});
|
|
516
529
|
}
|
|
517
530
|
|
|
518
|
-
|
|
531
|
+
const normalized = {
|
|
519
532
|
id: run.id,
|
|
520
533
|
task: sanitizeAssistantVisibleText(run.task) || 'untitled task',
|
|
521
534
|
mode: typeof run.mode === 'string' ? run.mode : '',
|
|
@@ -524,6 +537,7 @@
|
|
|
524
537
|
speedTier: typeof run.speedTier === 'string' ? run.speedTier : '',
|
|
525
538
|
status: shouldStopRestoredRun ? 'failed' : normalizeRunStatus(run.status),
|
|
526
539
|
statusText: shouldStopRestoredRun ? i18n.t(locale, 'restoredRunStoppedStatus') : sanitizeAssistantVisibleText(run.statusText),
|
|
540
|
+
runProjectId: normalizeProjectPrefKey(run.runProjectId),
|
|
527
541
|
startedAt: typeof run.startedAt === 'string' ? run.startedAt : '',
|
|
528
542
|
finishedAt: shouldStopRestoredRun ? new Date().toISOString() : typeof run.finishedAt === 'string' ? run.finishedAt : '',
|
|
529
543
|
events: events.slice(-MAX_RUN_EVENTS),
|
|
@@ -535,10 +549,83 @@
|
|
|
535
549
|
undoExpectedFiles: normalizeRunFiles(run.undoExpectedFiles),
|
|
536
550
|
undoStatus: sanitizeAssistantVisibleText(run.undoStatus)
|
|
537
551
|
};
|
|
552
|
+
|
|
553
|
+
applyTrackedChangeStatus(normalized, run.trackedChangeStatus);
|
|
554
|
+
|
|
555
|
+
return normalized;
|
|
538
556
|
}
|
|
539
557
|
|
|
558
|
+
// Resolves `trackedChangeStatus` on an already-normalized run via three ordered
|
|
559
|
+
// steps: (1) value recovery, (2) migration of pre-feature runs, (3) terminal
|
|
560
|
+
// payload cleanup. Mutates `run` in place. Idempotent: re-running it on its own
|
|
561
|
+
// output yields the same result.
|
|
562
|
+
function applyTrackedChangeStatus(run, rawStatus) {
|
|
563
|
+
const hasRefs = run.undoTrackedChanges.length > 0;
|
|
564
|
+
const hasRawStatus = rawStatus !== undefined && rawStatus !== null && rawStatus !== '';
|
|
565
|
+
|
|
566
|
+
// Step 1 — value recovery. Keep a stable value; recover any other present
|
|
567
|
+
// value (corruption, an old persisted `partial_accept` / `partial_reject` /
|
|
568
|
+
// `resolved_elsewhere`, a stray in-flight value) to `pending` (with refs)
|
|
569
|
+
// or drop it. An absent value falls through.
|
|
570
|
+
let status;
|
|
571
|
+
if (VALID_TRACKED_CHANGE_STATUS.has(rawStatus)) {
|
|
572
|
+
status = rawStatus;
|
|
573
|
+
} else if (hasRawStatus) {
|
|
574
|
+
status = hasRefs ? 'pending' : undefined;
|
|
575
|
+
} else {
|
|
576
|
+
status = undefined;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Step 1 — reload reconciliation. A non-terminal status (`pending`) with no
|
|
580
|
+
// refs is the post-reload state of an un-acted tracked-change run: the heavy refs are
|
|
581
|
+
// never persisted, so without them there is nothing to act on. Drop it so
|
|
582
|
+
// the run returns to the legacy-undo world. A terminal status with no refs
|
|
583
|
+
// is kept — step 3 already empties terminal payloads and the label stays
|
|
584
|
+
// meaningful.
|
|
585
|
+
if (!hasRefs && status !== undefined && !TERMINAL_TRACKED_CHANGE_STATUS.has(status)) {
|
|
586
|
+
status = undefined;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Step 2 — migration of pre-feature runs (no status after step 1).
|
|
590
|
+
if (status === undefined && hasRefs) {
|
|
591
|
+
status = run.undoStatus === 'applied' ? 'rejected' : 'pending';
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Step 3 — terminal payload cleanup; keeps `trackedChangeStatus`.
|
|
595
|
+
if (TERMINAL_TRACKED_CHANGE_STATUS.has(status)) {
|
|
596
|
+
run.undoTrackedChanges = [];
|
|
597
|
+
run.undoExpectedFiles = [];
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (status !== undefined) {
|
|
601
|
+
run.trackedChangeStatus = status;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
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
|
+
|
|
540
621
|
function normalizeRunStatus(status) {
|
|
541
|
-
|
|
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';
|
|
542
629
|
}
|
|
543
630
|
|
|
544
631
|
function normalizeEventStatus(status) {
|
|
@@ -803,7 +890,7 @@
|
|
|
803
890
|
function compactSessionForStorage(session, fallbackState, limits) {
|
|
804
891
|
const runs = compactRunsForStorage(session.runs, limits);
|
|
805
892
|
const titleSource = VALID_TITLE_SOURCES.has(session.titleSource) ? session.titleSource : 'auto';
|
|
806
|
-
|
|
893
|
+
const compact = {
|
|
807
894
|
id: session.id,
|
|
808
895
|
title: compactSessionTitleForStorage(session, titleSource, limits),
|
|
809
896
|
titleSource,
|
|
@@ -819,6 +906,24 @@
|
|
|
819
906
|
requireReviewing: session.requireReviewing !== false,
|
|
820
907
|
focusFiles: normalizeFocusFiles(session.focusFiles)
|
|
821
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;
|
|
822
927
|
}
|
|
823
928
|
|
|
824
929
|
function compactSessionTitleForStorage(session, titleSource, limits) {
|
|
@@ -861,7 +966,7 @@
|
|
|
861
966
|
|
|
862
967
|
function compactRunForStorage(run, limits, keepUndoPayload) {
|
|
863
968
|
const undoPayload = compactUndoPayload(run, limits, keepUndoPayload);
|
|
864
|
-
|
|
969
|
+
const compact = {
|
|
865
970
|
id: run.id,
|
|
866
971
|
task: summarizeTextForStorage(run.task || 'untitled task', 'run task'),
|
|
867
972
|
mode: typeof run.mode === 'string' ? run.mode : '',
|
|
@@ -870,6 +975,7 @@
|
|
|
870
975
|
speedTier: typeof run.speedTier === 'string' ? run.speedTier : '',
|
|
871
976
|
status: normalizeRunStatus(run.status),
|
|
872
977
|
statusText: summarizeTextForStorage(run.statusText, 'status text'),
|
|
978
|
+
runProjectId: normalizeProjectPrefKey(run.runProjectId),
|
|
873
979
|
startedAt: typeof run.startedAt === 'string' ? run.startedAt : '',
|
|
874
980
|
finishedAt: typeof run.finishedAt === 'string' ? run.finishedAt : '',
|
|
875
981
|
events: compactRunEvents(run.events, limits),
|
|
@@ -881,6 +987,10 @@
|
|
|
881
987
|
undoExpectedFiles: undoPayload.undoExpectedFiles,
|
|
882
988
|
undoStatus: summarizeTextForStorage(run.undoStatus, 'undo status')
|
|
883
989
|
};
|
|
990
|
+
if (VALID_TRACKED_CHANGE_STATUS.has(run.trackedChangeStatus)) {
|
|
991
|
+
compact.trackedChangeStatus = run.trackedChangeStatus;
|
|
992
|
+
}
|
|
993
|
+
return compact;
|
|
884
994
|
}
|
|
885
995
|
|
|
886
996
|
function compactRunEvents(events, limits) {
|
|
@@ -1019,6 +1129,51 @@
|
|
|
1019
1129
|
return Math.round(Math.min(760, Math.max(340, width)));
|
|
1020
1130
|
}
|
|
1021
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
|
+
|
|
1022
1177
|
function normalizeTextField(value, maxChars) {
|
|
1023
1178
|
const text = sanitizeAssistantVisibleText(value);
|
|
1024
1179
|
if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars) {
|
|
@@ -1100,6 +1255,20 @@
|
|
|
1100
1255
|
return null;
|
|
1101
1256
|
}
|
|
1102
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
|
+
|
|
1103
1272
|
function fallbackSanitizeLocalReferences(value) {
|
|
1104
1273
|
return String(value || '')
|
|
1105
1274
|
.replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_raw, label, target) => {
|
|
@@ -1202,6 +1371,7 @@
|
|
|
1202
1371
|
updateActiveSession,
|
|
1203
1372
|
normalizeRuns,
|
|
1204
1373
|
prepareStateForStorage,
|
|
1205
|
-
estimateJsonBytes
|
|
1374
|
+
estimateJsonBytes,
|
|
1375
|
+
computeSafeTaskSummary
|
|
1206
1376
|
};
|
|
1207
1377
|
});
|