Skip to content

feat(plugins): add ChatGPT conversation export - #921

Open
TanChuping wants to merge 15 commits into
Nagi-ovo:mainfrom
TanChuping:feat/chatgpt-export-plugin
Open

feat(plugins): add ChatGPT conversation export#921
TanChuping wants to merge 15 commits into
Nagi-ovo:mainfrom
TanChuping:feat/chatgpt-export-plugin

Conversation

@TanChuping

@TanChuping TanChuping commented Aug 9, 2026

Copy link
Copy Markdown

Description

  • Add an opt-in native plugin for exporting ChatGPT conversations as Markdown, JSON, or PDF.
  • Support whole-conversation export, progressive inline message selection without forced full-history loading, and temporary-chat handoff.
  • Keep ChatGPT access behind optional host permission and manage all injected UI through PluginScope lifecycle cleanup.
  • Add a compact ChatGPT-style print layout with rich-content and captured-text fallbacks.

Related Issue

Refs #841

PR #920 opened while this branch was being prepared. It was not open at the preceding check, so the two implementations arrived independently within minutes of each other.

Visual Proof

Format selection dialog:

ChatGPT export format selection

PDF output:

ChatGPT-style PDF output

Browser Testing

Tested commit: 72ad036

Browser / version Scenario and result Evidence
Chrome 151.0.7922.76 Enabled/disabled the plugin; exercised whole and selected Markdown/JSON export, PDF print preview, temporary-chat handoff, and lifecycle cleanup. Passed. See Visual Proof

Missing checks and owner, or N/A reason:

  • Edge, Firefox, and Safari live browser workflows were not exercised. Their production builds passed; follow-up owner: @TanChuping.

Commands not run and reason:

  • None.

Verification notes:

  • bun run format: passed.
  • bun run lint: passed with 0 errors; existing repository warnings remain.
  • bun run verify:pr at 97618a7: ran through the standard checks. 2672/2673 tests passed; the only failure is an unrelated Windows path-separator assertion for allowed embedded provisioning profiles.
  • Latest review-fix targeted Vitest runs: 77/77, 49/49, 70/70, and 65/65 passed.
  • Chrome, Firefox, Safari, and Edge production builds passed. Edge packaging required a local Windows zip compatibility shim; no shim or build output is included in this PR.
  • bun run docs:build: passed.
  • KaTeX PDF export verification: passed.

Checklist

  • If I used an agent, I discussed the requirement, affected scope, and verification plan clearly.
  • I have manually verified that the feature works as intended.
  • For UI/behavior changes, I have tried the real workflow for about 15 minutes when possible.
  • For UI/behavior changes, I have included visual proof after verification.
  • I have confirmed that this PR does not break existing functionality.
  • This PR focuses on one issue or one coherent change.
  • I ran bun run format, bun run lint, then the standard local bun run verify:pr, and documented the local verification exceptions above.
  • I added/updated regression tests for behavior changes.
  • I listed the affected browsers actually tested and identified the follow-up owner.

Add opt-in Markdown, JSON, PDF, selection, and temporary-chat export flows.

Co-authored-by: Codex <codex@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds a ChatGPT export plugin for Markdown, JSON, and PDF. It collects virtualized conversations, supports message selection and temporary-chat handoff, adds localized UI, and introduces ChatGPT-specific PDF rendering.

Changes

ChatGPT export

