codex-overleaf-link 2.6.0 → 2.6.5
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 +9 -9
- package/README.zh-CN.md +9 -9
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/src/background.js +70 -0
- package/extension/src/content/composerAttachments.js +35 -8
- package/extension/src/content/contentRuntime.js +200 -51
- package/extension/src/content/diagnosticsController.js +77 -34
- package/extension/src/content/diagnosticsExport.js +1 -1
- package/extension/src/content/diagnosticsPanel.js +129 -42
- package/extension/src/content/generated/content.bundle.js +1283 -331
- package/extension/src/content/generated/content.bundle.meta.json +3 -3
- package/extension/src/content/localSkillsPanel.js +4 -2
- package/extension/src/content/markdownText.js +11 -9
- package/extension/src/content/modelPicker.js +28 -19
- package/extension/src/content/nativeCompatibilityController.js +23 -9
- package/extension/src/content/pageBridgeClient.js +5 -5
- package/extension/src/content/panelMaintenance.js +4 -0
- package/extension/src/content/panelRenderer.js +4 -1
- package/extension/src/content/providerSettingsDialog.js +26 -18
- package/extension/src/content/recentProjects.js +26 -16
- package/extension/src/content/runQueueScheduler.js +19 -9
- package/extension/src/content/runResultActions.js +51 -4
- package/extension/src/content/runReviewController.js +9 -3
- package/extension/src/content/scopedPersistencePanelState.js +34 -25
- package/extension/src/content/selectionContextView.js +30 -3
- package/extension/src/content/sharedSessionViewSync.js +9 -1
- package/extension/src/content/writebackOrchestrator.js +266 -50
- package/extension/src/content/writingStyleSettings.js +70 -17
- package/extension/src/page/overleafEditor.js +12 -3
- package/extension/src/page/overleafProjectSnapshot.js +56 -3
- package/extension/src/page/snapshotRouter.js +75 -66
- package/extension/src/page/treeOperations.js +200 -19
- package/extension/src/page/writebackRouter.js +152 -40
- package/extension/src/pageBridge.js +17 -7
- package/extension/src/shared/agentTranscript.js +23 -2
- package/extension/src/shared/auditRecords.js +1 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/composerAttachmentDraft.js +22 -7
- package/extension/src/shared/failureReasons.js +15 -0
- package/extension/src/shared/i18n.js +16 -0
- package/extension/src/shared/pageRpcContract.js +1 -1
- package/extension/src/shared/projectFiles.js +2 -1
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +34 -0
- package/extension/src/shared/staleGuard.js +58 -0
- package/extension/src/shared/storageMigration.js +104 -1
- package/extension/styles/panel.css +191 -63
- package/native-host/src/codexSessionRunner.js +1 -0
- package/native-host/src/debugLog.js +27 -3
- package/native-host/src/index.js +42 -11
- package/native-host/src/localSkills.js +1 -1
- package/native-host/src/mirrorWorkspace.js +47 -3
- package/native-host/src/nativeEnvironment.js +27 -5
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/skills/reviewer-response/SKILL.md +65 -0
- package/native-host/src/taskRunnerRuntime.js +11 -3
- package/native-host/src/updateManager.js +24 -6
- package/native-host/src/writingStyleRuntime.js +1 -1
- package/package.json +1 -1
|
@@ -403,6 +403,16 @@
|
|
|
403
403
|
vertical-align: top;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
#codex-overleaf-panel :is(.run-stream-text, .run-final-answer) .run-markdown-table :is(th, td) {
|
|
407
|
+
overflow-wrap: break-word;
|
|
408
|
+
min-width: 4em;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
#codex-overleaf-panel :is(.run-stream-text, .run-final-answer) .run-markdown-table .codex-line-reference {
|
|
412
|
+
overflow-wrap: normal;
|
|
413
|
+
white-space: nowrap;
|
|
414
|
+
}
|
|
415
|
+
|
|
406
416
|
#codex-overleaf-panel :is(.run-stream-text, .run-final-answer) .run-markdown-table th {
|
|
407
417
|
background: var(--tl-surface-2);
|
|
408
418
|
color: var(--tl-fg-1);
|
|
@@ -1813,7 +1823,6 @@
|
|
|
1813
1823
|
#codex-overleaf-panel .codex-diagnostics-checks {
|
|
1814
1824
|
display: grid;
|
|
1815
1825
|
gap: 0;
|
|
1816
|
-
margin-top: 4px;
|
|
1817
1826
|
}
|
|
1818
1827
|
|
|
1819
1828
|
#codex-overleaf-panel .codex-diagnostics-check {
|
|
@@ -1827,7 +1836,7 @@
|
|
|
1827
1836
|
|
|
1828
1837
|
#codex-overleaf-panel .codex-diagnostics-check > summary {
|
|
1829
1838
|
display: grid;
|
|
1830
|
-
grid-template-columns:
|
|
1839
|
+
grid-template-columns: 8px minmax(0, 1fr) 10px;
|
|
1831
1840
|
gap: 8px;
|
|
1832
1841
|
align-items: center;
|
|
1833
1842
|
padding: 10px 0;
|
|
@@ -1852,37 +1861,39 @@
|
|
|
1852
1861
|
transform: rotate(45deg);
|
|
1853
1862
|
}
|
|
1854
1863
|
|
|
1855
|
-
#codex-overleaf-panel .codex-diagnostics-check-
|
|
1856
|
-
|
|
1864
|
+
#codex-overleaf-panel .codex-diagnostics-check-dot {
|
|
1865
|
+
width: 8px;
|
|
1866
|
+
height: 8px;
|
|
1867
|
+
border-radius: 50%;
|
|
1868
|
+
background: var(--tl-fg-4);
|
|
1857
1869
|
}
|
|
1858
1870
|
|
|
1859
|
-
#codex-overleaf-panel .codex-diagnostics-check-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
font-weight: 700;
|
|
1863
|
-
}
|
|
1871
|
+
#codex-overleaf-panel .codex-diagnostics-check[data-status="ok"] .codex-diagnostics-check-dot { background: var(--tl-ok); }
|
|
1872
|
+
#codex-overleaf-panel .codex-diagnostics-check[data-status="warn"] .codex-diagnostics-check-dot { background: var(--tl-review); }
|
|
1873
|
+
#codex-overleaf-panel .codex-diagnostics-check[data-status="fail"] .codex-diagnostics-check-dot { background: var(--tl-fail); }
|
|
1864
1874
|
|
|
1865
|
-
#codex-overleaf-panel .codex-diagnostics-check
|
|
1866
|
-
|
|
1867
|
-
|
|
1875
|
+
#codex-overleaf-panel .codex-diagnostics-check-text {
|
|
1876
|
+
display: grid;
|
|
1877
|
+
gap: 6px;
|
|
1878
|
+
margin: 0 0 10px 16px;
|
|
1879
|
+
}
|
|
1868
1880
|
|
|
1869
1881
|
#codex-overleaf-panel .codex-diagnostics-check-title {
|
|
1870
1882
|
color: var(--tl-fg-1);
|
|
1871
1883
|
font-size: var(--tl-text-sm, 12px);
|
|
1872
|
-
font-weight:
|
|
1884
|
+
font-weight: 500;
|
|
1873
1885
|
}
|
|
1874
1886
|
|
|
1875
1887
|
#codex-overleaf-panel .codex-diagnostics-check-summary {
|
|
1876
|
-
color: var(--tl-fg-
|
|
1877
|
-
font-size: var(--tl-text-
|
|
1878
|
-
line-height: 1.
|
|
1888
|
+
color: var(--tl-fg-2);
|
|
1889
|
+
font-size: var(--tl-text-sm, 12px);
|
|
1890
|
+
line-height: 1.5;
|
|
1879
1891
|
}
|
|
1880
1892
|
|
|
1881
1893
|
#codex-overleaf-panel .codex-diagnostics-check-next {
|
|
1882
|
-
color: var(--tl-
|
|
1883
|
-
font-size: var(--tl-text-
|
|
1884
|
-
line-height: 1.
|
|
1885
|
-
margin-top: 2px;
|
|
1894
|
+
color: var(--tl-fg-2);
|
|
1895
|
+
font-size: var(--tl-text-sm, 12px);
|
|
1896
|
+
line-height: 1.5;
|
|
1886
1897
|
}
|
|
1887
1898
|
|
|
1888
1899
|
#codex-overleaf-panel .codex-toast-region {
|
|
@@ -1975,7 +1986,7 @@
|
|
|
1975
1986
|
border: 1px solid var(--tl-border-strong);
|
|
1976
1987
|
border-radius: 6px;
|
|
1977
1988
|
background: var(--tl-surface-2);
|
|
1978
|
-
box-shadow:
|
|
1989
|
+
box-shadow: var(--tl-shadow-pop);
|
|
1979
1990
|
padding: 6px;
|
|
1980
1991
|
}
|
|
1981
1992
|
|
|
@@ -2042,7 +2053,7 @@
|
|
|
2042
2053
|
border: 1px solid var(--tl-border-strong);
|
|
2043
2054
|
border-radius: 8px;
|
|
2044
2055
|
background: var(--tl-surface-1);
|
|
2045
|
-
box-shadow:
|
|
2056
|
+
box-shadow: var(--tl-shadow-pop);
|
|
2046
2057
|
}
|
|
2047
2058
|
|
|
2048
2059
|
#codex-overleaf-panel .codex-diagnostics-menu::backdrop,
|
|
@@ -2059,14 +2070,6 @@
|
|
|
2059
2070
|
border-color: var(--tl-border-strong);
|
|
2060
2071
|
}
|
|
2061
2072
|
|
|
2062
|
-
#codex-overleaf-panel .codex-diagnostics-result[data-status="warning"] {
|
|
2063
|
-
border-color: var(--tl-review);
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
|
-
#codex-overleaf-panel .codex-diagnostics-result[data-status="failed"] {
|
|
2067
|
-
border-color: var(--tl-fail);
|
|
2068
|
-
}
|
|
2069
|
-
|
|
2070
2073
|
/* Only embedded settings replace the session view. The modal workbench keeps
|
|
2071
2074
|
the complete sidebar behind its backdrop, without reflowing the conversation. */
|
|
2072
2075
|
#codex-overleaf-panel:not([data-settings-workbench="true"])[data-view="settings"] .codex-vscode-head,
|
|
@@ -2663,13 +2666,44 @@
|
|
|
2663
2666
|
}
|
|
2664
2667
|
|
|
2665
2668
|
#codex-overleaf-panel .codex-diagnostics-result-title {
|
|
2669
|
+
display: flex;
|
|
2670
|
+
align-items: flex-start;
|
|
2671
|
+
gap: 8px;
|
|
2666
2672
|
color: var(--tl-fg-1);
|
|
2667
2673
|
font-size: var(--tl-text-base, 14px);
|
|
2668
2674
|
font-weight: 650;
|
|
2669
2675
|
line-height: 1.35;
|
|
2670
2676
|
}
|
|
2671
2677
|
|
|
2678
|
+
#codex-overleaf-panel .codex-diagnostics-status-dot {
|
|
2679
|
+
flex: 0 0 8px;
|
|
2680
|
+
width: 8px;
|
|
2681
|
+
height: 8px;
|
|
2682
|
+
margin-top: calc((1.35em - 8px) / 2);
|
|
2683
|
+
border-radius: 50%;
|
|
2684
|
+
background: var(--tl-fg-4);
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="completed"] .codex-diagnostics-status-dot { background: var(--tl-ok); }
|
|
2688
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="warning"] .codex-diagnostics-status-dot { background: var(--tl-review); }
|
|
2689
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="failed"] .codex-diagnostics-status-dot { background: var(--tl-fail); }
|
|
2690
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="running"] .codex-diagnostics-status-dot { animation: codex-diagnostics-pulse 1.2s ease-in-out infinite; }
|
|
2691
|
+
|
|
2692
|
+
@keyframes codex-diagnostics-pulse {
|
|
2693
|
+
50% {
|
|
2694
|
+
opacity: 0.3;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2699
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="running"] .codex-diagnostics-status-dot {
|
|
2700
|
+
animation: none;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2672
2704
|
#codex-overleaf-panel .codex-diagnostics-result-subtitle {
|
|
2705
|
+
text-wrap: pretty;
|
|
2706
|
+
margin-left: 16px;
|
|
2673
2707
|
margin-top: 2px;
|
|
2674
2708
|
color: var(--tl-fg-3);
|
|
2675
2709
|
font-size: var(--tl-text-xs, 11px);
|
|
@@ -2707,69 +2741,127 @@
|
|
|
2707
2741
|
}
|
|
2708
2742
|
|
|
2709
2743
|
#codex-overleaf-panel .codex-diagnostics-result-body {
|
|
2710
|
-
|
|
2744
|
+
display: grid;
|
|
2745
|
+
gap: 12px;
|
|
2746
|
+
padding: 12px;
|
|
2711
2747
|
color: var(--tl-fg-2);
|
|
2712
2748
|
font-size: var(--tl-text-sm, 12px);
|
|
2713
|
-
line-height: 1.
|
|
2749
|
+
line-height: 1.5;
|
|
2750
|
+
text-wrap: pretty;
|
|
2714
2751
|
}
|
|
2715
2752
|
|
|
2716
|
-
#codex-overleaf-panel .codex-diagnostics-result-body
|
|
2717
|
-
margin: 0
|
|
2753
|
+
#codex-overleaf-panel .codex-diagnostics-result-body > * {
|
|
2754
|
+
margin: 0;
|
|
2718
2755
|
}
|
|
2719
2756
|
|
|
2720
|
-
#codex-overleaf-panel .codex-diagnostics-result-
|
|
2721
|
-
|
|
2722
|
-
|
|
2757
|
+
#codex-overleaf-panel .codex-diagnostics-result[data-status="running"] .codex-diagnostics-summary { color: var(--tl-fg-3); }
|
|
2758
|
+
|
|
2759
|
+
#codex-overleaf-panel .codex-diagnostics-facts {
|
|
2760
|
+
display: grid;
|
|
2761
|
+
grid-template-columns: fit-content(40%) minmax(0, 1fr);
|
|
2762
|
+
column-gap: 16px;
|
|
2763
|
+
row-gap: 6px;
|
|
2723
2764
|
}
|
|
2724
2765
|
|
|
2725
|
-
#codex-overleaf-panel .codex-diagnostics-
|
|
2726
|
-
|
|
2766
|
+
#codex-overleaf-panel .codex-diagnostics-facts dt {
|
|
2767
|
+
color: var(--tl-fg-3);
|
|
2768
|
+
overflow-wrap: normal;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
#codex-overleaf-panel .codex-diagnostics-facts dd {
|
|
2772
|
+
margin: 0;
|
|
2773
|
+
min-width: 0;
|
|
2774
|
+
color: var(--tl-fg-1);
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
#codex-overleaf-panel .codex-diagnostics-facts dd[data-tone="warn"] { color: var(--tl-review); }
|
|
2778
|
+
#codex-overleaf-panel .codex-diagnostics-facts dd[data-tone="fail"] { color: var(--tl-fail); }
|
|
2779
|
+
|
|
2780
|
+
#codex-overleaf-panel .codex-diagnostics-notes {
|
|
2781
|
+
display: grid;
|
|
2782
|
+
gap: 4px;
|
|
2783
|
+
padding: 0;
|
|
2784
|
+
list-style: none;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
#codex-overleaf-panel .codex-diagnostics-notes li {
|
|
2788
|
+
position: relative;
|
|
2789
|
+
padding-left: 12px;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
#codex-overleaf-panel .codex-diagnostics-notes li::before {
|
|
2793
|
+
content: "";
|
|
2794
|
+
position: absolute;
|
|
2795
|
+
left: 2px;
|
|
2796
|
+
top: calc(0.75em - 2px);
|
|
2797
|
+
width: 4px;
|
|
2798
|
+
height: 4px;
|
|
2799
|
+
border-radius: 50%;
|
|
2800
|
+
background: var(--tl-fg-4);
|
|
2727
2801
|
}
|
|
2728
2802
|
|
|
2729
2803
|
#codex-overleaf-panel .codex-diagnostics-next-step {
|
|
2730
|
-
color: var(--tl-
|
|
2804
|
+
color: var(--tl-fg-2);
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
#codex-overleaf-panel .codex-diagnostics-next-label {
|
|
2808
|
+
color: var(--tl-fg-1);
|
|
2809
|
+
font-weight: 600;
|
|
2731
2810
|
}
|
|
2732
2811
|
|
|
2733
2812
|
#codex-overleaf-panel .codex-install-command {
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
border: 1px solid var(--tl-border-strong);
|
|
2737
|
-
border-radius: 7px;
|
|
2738
|
-
background: var(--tl-surface-0);
|
|
2813
|
+
display: grid;
|
|
2814
|
+
gap: 6px;
|
|
2739
2815
|
}
|
|
2740
2816
|
|
|
2741
|
-
#codex-overleaf-panel .codex-
|
|
2742
|
-
|
|
2817
|
+
#codex-overleaf-panel .codex-install-command-head {
|
|
2818
|
+
display: flex;
|
|
2819
|
+
align-items: center;
|
|
2820
|
+
justify-content: space-between;
|
|
2821
|
+
gap: 8px;
|
|
2743
2822
|
}
|
|
2744
2823
|
|
|
2745
2824
|
#codex-overleaf-panel .codex-install-command-label {
|
|
2746
|
-
margin-bottom: 6px;
|
|
2747
2825
|
color: var(--tl-fg-3);
|
|
2748
2826
|
font-size: var(--tl-text-xs, 11px);
|
|
2749
2827
|
}
|
|
2750
2828
|
|
|
2829
|
+
#codex-overleaf-panel .codex-install-command button {
|
|
2830
|
+
flex: 0 0 auto;
|
|
2831
|
+
width: auto;
|
|
2832
|
+
height: 22px;
|
|
2833
|
+
margin: 0;
|
|
2834
|
+
padding: 0 8px;
|
|
2835
|
+
border: 1px solid var(--tl-border-strong);
|
|
2836
|
+
border-radius: 5px;
|
|
2837
|
+
background: transparent;
|
|
2838
|
+
color: var(--tl-fg-1);
|
|
2839
|
+
font-size: var(--tl-text-xs, 11px);
|
|
2840
|
+
line-height: 20px;
|
|
2841
|
+
cursor: pointer;
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
#codex-overleaf-panel .codex-install-command button:hover {
|
|
2845
|
+
background: var(--tl-hover);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
#codex-overleaf-panel .codex-install-command button:focus-visible {
|
|
2849
|
+
outline: 2px solid var(--tl-accent);
|
|
2850
|
+
outline-offset: 2px;
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2751
2853
|
#codex-overleaf-panel .codex-install-command code {
|
|
2752
2854
|
display: block;
|
|
2753
2855
|
overflow: auto;
|
|
2754
2856
|
max-height: 90px;
|
|
2755
|
-
padding:
|
|
2857
|
+
padding: 8px 10px;
|
|
2756
2858
|
border-radius: 6px;
|
|
2757
2859
|
background: var(--tl-surface-2);
|
|
2758
|
-
color: var(--tl-
|
|
2860
|
+
color: var(--tl-fg-1);
|
|
2759
2861
|
white-space: pre-wrap;
|
|
2760
|
-
word-break:
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
#codex-overleaf-panel .codex-install-command button {
|
|
2765
|
-
width: 100%;
|
|
2766
|
-
margin-top: 8px;
|
|
2767
|
-
border: 1px solid var(--tl-ok);
|
|
2768
|
-
border-radius: 6px;
|
|
2769
|
-
background: var(--tl-ok-wash);
|
|
2770
|
-
color: var(--tl-ok);
|
|
2771
|
-
padding: 6px 8px;
|
|
2772
|
-
font-size: var(--tl-text-sm, 12px);
|
|
2862
|
+
word-break: normal;
|
|
2863
|
+
overflow-wrap: anywhere;
|
|
2864
|
+
font: var(--tl-text-xs, 11px)/1.5 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
2773
2865
|
}
|
|
2774
2866
|
|
|
2775
2867
|
#codex-overleaf-panel .codex-diagnostics-technical {
|
|
@@ -2782,11 +2874,41 @@
|
|
|
2782
2874
|
}
|
|
2783
2875
|
|
|
2784
2876
|
#codex-overleaf-panel .codex-diagnostics-technical summary {
|
|
2877
|
+
display: inline-flex;
|
|
2878
|
+
align-items: center;
|
|
2879
|
+
gap: 6px;
|
|
2785
2880
|
cursor: pointer;
|
|
2881
|
+
list-style: none;
|
|
2786
2882
|
color: var(--tl-fg-3);
|
|
2787
2883
|
font-size: var(--tl-text-xs, 11px);
|
|
2788
2884
|
}
|
|
2789
2885
|
|
|
2886
|
+
#codex-overleaf-panel .codex-diagnostics-technical summary::-webkit-details-marker {
|
|
2887
|
+
display: none;
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
#codex-overleaf-panel .codex-diagnostics-technical summary::after {
|
|
2891
|
+
content: "";
|
|
2892
|
+
width: 5px;
|
|
2893
|
+
height: 5px;
|
|
2894
|
+
border-right: 1px solid currentColor;
|
|
2895
|
+
border-bottom: 1px solid currentColor;
|
|
2896
|
+
transform: rotate(-45deg);
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
#codex-overleaf-panel .codex-diagnostics-technical[open] summary::after {
|
|
2900
|
+
transform: rotate(45deg);
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
#codex-overleaf-panel .codex-diagnostics-technical summary:hover {
|
|
2904
|
+
color: var(--tl-fg-1);
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
#codex-overleaf-panel .codex-diagnostics-check .codex-diagnostics-technical {
|
|
2908
|
+
border-top: 0;
|
|
2909
|
+
padding: 0;
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2790
2912
|
#codex-overleaf-panel .codex-diagnostics-technical pre {
|
|
2791
2913
|
overflow: auto;
|
|
2792
2914
|
max-height: 220px;
|
|
@@ -3112,6 +3234,7 @@
|
|
|
3112
3234
|
dark/light/auto). The whole panel reads these tokens so a theme is just a
|
|
3113
3235
|
value swap — no selector depends on the literals. */
|
|
3114
3236
|
#codex-overleaf-panel {
|
|
3237
|
+
--tl-shadow-pop: 0 14px 34px rgba(0, 0, 0, 0.48);
|
|
3115
3238
|
--tl-fg-1: #e4e4e4; /* primary prose / answer / strong labels */
|
|
3116
3239
|
--tl-fg-2: #b7b7b7; /* body text / activity titles / controls */
|
|
3117
3240
|
--tl-fg-3: #8a8a8a; /* meta / summaries / captions */
|
|
@@ -3157,6 +3280,7 @@
|
|
|
3157
3280
|
light via prefers-color-scheme). Dark needs no override (it is the baseline
|
|
3158
3281
|
above). State colors are darkened for AA contrast on light surfaces. */
|
|
3159
3282
|
#codex-overleaf-panel[data-theme="light"] {
|
|
3283
|
+
--tl-shadow-pop: 0 12px 32px rgba(31, 35, 40, 0.14), 0 2px 6px rgba(31, 35, 40, 0.08);
|
|
3160
3284
|
--tl-fg-1: #1f2328;
|
|
3161
3285
|
--tl-fg-2: #3d4651;
|
|
3162
3286
|
--tl-fg-3: #6a7280;
|
|
@@ -5123,6 +5247,10 @@
|
|
|
5123
5247
|
gap: 8px;
|
|
5124
5248
|
padding: 10px 24px 10px 10px;
|
|
5125
5249
|
}
|
|
5250
|
+
#codex-overleaf-panel .codex-attachment-preview-card[data-loading="true"] {
|
|
5251
|
+
border-style: dashed;
|
|
5252
|
+
background: var(--tl-surface-1);
|
|
5253
|
+
}
|
|
5126
5254
|
#codex-overleaf-panel .codex-attachment-file-icon {
|
|
5127
5255
|
display: grid;
|
|
5128
5256
|
place-items: center;
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
} = require('./nativeHostPlatform');
|
|
9
9
|
|
|
10
10
|
const MAX_FIELD_LENGTH = 8000;
|
|
11
|
+
const MAX_DEBUG_LOG_BYTES = 8 * 1024 * 1024;
|
|
11
12
|
|
|
12
13
|
function getDebugLogDir(options = {}) {
|
|
13
14
|
return getCodexOverleafHome(options);
|
|
@@ -22,12 +23,35 @@ function logDebug(event, detail = {}, options = {}) {
|
|
|
22
23
|
try {
|
|
23
24
|
const logDir = getDebugLogDir(options);
|
|
24
25
|
const logPath = getDebugLogPath(options);
|
|
25
|
-
|
|
26
|
-
fs.appendFileSync(logPath, `${JSON.stringify({
|
|
26
|
+
const record = `${JSON.stringify({
|
|
27
27
|
time: new Date().toISOString(),
|
|
28
28
|
event,
|
|
29
29
|
detail: sanitize(detail)
|
|
30
|
-
})}\n
|
|
30
|
+
})}\n`;
|
|
31
|
+
const recordBytes = Buffer.byteLength(record, 'utf8');
|
|
32
|
+
if (recordBytes > MAX_DEBUG_LOG_BYTES) return;
|
|
33
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
34
|
+
try {
|
|
35
|
+
const size = fs.statSync(logPath).size;
|
|
36
|
+
if (size > MAX_DEBUG_LOG_BYTES) {
|
|
37
|
+
// Discard oversized legacy logs instead of retaining a huge .1 copy.
|
|
38
|
+
fs.truncateSync(logPath, 0);
|
|
39
|
+
} else if (size + recordBytes > MAX_DEBUG_LOG_BYTES) {
|
|
40
|
+
fs.renameSync(logPath, `${logPath}.1`);
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error.code !== 'ENOENT') throw error;
|
|
44
|
+
}
|
|
45
|
+
fs.appendFileSync(logPath, record, 'utf8');
|
|
46
|
+
// Concurrent Hosts can cross the cap between stat and append/rename.
|
|
47
|
+
// Logging is best-effort: drop an oversized raced file rather than grow it.
|
|
48
|
+
for (const file of [logPath, `${logPath}.1`]) {
|
|
49
|
+
try {
|
|
50
|
+
if (fs.statSync(file).size > MAX_DEBUG_LOG_BYTES) fs.truncateSync(file, 0);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error.code !== 'ENOENT') throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
31
55
|
} catch {
|
|
32
56
|
// Debug logging must never break the native messaging host.
|
|
33
57
|
}
|
package/native-host/src/index.js
CHANGED
|
@@ -11,6 +11,8 @@ const { buildNativeRuntimeEnv, summarizeNativeEnvironment } = require('./nativeE
|
|
|
11
11
|
let buffered = Buffer.alloc(0);
|
|
12
12
|
let stdoutUnavailable = false;
|
|
13
13
|
let nativeDisconnectHandled = false;
|
|
14
|
+
let fatalShutdownStarted = false;
|
|
15
|
+
const FATAL_SHUTDOWN_TIMEOUT_MS = 3000;
|
|
14
16
|
const runtimeEnv = buildNativeRuntimeEnv(process.env);
|
|
15
17
|
Object.assign(process.env, runtimeEnv);
|
|
16
18
|
logDebug('environment.ready', summarizeNativeEnvironment(runtimeEnv));
|
|
@@ -93,21 +95,46 @@ process.on('uncaughtException', error => {
|
|
|
93
95
|
handleNativeDisconnect('uncaught_native_disconnect', error);
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
96
|
-
|
|
97
|
-
message: error.message,
|
|
98
|
-
stack: error.stack
|
|
99
|
-
});
|
|
100
|
-
process.exit(1);
|
|
98
|
+
handleFatalError('process.uncaught_exception', error);
|
|
101
99
|
});
|
|
102
100
|
|
|
103
101
|
process.on('unhandledRejection', reason => {
|
|
104
|
-
|
|
105
|
-
message: reason?.message || String(reason),
|
|
106
|
-
stack: reason?.stack
|
|
107
|
-
});
|
|
108
|
-
process.exit(1);
|
|
102
|
+
handleFatalError('process.unhandled_rejection', reason);
|
|
109
103
|
});
|
|
110
104
|
|
|
105
|
+
function handleFatalError(event, error) {
|
|
106
|
+
if (fatalShutdownStarted) {
|
|
107
|
+
process.exit(1);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
fatalShutdownStarted = true;
|
|
111
|
+
nativeDisconnectHandled = true;
|
|
112
|
+
stdoutUnavailable = true;
|
|
113
|
+
process.exitCode = 1;
|
|
114
|
+
logDebug(event, { message: error?.message || String(error), stack: error?.stack });
|
|
115
|
+
const exitTimer = setTimeout(() => {
|
|
116
|
+
const failures = quarantineActiveOperations();
|
|
117
|
+
logDebug('process.fatal_shutdown_deadline', { persistenceFailures: failures });
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}, FATAL_SHUTDOWN_TIMEOUT_MS);
|
|
120
|
+
try {
|
|
121
|
+
// Persist protection before aborting; stop confirmation owns its removal.
|
|
122
|
+
quarantineActiveOperations();
|
|
123
|
+
Promise.resolve(abortAllActiveOperations('Native Host stopped after a fatal error.')).then(() => {
|
|
124
|
+
clearTimeout(exitTimer);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}, failure => {
|
|
127
|
+
logDebug('process.fatal_shutdown_failed', { message: failure?.message });
|
|
128
|
+
clearTimeout(exitTimer);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
} catch (failure) {
|
|
132
|
+
logDebug('process.fatal_shutdown_failed', { message: failure?.message });
|
|
133
|
+
clearTimeout(exitTimer);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
111
138
|
function writeResponse(response) {
|
|
112
139
|
if (stdoutUnavailable || process.stdout.destroyed || process.stdout.writableEnded) {
|
|
113
140
|
logDebug('stdout.write_skipped', { ok: response?.ok, code: response?.error?.code });
|
|
@@ -152,6 +179,7 @@ function handleNativeDisconnect(source, error) {
|
|
|
152
179
|
// old owned process is still inside its interrupt/termination budget.
|
|
153
180
|
quarantineActiveOperations();
|
|
154
181
|
const exitTimer = setTimeout(() => {
|
|
182
|
+
if (fatalShutdownStarted) return;
|
|
155
183
|
const failures = quarantineActiveOperations();
|
|
156
184
|
logDebug('native_transport.shutdown_deadline', { persistenceFailures: failures });
|
|
157
185
|
process.exit(failures.length ? 1 : 0);
|
|
@@ -160,7 +188,10 @@ function handleNativeDisconnect(source, error) {
|
|
|
160
188
|
Promise.all([
|
|
161
189
|
abortAllActiveOperations('Native messaging transport disconnected.'),
|
|
162
190
|
new Promise(resolve => setTimeout(resolve, 1500))
|
|
163
|
-
]).then(() => {
|
|
191
|
+
]).then(() => {
|
|
192
|
+
clearTimeout(exitTimer);
|
|
193
|
+
if (!fatalShutdownStarted) process.exit(0);
|
|
194
|
+
});
|
|
164
195
|
}
|
|
165
196
|
|
|
166
197
|
function summarizeRequest(message) {
|
|
@@ -13,7 +13,7 @@ const MAX_SKILL_CONTENT_CHARS = MAX_SKILL_CONTENT_BYTES;
|
|
|
13
13
|
const MAX_SKILL_PREVIEW_CHARS = 240;
|
|
14
14
|
const PROJECT_SKILL_SCOPE = 'project';
|
|
15
15
|
const CODEX_OVERLEAF_SKILL_SCOPE = 'codex-overleaf';
|
|
16
|
-
const OFFICIAL_CODEX_OVERLEAF_SKILL_IDS = ['annotated-rewrite', 'parallel-subagents'];
|
|
16
|
+
const OFFICIAL_CODEX_OVERLEAF_SKILL_IDS = ['annotated-rewrite', 'parallel-subagents', 'reviewer-response'];
|
|
17
17
|
|
|
18
18
|
function listProjectSkills({ projectId, rootDir } = {}) {
|
|
19
19
|
const skillsDir = getProjectSkillsDir(projectId, { rootDir });
|
|
@@ -5,6 +5,7 @@ const fs = require('node:fs');
|
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
const { getHomeDir } = require('./nativeHostPlatform');
|
|
7
7
|
const { assertProjectPathsForPlatform } = require('./projectPathPlatform');
|
|
8
|
+
const { assessDocumentProvenance } = require('../../extension/src/shared/staleGuard');
|
|
8
9
|
|
|
9
10
|
const BASELINE_FILE = 'baseline.json';
|
|
10
11
|
const MAX_BINARY_FILE_BYTES = 10 * 1024 * 1024;
|
|
@@ -34,11 +35,20 @@ function getDefaultMirrorRoot(options = {}) {
|
|
|
34
35
|
return path.join(getHomeDir(options), '.codex-overleaf', 'projects');
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
async function syncOverleafToMirror({ projectId, project, rootDir }) {
|
|
38
|
+
async function syncOverleafToMirror({ projectId, project, rootDir, evidenceProjectId }) {
|
|
38
39
|
const mirror = getProjectMirror(projectId, { rootDir });
|
|
39
40
|
const normalized = normalizeProjectFilesDetailed(project?.files || []);
|
|
40
41
|
const files = normalized.files;
|
|
41
42
|
const previous = readBaseline(mirror.baselinePath);
|
|
43
|
+
// Page already admits evidence-free snapshot text against its own saved
|
|
44
|
+
// references, which may no longer be present after editor/writeback merging.
|
|
45
|
+
for (const file of project?.files || []) {
|
|
46
|
+
if (file.kind === 'binary' || typeof file.content !== 'string') continue;
|
|
47
|
+
if (file.documentIdentity !== undefined) {
|
|
48
|
+
assertDocumentProvenance(file.path, file.content, undefined, file.documentIdentity,
|
|
49
|
+
project?.id !== undefined && project.id !== evidenceProjectId ? undefined : evidenceProjectId);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
42
52
|
const fullProjectSnapshot = project?.capabilities?.fullProjectSnapshot !== false;
|
|
43
53
|
const skippedFiles = resolveUnreadSnapshotFiles(project, normalized, previous, fullProjectSnapshot);
|
|
44
54
|
// Runtime platform is authoritative; request fields cannot opt out of this check.
|
|
@@ -808,11 +818,20 @@ function buildOtStatusFields(baseline = {}, trusted) {
|
|
|
808
818
|
};
|
|
809
819
|
}
|
|
810
820
|
|
|
811
|
-
async function applyFileOverlays({ projectId, overlays, rootDir }) {
|
|
821
|
+
async function applyFileOverlays({ projectId, overlays, rootDir, evidenceProjectId }) {
|
|
812
822
|
const mirror = getProjectMirror(projectId, { rootDir });
|
|
813
823
|
const baseline = readBaseline(mirror.baselinePath);
|
|
814
824
|
const filesByPath = new Map((baseline.files || []).map(f => [f.path, f]));
|
|
815
825
|
const unreadPaths = new Set((baseline.unreadFiles || []).map(file => file.path));
|
|
826
|
+
const references = baselineTextReferences(baseline);
|
|
827
|
+
// Validate the entire request against the unchanged baseline before any file
|
|
828
|
+
// or baseline write. An earlier overlay cannot hide a later misattribution.
|
|
829
|
+
for (const overlay of overlays || []) {
|
|
830
|
+
if (!overlay?.path || typeof overlay.content !== 'string') continue;
|
|
831
|
+
const normalizedPath = normalizeRelativePath(overlay.path);
|
|
832
|
+
if (!unreadPaths.has(normalizedPath))
|
|
833
|
+
assertDocumentProvenance(normalizedPath, overlay.content, references, overlay.documentIdentity, evidenceProjectId);
|
|
834
|
+
}
|
|
816
835
|
|
|
817
836
|
for (const overlay of overlays || []) {
|
|
818
837
|
if (!overlay?.path || typeof overlay.content !== 'string') {
|
|
@@ -828,7 +847,7 @@ async function applyFileOverlays({ projectId, overlays, rootDir }) {
|
|
|
828
847
|
filesByPath.set(normalizedPath, {
|
|
829
848
|
path: normalizedPath,
|
|
830
849
|
kind: 'text',
|
|
831
|
-
hash:
|
|
850
|
+
hash: hashText(overlay.content),
|
|
832
851
|
content: overlay.content
|
|
833
852
|
});
|
|
834
853
|
}
|
|
@@ -840,6 +859,24 @@ async function applyFileOverlays({ projectId, overlays, rootDir }) {
|
|
|
840
859
|
});
|
|
841
860
|
}
|
|
842
861
|
|
|
862
|
+
function baselineTextReferences(baseline) {
|
|
863
|
+
return new Map((baseline.files || []).filter(file => file.kind === 'text' && typeof file.content === 'string')
|
|
864
|
+
.map(file => [file.path, file.content]));
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
function assertDocumentProvenance(path, text, references, documentIdentity, projectId) {
|
|
868
|
+
const result = documentIdentity !== undefined
|
|
869
|
+
&& (!documentIdentity || documentIdentity.contentSha256 !== hashText(text))
|
|
870
|
+
? { ok: false, code: 'document_identity_mismatch' }
|
|
871
|
+
: assessDocumentProvenance({ path, text, references, documentIdentity, projectId });
|
|
872
|
+
if (result.ok) return;
|
|
873
|
+
const error = new Error('Codex could not confirm that the editor content belongs to the target file, so it was not used.');
|
|
874
|
+
error.code = result.code;
|
|
875
|
+
error.path = path;
|
|
876
|
+
error.matchedPath = result.matchedPath;
|
|
877
|
+
throw error;
|
|
878
|
+
}
|
|
879
|
+
|
|
843
880
|
// v1.8.0: after a VERIFIED writeback, the workspace already holds the exact
|
|
844
881
|
// content that landed in Overleaf only while its hashes match the page's
|
|
845
882
|
// verified post-images. Check every target before updating any baseline.
|
|
@@ -932,6 +969,13 @@ async function patchMirrorFiles({ projectId, files, rootDir, source = 'ot' }) {
|
|
|
932
969
|
let lastOtPatchAt = baseline.lastOtPatchAt || '';
|
|
933
970
|
let lastOtErrorCode = '';
|
|
934
971
|
let patchBatchAt = '';
|
|
972
|
+
const references = baselineTextReferences(baseline);
|
|
973
|
+
for (const patch of Array.isArray(files) ? files : []) {
|
|
974
|
+
const normalized = normalizePatchPath(patch, mirror.workspacePath);
|
|
975
|
+
if (normalized.ok && baselineByPath.get(normalized.path)?.kind === 'text' && typeof patch?.nextContent === 'string') {
|
|
976
|
+
assertDocumentProvenance(normalized.path, patch.nextContent, references);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
935
979
|
|
|
936
980
|
for (const patch of Array.isArray(files) ? files : []) {
|
|
937
981
|
const normalized = normalizePatchPath(patch, mirror.workspacePath);
|