GitSyncMarks v3.0.0
Major release: multi-provider Git sync (GitHub, GitLab, Codeberg, Gitea family), Bitwarden / Vaultwarden backup to Git, nested-card UI, profile transfer, push mirrors, live sync progress, and full 12-language store listings. Builds on the 2.x foundation (three-way merge, Linkwarden, Smart Search, sync history, context menu, settings sync). Pre-releases: v3.0.0-beta.1 … v3.0.0-beta.7.
Added
- Multi-provider support: Provider capability map (
lib/git-provider-common.js). Separate UI entries for Forgejo, Codeberg, and Gogs (shared Gitea-family adapter). GitLab adapter (lib/providers/gitlab-api.js) for gitlab.com, self-managed instances, and subgroup project paths. Shared provider UI (lib/provider-ui.js). See docs/PROVIDERS.md. - Profile bookmark transfer: Copy bookmarks between profiles (full replace or folder merge) from the Profile tab. Supports push to target repository and sync-state update (
lib/profile-transfer.js,pushForProfile()). - Push mirror destinations: Optional secondary Git remotes receive a push-only copy after each successful primary commit (
lib/mirror-push.js,mirrors[]on profiles, per-mirror tokens). - Clean remote orphans: Sync sub-tab action to preview and delete remote bookmark files not present in local bookmarks (
previewRemoteOrphans(),cleanRemoteOrphans()inlib/sync-core.js). - Bitwarden / Vaultwarden backup to Git: Files → Bitwarden Backup — upload a password-protected encrypted JSON export, optional additional
gitsyncmarks-enc:v1wrap, push tobackups/bitwarden/(configurable), list, download, and delete remote backups. CLI/Git workflow guide and example workflowdocs/bitwarden-backup.example.yml. Plaintext JSON/CSV rejected; no Bitwarden API or vault decryption. Seedocs/IDEAS-BITWARDEN-BACKUP.md. - Gitea sync performance analysis:
docs/GITEA-PERFORMANCE.md(Contents vs Git Data API, compatibility matrix, try-first recommendation). Benchmark scriptscripts/benchmark-gitea-sync.js—npm run test:gitea-benchmark:estimate/npm run test:gitea-benchmark(env:GITSYNCMARKS_GITEA_*in.env.example).
Changed
- Unified nested-card UI: Feature subsections use
.card-nested(inset surface with title, description, and action row) across Options, setup wizard panels, popup conflict/status boxes, search results, and Linkwarden save metadata. Replaces flatautomation-blockdividers. Shared tokens inshared.css:--color-surface-nested,.panel-compact. - Bitwarden Git backup password: Stored per profile on this device (
bitwardenBackupPassword:{profileId}); legacy device-wide key migrates on first load. - Bitwarden backup list: Each remote backup row has Delete next to Download (commits removal from the repository after confirmation). Action buttons use a dedicated table layout so Download/Delete are not squashed beside long paths.
- Bitwarden backup delete: Inline confirmation dialog (consistent with profile delete) instead of
window.confirm. - Fast profile switch:
switchProfile()skips no-op commits, avoids post-commit full refetch, and loads the target profile fromlastSyncFileswhen remote HEAD matcheslastCommitSha; otherwise delta-pulls viafetchRemoteFileMap()with cached blob SHAs (lib/profile-switch-logic.js,lib/sync-diff.js). - Profile switch progress: Options page shows step progress (
Switching profile — 1 of 3) and per-file push progress during step 1 on Gitea-family providers. - Transfer progress: Profile transfer dialog shows spinner plus step text (e.g.
$1 of $2 filesduring push). Progress uses a dedicated runtime port so updates are not lost to a connect/message race. - Sync progress: Popup, onboarding wizard, connection-tab first push, pull, and Generate now show live step text (e.g.
$1 / $2 filesduring push,$1 / $2 bookmarksduring pull, generating files before commit). Uses asyncProgressruntime port (lib/sync-progress.js). - Gitea-family remote reads:
buildRemoteMaps()tries git tree + batched blob GETs before Contents API fallback (~18× faster full pull on Codeberg in benchmarks; see GITEA-PERFORMANCE.md). - Gitea-family writes:
GiteaAPI.atomicCommit()tries batchedPOST /git/blobs+ layeredPOST /git/trees(SHA refs, one commit) before Contents API sequential fallback. Console warning when git-data write falls back to Contents API (one commit per file). - Connection tab and onboarding wizard show provider-specific token and owner placeholders and hints (Gitea tokens are not
ghp_…GitHub-style strings). - Git repos bookmark folder adapts folder prefix per provider (
GitHubRepos,GiteaRepos, etc.). - Provider-neutral UI copy where all Git providers are meant (push/pull labels, connection tab title).
- Search results: Single border per result row (removed redundant panel wrapper border).
- Profile inline dialogs: Aligned with
panel-compactsurface tokens. - What's new: Popup shows 3.0 highlights (multi-provider, Bitwarden backup, nested UI) after update.
- i18n: Completed 3.0 strings (multi-provider UI, mirrors, transfer, sync history, wizard sync choice, clean orphans, Bitwarden backup) in all 12 locales. Apply script:
node scripts/apply-3.0-i18n.mjs. - Store listings: Full 3.0 feature descriptions in all 12 Chrome Web Store and Firefox Add-ons locales.
Fixed
- Setup wizard overwrote remote bookmarks (#146): Connection test no longer pushes to the repository. After check, user chooses pull, merge/sync, push, initialize structure, or skip — with confirm dialogs and push warnings when remote bookmarks exist.
- Codeberg / Gitea connection test falsely reported “Invalid token” when the PAT lacked
read:userbut had repository access (403 onGET /api/v1/user).GiteaAPInow uses a non-throwing_fetchand treats 403 on/useras ambiguous-valid, then verifies via repo endpoints. - Settings export/import and Git settings sync: Token read/write now uses
getProfileToken()/setEncryptedProfileToken()fromprofile-manager.js(supports mirror token layout and legacyprofileTokensmigration). Import restoresgitProvider,serverUrl, and legacyrepoOwner/githubTokenfields. - Codeberg sync/push failed with CORS / “Network error”:
https://codeberg.org/*was missing from manifesthost_permissions. Codeberg is a fixed public host (like GitLab.com) and does not request optional runtime permission, so API calls were blocked by the browser. - Bitwarden backup download with Git encryption: Decrypting
.gitsyncmarks.encfiles no longer fails with a false “Wrong password” error (caused by reassigning aconstblob). Download also uses the password field when typed, retries with a fresh prompt on mismatch, and auto-saves the password after a successful encrypted upload. - Custom Bitwarden backup folder sync isolation:
filterForDiff(), orphan cleanup, mirror filter, profile transfer, profile-switch push, and sync base state now respect each profile'sbitwardenBackupPath(not only the defaultbackups/bitwarden/prefix). - GitLab connection test on empty repo: Repos with commits but no
bookmarks/folder (e.g. README-only) no longer fail with “Git tree listing empty under base path”; connection test reports success and offers path initialization. - Deleted bookmark reappears after sync: Profile switch cached local bookmarks into
lastSyncFileswithout keeping removed paths, so the three-way base no longer recorded the deletion. The next sync took path 8 (remote-only change) and pulled the bookmark back from the remote.mergeLocalIntoSyncFiles()now keeps removed paths in the base until a successful push; successful switch pushes usesaveSyncState(). When the base is already stale and the user edited bookmarks locally, sync path 8 pushes remote deletes instead of pulling (localModifiedSinceSync,buildStaleBasePushChanges()). - Gitea replace push left orphan folders: The Contents-API commit fallback skipped file deletions (
content === null), so profile transfer or replace push could add new folders while old ones remained on the remote. Fallback now commits one path at a time viaatomicCommit, including deletes. - Stale “Last commit” in popup after Gitea sync: When sync found no content changes (path 6), the stored commit SHA was not refreshed from the remote HEAD. Sync now updates
lastCommitShafrom the fetched remote when it differs from the stored base. - Popup conflict buttons said “GitHub” for non-GitHub profiles: Push/pull labels and push-success message are provider-neutral (“Remote”).
- Transfer merge mode: Merge hint, preview warnings, and confirm dialog when the target already has remote data (duplicate-folder risk). Preview warns when the transfer result contains slug-collision folder pairs. Replace push runs a post-commit orphan sweep on the target remote. Connection test used form values while background sync read persisted settings (race/mismatch). First sync now passes connection fields to
bootstrapFirstSync. Gitea writes use the Contents API instead of the batch Change Files endpoint. Sync/push paths share a Gitea Contents-API fallback when a write still fails. - Gitea push crash (
reading 'sha'): Normalize Gitea API responses (sha/id/ commit tree metadata) ingetLatestCommitSha,getCommit, andcreateOrUpdateFile; cache commit tree SHA after Contents API writes so post-push state save does not fail on missingtree.sha. - Gitea sync in MV3 service worker: Replaced dynamic
import()ofdebug-log.jswith static imports (dynamic import is blocked in ServiceWorkerGlobalScope). - Gitea sync after successful push (
Commit … has no tree SHA): Gitea remote reads use the Contents API viabuildRemoteMaps()with a ref cascade, bypassing unreliable git/trees metadata on self-hosted instances. - CI E2E: Playwright extension fixture waits longer for the MV3 service worker and uses a 60s CI test timeout, fixing flaky
main tabs activate matching panelssetup failures.
Installation
Chrome / Chromium / Edge / Brave
- Download
GitSyncMarks-v3.0.0-chrome.zip - Extract the ZIP
- Open
chrome://extensions/ - Enable Developer mode (toggle in the top right)
- Click Load unpacked
- Select the extracted folder
Firefox
- Download
GitSyncMarks-v3.0.0-firefox.zip - Open
about:debugging#/runtime/this-firefox - Click Load Temporary Add-on...
- Select the ZIP file or the
manifest.jsoninside the extracted folder
More info: README