Layer / File(s) Summary
Conversation collection and metadata
src/features/plugins/builtin/chatgptExport/conversation.ts, src/features/plugins/builtin/chatgptExport/conversation.test.ts
Collects messages across virtualized scroll windows, builds ordered turns, extracts content, and creates metadata.
Export payloads and content extraction
src/features/plugins/builtin/chatgptExport/exporter.ts, src/features/export/services/DOMContentExtractor.ts, src/features/formulaCopy/FormulaCopyService.ts, src/features/plugins/builtin/chatgptExport/exporter.test.ts, src/features/export/services/__tests__/DOMContentExtractor.test.ts
Generates Markdown and JSON payloads, delegates PDF export, and preserves links, attachments, formulas, and code blocks.
ChatGPT PDF rendering
src/features/export/services/PDFPrintService.ts, src/features/export/services/__tests__/PDFPrintService.test.ts
Adds ChatGPT appearance options, title handling, fallback content, metadata propagation, and ChatGPT-specific print CSS.
Plugin activation and export UI
src/features/plugins/builtin/chatgptExport/index.ts, src/features/plugins/builtin/chatgptExport/ui.ts, src/features/plugins/builtin/chatgptExport/styles.ts, src/features/plugins/builtin/chatgptExport/i18n.ts, src/features/plugins/builtin/index.ts, src/pages/content/pluginNativeRegistration.ts, src/features/plugins/builtin/chatgptExport/*test.ts
Adds export-button injection, menus, dialogs, progress, toasts, lifecycle cleanup, localization, responsive styling, manifest data, and native registration.
Message selection
src/features/plugins/builtin/chatgptExport/selectionMode.ts, src/features/plugins/builtin/chatgptExport/selectionMode.test.ts
Adds inline message selection controls that preserve selections across virtualization, scrolling, and DOM mutations.
Temporary-chat handoff
src/features/plugins/builtin/chatgptExport/tempHandoff.ts, src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
Adds inline or attachment-based transcript handoff, session persistence, temporary-chat exit, composer insertion, and post-navigation resumption.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

  • Nagi-ovo/voyager#865: Extends the ChatGPT export functionality introduced in this PR.
  • Nagi-ovo/voyager#919: Extends the ChatGPT export implementation with enhanced PDF styling and extraction fallbacks.
  • Nagi-ovo/voyager#920: Extends the ChatGPT export implementation with dedicated conversation collection and export flows.

Suggested reviewers: nagi-ovo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: adding ChatGPT conversation export support.
Description check ✅ Passed The description covers the goal, issue, visual proof, browser testing, verification results, known limitations, and checklist requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (1)
src/features/export/services/__tests__/PDFPrintService.test.ts (1)

95-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the title assertion discriminating, and reduce CSS string coupling.

Two points:

  1. Line 96 and Line 105 use the same value, Export test. The ChatGPT branch at getPrintDialogTitle prefers metadata.title over the page title. With identical values the assertion at Line 116 passes for either precedence order. Use distinct values to lock the intended behavior.
  2. Lines 117-123 assert exact CSS declaration text, including spacing. A reformat of buildChatGptPrintStyles breaks these tests without any behavior change. Assert on the scoped selector plus a small number of load-bearing declarations, or assert on computed markup instead.
💚 Proposed change for point 1
-    document.title = 'Export test';
+    document.title = 'Stale page title';
     window.print = vi.fn();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/export/services/__tests__/PDFPrintService.test.ts` around lines
95 - 124, Update the ChatGPT layout test around PDFPrintService.export to use
distinct page and metadata titles, then assert the resulting document.title
reflects the metadata-title precedence. Replace exact CSS string/spacing
assertions with less brittle checks that verify the scoped selector and only
essential load-bearing declarations or computed markup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/export/services/PDFPrintService.ts`:
- Around line 534-543: Update isMeaningfulConversationTitle to reject the
literal title “ChatGPT” alongside the existing Gemini exclusions, so
getConversationTitle cannot use document.title as a meaningful fallback and
empty metadata titles resolve to the intended neutral fallback.
- Around line 1262-1283: Update the generated code-block styles in the PDF print
template around the `.gv-print-turn-text pre` rule to preserve readable contrast
when print background graphics are disabled. Keep the existing dark styling by
default, and add a `forced-colors` or no-background safeguard that switches the
code surface and text to a light, bordered presentation without relying on the
dark background.

In `@src/features/plugins/builtin/chatgptExport/conversation.ts`:
- Around line 256-275: Update the collection loop around the conversation
collector to merge mounted messages after the final scroll, including when
maxSteps is reached. If collection remains above the bottom once the step limit
is exhausted, return an explicit incomplete-collection error instead of
exporting collected messages; preserve normal completion behavior at the bottom.
Add a regression test using a small maxSteps value that verifies the error and
final-scroll merge.
- Around line 118-132: Update readStableId so fallback identities never use the
scan-local order, which is unstable across virtualized windows. Prefer a stable
ChatGPT identifier for every supported schema; when none exists, return a
non-deduplicating identity or otherwise ensure the message is retained rather
than merged in collected. Add coverage for window swaps containing repeated
role/text messages.

In `@src/features/plugins/builtin/chatgptExport/exporter.test.ts`:
- Around line 18-89: Add a JSON export test to the ChatGPT export formats suite
using exportChatGptConversation with format 'json'; stub the Blob/download path,
parse the generated payload, and assert the schema preserves selected state,
message IDs, roles, and content. Reuse collectMountedChatGptMessages and the
existing metadata setup, while keeping the current Markdown and PDF coverage
unchanged.

In `@src/features/plugins/builtin/chatgptExport/i18n.ts`:
- Line 93: Update the tempRegret and tempTitle translation strings in the chat
export i18n definitions to describe saving and transferring the temporary chat
to a normal chat, replacing the regret wording. Keep both labels aligned and
readable across themes.

In `@src/features/plugins/builtin/chatgptExport/index.ts`:
- Around line 67-70: The whole-conversation icon path in the paths mapping
should use coordinates that keep the downward arrow within the SVG viewport.
Update the whole entry’s arrow segment while preserving its existing vertical
stem and bottom bar; leave the selected and temporary paths unchanged.

In `@src/features/plugins/builtin/chatgptExport/styles.ts`:
- Around line 284-315: Complete the dark-theme selector coverage in the styles
for .gv-chatgpt-export-menu-item:hover,
.gv-chatgpt-export-menu-item:focus-visible, .gv-chatgpt-export-btn:hover,
.gv-chatgpt-export-format-option:has(input:checked), and
.gv-chatgpt-export-button--floating by adding the missing body.dark variants.
Preserve the existing light-theme rules and dark colors for html.dark,
body.dark, and [data-theme='dark'].

In `@src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts`:
- Around line 19-53: Extend the temporary chat handoff tests to cover
handoffTemporaryChat and resumePendingHandoff lifecycle behavior, pending-entry
expiry, and attachment-delivery failure. Verify failed attachment delivery
preserves the existing composer draft instead of clearing it through
input.replaceChildren(), while retaining the current route, transcript, and
attachment assertions. Run bun run test, bun run lint, and bun run typecheck.

In `@src/features/plugins/builtin/chatgptExport/tempHandoff.ts`:
- Around line 182-187: Update the attachment fallback in tempHandoff around
dispatchPaste so a false result never calls input.replaceChildren or overwrites
the existing composer draft. Instead, return a delivery failure and display the
appropriate error while preserving the user's current content; keep the
successful paste path unchanged.
- Around line 106-110: Update writePending and resumePendingHandoff to persist a
stable active ChatGPT account identity in PendingHandoff and compare it before
delivery; clear the pending handoff and skip delivery when identities differ.
Also adjust the attachment-paste fallback in deliver so it preserves existing
composer content or requires confirmation before replacing it, rather than
clearing the draft automatically.

In `@src/features/plugins/builtin/chatgptExport/ui.ts`:
- Around line 45-83: Update the dialog creation and lifecycle around the
existing overlay/dialog helpers to add an accessible name via the title element,
then reuse the established gv-pm-* modal precedent for Tab focus trapping,
Escape/outside dismissal, focus restoration to the trigger, teardown, and theme
behavior. Add keyboard coverage verifying Tab cycling within the modal and
restoring focus after close.

---

Nitpick comments:
In `@src/features/export/services/__tests__/PDFPrintService.test.ts`:
- Around line 95-124: Update the ChatGPT layout test around
PDFPrintService.export to use distinct page and metadata titles, then assert the
resulting document.title reflects the metadata-title precedence. Replace exact
CSS string/spacing assertions with less brittle checks that verify the scoped
selector and only essential load-bearing declarations or computed markup
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b7469713-a40e-4214-a43b-f3ca24e62781

📥 Commits

Reviewing files that changed from the base of the PR and between 7800540 and 2bb4b8e.

📒 Files selected for processing (19)
  • src/features/export/services/PDFPrintService.ts
  • src/features/export/services/__tests__/PDFPrintService.test.ts
  • src/features/plugins/builtin/builtin.test.ts
  • src/features/plugins/builtin/chatgptExport/conversation.test.ts
  • src/features/plugins/builtin/chatgptExport/conversation.ts
  • src/features/plugins/builtin/chatgptExport/exporter.test.ts
  • src/features/plugins/builtin/chatgptExport/exporter.ts
  • src/features/plugins/builtin/chatgptExport/i18n.ts
  • src/features/plugins/builtin/chatgptExport/index.test.ts
  • src/features/plugins/builtin/chatgptExport/index.ts
  • src/features/plugins/builtin/chatgptExport/selectionMode.test.ts
  • src/features/plugins/builtin/chatgptExport/selectionMode.ts
  • src/features/plugins/builtin/chatgptExport/styles.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts
  • src/features/plugins/builtin/chatgptExport/ui.test.ts
  • src/features/plugins/builtin/chatgptExport/ui.ts
  • src/features/plugins/builtin/index.ts
  • src/pages/content/pluginNativeRegistration.ts

Comment thread src/features/export/services/PDFPrintService.ts
Comment thread src/features/export/services/PDFPrintService.ts
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/exporter.test.ts
Comment thread src/features/plugins/builtin/chatgptExport/styles.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/ui.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2bb4b8e4ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/exporter.ts
Comment on lines +132 to +133
export function getChatGptExportCopy(): ChatGptExportCopy {
return /^zh(?:-|_|$)/i.test(navigator.language) ? ZH : EN;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Localize the export UI for all supported locales

This chooses copy from navigator.language rather than Voyager's stored language and only provides English and Chinese dictionaries; the manifest similarly supplies only zh and zh_TW. Users selecting ar, es, fr, ja, ko, pt, or ru therefore see English plugin metadata and controls, and even a Chinese Voyager setting is ignored when the browser language differs. Load the configured language and provide copy for the complete supported locale set.

AGENTS.md reference: AGENTS.md:L82-L82

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preference bug is fixed in 1f0e159: runtime copy follows the stored Voyager language. This plugin intentionally ships authored English and Chinese copy with English fallback; I am not adding unreviewed machine translations for the other locales in this fix.

Co-authored-by: Codex <codex@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 655ea91a99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts
Co-authored-by: Codex <codex@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts`:
- Around line 122-139: Add a test for the immediate account-change path in
handoffTemporaryChat, covering navigation from /u/0/ to /u/1/. Assert it returns
account-mismatch, preserves the existing composer draft, and removes the pending
state; then run bun run test, bun run lint, and bun run typecheck.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b363876c-3abf-4109-ab80-962d65fdc8de

📥 Commits

Reviewing files that changed from the base of the PR and between 2bb4b8e and 1f0e159.

📒 Files selected for processing (14)
  • src/features/export/services/PDFPrintService.ts
  • src/features/export/services/__tests__/PDFPrintService.test.ts
  • src/features/plugins/builtin/chatgptExport/conversation.test.ts
  • src/features/plugins/builtin/chatgptExport/conversation.ts
  • src/features/plugins/builtin/chatgptExport/exporter.test.ts
  • src/features/plugins/builtin/chatgptExport/exporter.ts
  • src/features/plugins/builtin/chatgptExport/i18n.ts
  • src/features/plugins/builtin/chatgptExport/index.test.ts
  • src/features/plugins/builtin/chatgptExport/index.ts
  • src/features/plugins/builtin/chatgptExport/styles.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts
  • src/features/plugins/builtin/chatgptExport/ui.test.ts
  • src/features/plugins/builtin/chatgptExport/ui.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/features/plugins/builtin/chatgptExport/i18n.ts
  • src/features/plugins/builtin/chatgptExport/index.test.ts
  • src/features/export/services/tests/PDFPrintService.test.ts
  • src/features/plugins/builtin/chatgptExport/ui.test.ts
  • src/features/plugins/builtin/chatgptExport/ui.ts
  • src/features/plugins/builtin/chatgptExport/conversation.ts
  • src/features/export/services/PDFPrintService.ts

Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f0e159199

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Co-authored-by: Codex <codex@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 096a5f8c69

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts Outdated
Comment thread src/features/export/services/DOMContentExtractor.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/export/services/DOMContentExtractor.ts`:
- Around line 82-87: Update extractAssistantContent and its processNodes flow to
include direct text nodes alongside child elements, preserving their DOM order
when combining ordinary user-content such as text surrounding links. Ensure
mixed content retains both surrounding text and extracted element output, and
add a regression case covering text before and after an anchor.
- Around line 82-87: Update the empty-content fallback in DOMContentExtractor so
standard ChatGPT file-pill metadata is extracted and merged into
ExtractedContent.attachments instead of relying only on
extractAssistantContent(element). Preserve the existing text and HTML fallback
behavior, and add a regression test covering standard file pills in the JSON
export.
- Around line 610-624: Update both anchor-handling branches, including the
standalone-link block and the corresponding branch around the other reported
location, to serialize anchor children through the existing inline extractor
instead of using link.textContent. Wrap the extracted HTML and Markdown in the
link destination while preserving rich child elements such as images, bold text,
and emphasis; retain the current URL fallback only when the extracted content is
empty.
- Around line 610-624: Validate link URLs in both anchor-export paths, including
the standalone-link branch around the visible `tagName === 'a'` logic and the
other anchor branch near the corresponding export code, before adding them to
`htmlParts` or `textParts`. Allow only intended schemes such as `http` and
`https`; skip or safely handle disallowed schemes like `javascript:` while
preserving existing label and escaping behavior for valid links.
- Around line 610-624: Update the standalone-link handling in the extraction
method to resolve relative href values against link.ownerDocument.baseURI before
generating either HTML or Markdown output, using the resolved destination
consistently for both paths. Apply the same normalization in the corresponding
link serialization logic around the later link-handling block.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7255be61-b37c-4558-87ea-2d2521087360

📥 Commits

Reviewing files that changed from the base of the PR and between 1f0e159 and 096a5f8.

📒 Files selected for processing (5)
  • src/features/export/services/DOMContentExtractor.ts
  • src/features/export/services/__tests__/DOMContentExtractor.test.ts
  • src/features/plugins/builtin/chatgptExport/exporter.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/features/plugins/builtin/chatgptExport/exporter.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts

Comment thread src/features/export/services/DOMContentExtractor.ts Outdated
Comment thread src/features/export/services/DOMContentExtractor.ts
Comment thread src/features/export/services/DOMContentExtractor.ts
Co-authored-by: Codex <codex@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37bb145ada

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/index.ts
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts Outdated
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Co-authored-by: Codex <codex@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: daab5703cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts
Co-authored-by: Codex <codex@users.noreply.github.com>
@TanChuping

Copy link
Copy Markdown
Author

The 80% docstring warning is not adopted. That threshold is not part of this repository's checks, and boilerplate docstrings on local plugin internals would add noise without improving a public API.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a5c6960b1a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/export/services/DOMContentExtractor.ts
Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts Outdated
@coderabbitai coderabbitai Bot mentioned this pull request Aug 9, 2026
10 tasks
Co-authored-by: Codex <codex@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/features/export/services/DOMContentExtractor.ts (1)

486-496: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Run the formula marker test before FormulaCopyService.extractLatexSource. Both extraction paths call extractLatexSource on every element node, and that helper performs closest plus up to two subtree querySelector scans. The cheap class/attribute test that gates the branch runs afterwards, so non-math subtrees are scanned repeatedly during export.

  • src/features/export/services/DOMContentExtractor.ts#L486-L496: compute the math-block / katex-display / data-math / data-math-source test first in processNodes, then call extractLatexSource only when it passes.
  • src/features/export/services/DOMContentExtractor.ts#L888-L897: apply the same ordering in processInlineContent, where the recursion repeats the scan at each nesting level.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/export/services/DOMContentExtractor.ts` around lines 486 - 496,
In src/features/export/services/DOMContentExtractor.ts lines 486-496 within
processNodes, evaluate the math-block/katex-display/data-math/data-math-source
marker before calling FormulaCopyService.extractLatexSource, and only extract
when the marker passes. Apply the same ordering in processInlineContent at lines
888-897 so both recursive paths avoid scanning non-math elements.
src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts (1)

139-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Dispose each PluginScope from a teardown hook.

Each test calls await scope.dispose() as the last statement. If an assertion fails earlier, the scope stays live. Its listeners, timers, and observers then leak into the following tests and can produce cascading failures that hide the original one. Register the scope in a shared list and dispose it in afterEach.

♻️ Proposed refactor
+const scopes: PluginScope[] = [];
+
+function createScope(): PluginScope {
+  const scope = new PluginScope();
+  scopes.push(scope);
+  return scope;
+}
+
+afterEach(async () => {
+  for (const scope of scopes.splice(0)) await scope.dispose();
+});

Then replace new PluginScope() with createScope() and remove the trailing await scope.dispose() calls.

Also applies to: 178-193

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts` around lines
139 - 149, Ensure every PluginScope created in the tests is disposed from an
afterEach teardown hook, including scopes created in the test blocks around
addComposer and handoffTemporaryChat. Register scopes through a shared
createScope helper backed by a list, replace direct new PluginScope() calls with
createScope(), and remove trailing await scope.dispose() statements.
src/features/formulaCopy/FormulaCopyService.ts (1)

186-186: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move extractLatexSource to a standalone helper module.

Import the helper directly from DOMContentExtractor, and re-export it from FormulaCopyService.ts to preserve existing callers. This avoids loading temml, webextension-polyfill, logger, and i18n dependencies for the two extractor call sites.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/formulaCopy/FormulaCopyService.ts` at line 186, Move
extractLatexSource out of the FormulaCopyService class into a standalone helper
module, then import that helper directly in DOMContentExtractor. Re-export the
helper from FormulaCopyService.ts so existing callers remain compatible, without
retaining the heavy service dependencies in the extractor paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/export/services/DOMContentExtractor.ts`:
- Around line 393-406: Update DOMContentExtractor.extractLinkLabel to normalize
and collapse whitespace in the resolved link text before constructing the
returned html and text values, while preserving the existing inline-content and
fallback behavior.

---

Nitpick comments:
In `@src/features/export/services/DOMContentExtractor.ts`:
- Around line 486-496: In src/features/export/services/DOMContentExtractor.ts
lines 486-496 within processNodes, evaluate the
math-block/katex-display/data-math/data-math-source marker before calling
FormulaCopyService.extractLatexSource, and only extract when the marker passes.
Apply the same ordering in processInlineContent at lines 888-897 so both
recursive paths avoid scanning non-math elements.

In `@src/features/formulaCopy/FormulaCopyService.ts`:
- Line 186: Move extractLatexSource out of the FormulaCopyService class into a
standalone helper module, then import that helper directly in
DOMContentExtractor. Re-export the helper from FormulaCopyService.ts so existing
callers remain compatible, without retaining the heavy service dependencies in
the extractor paths.

In `@src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts`:
- Around line 139-149: Ensure every PluginScope created in the tests is disposed
from an afterEach teardown hook, including scopes created in the test blocks
around addComposer and handoffTemporaryChat. Register scopes through a shared
createScope helper backed by a list, replace direct new PluginScope() calls with
createScope(), and remove trailing await scope.dispose() statements.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f25a327-82a3-46fe-8d10-bfad9bb4201f

📥 Commits

Reviewing files that changed from the base of the PR and between 37bb145 and f9ba16e.

📒 Files selected for processing (7)
  • src/features/export/services/DOMContentExtractor.ts
  • src/features/export/services/__tests__/DOMContentExtractor.test.ts
  • src/features/formulaCopy/FormulaCopyService.ts
  • src/features/plugins/builtin/chatgptExport/conversation.test.ts
  • src/features/plugins/builtin/chatgptExport/conversation.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.test.ts
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/features/plugins/builtin/chatgptExport/tempHandoff.ts
  • src/features/plugins/builtin/chatgptExport/conversation.ts

Comment thread src/features/export/services/DOMContentExtractor.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f9ba16e526

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/selectionMode.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
TanChuping and others added 3 commits August 10, 2026 15:24
Co-authored-by: Codex <codex@users.noreply.github.com>
Co-authored-by: Codex <codex@users.noreply.github.com>
@TanChuping
TanChuping force-pushed the feat/chatgpt-export-plugin branch from f414867 to 72ad036 Compare August 10, 2026 07:34
@TanChuping

Copy link
Copy Markdown
Author

Addressed the three folded review nits in \72ad036: formula extraction now runs only for marked math nodes, test scopes are disposed from \�fterEach, and the pure LaTeX-source helper is split out so DOM export no longer imports the heavier formula-copy service. The existing static API remains compatible.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72ad036f03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/selectionMode.ts
Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea9f8af0c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/selectionMode.ts Outdated
@TanChuping

Copy link
Copy Markdown
Author

@codex review

Please review the current HEAD (fa6165d) comprehensively and batch every remaining actionable finding into this single pass. Do not drip-feed additional issues one commit at a time; the serial review loop is wasting contributor time.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa6165d832

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/conversation.ts
Comment thread src/features/plugins/builtin/chatgptExport/index.ts Outdated
@TanChuping

Copy link
Copy Markdown
Author

Review boundary: the Codex reviewer responded to the explicitly requested comprehensive one-pass review with the two findings above; both are now addressed in 7003e4d with regression coverage. Treat that pass as complete. Do not restart the serial drip-feed loop by posting additional incremental findings against commits whose sole purpose is addressing this batch. Any later observations belong to a separate maintainer-requested review cycle and will be treated as out of scope here.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7003e4dd93

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/plugins/builtin/chatgptExport/tempHandoff.ts Outdated
Comment thread src/features/export/services/DOMContentExtractor.ts Outdated
@TanChuping

Copy link
Copy Markdown
Author

Review boundary: these two findings were on code that predates 7003e4d and therefore arrived after the prior one-pass review was explicitly declared complete. Both are nevertheless fixed in e00eb0a with regression coverage, and the threads are resolved. This review cycle is closed; please do not continue with serial incremental findings unless a maintainer explicitly requests a new review round.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e00eb0a401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +315 to +317
const signature = `${target?.scrollHeight ?? 0}:${mounted
.map(({ id, text }) => `${id}:${text}`)
.join('|')}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include rich DOM state in bottom stability checks

After the generation-state fix, a response can still change without changing this signature: for example, a generated-image placeholder can keep the same text and dimensions while its <img> source is populated after the three 120 ms samples. The collector then returns the last detached clone before the image appeared, so Markdown, JSON, and PDF silently omit that content; include relevant rich DOM state in the signature or explicitly wait for pending media placeholders to settle.

Useful? React with 👍 / 👎.

mode: 'attachment',
directive: `${title}\n\n${attachmentInstruction}`,
attachment: transcript,
filename: `chatgpt-temporary-handoff-${stamp}.md`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Give each handoff attachment a unique filename

When two temporary-chat handoffs occur on the same day, both attachments receive this identical filename. If the first attachment preview remains in the normal composer, dispatchAttachmentAndVerify() treats that name match as proof that the second transcript was already uploaded, skips its paste, inserts only the new directive, and clears the pending payload; the user is therefore handed off with the old transcript. Add a per-handoff timestamp or nonce to the filename so the retry-by-name logic cannot collide across distinct transcripts.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫤

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant