Skip to content

feat(ext): bookmark all open tabs in one action (#46)#50

Merged
paperhurts merged 1 commit into
feat/extension-ui-polishfrom
feat/bookmark-all-tabs
Jun 13, 2026
Merged

feat(ext): bookmark all open tabs in one action (#46)#50
paperhurts merged 1 commit into
feat/extension-ui-polishfrom
feat/bookmark-all-tabs

Conversation

@paperhurts

Copy link
Copy Markdown
Owner

Closes #46.

Stacked on #49 (base = feat/extension-ui-polish). Merge #49 first; this PR's diff is just the bookmark-all-tabs work. It depends on save-result-view.ts introduced in #49 and shares popup.ts. After #49 merges I'll retarget this to main.

What

A "Save all tabs" button in the popup saves every http(s) tab in the current window in one batched bookmarks.json write — for closing out a research session.

Behavior

  • Batched single write. Builds a Bookmark per tab and persists them through one updateBookmarksOrBootstrap call (one client.update, replay-safe), not one-per-tab.
  • Dedupe. New core addBookmarks(file, bookmarks, nowIso) skips any candidate whose URL matches an existing active bookmark, and de-dupes within the batch. Tombstoned URLs aren't treated as duplicates (so a deleted page can be re-saved). The dedupe runs inside the mutator, so it stays correct across a 409 replay.
  • Folder. Saves group into a dated Session YYYY-MM-DD folder (the issue's example). Folder is a saveAllTabs option; the popup passes the dated name.
  • URL handling. The popup restricts the batch to http(s) tabs. Note: isSafeBookmarkUrl (the XSS allowlist) intentionally permits chrome:/about:, so it alone wouldn't skip browser-internal tabs — saveAllTabs still applies it as a defense-in-depth guard (skippedUnsafe), but the "only real web pages" policy lives in the popup.
  • Feedback. Status reads ✓ saved N tabs (skipped M), then the popup auto-closes (reusing the Popup save button stuck in 'saving…' state with progress cursor after successful save #43 pattern).

⚠️ Permission change

Adds the tabs permission to both manifests — required to read every tab's URL/title. This widens the install prompt to "Read your browsing history". Calling out explicitly for review.

Files

  • core: addBookmarks + export.
  • extension-shared: bookmark-factory (folder), save-flow (saveAllTabs + SaveAllTabsResult/SaveFailure), save-result-view (applySaveAllResult), popup.ts/popup.html.
  • manifests (chrome + firefox); CLAUDE.md roadmap; both shell READMEs.

Out of scope (per issue)

History import; cross-window "all windows"; a folder/root chooser UI (dated folder is the default).

Verification

  • core tests: 82 (+5 addBookmarks)
  • extension-shared tests: 115 (+6 saveAllTabs, +3 applySaveAllResult)
  • typecheck (core, shared) clean; chrome + firefox builds clean

🤖 Generated with Claude Code

Adds a "Save all tabs" popup button that saves every http(s) tab in the
current window in one batched bookmarks.json write.

core:
- addBookmarks(file, bookmarks, nowIso): pure, replay-safe batch append that
  de-dupes by URL against existing *active* bookmarks and within the batch.
  Tombstoned URLs aren't treated as duplicates (re-save allowed). Exported.

extension-shared:
- bookmark-factory: optional `folder` input (default "").
- save-flow: saveAllTabs(...) + SaveAllTabsResult (shared SaveFailure type,
  reuses classify). Pre-filters unsafe schemes via isSafeBookmarkUrl, builds a
  bookmark per safe tab, then one updateBookmarksOrBootstrap call whose mutator
  applies addBookmarks; reports saved / skippedUnsafe / skippedDuplicate / total.
- save-result-view: applySaveAllResult(...) — count message + Saved ✓ + auto-close.
- popup: "Save all tabs" button (magenta secondary) + handler. Restricts the
  batch to http(s) tabs (isSafeBookmarkUrl also allows chrome:/about:, which
  aren't useful bookmarks); groups saves into a dated `Session YYYY-MM-DD` folder.

manifests: add the `tabs` permission (chrome + firefox). NOTE: this widens the
install prompt to "Read your browsing history" — needed to read every tab's
url/title.

tests: addBookmarks (5), saveAllTabs (6), applySaveAllResult (3).
docs: CLAUDE.md roadmap item 8 -> done; smoke-test steps in both READMEs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@paperhurts paperhurts merged commit b585a41 into feat/extension-ui-polish Jun 13, 2026
@paperhurts paperhurts deleted the feat/bookmark-all-tabs branch June 13, 2026 22:04
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