Skip to content

Harden capture: Readability, item index, Reader updates, toast retry - #2

Merged
cursor[bot] merged 5 commits into
mainfrom
cursor/review-correctness-fixes-b20b
Sep 4, 2026
Merged

cursor[bot] merged 5 commits into
mainfrom
cursor/review-correctness-fixes-b20b

Conversation

@randomradio

@randomradio randomradio commented Aug 30, 2026 •

Copy link
Copy Markdown
Owner

What changed

Follow-up to the review in this PR. The four remaining high-value items are now implemented, plus unit tests for every exported function.

Merged latest main (feat: make Pinboard and Readwise capture optional). Conflicts were complementary: this branch keeps retry/toast/Readability, and Pinboard now honors the save-on-capture toggle.

1. Real Readability

  • Bundles @mozilla/readability as dist/readability.js and attaches window.Readability in the isolated world.
  • Extraction still falls back to article/main, then document.body.innerText.

2. Indexed local items

  • findItemByUrl / listItems use an itemIndex (ids + byUrl) instead of chrome.storage.local.get(null).
  • Ordinary lookups no longer load API tokens.
  • Existing item: records are migrated once if no index exists.

3. Readwise create-or-update

  • POST /api/v3/save/ still creates the document.
  • HTTP 200 (already exists) now PATCH /api/v3/update/<id>/ with title, summary, and tags.
  • If we already stored readwiseDocumentId, later saves and tag edits PATCH directly.
  • The toast “Reader” link uses the document URL from the API when present.

4. Content-script toast

  • Capture UI is injected as content/toast.js (not an inline executeScript function).
  • Failed destinations show a Retry chip.
  • Edit tags updates the local item and re-syncs Pinboard/Readwise.

5. Unit tests for each exported function

  • Added tests for LLM tagging, Pinboard, Readwise, exporters, tab extraction, permissions, storage, preview, item index, toast helpers, and settings destination rendering.
  • Extracted a few pure helpers (preview-draft, toast-helpers, options-helpers) so they can be tested without Chrome/DOM bootstrapping.
  • Chrome-wired service-worker and options-page event handlers remain integration-level (not unit-tested).

6. CI

  • CI / test failed in actions/setup-node (cache: pnpm) with packages field missing or empty.
  • pnpm-workspace.yaml now declares packages: ['.'], and CI/release use pnpm 10 so pnpm store path works with allowBuilds.

Earlier review fixes still in this PR

  • Capture continues when LLM tagging fails.
  • CJK tags are kept.
  • Toast/tag HTML is no longer interpolated unsafely.
  • Pinboard tag import no longer double-counts.
  • Unused notifications / alarms permissions removed.
  • CI runs typecheck, tests, and build.

Tests

  • pnpm typecheck
  • pnpm test — 136 passing
  • pnpm build

Manual check after loading dist/

  • Save a page: toast appears with destination chips.
  • Fail or disconnect Pinboard/Readwise, click Retry.
  • Click Edit tags, change tags, confirm Reader/Pinboard update.
  • Save the same URL twice: local/Pinboard/Readwise skip or update in place.
  • Import Pinboard tags twice: counts do not double.

I could not load the unpacked extension in this environment’s browser; verification here is tests + build.

Open in Web Open in Cursor 

Keep saving locally when the LLM fails, stop dropping CJK tags, and
avoid treating page-injected tags as HTML. Also align extraction with
the isolated world, stop double-counting Pinboard imports, drop unused
permissions, and add CI for typecheck/tests.

Co-authored-by: i.an <randomradio@users.noreply.github.com>
@randomradio
randomradio marked this pull request as ready for review August 30, 2026 14:55
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-08-30T14:58:33.216240Z a6bba58 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: a6bba58279

ℹ️ 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/background/tabs.ts
if (root) {
const clone = root.cloneNode(true) as HTMLElement;
clone.querySelectorAll('script, style, noscript, nav, footer, aside, iframe, [role="navigation"]').forEach((el) => el.remove());
text = (clone.innerText || '').replace(/\n{3,}/g, '\n\n').trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Extract only rendered text from the page

When the bundled Readability stub is used, this reads innerText from a detached clone. Detached elements are not rendered, so innerText falls back to descendant text content rather than applying the page's rendered visibility; CSS-hidden text inside an article or main can therefore enter the excerpt and be sent to the configured LLM. Derive visibility from the connected DOM before cloning/removing unwanted elements.

Useful? React with 👍 / 👎.

Comment thread src/background/index.ts
try {
if (!tab?.id) throw new Error('No active tab');
const settings = await getSettings();
await ensureOriginPermission(settings.llm.baseUrl);

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 Continue local capture when LLM permission is denied

On a first toolbar capture for an LLM origin that has not been granted, declining the optional-host permission makes ensureOriginPermission throw before extraction and captureAndSync, so the page is not saved locally or sent to configured Pinboard/Readwise destinations. This bypasses the new pipeline behavior that records LLM failures while continuing the capture; treat a denied LLM permission as an LLM destination error rather than aborting the entire toolbar action.

Useful? React with 👍 / 👎.

Comment thread src/ui/options.ts
Comment on lines +289 to +291
} catch {
statusEl.textContent = 'Advanced config must be valid JSON.';
return;

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 Validate advanced JSON before granting host access

If a user enters a new LLM origin and invalid advanced JSON, the code grants permission for the new origin first and then returns here without saving the settings or removing that permission. The extension is left with unused host access that is no longer represented by its saved LLM origin; parse and validate the form before requesting permission, or revoke the newly granted permission on this failure path.

Useful? React with 👍 / 👎.

Bundle Mozilla Readability for extraction, look up saved items through
an index instead of scanning local storage, create-or-update Readwise
documents when they already exist, and move the capture toast into a
content script that can retry destinations and edit tags.

Co-authored-by: i.an <randomradio@users.noreply.github.com>
@cursor cursor Bot changed the title Harden capture after a full code review Harden capture: Readability, item index, Reader updates, toast retry Aug 30, 2026
cursoragent and others added 3 commits August 30, 2026 15:46
Cover each exported helper in background, common, toast, and settings
preview code, including LLM, Pinboard, Readwise, exporters, and storage.

Co-authored-by: i.an <randomradio@users.noreply.github.com>
setup-node cache: pnpm runs `pnpm store path`, which pnpm 9 rejects
when pnpm-workspace.yaml has only allowBuilds. Declare the root
package and run CI on pnpm 10 to match local.

Co-authored-by: i.an <randomradio@users.noreply.github.com>
Keep main's save-on-capture toggle and this branch's destination
retry, toast, and unit tests. Pinboard skips when capture is off.

Co-authored-by: i.an <randomradio@users.noreply.github.com>
@cursor
cursor Bot merged commit 26b5117 into main Sep 4, 2026
1 check passed
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.

2 participants